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