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
44REGISTER_TEST_CASE(FileIO);
45
46namespace {
47
48std::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
55std::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
83int32_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
106int32_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
130bool 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
145int32_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
172bool TestFileIO::Init() {
173  return CheckTestingInterface() && EnsureRunningOverHTTP();
174}
175
176void 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
195std::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
290std::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
316std::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.
440std::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
548std::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
605std::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
759std::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
846std::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
928std::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
1003std::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.
1075std::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
1109std::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
1276std::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