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 <algorithm> 15 #include <vector> 16 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/private/ppb_testing_private.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, RequestOSFileHandle, filter); 187 RUN_CALLBACK_TEST(TestFileIO, RequestOSFileHandleWithOpenExclusive, filter); 188 RUN_CALLBACK_TEST(TestFileIO, Mmap, filter); 189 190 // TODO(viettrungluu): add tests: 191 // - that PP_ERROR_PENDING is correctly returned 192 // - that operations respect the file open modes (flags) 193 } 194 195 std::string TestFileIO::TestOpen() { 196 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 197 198 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 199 pp::FileRef file_ref(file_system, "/file_open"); 200 201 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 202 CHECK_CALLBACK_BEHAVIOR(callback); 203 ASSERT_EQ(PP_OK, callback.result()); 204 205 std::string result; 206 result = MatchOpenExpectations( 207 &file_system, 208 PP_FILEOPENFLAG_READ, 209 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS); 210 if (!result.empty()) 211 return result; 212 213 // Test the behavior of the power set of 214 // { PP_FILEOPENFLAG_CREATE, 215 // PP_FILEOPENFLAG_TRUNCATE, 216 // PP_FILEOPENFLAG_EXCLUSIVE }. 217 218 // First of all, none of them are specified. 219 result = MatchOpenExpectations( 220 &file_system, 221 PP_FILEOPENFLAG_WRITE, 222 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS); 223 if (!result.empty()) 224 return result; 225 226 result = MatchOpenExpectations( 227 &file_system, 228 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE, 229 CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS); 230 if (!result.empty()) 231 return result; 232 233 result = MatchOpenExpectations( 234 &file_system, 235 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_EXCLUSIVE, 236 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS); 237 if (!result.empty()) 238 return result; 239 240 result = MatchOpenExpectations( 241 &file_system, 242 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_TRUNCATE, 243 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | TRUNCATE_IF_EXISTS); 244 if (!result.empty()) 245 return result; 246 247 result = MatchOpenExpectations( 248 &file_system, 249 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE | 250 PP_FILEOPENFLAG_EXCLUSIVE, 251 CREATE_IF_DOESNT_EXIST | DONT_OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS); 252 if (!result.empty()) 253 return result; 254 255 result = MatchOpenExpectations( 256 &file_system, 257 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_TRUNCATE, 258 CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | TRUNCATE_IF_EXISTS); 259 if (!result.empty()) 260 return result; 261 262 result = MatchOpenExpectations( 263 &file_system, 264 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_EXCLUSIVE | 265 PP_FILEOPENFLAG_TRUNCATE, 266 DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | TRUNCATE_IF_EXISTS); 267 if (!result.empty()) 268 return result; 269 270 result = MatchOpenExpectations( 271 &file_system, 272 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE | 273 PP_FILEOPENFLAG_EXCLUSIVE | PP_FILEOPENFLAG_TRUNCATE, 274 CREATE_IF_DOESNT_EXIST | DONT_OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS); 275 if (!result.empty()) 276 return result; 277 278 // Invalid combination: PP_FILEOPENFLAG_TRUNCATE without 279 // PP_FILEOPENFLAG_WRITE. 280 result = MatchOpenExpectations( 281 &file_system, 282 PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_TRUNCATE, 283 INVALID_FLAG_COMBINATION); 284 if (!result.empty()) 285 return result; 286 287 PASS(); 288 } 289 290 std::string TestFileIO::TestOpenDirectory() { 291 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 292 293 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 294 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 295 CHECK_CALLBACK_BEHAVIOR(callback); 296 ASSERT_EQ(PP_OK, callback.result()); 297 298 // Make a directory. 299 pp::FileRef dir_ref(file_system, "/test_dir_open_directory"); 300 callback.WaitForResult(dir_ref.MakeDirectory( 301 PP_MAKEDIRECTORYFLAG_NONE, 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 // Disabled due to DST-related failure: crbug.com/314579 593 //(info.last_access_time != last_access_time) || 594 //(info.last_modified_time != last_modified_time)) 595 return "FileIO::Query() has returned bad data."; 596 597 // Call |Query()| again, to make sure it works a second time. 598 callback.WaitForResult(file_io.Query(&info, callback.GetCallback())); 599 CHECK_CALLBACK_BEHAVIOR(callback); 600 ASSERT_EQ(PP_OK, callback.result()); 601 602 PASS(); 603 } 604 605 std::string TestFileIO::TestAbortCalls() { 606 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 607 608 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 609 pp::FileRef file_ref(file_system, "/file_abort_calls"); 610 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 611 CHECK_CALLBACK_BEHAVIOR(callback); 612 ASSERT_EQ(PP_OK, callback.result()); 613 614 int32_t rv = PP_ERROR_FAILED; 615 // First, create a file on which to do ops. 616 { 617 pp::FileIO file_io(instance_); 618 callback.WaitForResult( 619 file_io.Open(file_ref, 620 PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE, 621 callback.GetCallback())); 622 CHECK_CALLBACK_BEHAVIOR(callback); 623 ASSERT_EQ(PP_OK, callback.result()); 624 625 // N.B.: Should write at least 3 bytes. 626 rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0, 627 "foobarbazquux", callback_type()); 628 ASSERT_EQ(PP_OK, rv); 629 } 630 631 // Abort |Open()|. 632 { 633 rv = pp::FileIO(instance_) 634 .Open(file_ref, PP_FILEOPENFLAG_READ, callback.GetCallback()); 635 } 636 callback.WaitForAbortResult(rv); 637 CHECK_CALLBACK_BEHAVIOR(callback); 638 639 // Abort |Query()|. 640 { 641 PP_FileInfo info = { 0 }; 642 // Save a copy and make sure |info| doesn't get written to if it is aborted. 643 PP_FileInfo info_copy; 644 memcpy(&info_copy, &info, sizeof(info)); 645 { 646 pp::FileIO file_io(instance_); 647 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_READ, 648 callback.GetCallback())); 649 CHECK_CALLBACK_BEHAVIOR(callback); 650 ASSERT_EQ(PP_OK, callback.result()); 651 652 rv = file_io.Query(&info, callback.GetCallback()); 653 } // Destroy |file_io|. 654 callback.WaitForResult(rv); 655 CHECK_CALLBACK_BEHAVIOR(callback); 656 if (callback_type() == PP_BLOCKING) { 657 ASSERT_EQ(PP_OK, callback.result()); 658 // The operation completed synchronously, so |info| should have changed. 659 ASSERT_NE(0, memcmp(&info_copy, &info, sizeof(info))); 660 } else { 661 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 662 ASSERT_EQ(0, memcmp(&info_copy, &info, sizeof(info))); 663 } 664 } 665 666 // Abort |Touch()|. 667 { 668 { 669 pp::FileIO file_io(instance_); 670 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE, 671 callback.GetCallback())); 672 CHECK_CALLBACK_BEHAVIOR(callback); 673 ASSERT_EQ(PP_OK, callback.result()); 674 675 rv = file_io.Touch(0, 0, callback.GetCallback()); 676 } // Destroy |file_io|. 677 callback.WaitForAbortResult(rv); 678 CHECK_CALLBACK_BEHAVIOR(callback); 679 } 680 681 // Abort |Read()|. 682 { 683 char buf[3] = { 0 }; 684 { 685 pp::FileIO file_io(instance_); 686 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_READ, 687 callback.GetCallback())); 688 CHECK_CALLBACK_BEHAVIOR(callback); 689 ASSERT_EQ(PP_OK, callback.result()); 690 691 rv = file_io.Read(0, buf, sizeof(buf), callback.GetCallback()); 692 } // Destroy |file_io|. 693 // Save a copy to make sure buf isn't written to in the async case. 694 char buf_copy[3]; 695 memcpy(&buf_copy, &buf, sizeof(buf)); 696 callback.WaitForResult(rv); 697 CHECK_CALLBACK_BEHAVIOR(callback); 698 if (callback_type() == PP_BLOCKING) { 699 ASSERT_EQ(callback.result(), sizeof(buf)); 700 } else { 701 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 702 ASSERT_EQ(0, memcmp(&buf_copy, &buf, sizeof(buf))); 703 } 704 } 705 706 // Abort |Write()|. 707 { 708 char buf[3] = { 0 }; 709 { 710 pp::FileIO file_io(instance_); 711 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE, 712 callback.GetCallback())); 713 CHECK_CALLBACK_BEHAVIOR(callback); 714 ASSERT_EQ(PP_OK, callback.result()); 715 716 rv = file_io.Write(0, buf, sizeof(buf), callback.GetCallback()); 717 } // Destroy |file_io|. 718 callback.WaitForResult(rv); 719 CHECK_CALLBACK_BEHAVIOR(callback); 720 if (callback_type() == PP_BLOCKING) 721 ASSERT_EQ(callback.result(), sizeof(buf)); 722 else 723 ASSERT_EQ(PP_ERROR_ABORTED, callback.result()); 724 } 725 726 // Abort |SetLength()|. 727 { 728 { 729 pp::FileIO file_io(instance_); 730 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE, 731 callback.GetCallback())); 732 CHECK_CALLBACK_BEHAVIOR(callback); 733 ASSERT_EQ(PP_OK, callback.result()); 734 735 rv = file_io.SetLength(3, callback.GetCallback()); 736 } // Destroy |file_io|. 737 callback.WaitForAbortResult(rv); 738 CHECK_CALLBACK_BEHAVIOR(callback); 739 } 740 741 // Abort |Flush|. 742 { 743 { 744 pp::FileIO file_io(instance_); 745 callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE, 746 callback.GetCallback())); 747 CHECK_CALLBACK_BEHAVIOR(callback); 748 ASSERT_EQ(PP_OK, callback.result()); 749 750 rv = file_io.Flush(callback.GetCallback()); 751 } // Destroy |file_io|. 752 callback.WaitForAbortResult(rv); 753 CHECK_CALLBACK_BEHAVIOR(callback); 754 } 755 756 PASS(); 757 } 758 759 std::string TestFileIO::TestParallelReads() { 760 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 761 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 762 pp::FileRef file_ref(file_system, "/file_parallel_reads"); 763 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 764 CHECK_CALLBACK_BEHAVIOR(callback); 765 ASSERT_EQ(PP_OK, callback.result()); 766 767 pp::FileIO file_io(instance_); 768 callback.WaitForResult(file_io.Open(file_ref, 769 PP_FILEOPENFLAG_CREATE | 770 PP_FILEOPENFLAG_TRUNCATE | 771 PP_FILEOPENFLAG_READ | 772 PP_FILEOPENFLAG_WRITE, 773 callback.GetCallback())); 774 CHECK_CALLBACK_BEHAVIOR(callback); 775 ASSERT_EQ(PP_OK, callback.result()); 776 777 // Set up testing contents. 778 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0, 779 "abcdefghijkl", callback_type()); 780 ASSERT_EQ(PP_OK, rv); 781 782 // Parallel read operations. 783 const char* border = "__border__"; 784 const int32_t border_size = strlen(border); 785 786 TestCompletionCallback callback_1(instance_->pp_instance(), callback_type()); 787 int32_t read_offset_1 = 0; 788 int32_t size_1 = 3; 789 std::vector<char> extended_buf_1(border_size * 2 + size_1); 790 char* buf_1 = &extended_buf_1[border_size]; 791 memcpy(&extended_buf_1[0], border, border_size); 792 memcpy(buf_1 + size_1, border, border_size); 793 794 TestCompletionCallback callback_2(instance_->pp_instance(), callback_type()); 795 int32_t read_offset_2 = size_1; 796 int32_t size_2 = 9; 797 std::vector<char> extended_buf_2(border_size * 2 + size_2); 798 char* buf_2 = &extended_buf_2[border_size]; 799 memcpy(&extended_buf_2[0], border, border_size); 800 memcpy(buf_2 + size_2, border, border_size); 801 802 int32_t rv_1 = PP_OK; 803 int32_t rv_2 = PP_OK; 804 while (size_1 >= 0 && size_2 >= 0 && size_1 + size_2 > 0) { 805 if (size_1 > 0) { 806 rv_1 = file_io.Read(read_offset_1, buf_1, size_1, 807 callback_1.GetCallback()); 808 } 809 if (size_2 > 0) { 810 rv_2 = file_io.Read(read_offset_2, buf_2, size_2, 811 callback_2.GetCallback()); 812 } 813 if (size_1 > 0) { 814 callback_1.WaitForResult(rv_1); 815 CHECK_CALLBACK_BEHAVIOR(callback_1); 816 ASSERT_TRUE(callback_1.result() > 0); 817 read_offset_1 += callback_1.result(); 818 buf_1 += callback_1.result(); 819 size_1 -= callback_1.result(); 820 } 821 822 if (size_2 > 0) { 823 callback_2.WaitForResult(rv_2); 824 CHECK_CALLBACK_BEHAVIOR(callback_2); 825 ASSERT_TRUE(callback_2.result() > 0); 826 read_offset_2 += callback_2.result(); 827 buf_2 += callback_2.result(); 828 size_2 -= callback_2.result(); 829 } 830 } 831 832 // If |size_1| or |size_2| is not 0, we have invoked wrong callback(s). 833 ASSERT_EQ(0, size_1); 834 ASSERT_EQ(0, size_2); 835 836 // Make sure every read operation writes into the correct buffer. 837 const char expected_result_1[] = "__border__abc__border__"; 838 const char expected_result_2[] = "__border__defghijkl__border__"; 839 ASSERT_TRUE(strncmp(&extended_buf_1[0], expected_result_1, 840 strlen(expected_result_1)) == 0); 841 ASSERT_TRUE(strncmp(&extended_buf_2[0], expected_result_2, 842 strlen(expected_result_2)) == 0); 843 PASS(); 844 } 845 846 std::string TestFileIO::TestParallelWrites() { 847 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 848 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 849 pp::FileRef file_ref(file_system, "/file_parallel_writes"); 850 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 851 CHECK_CALLBACK_BEHAVIOR(callback); 852 ASSERT_EQ(PP_OK, callback.result()); 853 854 pp::FileIO file_io(instance_); 855 callback.WaitForResult(file_io.Open(file_ref, 856 PP_FILEOPENFLAG_CREATE | 857 PP_FILEOPENFLAG_TRUNCATE | 858 PP_FILEOPENFLAG_READ | 859 PP_FILEOPENFLAG_WRITE, 860 callback.GetCallback())); 861 CHECK_CALLBACK_BEHAVIOR(callback); 862 ASSERT_EQ(PP_OK, callback.result()); 863 864 // Parallel write operations. 865 TestCompletionCallback callback_1(instance_->pp_instance(), callback_type()); 866 int32_t write_offset_1 = 0; 867 const char* buf_1 = "abc"; 868 int32_t size_1 = strlen(buf_1); 869 870 TestCompletionCallback callback_2(instance_->pp_instance(), callback_type()); 871 int32_t write_offset_2 = size_1; 872 const char* buf_2 = "defghijkl"; 873 int32_t size_2 = strlen(buf_2); 874 875 int32_t rv_1 = PP_OK; 876 int32_t rv_2 = PP_OK; 877 while (size_1 >= 0 && size_2 >= 0 && size_1 + size_2 > 0) { 878 if (size_1 > 0) { 879 // Copy the buffer so we can erase it below. 880 std::string str_1(buf_1); 881 rv_1 = file_io.Write( 882 write_offset_1, &str_1[0], str_1.size(), callback_1.GetCallback()); 883 // Erase the buffer to test that async writes copy it. 884 std::fill(str_1.begin(), str_1.end(), 0); 885 } 886 if (size_2 > 0) { 887 // Copy the buffer so we can erase it below. 888 std::string str_2(buf_2); 889 rv_2 = file_io.Write( 890 write_offset_2, &str_2[0], str_2.size(), callback_2.GetCallback()); 891 // Erase the buffer to test that async writes copy it. 892 std::fill(str_2.begin(), str_2.end(), 0); 893 } 894 895 if (size_1 > 0) { 896 callback_1.WaitForResult(rv_1); 897 CHECK_CALLBACK_BEHAVIOR(callback_1); 898 ASSERT_TRUE(callback_1.result() > 0); 899 write_offset_1 += callback_1.result(); 900 buf_1 += callback_1.result(); 901 size_1 -= callback_1.result(); 902 } 903 904 if (size_2 > 0) { 905 callback_2.WaitForResult(rv_2); 906 CHECK_CALLBACK_BEHAVIOR(callback_2); 907 ASSERT_TRUE(callback_2.result() > 0); 908 write_offset_2 += callback_2.result(); 909 buf_2 += callback_2.result(); 910 size_2 -= callback_2.result(); 911 } 912 } 913 914 // If |size_1| or |size_2| is not 0, we have invoked wrong callback(s). 915 ASSERT_EQ(0, size_1); 916 ASSERT_EQ(0, size_2); 917 918 // Check the file contents. 919 std::string read_buffer; 920 int32_t rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, 921 &read_buffer, callback_type()); 922 ASSERT_EQ(PP_OK, rv); 923 ASSERT_EQ(std::string("abcdefghijkl"), read_buffer); 924 925 PASS(); 926 } 927 928 std::string TestFileIO::TestNotAllowMixedReadWrite() { 929 if (callback_type() == PP_BLOCKING) { 930 // This test does not make sense for blocking callbacks. 931 PASS(); 932 } 933 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 934 935 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 936 pp::FileRef file_ref(file_system, "/file_not_allow_mixed_read_write"); 937 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 938 CHECK_CALLBACK_BEHAVIOR(callback); 939 ASSERT_EQ(PP_OK, callback.result()); 940 941 pp::FileIO file_io(instance_); 942 callback.WaitForResult(file_io.Open(file_ref, 943 PP_FILEOPENFLAG_CREATE | 944 PP_FILEOPENFLAG_TRUNCATE | 945 PP_FILEOPENFLAG_READ | 946 PP_FILEOPENFLAG_WRITE, 947 callback.GetCallback())); 948 CHECK_CALLBACK_BEHAVIOR(callback); 949 ASSERT_EQ(PP_OK, callback.result()); 950 951 TestCompletionCallback callback_1(instance_->pp_instance(), PP_REQUIRED); 952 int32_t write_offset_1 = 0; 953 const char* buf_1 = "mnopqrstuvw"; 954 int32_t rv_1 = file_io.Write(write_offset_1, buf_1, strlen(buf_1), 955 callback_1.GetCallback()); 956 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1); 957 958 TestCompletionCallback callback_2(instance_->pp_instance(), callback_type()); 959 int32_t read_offset_2 = 4; 960 char buf_2[3]; 961 callback_2.WaitForResult(file_io.Read(read_offset_2, buf_2, sizeof(buf_2), 962 callback_2.GetCallback())); 963 CHECK_CALLBACK_BEHAVIOR(callback_2); 964 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result()); 965 callback_1.WaitForResult(rv_1); 966 CHECK_CALLBACK_BEHAVIOR(callback_1); 967 968 // Cannot query while a write is pending. 969 rv_1 = file_io.Write(write_offset_1, buf_1, strlen(buf_1), 970 callback_1.GetCallback()); 971 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1); 972 PP_FileInfo info; 973 callback_2.WaitForResult(file_io.Query(&info, callback_2.GetCallback())); 974 CHECK_CALLBACK_BEHAVIOR(callback_2); 975 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result()); 976 callback_1.WaitForResult(rv_1); 977 CHECK_CALLBACK_BEHAVIOR(callback_1); 978 979 // Cannot touch while a write is pending. 980 rv_1 = file_io.Write(write_offset_1, buf_1, strlen(buf_1), 981 callback_1.GetCallback()); 982 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1); 983 callback_2.WaitForResult(file_io.Touch(1234.0, 5678.0, 984 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 // Cannot set length while a write is pending. 991 rv_1 = file_io.Write(write_offset_1, buf_1, strlen(buf_1), 992 callback_1.GetCallback()); 993 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1); 994 callback_2.WaitForResult(file_io.SetLength(123, callback_2.GetCallback())); 995 CHECK_CALLBACK_BEHAVIOR(callback_2); 996 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result()); 997 callback_1.WaitForResult(rv_1); 998 CHECK_CALLBACK_BEHAVIOR(callback_1); 999 1000 PASS(); 1001 } 1002 1003 std::string TestFileIO::TestRequestOSFileHandle() { 1004 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 1005 1006 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 1007 pp::FileRef file_ref(file_system, "/file_os_fd"); 1008 1009 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 1010 ASSERT_EQ(PP_OK, callback.result()); 1011 1012 pp::FileIO_Private file_io(instance_); 1013 callback.WaitForResult(file_io.Open(file_ref, 1014 PP_FILEOPENFLAG_CREATE | 1015 PP_FILEOPENFLAG_TRUNCATE | 1016 PP_FILEOPENFLAG_READ | 1017 PP_FILEOPENFLAG_WRITE, 1018 callback.GetCallback())); 1019 ASSERT_EQ(PP_OK, callback.result()); 1020 1021 TestCompletionCallbackWithOutput<pp::PassFileHandle> output_callback( 1022 instance_->pp_instance(), callback_type()); 1023 output_callback.WaitForResult( 1024 file_io.RequestOSFileHandle(output_callback.GetCallback())); 1025 PP_FileHandle handle = output_callback.output().Release(); 1026 ASSERT_EQ(PP_OK, output_callback.result()); 1027 1028 if (handle == PP_kInvalidFileHandle) 1029 return "FileIO::RequestOSFileHandle() returned a bad file handle."; 1030 #if defined(PPAPI_OS_WIN) 1031 int fd = _open_osfhandle(reinterpret_cast<intptr_t>(handle), 1032 _O_RDWR | _O_BINARY); 1033 #else 1034 int fd = handle; 1035 #endif 1036 if (fd < 0) 1037 return "FileIO::RequestOSFileHandle() returned a bad file descriptor."; 1038 1039 // Check write(2) for the native FD. 1040 const std::string msg = "foobar"; 1041 ssize_t cnt = write(fd, msg.data(), msg.size()); 1042 if (cnt < 0) 1043 return ReportError("write for native FD returned error", errno); 1044 if (cnt != static_cast<ssize_t>(msg.size())) 1045 return ReportError("write for native FD count mismatch", cnt); 1046 1047 // Check lseek(2) for the native FD. 1048 off_t off = lseek(fd, 0, SEEK_CUR); 1049 if (off == static_cast<off_t>(-1)) 1050 return ReportError("lseek for native FD returned error", errno); 1051 if (off != static_cast<off_t>(msg.size())) 1052 return ReportError("lseek for native FD offset mismatch", off); 1053 1054 off = lseek(fd, 0, SEEK_SET); 1055 if (off == static_cast<off_t>(-1)) 1056 return ReportError("lseek for native FD returned error", errno); 1057 if (off != 0) 1058 return ReportError("lseek for native FD offset mismatch", off); 1059 1060 // Check read(2) for the native FD. 1061 std::string buf(msg.size(), '\0'); 1062 cnt = read(fd, &buf[0], msg.size()); 1063 if (cnt < 0) 1064 return ReportError("read for native FD returned error", errno); 1065 if (cnt != static_cast<ssize_t>(msg.size())) 1066 return ReportError("read for native FD count mismatch", cnt); 1067 if (msg != buf) 1068 return ReportMismatch("read for native FD", buf, msg); 1069 PASS(); 1070 } 1071 1072 // Calling RequestOSFileHandle with the FileIO that is opened with 1073 // PP_FILEOPENFLAG_EXCLUSIVE used to cause NaCl module to crash while loading. 1074 // This is a regression test for crbug.com/243241. 1075 std::string TestFileIO::TestRequestOSFileHandleWithOpenExclusive() { 1076 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 1077 1078 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 1079 pp::FileRef file_ref(file_system, "/file_os_fd2"); 1080 1081 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 1082 ASSERT_EQ(PP_OK, callback.result()); 1083 1084 // Open with PP_FILEOPENFLAG_CREATE and PP_FILEOPENFLAG_EXCLUSIVE will fail 1085 // if the file already exists. Delete it here to make sure it does not. 1086 callback.WaitForResult(file_ref.Delete(callback.GetCallback())); 1087 1088 pp::FileIO_Private file_io(instance_); 1089 callback.WaitForResult(file_io.Open(file_ref, 1090 PP_FILEOPENFLAG_CREATE | 1091 PP_FILEOPENFLAG_READ | 1092 PP_FILEOPENFLAG_WRITE | 1093 PP_FILEOPENFLAG_EXCLUSIVE, 1094 callback.GetCallback())); 1095 ASSERT_EQ(PP_OK, callback.result()); 1096 1097 TestCompletionCallbackWithOutput<pp::PassFileHandle> output_callback( 1098 instance_->pp_instance(), callback_type()); 1099 output_callback.WaitForResult( 1100 file_io.RequestOSFileHandle(output_callback.GetCallback())); 1101 PP_FileHandle handle = output_callback.output().Release(); 1102 if (handle == PP_kInvalidFileHandle) 1103 return "FileIO::RequestOSFileHandle() returned a bad file handle."; 1104 ASSERT_EQ(PP_OK, output_callback.result()); 1105 1106 PASS(); 1107 } 1108 1109 std::string TestFileIO::TestMmap() { 1110 #if !defined(PPAPI_OS_WIN) 1111 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 1112 1113 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 1114 pp::FileRef file_ref(file_system, "/file_os_fd"); 1115 1116 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 1117 ASSERT_EQ(PP_OK, callback.result()); 1118 1119 pp::FileIO_Private file_io(instance_); 1120 callback.WaitForResult(file_io.Open(file_ref, 1121 PP_FILEOPENFLAG_CREATE | 1122 PP_FILEOPENFLAG_TRUNCATE | 1123 PP_FILEOPENFLAG_READ | 1124 PP_FILEOPENFLAG_WRITE, 1125 callback.GetCallback())); 1126 ASSERT_EQ(PP_OK, callback.result()); 1127 1128 TestCompletionCallbackWithOutput<pp::PassFileHandle> output_callback( 1129 instance_->pp_instance(), callback_type()); 1130 output_callback.WaitForResult( 1131 file_io.RequestOSFileHandle(output_callback.GetCallback())); 1132 PP_FileHandle handle = output_callback.output().Release(); 1133 ASSERT_EQ(PP_OK, output_callback.result()); 1134 1135 if (handle == PP_kInvalidFileHandle) 1136 return "FileIO::RequestOSFileHandle() returned a bad file handle."; 1137 int fd = handle; 1138 if (fd < 0) 1139 return "FileIO::RequestOSFileHandle() returned a bad file descriptor."; 1140 1141 // Check write(2) for the native FD. 1142 const std::string msg = "foobar"; 1143 ssize_t cnt = write(fd, msg.data(), msg.size()); 1144 if (cnt < 0) 1145 return ReportError("write for native FD returned error", errno); 1146 if (cnt != static_cast<ssize_t>(msg.size())) 1147 return ReportError("write for native FD count mismatch", cnt); 1148 1149 // BEGIN mmap(2) test with a file handle opened in READ-WRITE mode. 1150 // Check mmap(2) for read. 1151 { 1152 char* mapped = reinterpret_cast<char*>( 1153 mmap(NULL, msg.size(), PROT_READ, MAP_PRIVATE, fd, 0)); 1154 if (mapped == MAP_FAILED) 1155 return ReportError("mmap(r) for native FD returned errno", errno); 1156 // Make sure the buffer is cleared. 1157 std::string buf = std::string(msg.size(), '\0'); 1158 memcpy(&buf[0], mapped, msg.size()); 1159 if (msg != buf) 1160 return ReportMismatch("mmap(r) for native FD", buf, msg); 1161 int r = munmap(mapped, msg.size()); 1162 if (r < 0) 1163 return ReportError("munmap for native FD returned error", errno); 1164 } 1165 1166 // Check mmap(2) for write with MAP_PRIVATE 1167 { 1168 char* mapped = reinterpret_cast<char*>( 1169 mmap(NULL, msg.size(), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)); 1170 if (mapped == MAP_FAILED) 1171 return ReportError("mmap(r) for native FD returned errno", errno); 1172 // Make sure the file is not polluted by writing to privage mmap. 1173 strncpy(mapped, "baz", 3); 1174 std::string read_buffer; 1175 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd, &read_buffer)); 1176 if (msg != read_buffer) 1177 return ReportMismatch("file content != msg", read_buffer, msg); 1178 int r = munmap(mapped, msg.size()); 1179 if (r < 0) 1180 return ReportError("munmap for native FD returned error", errno); 1181 } 1182 1183 // Check mmap(2) for write with MAP_SHARED. 1184 { 1185 char* mapped = reinterpret_cast<char*>( 1186 mmap(NULL, msg.size(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); 1187 if (mapped == MAP_FAILED) 1188 return ReportError("mmap(w) for native FD returned errno", errno); 1189 // s/foo/baz/ 1190 strncpy(mapped, "baz", 3); 1191 std::string read_buffer; 1192 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd, &read_buffer)); 1193 if (read_buffer != "bazbar") 1194 return ReportMismatch("file content != msg", read_buffer, "bazbar"); 1195 int r = munmap(mapped, msg.size()); 1196 if (r < 0) 1197 return ReportError("munmap for native FD returned error", errno); 1198 } 1199 // END mmap(2) test with a file handle opened in READ-WRITE mode. 1200 1201 if (close(fd) < 0) 1202 return ReportError("close for native FD returned error", errno); 1203 1204 // BEGIN mmap(2) test with a file handle opened in READONLY mode. 1205 file_io = pp::FileIO_Private(instance_); 1206 callback.WaitForResult(file_io.Open(file_ref, 1207 PP_FILEOPENFLAG_READ, 1208 callback.GetCallback())); 1209 ASSERT_EQ(PP_OK, callback.result()); 1210 1211 output_callback = TestCompletionCallbackWithOutput<pp::PassFileHandle>( 1212 instance_->pp_instance(), callback_type()); 1213 output_callback.WaitForResult( 1214 file_io.RequestOSFileHandle(output_callback.GetCallback())); 1215 handle = output_callback.output().Release(); 1216 ASSERT_EQ(PP_OK, output_callback.result()); 1217 1218 if (handle == PP_kInvalidFileHandle) 1219 return "FileIO::RequestOSFileHandle() returned a bad file handle."; 1220 fd = handle; 1221 if (fd < 0) 1222 return "FileIO::RequestOSFileHandle() returned a bad file descriptor."; 1223 1224 const std::string msg2 = "bazbar"; 1225 1226 // Check mmap(2) for read. 1227 { 1228 char* mapped = reinterpret_cast<char*>( 1229 mmap(NULL, msg2.size(), PROT_READ, MAP_PRIVATE, fd, 0)); 1230 if (mapped == MAP_FAILED) 1231 return ReportError("mmap(r) for native FD returned errno", errno); 1232 // Make sure the buffer is cleared. 1233 std::string buf = std::string(msg2.size(), '\0'); 1234 memcpy(&buf[0], mapped, msg2.size()); 1235 if (msg2 != buf) 1236 return ReportMismatch("mmap(r) for native FD", buf, msg2); 1237 int r = munmap(mapped, msg2.size()); 1238 if (r < 0) 1239 return ReportError("munmap for native FD returned error", errno); 1240 } 1241 1242 // Check mmap(2) for write with MAP_PRIVATE 1243 { 1244 char* mapped = reinterpret_cast<char*>( 1245 mmap(NULL, msg2.size(), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)); 1246 if (mapped == MAP_FAILED) 1247 return ReportError("mmap(r) for native FD returned errno", errno); 1248 // Make sure the file is not polluted by writing to privage mmap. 1249 strncpy(mapped, "baz", 3); 1250 std::string read_buffer; 1251 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd, &read_buffer)); 1252 if (msg2 != read_buffer) 1253 return ReportMismatch("file content != msg2", read_buffer, msg2); 1254 int r = munmap(mapped, msg2.size()); 1255 if (r < 0) 1256 return ReportError("munmap for native FD returned error", errno); 1257 } 1258 1259 // Check mmap(2) for write with MAP_SHARED. 1260 { 1261 char* mapped = reinterpret_cast<char*>( 1262 mmap(NULL, msg2.size(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); 1263 if (mapped != MAP_FAILED) 1264 return ReportError("mmap(w) for native FD must fail when opened readonly", 1265 -1); 1266 } 1267 // END mmap(2) test with a file handle opened in READONLY mode. 1268 1269 if (close(fd) < 0) 1270 return ReportError("close for native FD returned error", errno); 1271 #endif // !defined(PPAPI_OS_WIN) 1272 1273 PASS(); 1274 } 1275 1276 std::string TestFileIO::MatchOpenExpectations(pp::FileSystem* file_system, 1277 size_t open_flags, 1278 size_t expectations) { 1279 std::string bad_argument = 1280 "TestFileIO::MatchOpenExpectations has invalid input arguments."; 1281 bool invalid_combination = !!(expectations & INVALID_FLAG_COMBINATION); 1282 if (invalid_combination) { 1283 if (expectations != INVALID_FLAG_COMBINATION) 1284 return bad_argument; 1285 } else { 1286 // Validate that one and only one of <some_expectation> and 1287 // DONT_<some_expectation> is specified. 1288 for (size_t remains = expectations, end = END_OF_OPEN_EXPECATION_PAIRS; 1289 end != 0; remains >>= 2, end >>= 2) { 1290 if (!!(remains & 1) == !!(remains & 2)) 1291 return bad_argument; 1292 } 1293 } 1294 bool create_if_doesnt_exist = !!(expectations & CREATE_IF_DOESNT_EXIST); 1295 bool open_if_exists = !!(expectations & OPEN_IF_EXISTS); 1296 bool truncate_if_exists = !!(expectations & TRUNCATE_IF_EXISTS); 1297 1298 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 1299 pp::FileRef existent_file_ref( 1300 *file_system, "/match_open_expectation_existent_non_empty_file"); 1301 pp::FileRef nonexistent_file_ref( 1302 *file_system, "/match_open_expectation_nonexistent_file"); 1303 1304 // Setup files for test. 1305 { 1306 callback.WaitForResult(existent_file_ref.Delete(callback.GetCallback())); 1307 CHECK_CALLBACK_BEHAVIOR(callback); 1308 ASSERT_TRUE(callback.result() == PP_OK || 1309 callback.result() == PP_ERROR_FILENOTFOUND); 1310 callback.WaitForResult(nonexistent_file_ref.Delete(callback.GetCallback())); 1311 CHECK_CALLBACK_BEHAVIOR(callback); 1312 ASSERT_TRUE(callback.result() == PP_OK || 1313 callback.result() == PP_ERROR_FILENOTFOUND); 1314 1315 pp::FileIO existent_file_io(instance_); 1316 callback.WaitForResult(existent_file_io.Open( 1317 existent_file_ref, 1318 PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE, 1319 callback.GetCallback())); 1320 CHECK_CALLBACK_BEHAVIOR(callback); 1321 ASSERT_EQ(PP_OK, callback.result()); 1322 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &existent_file_io, 1323 0, "foobar", callback_type()); 1324 ASSERT_EQ(PP_OK, rv); 1325 } 1326 1327 pp::FileIO existent_file_io(instance_); 1328 callback.WaitForResult(existent_file_io.Open(existent_file_ref, open_flags, 1329 callback.GetCallback())); 1330 CHECK_CALLBACK_BEHAVIOR(callback); 1331 if ((invalid_combination && callback.result() == PP_OK) || 1332 (!invalid_combination && 1333 ((callback.result() == PP_OK) != open_if_exists))) { 1334 return ReportOpenError(open_flags); 1335 } 1336 1337 if (!invalid_combination && open_if_exists) { 1338 PP_FileInfo info; 1339 callback.WaitForResult(existent_file_io.Query(&info, 1340 callback.GetCallback())); 1341 CHECK_CALLBACK_BEHAVIOR(callback); 1342 ASSERT_EQ(PP_OK, callback.result()); 1343 if (truncate_if_exists != (info.size == 0)) 1344 return ReportOpenError(open_flags); 1345 } 1346 1347 pp::FileIO nonexistent_file_io(instance_); 1348 callback.WaitForResult(nonexistent_file_io.Open(nonexistent_file_ref, 1349 open_flags, 1350 callback.GetCallback())); 1351 CHECK_CALLBACK_BEHAVIOR(callback); 1352 if ((invalid_combination && callback.result() == PP_OK) || 1353 (!invalid_combination && 1354 ((callback.result() == PP_OK) != create_if_doesnt_exist))) { 1355 return ReportOpenError(open_flags); 1356 } 1357 1358 return std::string(); 1359 } 1360 1361 // TODO(viettrungluu): Test Close(). crbug.com/69457 1362