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 <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