Drive: Add BatchableRequest subclass.
[chromium-blink-merge.git] / ppapi / tests / test_file_io.cc
blob87839055feb9963692958d0a07062a00bc2d2c94
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.
5 #include "ppapi/tests/test_file_io.h"
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>
14 #include <algorithm>
15 #include <vector>
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"
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
44 REGISTER_TEST_CASE(FileIO);
46 namespace {
48 std::string ReportMismatch(const std::string& method_name,
49 const std::string& returned_result,
50 const std::string& expected_result) {
51 return method_name + " returned '" + returned_result + "'; '" +
52 expected_result + "' expected.";
55 std::string ReportOpenError(int32_t open_flags) {
56 static const char* kFlagNames[] = {
57 "PP_FILEOPENFLAG_READ",
58 "PP_FILEOPENFLAG_WRITE",
59 "PP_FILEOPENFLAG_CREATE",
60 "PP_FILEOPENFLAG_TRUNCATE",
61 "PP_FILEOPENFLAG_EXCLUSIVE"
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 += " | ";
74 result += kFlagNames[index];
77 if (first_flag)
78 result += "[None]";
80 return result;
83 int32_t ReadEntireFile(PP_Instance instance,
84 pp::FileIO* file_io,
85 int32_t offset,
86 std::string* data,
87 CallbackType callback_type) {
88 TestCompletionCallback callback(instance, callback_type);
89 char buf[256];
90 int32_t read_offset = offset;
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());
103 return PP_OK;
106 int32_t ReadToArrayEntireFile(PP_Instance instance,
107 pp::FileIO* file_io,
108 int32_t offset,
109 std::string* data,
110 CallbackType callback_type) {
111 TestCompletionCallbackWithOutput< std::vector<char> > callback(
112 instance, callback_type);
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());
127 return PP_OK;
130 bool ReadEntireFileFromFileHandle(int fd, std::string* data) {
131 if (lseek(fd, 0, SEEK_SET) < 0)
132 return false;
133 data->clear();
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;
145 int32_t WriteEntireBuffer(PP_Instance instance,
146 pp::FileIO* file_io,
147 int32_t offset,
148 const std::string& data,
149 CallbackType callback_type) {
150 TestCompletionCallback callback(instance, callback_type);
151 int32_t write_offset = offset;
152 const char* buf = data.c_str();
153 int32_t size = static_cast<int32_t>(data.size());
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();
167 return PP_OK;
170 } // namespace
172 bool TestFileIO::Init() {
173 return CheckTestingInterface() && EnsureRunningOverHTTP();
176 void TestFileIO::RunTests(const std::string& filter) {
177 RUN_CALLBACK_TEST(TestFileIO, Open, filter);
178 RUN_CALLBACK_TEST(TestFileIO, OpenDirectory, filter);
179 RUN_CALLBACK_TEST(TestFileIO, ReadWriteSetLength, filter);
180 RUN_CALLBACK_TEST(TestFileIO, ReadToArrayWriteSetLength, filter);
181 RUN_CALLBACK_TEST(TestFileIO, TouchQuery, filter);
182 RUN_CALLBACK_TEST(TestFileIO, AbortCalls, filter);
183 RUN_CALLBACK_TEST(TestFileIO, ParallelReads, filter);
184 RUN_CALLBACK_TEST(TestFileIO, ParallelWrites, filter);
185 RUN_CALLBACK_TEST(TestFileIO, NotAllowMixedReadWrite, filter);
186 RUN_CALLBACK_TEST(TestFileIO, RequestOSFileHandle, filter);
187 RUN_CALLBACK_TEST(TestFileIO, RequestOSFileHandleWithOpenExclusive, filter);
188 RUN_CALLBACK_TEST(TestFileIO, Mmap, filter);
190 // TODO(viettrungluu): add tests:
191 // - that PP_ERROR_PENDING is correctly returned
192 // - that operations respect the file open modes (flags)
195 std::string TestFileIO::TestOpen() {
196 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
198 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
199 pp::FileRef file_ref(file_system, "/file_open");
201 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
202 CHECK_CALLBACK_BEHAVIOR(callback);
203 ASSERT_EQ(PP_OK, callback.result());
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;
213 // Test the behavior of the power set of
214 // { PP_FILEOPENFLAG_CREATE,
215 // PP_FILEOPENFLAG_TRUNCATE,
216 // PP_FILEOPENFLAG_EXCLUSIVE }.
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;
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;
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;
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;
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;
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;
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;
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;
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;
287 PASS();
290 std::string TestFileIO::TestOpenDirectory() {
291 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
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());
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());
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());
313 PASS();
316 std::string TestFileIO::TestReadWriteSetLength() {
317 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
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());
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());
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);
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,
345 callback.GetCallback()));
346 CHECK_CALLBACK_BEHAVIOR(callback);
347 ASSERT_EQ(PP_ERROR_FAILED, callback.result());
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);
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());
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);
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());
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);
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);
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());
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);
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);
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);
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);
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);
434 PASS();
437 // This is basically a copy of TestReadWriteSetLength, but with the new Read
438 // API. With this test case, we can make sure the two Read's have the same
439 // behavior.
440 std::string TestFileIO::TestReadToArrayWriteSetLength() {
441 if (callback_type() == PP_BLOCKING) {
442 // This test does not make sense for blocking callbacks.
443 PASS();
445 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
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());
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());
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);
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());
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);
483 // Truncate the file.
484 callback.WaitForResult(file_io.SetLength(4, callback.GetCallback()));
485 CHECK_CALLBACK_BEHAVIOR(callback);
486 ASSERT_EQ(PP_OK, rv);
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);
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());
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);
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);
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());
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);
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);
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);
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);
545 PASS();
548 std::string TestFileIO::TestTouchQuery() {
549 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
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());
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());
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());
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());
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());
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.";
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());
602 PASS();
605 std::string TestFileIO::TestAbortCalls() {
606 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
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());
614 int32_t rv = PP_ERROR_FAILED;
615 // First, create a file on which to do ops.
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());
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);
631 // Abort |Open()|.
633 rv = pp::FileIO(instance_)
634 .Open(file_ref, PP_FILEOPENFLAG_READ, callback.GetCallback());
636 callback.WaitForAbortResult(rv);
637 CHECK_CALLBACK_BEHAVIOR(callback);
639 // Abort |Query()|.
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));
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());
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)));
666 // Abort |Touch()|.
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());
675 rv = file_io.Touch(0, 0, callback.GetCallback());
676 } // Destroy |file_io|.
677 callback.WaitForAbortResult(rv);
678 CHECK_CALLBACK_BEHAVIOR(callback);
681 // Abort |Read()|.
683 char buf[3] = { 0 };
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());
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)));
706 // Abort |Write()|.
708 char buf[3] = { 0 };
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());
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());
726 // Abort |SetLength()|.
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());
735 rv = file_io.SetLength(3, callback.GetCallback());
736 } // Destroy |file_io|.
737 callback.WaitForAbortResult(rv);
738 CHECK_CALLBACK_BEHAVIOR(callback);
741 // Abort |Flush|.
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());
750 rv = file_io.Flush(callback.GetCallback());
751 } // Destroy |file_io|.
752 callback.WaitForAbortResult(rv);
753 CHECK_CALLBACK_BEHAVIOR(callback);
756 PASS();
759 std::string TestFileIO::TestParallelReads() {
760 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
761 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
762 pp::FileRef file_ref(file_system, "/file_parallel_reads");
763 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
764 CHECK_CALLBACK_BEHAVIOR(callback);
765 ASSERT_EQ(PP_OK, callback.result());
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());
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);
782 // Parallel read operations.
783 const char* border = "__border__";
784 const int32_t border_size = static_cast<int32_t>(strlen(border));
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);
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);
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());
809 if (size_2 > 0) {
810 rv_2 = file_io.Read(read_offset_2, buf_2, size_2,
811 callback_2.GetCallback());
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();
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();
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);
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();
846 std::string TestFileIO::TestParallelWrites() {
847 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
848 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
849 pp::FileRef file_ref(file_system, "/file_parallel_writes");
850 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
851 CHECK_CALLBACK_BEHAVIOR(callback);
852 ASSERT_EQ(PP_OK, callback.result());
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());
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 = static_cast<int32_t>(strlen(buf_1));
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 = static_cast<int32_t>(strlen(buf_2));
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], static_cast<int32_t>(str_1.size()),
883 callback_1.GetCallback());
884 // Erase the buffer to test that async writes copy it.
885 std::fill(str_1.begin(), str_1.end(), 0);
887 if (size_2 > 0) {
888 // Copy the buffer so we can erase it below.
889 std::string str_2(buf_2);
890 rv_2 = file_io.Write(
891 write_offset_2, &str_2[0], static_cast<int32_t>(str_2.size()),
892 callback_2.GetCallback());
893 // Erase the buffer to test that async writes copy it.
894 std::fill(str_2.begin(), str_2.end(), 0);
897 if (size_1 > 0) {
898 callback_1.WaitForResult(rv_1);
899 CHECK_CALLBACK_BEHAVIOR(callback_1);
900 ASSERT_TRUE(callback_1.result() > 0);
901 write_offset_1 += callback_1.result();
902 buf_1 += callback_1.result();
903 size_1 -= callback_1.result();
906 if (size_2 > 0) {
907 callback_2.WaitForResult(rv_2);
908 CHECK_CALLBACK_BEHAVIOR(callback_2);
909 ASSERT_TRUE(callback_2.result() > 0);
910 write_offset_2 += callback_2.result();
911 buf_2 += callback_2.result();
912 size_2 -= callback_2.result();
916 // If |size_1| or |size_2| is not 0, we have invoked wrong callback(s).
917 ASSERT_EQ(0, size_1);
918 ASSERT_EQ(0, size_2);
920 // Check the file contents.
921 std::string read_buffer;
922 int32_t rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0,
923 &read_buffer, callback_type());
924 ASSERT_EQ(PP_OK, rv);
925 ASSERT_EQ(std::string("abcdefghijkl"), read_buffer);
927 PASS();
930 std::string TestFileIO::TestNotAllowMixedReadWrite() {
931 if (callback_type() == PP_BLOCKING) {
932 // This test does not make sense for blocking callbacks.
933 PASS();
935 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
937 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
938 pp::FileRef file_ref(file_system, "/file_not_allow_mixed_read_write");
939 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
940 CHECK_CALLBACK_BEHAVIOR(callback);
941 ASSERT_EQ(PP_OK, callback.result());
943 pp::FileIO file_io(instance_);
944 callback.WaitForResult(file_io.Open(file_ref,
945 PP_FILEOPENFLAG_CREATE |
946 PP_FILEOPENFLAG_TRUNCATE |
947 PP_FILEOPENFLAG_READ |
948 PP_FILEOPENFLAG_WRITE,
949 callback.GetCallback()));
950 CHECK_CALLBACK_BEHAVIOR(callback);
951 ASSERT_EQ(PP_OK, callback.result());
953 TestCompletionCallback callback_1(instance_->pp_instance(), PP_REQUIRED);
954 int32_t write_offset_1 = 0;
955 const char* buf_1 = "mnopqrstuvw";
956 int32_t rv_1 = file_io.Write(write_offset_1, buf_1,
957 static_cast<int32_t>(strlen(buf_1)),
958 callback_1.GetCallback());
959 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1);
961 TestCompletionCallback callback_2(instance_->pp_instance(), callback_type());
962 int32_t read_offset_2 = 4;
963 char buf_2[3];
964 callback_2.WaitForResult(file_io.Read(read_offset_2, buf_2, sizeof(buf_2),
965 callback_2.GetCallback()));
966 CHECK_CALLBACK_BEHAVIOR(callback_2);
967 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
968 callback_1.WaitForResult(rv_1);
969 CHECK_CALLBACK_BEHAVIOR(callback_1);
971 // Cannot query while a write is pending.
972 rv_1 = file_io.Write(write_offset_1, buf_1,
973 static_cast<int32_t>(strlen(buf_1)),
974 callback_1.GetCallback());
975 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1);
976 PP_FileInfo info;
977 callback_2.WaitForResult(file_io.Query(&info, callback_2.GetCallback()));
978 CHECK_CALLBACK_BEHAVIOR(callback_2);
979 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
980 callback_1.WaitForResult(rv_1);
981 CHECK_CALLBACK_BEHAVIOR(callback_1);
983 // Cannot touch while a write is pending.
984 rv_1 = file_io.Write(write_offset_1, buf_1,
985 static_cast<int32_t>(strlen(buf_1)),
986 callback_1.GetCallback());
987 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1);
988 callback_2.WaitForResult(file_io.Touch(1234.0, 5678.0,
989 callback_2.GetCallback()));
990 CHECK_CALLBACK_BEHAVIOR(callback_2);
991 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
992 callback_1.WaitForResult(rv_1);
993 CHECK_CALLBACK_BEHAVIOR(callback_1);
995 // Cannot set length while a write is pending.
996 rv_1 = file_io.Write(write_offset_1, buf_1,
997 static_cast<int32_t>(strlen(buf_1)),
998 callback_1.GetCallback());
999 ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1);
1000 callback_2.WaitForResult(file_io.SetLength(123, callback_2.GetCallback()));
1001 CHECK_CALLBACK_BEHAVIOR(callback_2);
1002 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
1003 callback_1.WaitForResult(rv_1);
1004 CHECK_CALLBACK_BEHAVIOR(callback_1);
1006 PASS();
1009 std::string TestFileIO::TestRequestOSFileHandle() {
1010 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1012 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
1013 pp::FileRef file_ref(file_system, "/file_os_fd");
1015 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
1016 ASSERT_EQ(PP_OK, callback.result());
1018 pp::FileIO_Private file_io(instance_);
1019 callback.WaitForResult(file_io.Open(file_ref,
1020 PP_FILEOPENFLAG_CREATE |
1021 PP_FILEOPENFLAG_TRUNCATE |
1022 PP_FILEOPENFLAG_READ |
1023 PP_FILEOPENFLAG_WRITE,
1024 callback.GetCallback()));
1025 ASSERT_EQ(PP_OK, callback.result());
1027 TestCompletionCallbackWithOutput<pp::PassFileHandle> output_callback(
1028 instance_->pp_instance(), callback_type());
1029 output_callback.WaitForResult(
1030 file_io.RequestOSFileHandle(output_callback.GetCallback()));
1031 PP_FileHandle handle = output_callback.output().Release();
1032 ASSERT_EQ(PP_OK, output_callback.result());
1034 if (handle == PP_kInvalidFileHandle)
1035 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1036 #if defined(PPAPI_OS_WIN)
1037 int fd = _open_osfhandle(reinterpret_cast<intptr_t>(handle),
1038 _O_RDWR | _O_BINARY);
1039 #else
1040 int fd = handle;
1041 #endif
1042 if (fd < 0)
1043 return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
1045 // Check write(2) for the native FD.
1046 const std::string msg = "foobar";
1047 ssize_t cnt = write(fd, msg.data(), static_cast<unsigned>(msg.size()));
1048 if (cnt < 0)
1049 return ReportError("write for native FD returned error", errno);
1050 if (cnt != static_cast<ssize_t>(msg.size()))
1051 return ReportError("write for native FD count mismatch", cnt);
1053 // Check lseek(2) for the native FD.
1054 off_t off = lseek(fd, 0, SEEK_CUR);
1055 if (off == static_cast<off_t>(-1))
1056 return ReportError("lseek for native FD returned error", errno);
1057 if (off != static_cast<off_t>(msg.size()))
1058 return ReportError("lseek for native FD offset mismatch", off);
1060 off = lseek(fd, 0, SEEK_SET);
1061 if (off == static_cast<off_t>(-1))
1062 return ReportError("lseek for native FD returned error", errno);
1063 if (off != 0)
1064 return ReportError("lseek for native FD offset mismatch", off);
1066 // Check read(2) for the native FD.
1067 std::string buf(msg.size(), '\0');
1068 cnt = read(fd, &buf[0], static_cast<unsigned>(msg.size()));
1069 if (cnt < 0)
1070 return ReportError("read for native FD returned error", errno);
1071 if (cnt != static_cast<ssize_t>(msg.size()))
1072 return ReportError("read for native FD count mismatch", cnt);
1073 if (msg != buf)
1074 return ReportMismatch("read for native FD", buf, msg);
1075 PASS();
1078 // Calling RequestOSFileHandle with the FileIO that is opened with
1079 // PP_FILEOPENFLAG_EXCLUSIVE used to cause NaCl module to crash while loading.
1080 // This is a regression test for crbug.com/243241.
1081 std::string TestFileIO::TestRequestOSFileHandleWithOpenExclusive() {
1082 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1084 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
1085 pp::FileRef file_ref(file_system, "/file_os_fd2");
1087 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
1088 ASSERT_EQ(PP_OK, callback.result());
1090 // Open with PP_FILEOPENFLAG_CREATE and PP_FILEOPENFLAG_EXCLUSIVE will fail
1091 // if the file already exists. Delete it here to make sure it does not.
1092 callback.WaitForResult(file_ref.Delete(callback.GetCallback()));
1094 pp::FileIO_Private file_io(instance_);
1095 callback.WaitForResult(file_io.Open(file_ref,
1096 PP_FILEOPENFLAG_CREATE |
1097 PP_FILEOPENFLAG_READ |
1098 PP_FILEOPENFLAG_WRITE |
1099 PP_FILEOPENFLAG_EXCLUSIVE,
1100 callback.GetCallback()));
1101 ASSERT_EQ(PP_OK, callback.result());
1103 TestCompletionCallbackWithOutput<pp::PassFileHandle> output_callback(
1104 instance_->pp_instance(), callback_type());
1105 output_callback.WaitForResult(
1106 file_io.RequestOSFileHandle(output_callback.GetCallback()));
1107 PP_FileHandle handle = output_callback.output().Release();
1108 if (handle == PP_kInvalidFileHandle)
1109 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1110 ASSERT_EQ(PP_OK, output_callback.result());
1112 PASS();
1115 std::string TestFileIO::TestMmap() {
1116 #if !defined(PPAPI_OS_WIN)
1117 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1119 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
1120 pp::FileRef file_ref(file_system, "/file_os_fd");
1122 callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
1123 ASSERT_EQ(PP_OK, callback.result());
1125 pp::FileIO_Private file_io(instance_);
1126 callback.WaitForResult(file_io.Open(file_ref,
1127 PP_FILEOPENFLAG_CREATE |
1128 PP_FILEOPENFLAG_TRUNCATE |
1129 PP_FILEOPENFLAG_READ |
1130 PP_FILEOPENFLAG_WRITE,
1131 callback.GetCallback()));
1132 ASSERT_EQ(PP_OK, callback.result());
1134 TestCompletionCallbackWithOutput<pp::PassFileHandle> output_callback(
1135 instance_->pp_instance(), callback_type());
1136 output_callback.WaitForResult(
1137 file_io.RequestOSFileHandle(output_callback.GetCallback()));
1138 PP_FileHandle handle = output_callback.output().Release();
1139 ASSERT_EQ(PP_OK, output_callback.result());
1141 if (handle == PP_kInvalidFileHandle)
1142 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1143 int fd = handle;
1144 if (fd < 0)
1145 return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
1147 // Check write(2) for the native FD.
1148 const std::string msg = "foobar";
1149 ssize_t cnt = write(fd, msg.data(), msg.size());
1150 if (cnt < 0)
1151 return ReportError("write for native FD returned error", errno);
1152 if (cnt != static_cast<ssize_t>(msg.size()))
1153 return ReportError("write for native FD count mismatch", cnt);
1155 // BEGIN mmap(2) test with a file handle opened in READ-WRITE mode.
1156 // Check mmap(2) for read.
1158 char* mapped = reinterpret_cast<char*>(
1159 mmap(NULL, msg.size(), PROT_READ, MAP_PRIVATE, fd, 0));
1160 if (mapped == MAP_FAILED)
1161 return ReportError("mmap(r) for native FD returned errno", errno);
1162 // Make sure the buffer is cleared.
1163 std::string buf = std::string(msg.size(), '\0');
1164 memcpy(&buf[0], mapped, msg.size());
1165 if (msg != buf)
1166 return ReportMismatch("mmap(r) for native FD", buf, msg);
1167 int r = munmap(mapped, msg.size());
1168 if (r < 0)
1169 return ReportError("munmap for native FD returned error", errno);
1172 // Check mmap(2) for write with MAP_PRIVATE
1174 char* mapped = reinterpret_cast<char*>(
1175 mmap(NULL, msg.size(), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0));
1176 if (mapped == MAP_FAILED)
1177 return ReportError("mmap(r) for native FD returned errno", errno);
1178 // Make sure the file is not polluted by writing to privage mmap.
1179 strncpy(mapped, "baz", 3);
1180 std::string read_buffer;
1181 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd, &read_buffer));
1182 if (msg != read_buffer)
1183 return ReportMismatch("file content != msg", read_buffer, msg);
1184 int r = munmap(mapped, msg.size());
1185 if (r < 0)
1186 return ReportError("munmap for native FD returned error", errno);
1189 // Check mmap(2) for write with MAP_SHARED.
1191 char* mapped = reinterpret_cast<char*>(
1192 mmap(NULL, msg.size(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
1193 if (mapped == MAP_FAILED)
1194 return ReportError("mmap(w) for native FD returned errno", errno);
1195 // s/foo/baz/
1196 strncpy(mapped, "baz", 3);
1197 std::string read_buffer;
1198 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd, &read_buffer));
1199 if (read_buffer != "bazbar")
1200 return ReportMismatch("file content != msg", read_buffer, "bazbar");
1201 int r = munmap(mapped, msg.size());
1202 if (r < 0)
1203 return ReportError("munmap for native FD returned error", errno);
1205 // END mmap(2) test with a file handle opened in READ-WRITE mode.
1207 if (close(fd) < 0)
1208 return ReportError("close for native FD returned error", errno);
1210 // BEGIN mmap(2) test with a file handle opened in READONLY mode.
1211 file_io = pp::FileIO_Private(instance_);
1212 callback.WaitForResult(file_io.Open(file_ref,
1213 PP_FILEOPENFLAG_READ,
1214 callback.GetCallback()));
1215 ASSERT_EQ(PP_OK, callback.result());
1217 output_callback = TestCompletionCallbackWithOutput<pp::PassFileHandle>(
1218 instance_->pp_instance(), callback_type());
1219 output_callback.WaitForResult(
1220 file_io.RequestOSFileHandle(output_callback.GetCallback()));
1221 handle = output_callback.output().Release();
1222 ASSERT_EQ(PP_OK, output_callback.result());
1224 if (handle == PP_kInvalidFileHandle)
1225 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1226 fd = handle;
1227 if (fd < 0)
1228 return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
1230 const std::string msg2 = "bazbar";
1232 // Check mmap(2) for read.
1234 char* mapped = reinterpret_cast<char*>(
1235 mmap(NULL, msg2.size(), PROT_READ, MAP_PRIVATE, fd, 0));
1236 if (mapped == MAP_FAILED)
1237 return ReportError("mmap(r) for native FD returned errno", errno);
1238 // Make sure the buffer is cleared.
1239 std::string buf = std::string(msg2.size(), '\0');
1240 memcpy(&buf[0], mapped, msg2.size());
1241 if (msg2 != buf)
1242 return ReportMismatch("mmap(r) for native FD", buf, msg2);
1243 int r = munmap(mapped, msg2.size());
1244 if (r < 0)
1245 return ReportError("munmap for native FD returned error", errno);
1248 // Check mmap(2) for write with MAP_PRIVATE
1250 char* mapped = reinterpret_cast<char*>(
1251 mmap(NULL, msg2.size(), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0));
1252 if (mapped == MAP_FAILED)
1253 return ReportError("mmap(r) for native FD returned errno", errno);
1254 // Make sure the file is not polluted by writing to privage mmap.
1255 strncpy(mapped, "baz", 3);
1256 std::string read_buffer;
1257 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd, &read_buffer));
1258 if (msg2 != read_buffer)
1259 return ReportMismatch("file content != msg2", read_buffer, msg2);
1260 int r = munmap(mapped, msg2.size());
1261 if (r < 0)
1262 return ReportError("munmap for native FD returned error", errno);
1265 // Check mmap(2) for write with MAP_SHARED.
1267 char* mapped = reinterpret_cast<char*>(
1268 mmap(NULL, msg2.size(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
1269 if (mapped != MAP_FAILED)
1270 return ReportError("mmap(w) for native FD must fail when opened readonly",
1271 -1);
1273 // END mmap(2) test with a file handle opened in READONLY mode.
1275 if (close(fd) < 0)
1276 return ReportError("close for native FD returned error", errno);
1277 #endif // !defined(PPAPI_OS_WIN)
1279 PASS();
1282 std::string TestFileIO::MatchOpenExpectations(pp::FileSystem* file_system,
1283 int32_t open_flags,
1284 int32_t expectations) {
1285 std::string bad_argument =
1286 "TestFileIO::MatchOpenExpectations has invalid input arguments.";
1287 bool invalid_combination = !!(expectations & INVALID_FLAG_COMBINATION);
1288 if (invalid_combination) {
1289 if (expectations != INVALID_FLAG_COMBINATION)
1290 return bad_argument;
1291 } else {
1292 // Validate that one and only one of <some_expectation> and
1293 // DONT_<some_expectation> is specified.
1294 for (size_t remains = expectations, end = END_OF_OPEN_EXPECATION_PAIRS;
1295 end != 0; remains >>= 2, end >>= 2) {
1296 if (!!(remains & 1) == !!(remains & 2))
1297 return bad_argument;
1300 bool create_if_doesnt_exist = !!(expectations & CREATE_IF_DOESNT_EXIST);
1301 bool open_if_exists = !!(expectations & OPEN_IF_EXISTS);
1302 bool truncate_if_exists = !!(expectations & TRUNCATE_IF_EXISTS);
1304 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1305 pp::FileRef existent_file_ref(
1306 *file_system, "/match_open_expectation_existent_non_empty_file");
1307 pp::FileRef nonexistent_file_ref(
1308 *file_system, "/match_open_expectation_nonexistent_file");
1310 // Setup files for test.
1312 callback.WaitForResult(existent_file_ref.Delete(callback.GetCallback()));
1313 CHECK_CALLBACK_BEHAVIOR(callback);
1314 ASSERT_TRUE(callback.result() == PP_OK ||
1315 callback.result() == PP_ERROR_FILENOTFOUND);
1316 callback.WaitForResult(nonexistent_file_ref.Delete(callback.GetCallback()));
1317 CHECK_CALLBACK_BEHAVIOR(callback);
1318 ASSERT_TRUE(callback.result() == PP_OK ||
1319 callback.result() == PP_ERROR_FILENOTFOUND);
1321 pp::FileIO existent_file_io(instance_);
1322 callback.WaitForResult(existent_file_io.Open(
1323 existent_file_ref,
1324 PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE,
1325 callback.GetCallback()));
1326 CHECK_CALLBACK_BEHAVIOR(callback);
1327 ASSERT_EQ(PP_OK, callback.result());
1328 int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &existent_file_io,
1329 0, "foobar", callback_type());
1330 ASSERT_EQ(PP_OK, rv);
1333 pp::FileIO existent_file_io(instance_);
1334 callback.WaitForResult(existent_file_io.Open(existent_file_ref, open_flags,
1335 callback.GetCallback()));
1336 CHECK_CALLBACK_BEHAVIOR(callback);
1337 if ((invalid_combination && callback.result() == PP_OK) ||
1338 (!invalid_combination &&
1339 ((callback.result() == PP_OK) != open_if_exists))) {
1340 return ReportOpenError(open_flags);
1343 if (!invalid_combination && open_if_exists) {
1344 PP_FileInfo info;
1345 callback.WaitForResult(existent_file_io.Query(&info,
1346 callback.GetCallback()));
1347 CHECK_CALLBACK_BEHAVIOR(callback);
1348 ASSERT_EQ(PP_OK, callback.result());
1349 if (truncate_if_exists != (info.size == 0))
1350 return ReportOpenError(open_flags);
1353 pp::FileIO nonexistent_file_io(instance_);
1354 callback.WaitForResult(nonexistent_file_io.Open(nonexistent_file_ref,
1355 open_flags,
1356 callback.GetCallback()));
1357 CHECK_CALLBACK_BEHAVIOR(callback);
1358 if ((invalid_combination && callback.result() == PP_OK) ||
1359 (!invalid_combination &&
1360 ((callback.result() == PP_OK) != create_if_doesnt_exist))) {
1361 return ReportOpenError(open_flags);
1364 return std::string();
1367 // TODO(viettrungluu): Test Close(). crbug.com/69457