1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ppapi/tests/test_file_io.h" 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <stdio.h> 10 #include <string.h> 11 #include <sys/stat.h> 12 #include <sys/types.h> 13 14 #include <vector> 15 16 #include "ppapi/c/dev/ppb_testing_dev.h" 17 #include "ppapi/c/pp_errors.h" 18 #include "ppapi/c/ppb_file_io.h" 19 #include "ppapi/c/private/pp_file_handle.h" 20 #include "ppapi/c/trusted/ppb_file_io_trusted.h" 21 #include "ppapi/cpp/file_io.h" 22 #include "ppapi/cpp/file_ref.h" 23 #include "ppapi/cpp/file_system.h" 24 #include "ppapi/cpp/instance.h" 25 #include "ppapi/cpp/module.h" 26 #include "ppapi/cpp/private/file_io_private.h" 27 #include "ppapi/cpp/private/pass_file_handle.h" 28 #include "ppapi/tests/test_utils.h" 29 #include "ppapi/tests/testing_instance.h" 30 31 #if defined(PPAPI_OS_WIN) 32 # include <io.h> 33 # include <windows.h> 34 // TODO(hamaji): Use standard windows APIs instead of compatibility layer? 35 # define lseek _lseek 36 # define read _read 37 # define write _write 38 # define ssize_t int 39 #else 40 # include <sys/mman.h> 41 # include <unistd.h> 42 #endif 43 44 REGISTER_TEST_CASE(FileIO); 45 46 namespace { 47 48 std::string ReportMismatch(const std::string& method_name, 49 const std::string& returned_result, 50 const std::string& expected_result) { 51 return method_name + " returned '" + returned_result + "'; '" + 52 expected_result + "' expected."; 53 } 54 55 std::string ReportOpenError(int32_t open_flags) { 56 static const char* kFlagNames[] = { 57 "PP_FILEOPENFLAG_READ", 58 "PP_FILEOPENFLAG_WRITE", 59 "PP_FILEOPENFLAG_CREATE", 60 "PP_FILEOPENFLAG_TRUNCATE", 61 "PP_FILEOPENFLAG_EXCLUSIVE" 62 }; 63 64 std::string result = "FileIO:Open had unexpected behavior with flags: "; 65 bool first_flag = true; 66 for (int32_t mask = 1, index = 0; mask <= PP_FILEOPENFLAG_EXCLUSIVE; 67 mask <<= 1, ++index) { 68 if (mask & open_flags) { 69 if (first_flag) { 70 first_flag = false; 71 } else { 72 result += " | "; 73 } 74 result += kFlagNames[index]; 75 } 76 } 77 if (first_flag) 78 result += "[None]"; 79 80 return result; 81 } 82 83 int32_t ReadEntireFile(PP_Instance instance, 84 pp::FileIO* file_io, 85 int32_t offset, 86 std::string* data, 87 CallbackType callback_type) { 88 TestCompletionCallback callback(instance, callback_type); 89 char buf[256]; 90 int32_t read_offset = offset; 91 92 for (;;) { 93 callback.WaitForResult( 94 file_io->Read(read_offset, buf, sizeof(buf), callback.GetCallback())); 95 if (callback.result() < 0) 96 return callback.result(); 97 if (callback.result() == 0) 98 break; 99 read_offset += callback.result(); 100 data->append(buf, callback.result()); 101 } 102 103 return PP_OK; 104 } 105 106 int32_t ReadToArrayEntireFile(PP_Instance instance, 107 pp::FileIO* file_io, 108 int32_t offset, 109 std::string* data, 110 CallbackType callback_type) { 111 TestCompletionCallbackWithOutput< std::vector<char> > callback( 112 instance, callback_type); 113 114 for (;;) { 115 callback.WaitForResult(file_io->Read(offset, 256, callback.GetCallback())); 116 int32_t rv = callback.result(); 117 if (rv < 0) 118 return rv; 119 if (rv == 0) 120 break; 121 const std::vector<char>& output = callback.output(); 122 assert(rv == static_cast<int32_t>(output.size())); 123 offset += rv; 124 data->append(output.begin(), output.end()); 125 } 126 127 return PP_OK; 128 } 129 130 bool ReadEntireFileFromFileHandle(int fd, std::string* data) { 131 if (lseek(fd, 0, SEEK_SET) < 0) 132 return false; 133 data->clear(); 134 135 int ret; 136 do { 137 char buf[8192]; 138 ret = read(fd, buf, sizeof(buf)); 139 if (ret > 0) 140 data->append(buf, ret); 141 } while (ret > 0); 142 return ret == 0; 143 } 144 145 int32_t WriteEntireBuffer(PP_Instance instance, 146 pp::FileIO* file_io, 147 int32_t offset, 148 const std::string& data, 149 CallbackType callback_type) { 150 TestCompletionCallback callback(instance, callback_type); 151 int32_t write_offset = offset; 152 const char* buf = data.c_str(); 153 int32_t size = data.size(); 154 155 while (write_offset < offset + size) { 156 callback.WaitForResult(file_io->Write(write_offset, 157 &buf[write_offset - offset], 158 size - write_offset + offset, 159 callback.GetCallback())); 160 if (callback.result() < 0) 161 return callback.result(); 162 if (callback.result() == 0) 163 return PP_ERROR_FAILED; 164 write_offset += callback.result(); 165 } 166 167 return PP_OK; 168 } 169 170 } // namespace 171 172 bool TestFileIO::Init() { 173 return CheckTestingInterface() && EnsureRunningOverHTTP(); 174 } 175 176 void TestFileIO::RunTests(const std::string& filter) { 177 RUN_CALLBACK_TEST(TestFileIO, Open, filter); 178 RUN_CALLBACK_TEST(TestFileIO, OpenDirectory, filter); 179 RUN_CALLBACK_TEST(TestFileIO, ReadWriteSetLength, filter); 180 RUN_CALLBACK_TEST(TestFileIO, ReadToArrayWriteSetLength, filter); 181 RUN_CALLBACK_TEST(TestFileIO, TouchQuery, filter); 182 RUN_CALLBACK_TEST(TestFileIO, AbortCalls, filter); 183 RUN_CALLBACK_TEST(TestFileIO, ParallelReads, filter); 184 RUN_CALLBACK_TEST(TestFileIO, ParallelWrites, filter); 185 RUN_CALLBACK_TEST(TestFileIO, NotAllowMixedReadWrite, filter); 186 RUN_CALLBACK_TEST(TestFileIO, WillWriteWillSetLength, filter); 187 RUN_CALLBACK_TEST(TestFileIO, RequestOSFileHandle, filter); 188 RUN_CALLBACK_TEST(TestFileIO, RequestOSFileHandleWithOpenExclusive, filter); 189 RUN_CALLBACK_TEST(TestFileIO, Mmap, filter); 190 191 // TODO(viettrungluu): add tests: 192 // - that PP_ERROR_PENDING is correctly returned 193 // - that operations respect the file open modes (flags) 194 } 195 196 std::string TestFileIO::TestOpen() { 197 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 198 199 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 200 pp::FileRef file_ref(file_system, "/file_open"); 201 202 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 203 CHECK_CALLBACK_BEHAVIOR(callback); 204 ASSERT_EQ(PP_OK, callback.result()); 205 206 std::string result; 207 result = MatchOpenExpectations( 208 &file_system, 209 PP_FILEOPENFLAG_READ, 210 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS); 211 if (!result.empty()) 212 return result; 213 214 // Test the behavior of the power set of 215 // { PP_FILEOPENFLAG_CREATE, 216 // PP_FILEOPENFLAG_TRUNCATE, 217 // PP_FILEOPENFLAG_EXCLUSIVE }. 218 219 // First of all, none of them are specified. 220 result = MatchOpenExpectations( 221 &file_system, 222 PP_FILEOPENFLAG_WRITE, 223 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS); 224 if (!result.empty()) 225 return result; 226 227 result = MatchOpenExpectations( 228 &file_system, 229 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE, 230 CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS); 231 if (!result.empty()) 232 return result; 233 234 result = MatchOpenExpectations( 235 &file_system, 236 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_EXCLUSIVE, 237 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS); 238 if (!result.empty()) 239 return result; 240 241 result = MatchOpenExpectations( 242 &file_system, 243 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_TRUNCATE, 244 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | TRUNCATE_IF_EXISTS); 245 if (!result.empty()) 246 return result; 247 248 result = MatchOpenExpectations( 249 &file_system, 250 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE | 251 PP_FILEOPENFLAG_EXCLUSIVE, 252 CREATE_IF_DOESNT_EXIST | DONT_OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS); 253 if (!result.empty()) 254 return result; 255 256 result = MatchOpenExpectations( 257 &file_system, 258 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_TRUNCATE, 259 CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | TRUNCATE_IF_EXISTS); 260 if (!result.empty()) 261 return result; 262 263 result = MatchOpenExpectations( 264 &file_system, 265 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_EXCLUSIVE | 266 PP_FILEOPENFLAG_TRUNCATE, 267 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | TRUNCATE_IF_EXISTS); 268 if (!result.empty()) 269 return result; 270 271 result = MatchOpenExpectations( 272 &file_system, 273 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE | 274 PP_FILEOPENFLAG_EXCLUSIVE | PP_FILEOPENFLAG_TRUNCATE, 275 CREATE_IF_DOESNT_EXIST | DONT_OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS); 276 if (!result.empty()) 277 return result; 278 279 // Invalid combination: PP_FILEOPENFLAG_TRUNCATE without 280 // PP_FILEOPENFLAG_WRITE. 281 result = MatchOpenExpectations( 282 &file_system, 283 PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_TRUNCATE, 284 INVALID_FLAG_COMBINATION); 285 if (!result.empty()) 286 return result; 287 288 PASS(); 289 } 290 291 std::string TestFileIO::TestOpenDirectory() { 292 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 293 294 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 295 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 296 CHECK_CALLBACK_BEHAVIOR(callback); 297 ASSERT_EQ(PP_OK, callback.result()); 298 299 // Make a directory. 300 pp::FileRef dir_ref(file_system, "/test_dir_open_directory"); 301 callback.WaitForResult(dir_ref.MakeDirectory(callback.GetCallback())); 302 CHECK_CALLBACK_BEHAVIOR(callback); 303 ASSERT_EQ(PP_OK, callback.result()); 304 305 // Open the directory. This is expected to fail since directories cannot be 306 // opened. 307 pp::FileIO file_io(instance_); 308 callback.WaitForResult(file_io.Open(dir_ref, PP_FILEOPENFLAG_READ, 309 callback.GetCallback())); 310 CHECK_CALLBACK_BEHAVIOR(callback); 311 ASSERT_EQ(PP_ERROR_NOTAFILE, callback.result()); 312 313 PASS(); 314 } 315 316 std::string TestFileIO::TestReadWriteSetLength() { 317 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 318 319 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 320 pp::FileRef file_ref(file_system, "/file_read_write_setlength"); 321 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 322 CHECK_CALLBACK_BEHAVIOR(callback); 323 ASSERT_EQ(PP_OK, callback.result()); 324 325 pp::FileIO file_io(instance_); 326 callback.WaitForResult(file_io.Open(file_ref, 327 PP_FILEOPENFLAG_CREATE | 328 PP_FILEOPENFLAG_TRUNCATE | 329 PP_FILEOPENFLAG_READ | 330 PP_FILEOPENFLAG_WRITE, 331 callback.GetCallback())); 332 CHECK_CALLBACK_BEHAVIOR(callback); 333 ASSERT_EQ(PP_OK, callback.result()); 334 335 // Write something to the file. 336 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0, 337 "test_test", callback_type()); 338 ASSERT_EQ(PP_OK, rv); 339 340 // Attempt to read a negative number of bytes; it should fail. 341 char buf[256]; 342 callback.WaitForResult(file_io.Read(0, 343 buf, 344 -1, 345 callback.GetCallback())); 346 CHECK_CALLBACK_BEHAVIOR(callback); 347 ASSERT_EQ(PP_ERROR_FAILED, callback.result()); 348 349 // Read the entire file. 350 std::string read_buffer; 351 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer, 352 callback_type()); 353 ASSERT_EQ(PP_OK, rv); 354 ASSERT_EQ(std::string("test_test"), read_buffer); 355 356 // Truncate the file. 357 callback.WaitForResult(file_io.SetLength(4, callback.GetCallback())); 358 CHECK_CALLBACK_BEHAVIOR(callback); 359 ASSERT_EQ(PP_OK, callback.result()); 360 361 // Check the file contents. 362 read_buffer.clear(); 363 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer, 364 callback_type()); 365 ASSERT_EQ(PP_OK, rv); 366 ASSERT_EQ(std::string("test"), read_buffer); 367 368 // Try to read past the end of the file. 369 read_buffer.clear(); 370 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 100, &read_buffer, 371 callback_type()); 372 ASSERT_EQ(PP_OK, rv); 373 ASSERT_TRUE(read_buffer.empty()); 374 375 // Write past the end of the file. The file should be zero-padded. 376 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 8, "test", 377 callback_type()); 378 ASSERT_EQ(PP_OK, rv); 379 380 // Check the contents of the file. 381 read_buffer.clear(); 382 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer, 383 callback_type()); 384 ASSERT_EQ(PP_OK, rv); 385 ASSERT_EQ(std::string("test\0\0\0\0test", 12), read_buffer); 386 387 // Extend the file. 388 callback.WaitForResult(file_io.SetLength(16, callback.GetCallback())); 389 CHECK_CALLBACK_BEHAVIOR(callback); 390 ASSERT_EQ(PP_OK, callback.result()); 391 392 // Check the contents of the file. 393 read_buffer.clear(); 394 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer, 395 callback_type()); 396 ASSERT_EQ(PP_OK, rv); 397 ASSERT_EQ(std::string("test\0\0\0\0test\0\0\0\0", 16), read_buffer); 398 399 // Write in the middle of the file. 400 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 4, "test", 401 callback_type()); 402 ASSERT_EQ(PP_OK, rv); 403 404 // Check the contents of the file. 405 read_buffer.clear(); 406 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer, 407 callback_type()); 408 ASSERT_EQ(PP_OK, rv); 409 ASSERT_EQ(std::string("testtesttest\0\0\0\0", 16), read_buffer); 410 411 // Read from the middle of the file. 412 read_buffer.clear(); 413 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 4, &read_buffer, 414 callback_type()); 415 ASSERT_EQ(PP_OK, rv); 416 ASSERT_EQ(std::string("testtest\0\0\0\0", 12), read_buffer); 417 418 // Append to the end of the file. 419 pp::FileIO file_io2(instance_); 420 callback.WaitForResult(file_io2.Open(file_ref, 421 PP_FILEOPENFLAG_CREATE | 422 PP_FILEOPENFLAG_READ | 423 PP_FILEOPENFLAG_APPEND, 424 callback.GetCallback())); 425 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io2, 0, "appended", 426 callback_type()); 427 ASSERT_EQ(PP_OK, rv); 428 read_buffer.clear(); 429 rv = ReadEntireFile(instance_->pp_instance(), &file_io2, 0, &read_buffer, 430 callback_type()); 431 ASSERT_EQ(PP_OK, rv); 432 ASSERT_EQ(std::string("testtesttest\0\0\0\0appended", 24), read_buffer); 433 434 PASS(); 435 } 436 437 // This is basically a copy of TestReadWriteSetLength, but with the new Read 438 // API. With this test case, we can make sure the two Read's have the same 439 // behavior. 440 std::string TestFileIO::TestReadToArrayWriteSetLength() { 441 if (callback_type() == PP_BLOCKING) { 442 // This test does not make sense for blocking callbacks. 443 PASS(); 444 } 445 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 446 447 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 448 pp::FileRef file_ref(file_system, "/file_read_write_setlength"); 449 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 450 CHECK_CALLBACK_BEHAVIOR(callback); 451 ASSERT_EQ(PP_OK, callback.result()); 452 453 pp::FileIO file_io(instance_); 454 callback.WaitForResult(file_io.Open(file_ref, 455 PP_FILEOPENFLAG_CREATE | 456 PP_FILEOPENFLAG_TRUNCATE | 457 PP_FILEOPENFLAG_READ | 458 PP_FILEOPENFLAG_WRITE, 459 callback.GetCallback())); 460 CHECK_CALLBACK_BEHAVIOR(callback); 461 ASSERT_EQ(PP_OK, callback.result()); 462 463 // Write something to the file. 464 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0, 465 "test_test", callback_type()); 466 ASSERT_EQ(PP_OK, rv); 467 468 TestCompletionCallbackWithOutput< std::vector<char> > callback2( 469 instance_->pp_instance(), callback_type()); 470 // Attempt to read a negative number of bytes; it should fail. 471 callback2.WaitForResult(file_io.Read(0, -1, callback2.GetCallback())); 472 CHECK_CALLBACK_BEHAVIOR(callback2); 473 ASSERT_EQ(PP_ERROR_FAILED, callback2.result()); 474 475 // Read the entire file. 476 std::string read_buffer; 477 read_buffer.reserve(10); 478 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0, 479 &read_buffer, callback_type()); 480 ASSERT_EQ(PP_OK, rv); 481 ASSERT_EQ(std::string("test_test"), read_buffer); 482 483 // Truncate the file. 484 callback.WaitForResult(file_io.SetLength(4, callback.GetCallback())); 485 CHECK_CALLBACK_BEHAVIOR(callback); 486 ASSERT_EQ(PP_OK, rv); 487 488 // Check the file contents. 489 read_buffer.clear(); 490 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0, 491 &read_buffer, callback_type()); 492 ASSERT_EQ(PP_OK, rv); 493 ASSERT_EQ(std::string("test"), read_buffer); 494 495 // Try to read past the end of the file. 496 read_buffer.clear(); 497 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 100, 498 &read_buffer, callback_type()); 499 ASSERT_EQ(PP_OK, rv); 500 ASSERT_TRUE(read_buffer.empty()); 501 502 // Write past the end of the file. The file should be zero-padded. 503 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 8, "test", 504 callback_type()); 505 ASSERT_EQ(PP_OK, rv); 506 507 // Check the contents of the file. 508 read_buffer.clear(); 509 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0, 510 &read_buffer, callback_type()); 511 ASSERT_EQ(PP_OK, rv); 512 ASSERT_EQ(std::string("test\0\0\0\0test", 12), read_buffer); 513 514 // Extend the file. 515 callback.WaitForResult(file_io.SetLength(16, callback.GetCallback())); 516 CHECK_CALLBACK_BEHAVIOR(callback); 517 ASSERT_EQ(PP_OK, callback.result()); 518 519 // Check the contents of the file. 520 read_buffer.clear(); 521 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0, 522 &read_buffer, callback_type()); 523 ASSERT_EQ(PP_OK, rv); 524 ASSERT_EQ(std::string("test\0\0\0\0test\0\0\0\0", 16), read_buffer); 525 526 // Write in the middle of the file. 527 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 4, "test", 528 callback_type()); 529 ASSERT_EQ(PP_OK, rv); 530 531 // Check the contents of the file. 532 read_buffer.clear(); 533 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0, 534 &read_buffer, callback_type()); 535 ASSERT_EQ(PP_OK, rv); 536 ASSERT_EQ(std::string("testtesttest\0\0\0\0", 16), read_buffer); 537 538 // Read from the middle of the file. 539 read_buffer.clear(); 540 rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 4, 541 &read_buffer, callback_type()); 542 ASSERT_EQ(PP_OK, rv); 543 ASSERT_EQ(std::string("testtest\0\0\0\0", 12), read_buffer); 544 545 PASS(); 546 } 547 548 std::string TestFileIO::TestTouchQuery() { 549 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 550 551 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 552 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 553 CHECK_CALLBACK_BEHAVIOR(callback); 554 ASSERT_EQ(PP_OK, callback.result()); 555 556 pp::FileRef file_ref(file_system, "/file_touch"); 557 pp::FileIO file_io(instance_); 558 callback.WaitForResult(file_io.Open(file_ref, 559 PP_FILEOPENFLAG_CREATE | 560 PP_FILEOPENFLAG_TRUNCATE | 561 PP_FILEOPENFLAG_WRITE, 562 callback.GetCallback())); 563 CHECK_CALLBACK_BEHAVIOR(callback); 564 ASSERT_EQ(PP_OK, callback.result()); 565 566 // Write some data to have a non-zero file size. 567 callback.WaitForResult(file_io.Write(0, "test", 4, callback.GetCallback())); 568 CHECK_CALLBACK_BEHAVIOR(callback); 569 ASSERT_EQ(4, callback.result()); 570 571 const PP_Time last_access_time = 123 * 24 * 3600.0; 572 // last_modified_time's granularity is 2 seconds 573 // NOTE: In NaCl on Windows, NaClDescIO uses _fstat64 to retrieve file info. 574 // This function returns strange values for very small time values (near the 575 // Unix Epoch). For a value like 246.0, it returns -1. For larger values, it 576 // returns values that are exactly an hour less. The value below is handled 577 // correctly, and is only 100 days after the start of Unix time. 578 const PP_Time last_modified_time = 100 * 24 * 3600.0; 579 callback.WaitForResult(file_io.Touch(last_access_time, last_modified_time, 580 callback.GetCallback())); 581 CHECK_CALLBACK_BEHAVIOR(callback); 582 ASSERT_EQ(PP_OK, callback.result()); 583 584 PP_FileInfo info; 585 callback.WaitForResult(file_io.Query(&info, callback.GetCallback())); 586 CHECK_CALLBACK_BEHAVIOR(callback); 587 ASSERT_EQ(PP_OK, callback.result()); 588 589 if ((info.size != 4) || 590 (info.type != PP_FILETYPE_REGULAR) || 591 (info.system_type != PP_FILESYSTEMTYPE_LOCALTEMPORARY) || 592 (info.last_access_time != last_access_time) || 593 (info.last_modified_time != last_modified_time)) 594 return "FileIO::Query() has returned bad data."; 595 596 // Call |Query()| again, to make sure it works a second time. 597 callback.WaitForResult(file_io.Query(&info, callback.GetCallback())); 598 CHECK_CALLBACK_BEHAVIOR(callback); 599 ASSERT_EQ(PP_OK, callback.result()); 600 601 PASS(); 602 } 603 604 std::string TestFileIO::TestAbortCalls() { 605 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 606 607 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 608 pp::FileRef file_ref(file_system, "/file_abort_calls"); 609 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 610 CHECK_CALLBACK_BEHAVIOR(callback); 611 ASSERT_EQ(PP_OK, callback.result()); 612 613 int32_t rv = PP_ERROR_FAILED; 614 // First, create a file on which to do ops. 615 { 616 pp::FileIO file_io(instance_); 617 callback.WaitForResult( 618 file_io.Open(file_ref, 619 PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE, 620 callback.GetCallback())); 621 CHECK_CALLBACK_BEHAVIOR(callback); 622 ASSERT_EQ(PP_OK, callback.result()); 623 624 // N.B.: Should write at least 3 bytes. 625 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0, 626 "foobarbazquux", callback_type()); 627 ASSERT_EQ(PP_OK, rv); 628 } 629 630 // Abort |Open()|. 631 { 632 rv = pp::FileIO(instance_) 633 .Open(file_ref, PP_FILEOPENFLAG_READ, callback.GetCallback()); 634 } 635 callback.WaitForAbortResult(rv); 636 CHECK_CALLBACK_BEHAVIOR(callback); 637 638 // Abort |Query()|. 639 { 640 PP_FileInfo info = { 0 }; 641 // Save a copy and make sure |info| doesn't get written to if it is aborted. 642 PP_FileInfo info_copy; 643 memcpy(&info_copy, &info, sizeof(info)); 644 { 645 pp::FileIO file_io(instance_); 646 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_READ, 647 callback.GetCallback())); 648 CHECK_CALLBACK_BEHAVIOR(callback); 649 ASSERT_EQ(PP_OK, callback.result()); 650 651 rv = file_io.Query(&info, callback.GetCallback()); 652 } // Destroy |file_io|. 653 callback.WaitForResult(rv); 654 CHECK_CALLBACK_BEHAVIOR(callback); 655 if (callback_type() == PP_BLOCKING) { 656 ASSERT_EQ(callback.result(), PP_OK); 657 // The operation completed synchronously, so |info| should have changed. 658 ASSERT_NE(0, memcmp(&info_copy, &info, sizeof(info))); 659 } else { 660 ASSERT_EQ(callback.result(), PP_ERROR_ABORTED); 661 ASSERT_EQ(0, memcmp(&info_copy, &info, sizeof(info))); 662 } 663 } 664 665 // Abort |Touch()|. 666 { 667 { 668 pp::FileIO file_io(instance_); 669 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE, 670 callback.GetCallback())); 671 CHECK_CALLBACK_BEHAVIOR(callback); 672 ASSERT_EQ(PP_OK, callback.result()); 673 674 rv = file_io.Touch(0, 0, callback.GetCallback()); 675 } // Destroy |file_io|. 676 callback.WaitForAbortResult(rv); 677 CHECK_CALLBACK_BEHAVIOR(callback); 678 } 679 680 // Abort |Read()|. 681 { 682 char buf[3] = { 0 }; 683 { 684 pp::FileIO file_io(instance_); 685 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_READ, 686 callback.GetCallback())); 687 CHECK_CALLBACK_BEHAVIOR(callback); 688 ASSERT_EQ(PP_OK, callback.result()); 689 690 rv = file_io.Read(0, buf, sizeof(buf), callback.GetCallback()); 691 } // Destroy |file_io|. 692 // Save a copy to make sure buf isn't written to in the async case. 693 char buf_copy[3]; 694 memcpy(&buf_copy, &buf, sizeof(buf)); 695 callback.WaitForResult(rv); 696 CHECK_CALLBACK_BEHAVIOR(callback); 697 if (callback_type() == PP_BLOCKING) { 698 ASSERT_EQ(callback.result(), sizeof(buf)); 699 } else { 700 ASSERT_EQ(callback.result(), PP_ERROR_ABORTED); 701 ASSERT_EQ(0, memcmp(&buf_copy, &buf, sizeof(buf))); 702 } 703 } 704 705 // Abort |Write()|. 706 { 707 char buf[3] = { 0 }; 708 { 709 pp::FileIO file_io(instance_); 710 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE, 711 callback.GetCallback())); 712 CHECK_CALLBACK_BEHAVIOR(callback); 713 ASSERT_EQ(PP_OK, callback.result()); 714 715 rv = file_io.Write(0, buf, sizeof(buf), callback.GetCallback()); 716 } // Destroy |file_io|. 717 callback.WaitForResult(rv); 718 CHECK_CALLBACK_BEHAVIOR(callback); 719 if (callback_type() == PP_BLOCKING) 720 ASSERT_EQ(callback.result(), sizeof(buf)); 721 else 722 ASSERT_EQ(callback.result(), PP_ERROR_ABORTED); 723 } 724 725 // Abort |SetLength()|. 726 { 727 { 728 pp::FileIO file_io(instance_); 729 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_READ, 730 callback.GetCallback())); 731 CHECK_CALLBACK_BEHAVIOR(callback); 732 ASSERT_EQ(PP_OK, callback.result()); 733 734 rv = file_io.SetLength(3, callback.GetCallback()); 735 } // Destroy |file_io|. 736 callback.WaitForAbortResult(rv); 737 CHECK_CALLBACK_BEHAVIOR(callback); 738 } 739 740 // Abort |Flush|. 741 { 742 { 743 pp::FileIO file_io(instance_); 744 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE, 745 callback.GetCallback())); 746 CHECK_CALLBACK_BEHAVIOR(callback); 747 ASSERT_EQ(PP_OK, callback.result()); 748 749 rv = file_io.Flush(callback.GetCallback()); 750 } // Destroy |file_io|. 751 callback.WaitForAbortResult(rv); 752 CHECK_CALLBACK_BEHAVIOR(callback); 753 } 754 755 PASS(); 756 } 757 758 std::string TestFileIO::TestParallelReads() { 759 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 760 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 761 pp::FileRef file_ref(file_system, "/file_parallel_reads"); 762 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 763 CHECK_CALLBACK_BEHAVIOR(callback); 764 ASSERT_EQ(PP_OK, callback.result()); 765 766 pp::FileIO file_io(instance_); 767 callback.WaitForResult(file_io.Open(file_ref, 768 PP_FILEOPENFLAG_CREATE | 769 PP_FILEOPENFLAG_TRUNCATE | 770 PP_FILEOPENFLAG_READ | 771 PP_FILEOPENFLAG_WRITE, 772 callback.GetCallback())); 773 CHECK_CALLBACK_BEHAVIOR(callback); 774 ASSERT_EQ(PP_OK, callback.result()); 775 776 // Set up testing contents. 777 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0, 778 "abcdefghijkl", callback_type()); 779 ASSERT_EQ(PP_OK, rv); 780 781 // Parallel read operations. 782 const char* border = "__border__"; 783 const int32_t border_size = strlen(border); 784 785 TestCompletionCallback callback_1(instance_->pp_instance(), callback_type()); 786 int32_t read_offset_1 = 0; 787 int32_t size_1 = 3; 788 std::vector<char> extended_buf_1(border_size * 2 + size_1); 789 char* buf_1 = &extended_buf_1[border_size]; 790 memcpy(&extended_buf_1[0], border, border_size); 791 memcpy(buf_1 + size_1, border, border_size); 792 793 TestCompletionCallback callback_2(instance_->pp_instance(), callback_type()); 794 int32_t read_offset_2 = size_1; 795 int32_t size_2 = 9; 796 std::vector<char> extended_buf_2(border_size * 2 + size_2); 797 char* buf_2 = &extended_buf_2[border_size]; 798 memcpy(&extended_buf_2[0], border, border_size); 799 memcpy(buf_2 + size_2, border, border_size); 800 801 int32_t rv_1 = PP_OK; 802 int32_t rv_2 = PP_OK; 803 while (size_1 >= 0 && size_2 >= 0 && size_1 + size_2 > 0) { 804 if (size_1 > 0) { 805 rv_1 = file_io.Read(read_offset_1, buf_1, size_1, 806 callback_1.GetCallback()); 807 } 808 if (size_2 > 0) { 809 rv_2 = file_io.Read(read_offset_2, buf_2, size_2, 810 callback_2.GetCallback()); 811 } 812 if (size_1 > 0) { 813 callback_1.WaitForResult(rv_1); 814 CHECK_CALLBACK_BEHAVIOR(callback_1); 815 ASSERT_TRUE(callback_1.result() > 0); 816 read_offset_1 += callback_1.result(); 817 buf_1 += callback_1.result(); 818 size_1 -= callback_1.result(); 819 } 820 821 if (size_2 > 0) { 822 callback_2.WaitForResult(rv_2); 823 CHECK_CALLBACK_BEHAVIOR(callback_2); 824 ASSERT_TRUE(callback_2.result() > 0); 825 read_offset_2 += callback_2.result(); 826 buf_2 += callback_2.result(); 827 size_2 -= callback_2.result(); 828 } 829 } 830 831 // If |size_1| or |size_2| is not 0, we have invoked wrong callback(s). 832 ASSERT_EQ(0, size_1); 833 ASSERT_EQ(0, size_2); 834 835 // Make sure every read operation writes into the correct buffer. 836 const char expected_result_1[] = "__border__abc__border__"; 837 const char expected_result_2[] = "__border__defghijkl__border__"; 838 ASSERT_TRUE(strncmp(&extended_buf_1[0], expected_result_1, 839 strlen(expected_result_1)) == 0); 840 ASSERT_TRUE(strncmp(&extended_buf_2[0], expected_result_2, 841 strlen(expected_result_2)) == 0); 842 PASS(); 843 } 844 845 std::string TestFileIO::TestParallelWrites() { 846 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 847 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 848 pp::FileRef file_ref(file_system, "/file_parallel_writes"); 849 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 850 CHECK_CALLBACK_BEHAVIOR(callback); 851 ASSERT_EQ(PP_OK, callback.result()); 852 853 pp::FileIO file_io(instance_); 854 callback.WaitForResult(file_io.Open(file_ref, 855 PP_FILEOPENFLAG_CREATE | 856 PP_FILEOPENFLAG_TRUNCATE | 857 PP_FILEOPENFLAG_READ | 858 PP_FILEOPENFLAG_WRITE, 859 callback.GetCallback())); 860 CHECK_CALLBACK_BEHAVIOR(callback); 861 ASSERT_EQ(PP_OK, callback.result()); 862 863 // Parallel write operations. 864 TestCompletionCallback callback_1(instance_->pp_instance(), callback_type()); 865 int32_t write_offset_1 = 0; 866 const char* buf_1 = "abc"; 867 int32_t size_1 = strlen(buf_1); 868 869 TestCompletionCallback callback_2(instance_->pp_instance(), callback_type()); 870 int32_t write_offset_2 = size_1; 871 const char* buf_2 = "defghijkl"; 872 int32_t size_2 = strlen(buf_2); 873 874 int32_t rv_1 = PP_OK; 875 int32_t rv_2 = PP_OK; 876 while (size_1 >= 0 && size_2 >= 0 && size_1 + size_2 > 0) { 877 if (size_1 > 0) { 878 rv_1 = file_io.Write(write_offset_1, buf_1, size_1, 879 callback_1.GetCallback()); 880 } 881 if (size_2 > 0) { 882 rv_2 = file_io.Write(write_offset_2, buf_2, size_2, 883 callback_2.GetCallback()); 884 } 885 886 if (size_1 > 0) { 887 callback_1.WaitForResult(rv_1); 888 CHECK_CALLBACK_BEHAVIOR(callback_1); 889 ASSERT_TRUE(callback_1.result() > 0); 890 write_offset_1 += callback_1.result(); 891 buf_1 += callback_1.result(); 892 size_1 -= callback_1.result(); 893 } 894 895 if (size_2 > 0) { 896 callback_2.WaitForResult(rv_2); 897 CHECK_CALLBACK_BEHAVIOR(callback_2); 898 ASSERT_TRUE(callback_2.result() > 0); 899 write_offset_2 += callback_2.result(); 900 buf_2 += callback_2.result(); 901 size_2 -= callback_2.result(); 902 } 903 } 904 905 // If |size_1| or |size_2| is not 0, we have invoked wrong callback(s). 906 ASSERT_EQ(0, size_1); 907 ASSERT_EQ(0, size_2); 908 909 // Check the file contents. 910 std::string read_buffer; 911 int32_t rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, 912 &read_buffer, callback_type()); 913 ASSERT_EQ(PP_OK, rv); 914 ASSERT_EQ(std::string("abcdefghijkl"), read_buffer); 915 916 PASS(); 917 } 918 919 std::string TestFileIO::TestNotAllowMixedReadWrite() { 920 if (callback_type() == PP_BLOCKING) { 921 // This test does not make sense for blocking callbacks. 922 PASS(); 923 } 924 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 925 926 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 927 pp::FileRef file_ref(file_system, "/file_not_allow_mixed_read_write"); 928 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 929 CHECK_CALLBACK_BEHAVIOR(callback); 930 ASSERT_EQ(PP_OK, callback.result()); 931 932 pp::FileIO file_io(instance_); 933 callback.WaitForResult(file_io.Open(file_ref, 934 PP_FILEOPENFLAG_CREATE | 935 PP_FILEOPENFLAG_TRUNCATE | 936 PP_FILEOPENFLAG_READ | 937 PP_FILEOPENFLAG_WRITE, 938 callback.GetCallback())); 939 CHECK_CALLBACK_BEHAVIOR(callback); 940 ASSERT_EQ(PP_OK, callback.result()); 941 942 TestCompletionCallback callback_1(instance_->pp_instance(), PP_REQUIRED); 943 int32_t write_offset_1 = 0; 944 const char* buf_1 = "mnopqrstuvw"; 945 int32_t rv_1 = file_io.Write(write_offset_1, buf_1, strlen(buf_1), 946 callback_1.GetCallback()); 947 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1); 948 949 TestCompletionCallback callback_2(instance_->pp_instance(), callback_type()); 950 int32_t read_offset_2 = 4; 951 char buf_2[3]; 952 callback_2.WaitForResult(file_io.Read(read_offset_2, buf_2, sizeof(buf_2), 953 callback_2.GetCallback())); 954 CHECK_CALLBACK_BEHAVIOR(callback_2); 955 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result()); 956 callback_1.WaitForResult(rv_1); 957 CHECK_CALLBACK_BEHAVIOR(callback_1); 958 959 // Cannot query while a write is pending. 960 rv_1 = file_io.Write(write_offset_1, buf_1, strlen(buf_1), 961 callback_1.GetCallback()); 962 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1); 963 PP_FileInfo info; 964 callback_2.WaitForResult(file_io.Query(&info, callback_2.GetCallback())); 965 CHECK_CALLBACK_BEHAVIOR(callback_2); 966 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result()); 967 callback_1.WaitForResult(rv_1); 968 CHECK_CALLBACK_BEHAVIOR(callback_1); 969 970 // Cannot touch while a write is pending. 971 rv_1 = file_io.Write(write_offset_1, buf_1, strlen(buf_1), 972 callback_1.GetCallback()); 973 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1); 974 callback_2.WaitForResult(file_io.Touch(1234.0, 5678.0, 975 callback_2.GetCallback())); 976 CHECK_CALLBACK_BEHAVIOR(callback_2); 977 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result()); 978 callback_1.WaitForResult(rv_1); 979 CHECK_CALLBACK_BEHAVIOR(callback_1); 980 981 // Cannot set length while a write is pending. 982 rv_1 = file_io.Write(write_offset_1, buf_1, strlen(buf_1), 983 callback_1.GetCallback()); 984 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1); 985 callback_2.WaitForResult(file_io.SetLength(123, callback_2.GetCallback())); 986 CHECK_CALLBACK_BEHAVIOR(callback_2); 987 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result()); 988 callback_1.WaitForResult(rv_1); 989 CHECK_CALLBACK_BEHAVIOR(callback_1); 990 991 PASS(); 992 } 993 994 std::string TestFileIO::TestWillWriteWillSetLength() { 995 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 996 997 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 998 pp::FileRef file_ref(file_system, "/file_will_write"); 999 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 1000 CHECK_CALLBACK_BEHAVIOR(callback); 1001 ASSERT_EQ(PP_OK, callback.result()); 1002 1003 pp::FileIO file_io(instance_); 1004 callback.WaitForResult(file_io.Open(file_ref, 1005 PP_FILEOPENFLAG_CREATE | 1006 PP_FILEOPENFLAG_TRUNCATE | 1007 PP_FILEOPENFLAG_READ | 1008 PP_FILEOPENFLAG_WRITE, 1009 callback.GetCallback())); 1010 CHECK_CALLBACK_BEHAVIOR(callback); 1011 ASSERT_EQ(PP_OK, callback.result()); 1012 1013 const PPB_FileIOTrusted* trusted = static_cast<const PPB_FileIOTrusted*>( 1014 pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE)); 1015 ASSERT_TRUE(trusted); 1016 1017 // Get file descriptor. This is only supported in-process for now, so don't 1018 // test out of process. 1019 const PPB_Testing_Dev* testing_interface = GetTestingInterface(); 1020 if (testing_interface && !testing_interface->IsOutOfProcess()) { 1021 int32_t fd = trusted->GetOSFileDescriptor(file_io.pp_resource()); 1022 ASSERT_TRUE(fd >= 0); 1023 } 1024 1025 // Calling WillWrite. 1026 callback.WaitForResult(trusted->WillWrite( 1027 file_io.pp_resource(), 0, 9, 1028 callback.GetCallback().pp_completion_callback())); 1029 CHECK_CALLBACK_BEHAVIOR(callback); 1030 ASSERT_EQ(9, callback.result()); 1031 1032 // Writing the actual data. 1033 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0, 1034 "test_test", callback_type()); 1035 ASSERT_EQ(PP_OK, rv); 1036 1037 std::string read_buffer; 1038 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer, 1039 callback_type()); 1040 ASSERT_EQ(PP_OK, rv); 1041 ASSERT_EQ(std::string("test_test"), read_buffer); 1042 1043 // Calling WillSetLength. 1044 callback.WaitForResult(trusted->WillSetLength( 1045 file_io.pp_resource(), 4, 1046 callback.GetCallback().pp_completion_callback())); 1047 CHECK_CALLBACK_BEHAVIOR(callback); 1048 ASSERT_EQ(PP_OK, rv); 1049 1050 // Calling actual SetLength. 1051 callback.WaitForResult(file_io.SetLength(4, callback.GetCallback())); 1052 CHECK_CALLBACK_BEHAVIOR(callback); 1053 ASSERT_EQ(PP_OK, rv); 1054 1055 read_buffer.clear(); 1056 rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer, 1057 callback_type()); 1058 ASSERT_EQ(PP_OK, rv); 1059 ASSERT_EQ(std::string("test"), read_buffer); 1060 1061 PASS(); 1062 } 1063 1064 std::string TestFileIO::TestRequestOSFileHandle() { 1065 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 1066 1067 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 1068 pp::FileRef file_ref(file_system, "/file_os_fd"); 1069 1070 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 1071 ASSERT_EQ(PP_OK, callback.result()); 1072 1073 pp::FileIO_Private file_io(instance_); 1074 callback.WaitForResult(file_io.Open(file_ref, 1075 PP_FILEOPENFLAG_CREATE | 1076 PP_FILEOPENFLAG_TRUNCATE | 1077 PP_FILEOPENFLAG_READ | 1078 PP_FILEOPENFLAG_WRITE, 1079 callback.GetCallback())); 1080 ASSERT_EQ(PP_OK, callback.result()); 1081 1082 TestCompletionCallbackWithOutput<pp::PassFileHandle> output_callback( 1083 instance_->pp_instance(), callback_type()); 1084 output_callback.WaitForResult( 1085 file_io.RequestOSFileHandle(output_callback.GetCallback())); 1086 PP_FileHandle handle = output_callback.output().Release(); 1087 ASSERT_EQ(PP_OK, output_callback.result()); 1088 1089 if (handle == PP_kInvalidFileHandle) 1090 return "FileIO::RequestOSFileHandle() returned a bad file handle."; 1091 #if defined(PPAPI_OS_WIN) 1092 int fd = _open_osfhandle(reinterpret_cast<intptr_t>(handle), 1093 _O_RDWR | _O_BINARY); 1094 #else 1095 int fd = handle; 1096 #endif 1097 if (fd < 0) 1098 return "FileIO::RequestOSFileHandle() returned a bad file descriptor."; 1099 1100 // Check write(2) for the native FD. 1101 const std::string msg = "foobar"; 1102 ssize_t cnt = write(fd, msg.data(), msg.size()); 1103 if (cnt < 0) 1104 return ReportError("write for native FD returned error", errno); 1105 if (cnt != static_cast<ssize_t>(msg.size())) 1106 return ReportError("write for native FD count mismatch", cnt); 1107 1108 // Check lseek(2) for the native FD. 1109 off_t off = lseek(fd, 0, SEEK_CUR); 1110 if (off == static_cast<off_t>(-1)) 1111 return ReportError("lseek for native FD returned error", errno); 1112 if (off != static_cast<off_t>(msg.size())) 1113 return ReportError("lseek for native FD offset mismatch", off); 1114 1115 off = lseek(fd, 0, SEEK_SET); 1116 if (off == static_cast<off_t>(-1)) 1117 return ReportError("lseek for native FD returned error", errno); 1118 if (off != 0) 1119 return ReportError("lseek for native FD offset mismatch", off); 1120 1121 // Check read(2) for the native FD. 1122 std::string buf(msg.size(), '\0'); 1123 cnt = read(fd, &buf[0], msg.size()); 1124 if (cnt < 0) 1125 return ReportError("read for native FD returned error", errno); 1126 if (cnt != static_cast<ssize_t>(msg.size())) 1127 return ReportError("read for native FD count mismatch", cnt); 1128 if (msg != buf) 1129 return ReportMismatch("read for native FD", buf, msg); 1130 PASS(); 1131 } 1132 1133 // Calling RequestOSFileHandle with the FileIO that is opened with 1134 // PP_FILEOPENFLAG_EXCLUSIVE used to cause NaCl module to crash while loading. 1135 // This is a regression test for crbug.com/243241. 1136 std::string TestFileIO::TestRequestOSFileHandleWithOpenExclusive() { 1137 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 1138 1139 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 1140 pp::FileRef file_ref(file_system, "/file_os_fd2"); 1141 1142 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 1143 ASSERT_EQ(PP_OK, callback.result()); 1144 1145 // Open with PP_FILEOPENFLAG_CREATE and PP_FILEOPENFLAG_EXCLUSIVE will fail 1146 // if the file already exists. Delete it here to make sure it does not. 1147 callback.WaitForResult(file_ref.Delete(callback.GetCallback())); 1148 1149 pp::FileIO_Private file_io(instance_); 1150 callback.WaitForResult(file_io.Open(file_ref, 1151 PP_FILEOPENFLAG_CREATE | 1152 PP_FILEOPENFLAG_READ | 1153 PP_FILEOPENFLAG_WRITE | 1154 PP_FILEOPENFLAG_EXCLUSIVE, 1155 callback.GetCallback())); 1156 ASSERT_EQ(PP_OK, callback.result()); 1157 1158 TestCompletionCallbackWithOutput<pp::PassFileHandle> output_callback( 1159 instance_->pp_instance(), callback_type()); 1160 output_callback.WaitForResult( 1161 file_io.RequestOSFileHandle(output_callback.GetCallback())); 1162 PP_FileHandle handle = output_callback.output().Release(); 1163 if (handle == PP_kInvalidFileHandle) 1164 return "FileIO::RequestOSFileHandle() returned a bad file handle."; 1165 ASSERT_EQ(PP_OK, output_callback.result()); 1166 1167 PASS(); 1168 } 1169 1170 std::string TestFileIO::TestMmap() { 1171 #if !defined(PPAPI_OS_WIN) 1172 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 1173 1174 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 1175 pp::FileRef file_ref(file_system, "/file_os_fd"); 1176 1177 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 1178 ASSERT_EQ(PP_OK, callback.result()); 1179 1180 pp::FileIO_Private file_io(instance_); 1181 callback.WaitForResult(file_io.Open(file_ref, 1182 PP_FILEOPENFLAG_CREATE | 1183 PP_FILEOPENFLAG_TRUNCATE | 1184 PP_FILEOPENFLAG_READ | 1185 PP_FILEOPENFLAG_WRITE, 1186 callback.GetCallback())); 1187 ASSERT_EQ(PP_OK, callback.result()); 1188 1189 TestCompletionCallbackWithOutput<pp::PassFileHandle> output_callback( 1190 instance_->pp_instance(), callback_type()); 1191 output_callback.WaitForResult( 1192 file_io.RequestOSFileHandle(output_callback.GetCallback())); 1193 PP_FileHandle handle = output_callback.output().Release(); 1194 ASSERT_EQ(PP_OK, output_callback.result()); 1195 1196 if (handle == PP_kInvalidFileHandle) 1197 return "FileIO::RequestOSFileHandle() returned a bad file handle."; 1198 int fd = handle; 1199 if (fd < 0) 1200 return "FileIO::RequestOSFileHandle() returned a bad file descriptor."; 1201 1202 // Check write(2) for the native FD. 1203 const std::string msg = "foobar"; 1204 ssize_t cnt = write(fd, msg.data(), msg.size()); 1205 if (cnt < 0) 1206 return ReportError("write for native FD returned error", errno); 1207 if (cnt != static_cast<ssize_t>(msg.size())) 1208 return ReportError("write for native FD count mismatch", cnt); 1209 1210 // BEGIN mmap(2) test with a file handle opened in READ-WRITE mode. 1211 // Check mmap(2) for read. 1212 { 1213 char* mapped = reinterpret_cast<char*>( 1214 mmap(NULL, msg.size(), PROT_READ, MAP_PRIVATE, fd, 0)); 1215 if (mapped == MAP_FAILED) 1216 return ReportError("mmap(r) for native FD returned errno", errno); 1217 // Make sure the buffer is cleared. 1218 std::string buf = std::string(msg.size(), '\0'); 1219 memcpy(&buf[0], mapped, msg.size()); 1220 if (msg != buf) 1221 return ReportMismatch("mmap(r) for native FD", buf, msg); 1222 int r = munmap(mapped, msg.size()); 1223 if (r < 0) 1224 return ReportError("munmap for native FD returned error", errno); 1225 } 1226 1227 // Check mmap(2) for write with MAP_PRIVATE 1228 { 1229 char* mapped = reinterpret_cast<char*>( 1230 mmap(NULL, msg.size(), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)); 1231 if (mapped == MAP_FAILED) 1232 return ReportError("mmap(r) for native FD returned errno", errno); 1233 // Make sure the file is not polluted by writing to privage mmap. 1234 strncpy(mapped, "baz", 3); 1235 std::string read_buffer; 1236 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd, &read_buffer)); 1237 if (msg != read_buffer) 1238 return ReportMismatch("file content != msg", read_buffer, msg); 1239 int r = munmap(mapped, msg.size()); 1240 if (r < 0) 1241 return ReportError("munmap for native FD returned error", errno); 1242 } 1243 1244 // Check mmap(2) for write with MAP_SHARED. 1245 { 1246 char* mapped = reinterpret_cast<char*>( 1247 mmap(NULL, msg.size(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); 1248 if (mapped == MAP_FAILED) 1249 return ReportError("mmap(w) for native FD returned errno", errno); 1250 // s/foo/baz/ 1251 strncpy(mapped, "baz", 3); 1252 std::string read_buffer; 1253 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd, &read_buffer)); 1254 if (read_buffer != "bazbar") 1255 return ReportMismatch("file content != msg", read_buffer, "bazbar"); 1256 int r = munmap(mapped, msg.size()); 1257 if (r < 0) 1258 return ReportError("munmap for native FD returned error", errno); 1259 } 1260 // END mmap(2) test with a file handle opened in READ-WRITE mode. 1261 1262 if (close(fd) < 0) 1263 return ReportError("close for native FD returned error", errno); 1264 1265 // BEGIN mmap(2) test with a file handle opened in READONLY mode. 1266 file_io = pp::FileIO_Private(instance_); 1267 callback.WaitForResult(file_io.Open(file_ref, 1268 PP_FILEOPENFLAG_READ, 1269 callback.GetCallback())); 1270 ASSERT_EQ(PP_OK, callback.result()); 1271 1272 output_callback = TestCompletionCallbackWithOutput<pp::PassFileHandle>( 1273 instance_->pp_instance(), callback_type()); 1274 output_callback.WaitForResult( 1275 file_io.RequestOSFileHandle(output_callback.GetCallback())); 1276 handle = output_callback.output().Release(); 1277 ASSERT_EQ(PP_OK, output_callback.result()); 1278 1279 if (handle == PP_kInvalidFileHandle) 1280 return "FileIO::RequestOSFileHandle() returned a bad file handle."; 1281 fd = handle; 1282 if (fd < 0) 1283 return "FileIO::RequestOSFileHandle() returned a bad file descriptor."; 1284 1285 const std::string msg2 = "bazbar"; 1286 1287 // Check mmap(2) for read. 1288 { 1289 char* mapped = reinterpret_cast<char*>( 1290 mmap(NULL, msg2.size(), PROT_READ, MAP_PRIVATE, fd, 0)); 1291 if (mapped == MAP_FAILED) 1292 return ReportError("mmap(r) for native FD returned errno", errno); 1293 // Make sure the buffer is cleared. 1294 std::string buf = std::string(msg2.size(), '\0'); 1295 memcpy(&buf[0], mapped, msg2.size()); 1296 if (msg2 != buf) 1297 return ReportMismatch("mmap(r) for native FD", buf, msg2); 1298 int r = munmap(mapped, msg2.size()); 1299 if (r < 0) 1300 return ReportError("munmap for native FD returned error", errno); 1301 } 1302 1303 // Check mmap(2) for write with MAP_PRIVATE 1304 { 1305 char* mapped = reinterpret_cast<char*>( 1306 mmap(NULL, msg2.size(), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)); 1307 if (mapped == MAP_FAILED) 1308 return ReportError("mmap(r) for native FD returned errno", errno); 1309 // Make sure the file is not polluted by writing to privage mmap. 1310 strncpy(mapped, "baz", 3); 1311 std::string read_buffer; 1312 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd, &read_buffer)); 1313 if (msg2 != read_buffer) 1314 return ReportMismatch("file content != msg2", read_buffer, msg2); 1315 int r = munmap(mapped, msg2.size()); 1316 if (r < 0) 1317 return ReportError("munmap for native FD returned error", errno); 1318 } 1319 1320 // Check mmap(2) for write with MAP_SHARED. 1321 { 1322 char* mapped = reinterpret_cast<char*>( 1323 mmap(NULL, msg2.size(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); 1324 if (mapped != MAP_FAILED) 1325 return ReportError("mmap(w) for native FD must fail when opened readonly", 1326 -1); 1327 } 1328 // END mmap(2) test with a file handle opened in READONLY mode. 1329 1330 if (close(fd) < 0) 1331 return ReportError("close for native FD returned error", errno); 1332 #endif // !defined(PPAPI_OS_WIN) 1333 1334 PASS(); 1335 } 1336 1337 std::string TestFileIO::MatchOpenExpectations(pp::FileSystem* file_system, 1338 size_t open_flags, 1339 size_t expectations) { 1340 std::string bad_argument = 1341 "TestFileIO::MatchOpenExpectations has invalid input arguments."; 1342 bool invalid_combination = !!(expectations & INVALID_FLAG_COMBINATION); 1343 if (invalid_combination) { 1344 if (expectations != INVALID_FLAG_COMBINATION) 1345 return bad_argument; 1346 } else { 1347 // Validate that one and only one of <some_expectation> and 1348 // DONT_<some_expectation> is specified. 1349 for (size_t remains = expectations, end = END_OF_OPEN_EXPECATION_PAIRS; 1350 end != 0; remains >>= 2, end >>= 2) { 1351 if (!!(remains & 1) == !!(remains & 2)) 1352 return bad_argument; 1353 } 1354 } 1355 bool create_if_doesnt_exist = !!(expectations & CREATE_IF_DOESNT_EXIST); 1356 bool open_if_exists = !!(expectations & OPEN_IF_EXISTS); 1357 bool truncate_if_exists = !!(expectations & TRUNCATE_IF_EXISTS); 1358 1359 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 1360 pp::FileRef existent_file_ref( 1361 *file_system, "/match_open_expectation_existent_non_empty_file"); 1362 pp::FileRef nonexistent_file_ref( 1363 *file_system, "/match_open_expectation_nonexistent_file"); 1364 1365 // Setup files for test. 1366 { 1367 callback.WaitForResult(existent_file_ref.Delete(callback.GetCallback())); 1368 CHECK_CALLBACK_BEHAVIOR(callback); 1369 ASSERT_TRUE(callback.result() == PP_OK || 1370 callback.result() == PP_ERROR_FILENOTFOUND); 1371 callback.WaitForResult(nonexistent_file_ref.Delete(callback.GetCallback())); 1372 CHECK_CALLBACK_BEHAVIOR(callback); 1373 ASSERT_TRUE(callback.result() == PP_OK || 1374 callback.result() == PP_ERROR_FILENOTFOUND); 1375 1376 pp::FileIO existent_file_io(instance_); 1377 callback.WaitForResult(existent_file_io.Open( 1378 existent_file_ref, 1379 PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE, 1380 callback.GetCallback())); 1381 CHECK_CALLBACK_BEHAVIOR(callback); 1382 ASSERT_EQ(PP_OK, callback.result()); 1383 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &existent_file_io, 1384 0, "foobar", callback_type()); 1385 ASSERT_EQ(PP_OK, rv); 1386 } 1387 1388 pp::FileIO existent_file_io(instance_); 1389 callback.WaitForResult(existent_file_io.Open(existent_file_ref, open_flags, 1390 callback.GetCallback())); 1391 CHECK_CALLBACK_BEHAVIOR(callback); 1392 if ((invalid_combination && callback.result() == PP_OK) || 1393 (!invalid_combination && 1394 ((callback.result() == PP_OK) != open_if_exists))) { 1395 return ReportOpenError(open_flags); 1396 } 1397 1398 if (!invalid_combination && open_if_exists) { 1399 PP_FileInfo info; 1400 callback.WaitForResult(existent_file_io.Query(&info, 1401 callback.GetCallback())); 1402 CHECK_CALLBACK_BEHAVIOR(callback); 1403 ASSERT_EQ(PP_OK, callback.result()); 1404 if (truncate_if_exists != (info.size == 0)) 1405 return ReportOpenError(open_flags); 1406 } 1407 1408 pp::FileIO nonexistent_file_io(instance_); 1409 callback.WaitForResult(nonexistent_file_io.Open(nonexistent_file_ref, 1410 open_flags, 1411 callback.GetCallback())); 1412 CHECK_CALLBACK_BEHAVIOR(callback); 1413 if ((invalid_combination && callback.result() == PP_OK) || 1414 (!invalid_combination && 1415 ((callback.result() == PP_OK) != create_if_doesnt_exist))) { 1416 return ReportOpenError(open_flags); 1417 } 1418 1419 return std::string(); 1420 } 1421 1422 // TODO(viettrungluu): Test Close(). crbug.com/69457 1423