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