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