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