• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ReportMismatch(const std::string & method_name,const std::string & returned_result,const std::string & expected_result)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 
ReportOpenError(int32_t open_flags)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 
ReadEntireFile(PP_Instance instance,pp::FileIO * file_io,int32_t offset,std::string * data,CallbackType callback_type)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 
ReadToArrayEntireFile(PP_Instance instance,pp::FileIO * file_io,int32_t offset,std::string * data,CallbackType callback_type)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 
ReadEntireFileFromFileHandle(int fd,std::string * data)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 
WriteEntireBuffer(PP_Instance instance,pp::FileIO * file_io,int32_t offset,const std::string & data,CallbackType callback_type)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 
Init()172 bool TestFileIO::Init() {
173   return CheckTestingInterface() && EnsureRunningOverHTTP();
174 }
175 
RunTests(const std::string & filter)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 
TestOpen()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 
TestOpenDirectory()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 
TestReadWriteSetLength()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.
TestReadToArrayWriteSetLength()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 
TestTouchQuery()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 
TestAbortCalls()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 
TestParallelReads()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 
TestParallelWrites()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 
TestNotAllowMixedReadWrite()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 
TestRequestOSFileHandle()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.
TestRequestOSFileHandleWithOpenExclusive()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 
TestMmap()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 
MatchOpenExpectations(pp::FileSystem * file_system,size_t open_flags,size_t expectations)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