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"
12 #include <sys/types.h>
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)
34 // TODO(hamaji): Use standard windows APIs instead of compatibility layer?
40 # include <sys/mman.h>
44 REGISTER_TEST_CASE(FileIO
);
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
) {
74 result
+= kFlagNames
[index
];
83 int32_t ReadEntireFile(PP_Instance instance
,
87 CallbackType callback_type
) {
88 TestCompletionCallback
callback(instance
, callback_type
);
90 int32_t read_offset
= offset
;
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)
99 read_offset
+= callback
.result();
100 data
->append(buf
, callback
.result());
106 int32_t ReadToArrayEntireFile(PP_Instance instance
,
110 CallbackType callback_type
) {
111 TestCompletionCallbackWithOutput
< std::vector
<char> > callback(
112 instance
, callback_type
);
115 callback
.WaitForResult(file_io
->Read(offset
, 256, callback
.GetCallback()));
116 int32_t rv
= callback
.result();
121 const std::vector
<char>& output
= callback
.output();
122 assert(rv
== static_cast<int32_t>(output
.size()));
124 data
->append(output
.begin(), output
.end());
130 #if !defined(PPAPI_OS_WIN)
131 bool ReadEntireFileFromFileHandle(int fd
, std::string
* data
) {
132 if (lseek(fd
, 0, SEEK_SET
) < 0)
139 ret
= read(fd
, buf
, sizeof(buf
));
141 data
->append(buf
, ret
);
145 #endif // !defined(PPAPI_OS_WIN)
147 int32_t WriteEntireBuffer(PP_Instance instance
,
150 const std::string
& data
,
151 CallbackType callback_type
) {
152 TestCompletionCallback
callback(instance
, callback_type
);
153 int32_t write_offset
= offset
;
154 const char* buf
= data
.c_str();
155 int32_t size
= static_cast<int32_t>(data
.size());
157 while (write_offset
< offset
+ size
) {
158 callback
.WaitForResult(file_io
->Write(write_offset
,
159 &buf
[write_offset
- offset
],
160 size
- write_offset
+ offset
,
161 callback
.GetCallback()));
162 if (callback
.result() < 0)
163 return callback
.result();
164 if (callback
.result() == 0)
165 return PP_ERROR_FAILED
;
166 write_offset
+= callback
.result();
174 bool TestFileIO::Init() {
175 return CheckTestingInterface() && EnsureRunningOverHTTP();
178 void TestFileIO::RunTests(const std::string
& filter
) {
179 RUN_CALLBACK_TEST(TestFileIO
, Open
, filter
);
180 RUN_CALLBACK_TEST(TestFileIO
, OpenDirectory
, filter
);
181 RUN_CALLBACK_TEST(TestFileIO
, ReadWriteSetLength
, filter
);
182 RUN_CALLBACK_TEST(TestFileIO
, ReadToArrayWriteSetLength
, filter
);
183 RUN_CALLBACK_TEST(TestFileIO
, TouchQuery
, filter
);
184 RUN_CALLBACK_TEST(TestFileIO
, AbortCalls
, filter
);
185 RUN_CALLBACK_TEST(TestFileIO
, ParallelReads
, filter
);
186 RUN_CALLBACK_TEST(TestFileIO
, ParallelWrites
, filter
);
187 RUN_CALLBACK_TEST(TestFileIO
, NotAllowMixedReadWrite
, filter
);
188 RUN_CALLBACK_TEST(TestFileIO
, RequestOSFileHandle
, filter
);
189 RUN_CALLBACK_TEST(TestFileIO
, RequestOSFileHandleWithOpenExclusive
, filter
);
190 RUN_CALLBACK_TEST(TestFileIO
, Mmap
, filter
);
192 // TODO(viettrungluu): add tests:
193 // - that PP_ERROR_PENDING is correctly returned
194 // - that operations respect the file open modes (flags)
197 std::string
TestFileIO::TestOpen() {
198 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
200 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
201 pp::FileRef
file_ref(file_system
, "/file_open");
203 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
204 CHECK_CALLBACK_BEHAVIOR(callback
);
205 ASSERT_EQ(PP_OK
, callback
.result());
208 result
= MatchOpenExpectations(
210 PP_FILEOPENFLAG_READ
,
211 DONT_CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| DONT_TRUNCATE_IF_EXISTS
);
215 // Test the behavior of the power set of
216 // { PP_FILEOPENFLAG_CREATE,
217 // PP_FILEOPENFLAG_TRUNCATE,
218 // PP_FILEOPENFLAG_EXCLUSIVE }.
220 // First of all, none of them are specified.
221 result
= MatchOpenExpectations(
223 PP_FILEOPENFLAG_WRITE
,
224 DONT_CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| DONT_TRUNCATE_IF_EXISTS
);
228 result
= MatchOpenExpectations(
230 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_CREATE
,
231 CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| DONT_TRUNCATE_IF_EXISTS
);
235 result
= MatchOpenExpectations(
237 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_EXCLUSIVE
,
238 DONT_CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| DONT_TRUNCATE_IF_EXISTS
);
242 result
= MatchOpenExpectations(
244 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_TRUNCATE
,
245 DONT_CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| TRUNCATE_IF_EXISTS
);
249 result
= MatchOpenExpectations(
251 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_CREATE
|
252 PP_FILEOPENFLAG_EXCLUSIVE
,
253 CREATE_IF_DOESNT_EXIST
| DONT_OPEN_IF_EXISTS
| DONT_TRUNCATE_IF_EXISTS
);
257 result
= MatchOpenExpectations(
259 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_CREATE
| PP_FILEOPENFLAG_TRUNCATE
,
260 CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| TRUNCATE_IF_EXISTS
);
264 result
= MatchOpenExpectations(
266 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_EXCLUSIVE
|
267 PP_FILEOPENFLAG_TRUNCATE
,
268 DONT_CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| TRUNCATE_IF_EXISTS
);
272 result
= MatchOpenExpectations(
274 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_CREATE
|
275 PP_FILEOPENFLAG_EXCLUSIVE
| PP_FILEOPENFLAG_TRUNCATE
,
276 CREATE_IF_DOESNT_EXIST
| DONT_OPEN_IF_EXISTS
| DONT_TRUNCATE_IF_EXISTS
);
280 // Invalid combination: PP_FILEOPENFLAG_TRUNCATE without
281 // PP_FILEOPENFLAG_WRITE.
282 result
= MatchOpenExpectations(
284 PP_FILEOPENFLAG_READ
| PP_FILEOPENFLAG_TRUNCATE
,
285 INVALID_FLAG_COMBINATION
);
292 std::string
TestFileIO::TestOpenDirectory() {
293 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
295 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
296 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
297 CHECK_CALLBACK_BEHAVIOR(callback
);
298 ASSERT_EQ(PP_OK
, callback
.result());
301 pp::FileRef
dir_ref(file_system
, "/test_dir_open_directory");
302 callback
.WaitForResult(dir_ref
.MakeDirectory(
303 PP_MAKEDIRECTORYFLAG_NONE
, callback
.GetCallback()));
304 CHECK_CALLBACK_BEHAVIOR(callback
);
305 ASSERT_EQ(PP_OK
, callback
.result());
307 // Open the directory. This is expected to fail since directories cannot be
309 pp::FileIO
file_io(instance_
);
310 callback
.WaitForResult(file_io
.Open(dir_ref
, PP_FILEOPENFLAG_READ
,
311 callback
.GetCallback()));
312 CHECK_CALLBACK_BEHAVIOR(callback
);
313 ASSERT_EQ(PP_ERROR_NOTAFILE
, callback
.result());
318 std::string
TestFileIO::TestReadWriteSetLength() {
319 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
321 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
322 pp::FileRef
file_ref(file_system
, "/file_read_write_setlength");
323 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
324 CHECK_CALLBACK_BEHAVIOR(callback
);
325 ASSERT_EQ(PP_OK
, callback
.result());
327 pp::FileIO
file_io(instance_
);
328 callback
.WaitForResult(file_io
.Open(file_ref
,
329 PP_FILEOPENFLAG_CREATE
|
330 PP_FILEOPENFLAG_TRUNCATE
|
331 PP_FILEOPENFLAG_READ
|
332 PP_FILEOPENFLAG_WRITE
,
333 callback
.GetCallback()));
334 CHECK_CALLBACK_BEHAVIOR(callback
);
335 ASSERT_EQ(PP_OK
, callback
.result());
337 // Write something to the file.
338 int32_t rv
= WriteEntireBuffer(instance_
->pp_instance(), &file_io
, 0,
339 "test_test", callback_type());
340 ASSERT_EQ(PP_OK
, rv
);
342 // Attempt to read a negative number of bytes; it should fail.
344 callback
.WaitForResult(file_io
.Read(0,
347 callback
.GetCallback()));
348 CHECK_CALLBACK_BEHAVIOR(callback
);
349 ASSERT_EQ(PP_ERROR_FAILED
, callback
.result());
351 // Read the entire file.
352 std::string read_buffer
;
353 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 0, &read_buffer
,
355 ASSERT_EQ(PP_OK
, rv
);
356 ASSERT_EQ(std::string("test_test"), read_buffer
);
358 // Truncate the file.
359 callback
.WaitForResult(file_io
.SetLength(4, callback
.GetCallback()));
360 CHECK_CALLBACK_BEHAVIOR(callback
);
361 ASSERT_EQ(PP_OK
, callback
.result());
363 // Check the file contents.
365 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 0, &read_buffer
,
367 ASSERT_EQ(PP_OK
, rv
);
368 ASSERT_EQ(std::string("test"), read_buffer
);
370 // Try to read past the end of the file.
372 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 100, &read_buffer
,
374 ASSERT_EQ(PP_OK
, rv
);
375 ASSERT_TRUE(read_buffer
.empty());
377 // Write past the end of the file. The file should be zero-padded.
378 rv
= WriteEntireBuffer(instance_
->pp_instance(), &file_io
, 8, "test",
380 ASSERT_EQ(PP_OK
, rv
);
382 // Check the contents of the file.
384 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 0, &read_buffer
,
386 ASSERT_EQ(PP_OK
, rv
);
387 ASSERT_EQ(std::string("test\0\0\0\0test", 12), read_buffer
);
390 callback
.WaitForResult(file_io
.SetLength(16, callback
.GetCallback()));
391 CHECK_CALLBACK_BEHAVIOR(callback
);
392 ASSERT_EQ(PP_OK
, callback
.result());
394 // Check the contents of the file.
396 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 0, &read_buffer
,
398 ASSERT_EQ(PP_OK
, rv
);
399 ASSERT_EQ(std::string("test\0\0\0\0test\0\0\0\0", 16), read_buffer
);
401 // Write in the middle of the file.
402 rv
= WriteEntireBuffer(instance_
->pp_instance(), &file_io
, 4, "test",
404 ASSERT_EQ(PP_OK
, rv
);
406 // Check the contents of the file.
408 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 0, &read_buffer
,
410 ASSERT_EQ(PP_OK
, rv
);
411 ASSERT_EQ(std::string("testtesttest\0\0\0\0", 16), read_buffer
);
413 // Read from the middle of the file.
415 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 4, &read_buffer
,
417 ASSERT_EQ(PP_OK
, rv
);
418 ASSERT_EQ(std::string("testtest\0\0\0\0", 12), read_buffer
);
420 // Append to the end of the file.
421 pp::FileIO
file_io2(instance_
);
422 callback
.WaitForResult(file_io2
.Open(file_ref
,
423 PP_FILEOPENFLAG_CREATE
|
424 PP_FILEOPENFLAG_READ
|
425 PP_FILEOPENFLAG_APPEND
,
426 callback
.GetCallback()));
427 rv
= WriteEntireBuffer(instance_
->pp_instance(), &file_io2
, 0, "appended",
429 ASSERT_EQ(PP_OK
, rv
);
431 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io2
, 0, &read_buffer
,
433 ASSERT_EQ(PP_OK
, rv
);
434 ASSERT_EQ(std::string("testtesttest\0\0\0\0appended", 24), read_buffer
);
439 // This is basically a copy of TestReadWriteSetLength, but with the new Read
440 // API. With this test case, we can make sure the two Read's have the same
442 std::string
TestFileIO::TestReadToArrayWriteSetLength() {
443 if (callback_type() == PP_BLOCKING
) {
444 // This test does not make sense for blocking callbacks.
447 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
449 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
450 pp::FileRef
file_ref(file_system
, "/file_read_write_setlength");
451 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
452 CHECK_CALLBACK_BEHAVIOR(callback
);
453 ASSERT_EQ(PP_OK
, callback
.result());
455 pp::FileIO
file_io(instance_
);
456 callback
.WaitForResult(file_io
.Open(file_ref
,
457 PP_FILEOPENFLAG_CREATE
|
458 PP_FILEOPENFLAG_TRUNCATE
|
459 PP_FILEOPENFLAG_READ
|
460 PP_FILEOPENFLAG_WRITE
,
461 callback
.GetCallback()));
462 CHECK_CALLBACK_BEHAVIOR(callback
);
463 ASSERT_EQ(PP_OK
, callback
.result());
465 // Write something to the file.
466 int32_t rv
= WriteEntireBuffer(instance_
->pp_instance(), &file_io
, 0,
467 "test_test", callback_type());
468 ASSERT_EQ(PP_OK
, rv
);
470 TestCompletionCallbackWithOutput
< std::vector
<char> > callback2(
471 instance_
->pp_instance(), callback_type());
472 // Attempt to read a negative number of bytes; it should fail.
473 callback2
.WaitForResult(file_io
.Read(0, -1, callback2
.GetCallback()));
474 CHECK_CALLBACK_BEHAVIOR(callback2
);
475 ASSERT_EQ(PP_ERROR_FAILED
, callback2
.result());
477 // Read the entire file.
478 std::string read_buffer
;
479 read_buffer
.reserve(10);
480 rv
= ReadToArrayEntireFile(instance_
->pp_instance(), &file_io
, 0,
481 &read_buffer
, callback_type());
482 ASSERT_EQ(PP_OK
, rv
);
483 ASSERT_EQ(std::string("test_test"), read_buffer
);
485 // Truncate the file.
486 callback
.WaitForResult(file_io
.SetLength(4, callback
.GetCallback()));
487 CHECK_CALLBACK_BEHAVIOR(callback
);
488 ASSERT_EQ(PP_OK
, rv
);
490 // Check the file contents.
492 rv
= ReadToArrayEntireFile(instance_
->pp_instance(), &file_io
, 0,
493 &read_buffer
, callback_type());
494 ASSERT_EQ(PP_OK
, rv
);
495 ASSERT_EQ(std::string("test"), read_buffer
);
497 // Try to read past the end of the file.
499 rv
= ReadToArrayEntireFile(instance_
->pp_instance(), &file_io
, 100,
500 &read_buffer
, callback_type());
501 ASSERT_EQ(PP_OK
, rv
);
502 ASSERT_TRUE(read_buffer
.empty());
504 // Write past the end of the file. The file should be zero-padded.
505 rv
= WriteEntireBuffer(instance_
->pp_instance(), &file_io
, 8, "test",
507 ASSERT_EQ(PP_OK
, rv
);
509 // Check the contents of the file.
511 rv
= ReadToArrayEntireFile(instance_
->pp_instance(), &file_io
, 0,
512 &read_buffer
, callback_type());
513 ASSERT_EQ(PP_OK
, rv
);
514 ASSERT_EQ(std::string("test\0\0\0\0test", 12), read_buffer
);
517 callback
.WaitForResult(file_io
.SetLength(16, callback
.GetCallback()));
518 CHECK_CALLBACK_BEHAVIOR(callback
);
519 ASSERT_EQ(PP_OK
, callback
.result());
521 // Check the contents of the file.
523 rv
= ReadToArrayEntireFile(instance_
->pp_instance(), &file_io
, 0,
524 &read_buffer
, callback_type());
525 ASSERT_EQ(PP_OK
, rv
);
526 ASSERT_EQ(std::string("test\0\0\0\0test\0\0\0\0", 16), read_buffer
);
528 // Write in the middle of the file.
529 rv
= WriteEntireBuffer(instance_
->pp_instance(), &file_io
, 4, "test",
531 ASSERT_EQ(PP_OK
, rv
);
533 // Check the contents of the file.
535 rv
= ReadToArrayEntireFile(instance_
->pp_instance(), &file_io
, 0,
536 &read_buffer
, callback_type());
537 ASSERT_EQ(PP_OK
, rv
);
538 ASSERT_EQ(std::string("testtesttest\0\0\0\0", 16), read_buffer
);
540 // Read from the middle of the file.
542 rv
= ReadToArrayEntireFile(instance_
->pp_instance(), &file_io
, 4,
543 &read_buffer
, callback_type());
544 ASSERT_EQ(PP_OK
, rv
);
545 ASSERT_EQ(std::string("testtest\0\0\0\0", 12), read_buffer
);
550 std::string
TestFileIO::TestTouchQuery() {
551 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
553 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
554 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
555 CHECK_CALLBACK_BEHAVIOR(callback
);
556 ASSERT_EQ(PP_OK
, callback
.result());
558 pp::FileRef
file_ref(file_system
, "/file_touch");
559 pp::FileIO
file_io(instance_
);
560 callback
.WaitForResult(file_io
.Open(file_ref
,
561 PP_FILEOPENFLAG_CREATE
|
562 PP_FILEOPENFLAG_TRUNCATE
|
563 PP_FILEOPENFLAG_WRITE
,
564 callback
.GetCallback()));
565 CHECK_CALLBACK_BEHAVIOR(callback
);
566 ASSERT_EQ(PP_OK
, callback
.result());
568 // Write some data to have a non-zero file size.
569 callback
.WaitForResult(file_io
.Write(0, "test", 4, callback
.GetCallback()));
570 CHECK_CALLBACK_BEHAVIOR(callback
);
571 ASSERT_EQ(4, callback
.result());
573 const PP_Time last_access_time
= 123 * 24 * 3600.0;
574 // last_modified_time's granularity is 2 seconds
575 // NOTE: In NaCl on Windows, NaClDescIO uses _fstat64 to retrieve file info.
576 // This function returns strange values for very small time values (near the
577 // Unix Epoch). For a value like 246.0, it returns -1. For larger values, it
578 // returns values that are exactly an hour less. The value below is handled
579 // correctly, and is only 100 days after the start of Unix time.
580 const PP_Time last_modified_time
= 100 * 24 * 3600.0;
581 callback
.WaitForResult(file_io
.Touch(last_access_time
, last_modified_time
,
582 callback
.GetCallback()));
583 CHECK_CALLBACK_BEHAVIOR(callback
);
584 ASSERT_EQ(PP_OK
, callback
.result());
587 callback
.WaitForResult(file_io
.Query(&info
, callback
.GetCallback()));
588 CHECK_CALLBACK_BEHAVIOR(callback
);
589 ASSERT_EQ(PP_OK
, callback
.result());
591 if ((info
.size
!= 4) ||
592 (info
.type
!= PP_FILETYPE_REGULAR
) ||
593 (info
.system_type
!= PP_FILESYSTEMTYPE_LOCALTEMPORARY
))
594 // Disabled due to DST-related failure: crbug.com/314579
595 //(info.last_access_time != last_access_time) ||
596 //(info.last_modified_time != last_modified_time))
597 return "FileIO::Query() has returned bad data.";
599 // Call |Query()| again, to make sure it works a second time.
600 callback
.WaitForResult(file_io
.Query(&info
, callback
.GetCallback()));
601 CHECK_CALLBACK_BEHAVIOR(callback
);
602 ASSERT_EQ(PP_OK
, callback
.result());
607 std::string
TestFileIO::TestAbortCalls() {
608 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
610 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
611 pp::FileRef
file_ref(file_system
, "/file_abort_calls");
612 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
613 CHECK_CALLBACK_BEHAVIOR(callback
);
614 ASSERT_EQ(PP_OK
, callback
.result());
616 int32_t rv
= PP_ERROR_FAILED
;
617 // First, create a file on which to do ops.
619 pp::FileIO
file_io(instance_
);
620 callback
.WaitForResult(
621 file_io
.Open(file_ref
,
622 PP_FILEOPENFLAG_CREATE
| PP_FILEOPENFLAG_WRITE
,
623 callback
.GetCallback()));
624 CHECK_CALLBACK_BEHAVIOR(callback
);
625 ASSERT_EQ(PP_OK
, callback
.result());
627 // N.B.: Should write at least 3 bytes.
628 rv
= WriteEntireBuffer(instance_
->pp_instance(), &file_io
, 0,
629 "foobarbazquux", callback_type());
630 ASSERT_EQ(PP_OK
, rv
);
635 rv
= pp::FileIO(instance_
)
636 .Open(file_ref
, PP_FILEOPENFLAG_READ
, callback
.GetCallback());
638 callback
.WaitForAbortResult(rv
);
639 CHECK_CALLBACK_BEHAVIOR(callback
);
643 PP_FileInfo info
= { 0 };
644 // Save a copy and make sure |info| doesn't get written to if it is aborted.
645 PP_FileInfo info_copy
;
646 memcpy(&info_copy
, &info
, sizeof(info
));
648 pp::FileIO
file_io(instance_
);
649 callback
.WaitForResult(file_io
.Open(file_ref
, PP_FILEOPENFLAG_READ
,
650 callback
.GetCallback()));
651 CHECK_CALLBACK_BEHAVIOR(callback
);
652 ASSERT_EQ(PP_OK
, callback
.result());
654 rv
= file_io
.Query(&info
, callback
.GetCallback());
655 } // Destroy |file_io|.
656 callback
.WaitForResult(rv
);
657 CHECK_CALLBACK_BEHAVIOR(callback
);
658 if (callback_type() == PP_BLOCKING
) {
659 ASSERT_EQ(PP_OK
, callback
.result());
660 // The operation completed synchronously, so |info| should have changed.
661 ASSERT_NE(0, memcmp(&info_copy
, &info
, sizeof(info
)));
663 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
664 ASSERT_EQ(0, memcmp(&info_copy
, &info
, sizeof(info
)));
671 pp::FileIO
file_io(instance_
);
672 callback
.WaitForResult(file_io
.Open(file_ref
, PP_FILEOPENFLAG_WRITE
,
673 callback
.GetCallback()));
674 CHECK_CALLBACK_BEHAVIOR(callback
);
675 ASSERT_EQ(PP_OK
, callback
.result());
677 rv
= file_io
.Touch(0, 0, callback
.GetCallback());
678 } // Destroy |file_io|.
679 callback
.WaitForAbortResult(rv
);
680 CHECK_CALLBACK_BEHAVIOR(callback
);
687 pp::FileIO
file_io(instance_
);
688 callback
.WaitForResult(file_io
.Open(file_ref
, PP_FILEOPENFLAG_READ
,
689 callback
.GetCallback()));
690 CHECK_CALLBACK_BEHAVIOR(callback
);
691 ASSERT_EQ(PP_OK
, callback
.result());
693 rv
= file_io
.Read(0, buf
, sizeof(buf
), callback
.GetCallback());
694 } // Destroy |file_io|.
695 // Save a copy to make sure buf isn't written to in the async case.
697 memcpy(&buf_copy
, &buf
, sizeof(buf
));
698 callback
.WaitForResult(rv
);
699 CHECK_CALLBACK_BEHAVIOR(callback
);
700 if (callback_type() == PP_BLOCKING
) {
701 ASSERT_EQ(callback
.result(), sizeof(buf
));
703 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
704 ASSERT_EQ(0, memcmp(&buf_copy
, &buf
, sizeof(buf
)));
712 pp::FileIO
file_io(instance_
);
713 callback
.WaitForResult(file_io
.Open(file_ref
, PP_FILEOPENFLAG_WRITE
,
714 callback
.GetCallback()));
715 CHECK_CALLBACK_BEHAVIOR(callback
);
716 ASSERT_EQ(PP_OK
, callback
.result());
718 rv
= file_io
.Write(0, buf
, sizeof(buf
), callback
.GetCallback());
719 } // Destroy |file_io|.
720 callback
.WaitForResult(rv
);
721 CHECK_CALLBACK_BEHAVIOR(callback
);
722 if (callback_type() == PP_BLOCKING
)
723 ASSERT_EQ(callback
.result(), sizeof(buf
));
725 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
728 // Abort |SetLength()|.
731 pp::FileIO
file_io(instance_
);
732 callback
.WaitForResult(file_io
.Open(file_ref
, PP_FILEOPENFLAG_WRITE
,
733 callback
.GetCallback()));
734 CHECK_CALLBACK_BEHAVIOR(callback
);
735 ASSERT_EQ(PP_OK
, callback
.result());
737 rv
= file_io
.SetLength(3, callback
.GetCallback());
738 } // Destroy |file_io|.
739 callback
.WaitForAbortResult(rv
);
740 CHECK_CALLBACK_BEHAVIOR(callback
);
746 pp::FileIO
file_io(instance_
);
747 callback
.WaitForResult(file_io
.Open(file_ref
, PP_FILEOPENFLAG_WRITE
,
748 callback
.GetCallback()));
749 CHECK_CALLBACK_BEHAVIOR(callback
);
750 ASSERT_EQ(PP_OK
, callback
.result());
752 rv
= file_io
.Flush(callback
.GetCallback());
753 } // Destroy |file_io|.
754 callback
.WaitForAbortResult(rv
);
755 CHECK_CALLBACK_BEHAVIOR(callback
);
761 std::string
TestFileIO::TestParallelReads() {
762 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
763 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
764 pp::FileRef
file_ref(file_system
, "/file_parallel_reads");
765 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
766 CHECK_CALLBACK_BEHAVIOR(callback
);
767 ASSERT_EQ(PP_OK
, callback
.result());
769 pp::FileIO
file_io(instance_
);
770 callback
.WaitForResult(file_io
.Open(file_ref
,
771 PP_FILEOPENFLAG_CREATE
|
772 PP_FILEOPENFLAG_TRUNCATE
|
773 PP_FILEOPENFLAG_READ
|
774 PP_FILEOPENFLAG_WRITE
,
775 callback
.GetCallback()));
776 CHECK_CALLBACK_BEHAVIOR(callback
);
777 ASSERT_EQ(PP_OK
, callback
.result());
779 // Set up testing contents.
780 int32_t rv
= WriteEntireBuffer(instance_
->pp_instance(), &file_io
, 0,
781 "abcdefghijkl", callback_type());
782 ASSERT_EQ(PP_OK
, rv
);
784 // Parallel read operations.
785 const char* border
= "__border__";
786 const int32_t border_size
= static_cast<int32_t>(strlen(border
));
788 TestCompletionCallback
callback_1(instance_
->pp_instance(), callback_type());
789 int32_t read_offset_1
= 0;
791 std::vector
<char> extended_buf_1(border_size
* 2 + size_1
);
792 char* buf_1
= &extended_buf_1
[border_size
];
793 memcpy(&extended_buf_1
[0], border
, border_size
);
794 memcpy(buf_1
+ size_1
, border
, border_size
);
796 TestCompletionCallback
callback_2(instance_
->pp_instance(), callback_type());
797 int32_t read_offset_2
= size_1
;
799 std::vector
<char> extended_buf_2(border_size
* 2 + size_2
);
800 char* buf_2
= &extended_buf_2
[border_size
];
801 memcpy(&extended_buf_2
[0], border
, border_size
);
802 memcpy(buf_2
+ size_2
, border
, border_size
);
804 int32_t rv_1
= PP_OK
;
805 int32_t rv_2
= PP_OK
;
806 while (size_1
>= 0 && size_2
>= 0 && size_1
+ size_2
> 0) {
808 rv_1
= file_io
.Read(read_offset_1
, buf_1
, size_1
,
809 callback_1
.GetCallback());
812 rv_2
= file_io
.Read(read_offset_2
, buf_2
, size_2
,
813 callback_2
.GetCallback());
816 callback_1
.WaitForResult(rv_1
);
817 CHECK_CALLBACK_BEHAVIOR(callback_1
);
818 ASSERT_TRUE(callback_1
.result() > 0);
819 read_offset_1
+= callback_1
.result();
820 buf_1
+= callback_1
.result();
821 size_1
-= callback_1
.result();
825 callback_2
.WaitForResult(rv_2
);
826 CHECK_CALLBACK_BEHAVIOR(callback_2
);
827 ASSERT_TRUE(callback_2
.result() > 0);
828 read_offset_2
+= callback_2
.result();
829 buf_2
+= callback_2
.result();
830 size_2
-= callback_2
.result();
834 // If |size_1| or |size_2| is not 0, we have invoked wrong callback(s).
835 ASSERT_EQ(0, size_1
);
836 ASSERT_EQ(0, size_2
);
838 // Make sure every read operation writes into the correct buffer.
839 const char expected_result_1
[] = "__border__abc__border__";
840 const char expected_result_2
[] = "__border__defghijkl__border__";
841 ASSERT_TRUE(strncmp(&extended_buf_1
[0], expected_result_1
,
842 strlen(expected_result_1
)) == 0);
843 ASSERT_TRUE(strncmp(&extended_buf_2
[0], expected_result_2
,
844 strlen(expected_result_2
)) == 0);
848 std::string
TestFileIO::TestParallelWrites() {
849 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
850 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
851 pp::FileRef
file_ref(file_system
, "/file_parallel_writes");
852 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
853 CHECK_CALLBACK_BEHAVIOR(callback
);
854 ASSERT_EQ(PP_OK
, callback
.result());
856 pp::FileIO
file_io(instance_
);
857 callback
.WaitForResult(file_io
.Open(file_ref
,
858 PP_FILEOPENFLAG_CREATE
|
859 PP_FILEOPENFLAG_TRUNCATE
|
860 PP_FILEOPENFLAG_READ
|
861 PP_FILEOPENFLAG_WRITE
,
862 callback
.GetCallback()));
863 CHECK_CALLBACK_BEHAVIOR(callback
);
864 ASSERT_EQ(PP_OK
, callback
.result());
866 // Parallel write operations.
867 TestCompletionCallback
callback_1(instance_
->pp_instance(), callback_type());
868 int32_t write_offset_1
= 0;
869 const char* buf_1
= "abc";
870 int32_t size_1
= static_cast<int32_t>(strlen(buf_1
));
872 TestCompletionCallback
callback_2(instance_
->pp_instance(), callback_type());
873 int32_t write_offset_2
= size_1
;
874 const char* buf_2
= "defghijkl";
875 int32_t size_2
= static_cast<int32_t>(strlen(buf_2
));
877 int32_t rv_1
= PP_OK
;
878 int32_t rv_2
= PP_OK
;
879 while (size_1
>= 0 && size_2
>= 0 && size_1
+ size_2
> 0) {
881 // Copy the buffer so we can erase it below.
882 std::string
str_1(buf_1
);
883 rv_1
= file_io
.Write(
884 write_offset_1
, &str_1
[0], static_cast<int32_t>(str_1
.size()),
885 callback_1
.GetCallback());
886 // Erase the buffer to test that async writes copy it.
887 std::fill(str_1
.begin(), str_1
.end(), 0);
890 // Copy the buffer so we can erase it below.
891 std::string
str_2(buf_2
);
892 rv_2
= file_io
.Write(
893 write_offset_2
, &str_2
[0], static_cast<int32_t>(str_2
.size()),
894 callback_2
.GetCallback());
895 // Erase the buffer to test that async writes copy it.
896 std::fill(str_2
.begin(), str_2
.end(), 0);
900 callback_1
.WaitForResult(rv_1
);
901 CHECK_CALLBACK_BEHAVIOR(callback_1
);
902 ASSERT_TRUE(callback_1
.result() > 0);
903 write_offset_1
+= callback_1
.result();
904 buf_1
+= callback_1
.result();
905 size_1
-= callback_1
.result();
909 callback_2
.WaitForResult(rv_2
);
910 CHECK_CALLBACK_BEHAVIOR(callback_2
);
911 ASSERT_TRUE(callback_2
.result() > 0);
912 write_offset_2
+= callback_2
.result();
913 buf_2
+= callback_2
.result();
914 size_2
-= callback_2
.result();
918 // If |size_1| or |size_2| is not 0, we have invoked wrong callback(s).
919 ASSERT_EQ(0, size_1
);
920 ASSERT_EQ(0, size_2
);
922 // Check the file contents.
923 std::string read_buffer
;
924 int32_t rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 0,
925 &read_buffer
, callback_type());
926 ASSERT_EQ(PP_OK
, rv
);
927 ASSERT_EQ(std::string("abcdefghijkl"), read_buffer
);
932 std::string
TestFileIO::TestNotAllowMixedReadWrite() {
933 if (callback_type() == PP_BLOCKING
) {
934 // This test does not make sense for blocking callbacks.
937 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
939 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
940 pp::FileRef
file_ref(file_system
, "/file_not_allow_mixed_read_write");
941 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
942 CHECK_CALLBACK_BEHAVIOR(callback
);
943 ASSERT_EQ(PP_OK
, callback
.result());
945 pp::FileIO
file_io(instance_
);
946 callback
.WaitForResult(file_io
.Open(file_ref
,
947 PP_FILEOPENFLAG_CREATE
|
948 PP_FILEOPENFLAG_TRUNCATE
|
949 PP_FILEOPENFLAG_READ
|
950 PP_FILEOPENFLAG_WRITE
,
951 callback
.GetCallback()));
952 CHECK_CALLBACK_BEHAVIOR(callback
);
953 ASSERT_EQ(PP_OK
, callback
.result());
955 TestCompletionCallback
callback_1(instance_
->pp_instance(), PP_REQUIRED
);
956 int32_t write_offset_1
= 0;
957 const char* buf_1
= "mnopqrstuvw";
958 int32_t rv_1
= file_io
.Write(write_offset_1
, buf_1
,
959 static_cast<int32_t>(strlen(buf_1
)),
960 callback_1
.GetCallback());
961 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, rv_1
);
963 TestCompletionCallback
callback_2(instance_
->pp_instance(), callback_type());
964 int32_t read_offset_2
= 4;
966 callback_2
.WaitForResult(file_io
.Read(read_offset_2
, buf_2
, sizeof(buf_2
),
967 callback_2
.GetCallback()));
968 CHECK_CALLBACK_BEHAVIOR(callback_2
);
969 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback_2
.result());
970 callback_1
.WaitForResult(rv_1
);
971 CHECK_CALLBACK_BEHAVIOR(callback_1
);
973 // Cannot query while a write is pending.
974 rv_1
= file_io
.Write(write_offset_1
, buf_1
,
975 static_cast<int32_t>(strlen(buf_1
)),
976 callback_1
.GetCallback());
977 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, rv_1
);
979 callback_2
.WaitForResult(file_io
.Query(&info
, callback_2
.GetCallback()));
980 CHECK_CALLBACK_BEHAVIOR(callback_2
);
981 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback_2
.result());
982 callback_1
.WaitForResult(rv_1
);
983 CHECK_CALLBACK_BEHAVIOR(callback_1
);
985 // Cannot touch while a write is pending.
986 rv_1
= file_io
.Write(write_offset_1
, buf_1
,
987 static_cast<int32_t>(strlen(buf_1
)),
988 callback_1
.GetCallback());
989 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, rv_1
);
990 callback_2
.WaitForResult(file_io
.Touch(1234.0, 5678.0,
991 callback_2
.GetCallback()));
992 CHECK_CALLBACK_BEHAVIOR(callback_2
);
993 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback_2
.result());
994 callback_1
.WaitForResult(rv_1
);
995 CHECK_CALLBACK_BEHAVIOR(callback_1
);
997 // Cannot set length while a write is pending.
998 rv_1
= file_io
.Write(write_offset_1
, buf_1
,
999 static_cast<int32_t>(strlen(buf_1
)),
1000 callback_1
.GetCallback());
1001 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, rv_1
);
1002 callback_2
.WaitForResult(file_io
.SetLength(123, callback_2
.GetCallback()));
1003 CHECK_CALLBACK_BEHAVIOR(callback_2
);
1004 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback_2
.result());
1005 callback_1
.WaitForResult(rv_1
);
1006 CHECK_CALLBACK_BEHAVIOR(callback_1
);
1011 std::string
TestFileIO::TestRequestOSFileHandle() {
1012 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1014 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
1015 pp::FileRef
file_ref(file_system
, "/file_os_fd");
1017 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
1018 ASSERT_EQ(PP_OK
, callback
.result());
1020 pp::FileIO_Private
file_io(instance_
);
1021 callback
.WaitForResult(file_io
.Open(file_ref
,
1022 PP_FILEOPENFLAG_CREATE
|
1023 PP_FILEOPENFLAG_TRUNCATE
|
1024 PP_FILEOPENFLAG_READ
|
1025 PP_FILEOPENFLAG_WRITE
,
1026 callback
.GetCallback()));
1027 ASSERT_EQ(PP_OK
, callback
.result());
1029 TestCompletionCallbackWithOutput
<pp::PassFileHandle
> output_callback(
1030 instance_
->pp_instance(), callback_type());
1031 output_callback
.WaitForResult(
1032 file_io
.RequestOSFileHandle(output_callback
.GetCallback()));
1033 PP_FileHandle handle
= output_callback
.output().Release();
1034 ASSERT_EQ(PP_OK
, output_callback
.result());
1036 if (handle
== PP_kInvalidFileHandle
)
1037 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1038 #if defined(PPAPI_OS_WIN)
1039 int fd
= _open_osfhandle(reinterpret_cast<intptr_t>(handle
),
1040 _O_RDWR
| _O_BINARY
);
1045 return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
1047 // Check write(2) for the native FD.
1048 const std::string msg
= "foobar";
1049 ssize_t cnt
= write(fd
, msg
.data(), static_cast<unsigned>(msg
.size()));
1051 return ReportError("write for native FD returned error", errno
);
1052 if (cnt
!= static_cast<ssize_t
>(msg
.size()))
1053 return ReportError("write for native FD count mismatch", cnt
);
1055 // Check lseek(2) for the native FD.
1056 off_t off
= lseek(fd
, 0, SEEK_CUR
);
1057 if (off
== static_cast<off_t
>(-1))
1058 return ReportError("lseek for native FD returned error", errno
);
1059 if (off
!= static_cast<off_t
>(msg
.size()))
1060 return ReportError("lseek for native FD offset mismatch", off
);
1062 off
= lseek(fd
, 0, SEEK_SET
);
1063 if (off
== static_cast<off_t
>(-1))
1064 return ReportError("lseek for native FD returned error", errno
);
1066 return ReportError("lseek for native FD offset mismatch", off
);
1068 // Check read(2) for the native FD.
1069 std::string
buf(msg
.size(), '\0');
1070 cnt
= read(fd
, &buf
[0], static_cast<unsigned>(msg
.size()));
1072 return ReportError("read for native FD returned error", errno
);
1073 if (cnt
!= static_cast<ssize_t
>(msg
.size()))
1074 return ReportError("read for native FD count mismatch", cnt
);
1076 return ReportMismatch("read for native FD", buf
, msg
);
1080 // Calling RequestOSFileHandle with the FileIO that is opened with
1081 // PP_FILEOPENFLAG_EXCLUSIVE used to cause NaCl module to crash while loading.
1082 // This is a regression test for crbug.com/243241.
1083 std::string
TestFileIO::TestRequestOSFileHandleWithOpenExclusive() {
1084 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1086 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
1087 pp::FileRef
file_ref(file_system
, "/file_os_fd2");
1089 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
1090 ASSERT_EQ(PP_OK
, callback
.result());
1092 // Open with PP_FILEOPENFLAG_CREATE and PP_FILEOPENFLAG_EXCLUSIVE will fail
1093 // if the file already exists. Delete it here to make sure it does not.
1094 callback
.WaitForResult(file_ref
.Delete(callback
.GetCallback()));
1096 pp::FileIO_Private
file_io(instance_
);
1097 callback
.WaitForResult(file_io
.Open(file_ref
,
1098 PP_FILEOPENFLAG_CREATE
|
1099 PP_FILEOPENFLAG_READ
|
1100 PP_FILEOPENFLAG_WRITE
|
1101 PP_FILEOPENFLAG_EXCLUSIVE
,
1102 callback
.GetCallback()));
1103 ASSERT_EQ(PP_OK
, callback
.result());
1105 TestCompletionCallbackWithOutput
<pp::PassFileHandle
> output_callback(
1106 instance_
->pp_instance(), callback_type());
1107 output_callback
.WaitForResult(
1108 file_io
.RequestOSFileHandle(output_callback
.GetCallback()));
1109 PP_FileHandle handle
= output_callback
.output().Release();
1110 if (handle
== PP_kInvalidFileHandle
)
1111 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1112 ASSERT_EQ(PP_OK
, output_callback
.result());
1117 std::string
TestFileIO::TestMmap() {
1118 #if !defined(PPAPI_OS_WIN)
1119 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1121 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
1122 pp::FileRef
file_ref(file_system
, "/file_os_fd");
1124 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
1125 ASSERT_EQ(PP_OK
, callback
.result());
1127 pp::FileIO_Private
file_io(instance_
);
1128 callback
.WaitForResult(file_io
.Open(file_ref
,
1129 PP_FILEOPENFLAG_CREATE
|
1130 PP_FILEOPENFLAG_TRUNCATE
|
1131 PP_FILEOPENFLAG_READ
|
1132 PP_FILEOPENFLAG_WRITE
,
1133 callback
.GetCallback()));
1134 ASSERT_EQ(PP_OK
, callback
.result());
1136 TestCompletionCallbackWithOutput
<pp::PassFileHandle
> output_callback(
1137 instance_
->pp_instance(), callback_type());
1138 output_callback
.WaitForResult(
1139 file_io
.RequestOSFileHandle(output_callback
.GetCallback()));
1140 PP_FileHandle handle
= output_callback
.output().Release();
1141 ASSERT_EQ(PP_OK
, output_callback
.result());
1143 if (handle
== PP_kInvalidFileHandle
)
1144 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1147 return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
1149 // Check write(2) for the native FD.
1150 const std::string msg
= "foobar";
1151 ssize_t cnt
= write(fd
, msg
.data(), msg
.size());
1153 return ReportError("write for native FD returned error", errno
);
1154 if (cnt
!= static_cast<ssize_t
>(msg
.size()))
1155 return ReportError("write for native FD count mismatch", cnt
);
1157 // BEGIN mmap(2) test with a file handle opened in READ-WRITE mode.
1158 // Check mmap(2) for read.
1160 char* mapped
= reinterpret_cast<char*>(
1161 mmap(NULL
, msg
.size(), PROT_READ
, MAP_PRIVATE
, fd
, 0));
1162 if (mapped
== MAP_FAILED
)
1163 return ReportError("mmap(r) for native FD returned errno", errno
);
1164 // Make sure the buffer is cleared.
1165 std::string buf
= std::string(msg
.size(), '\0');
1166 memcpy(&buf
[0], mapped
, msg
.size());
1168 return ReportMismatch("mmap(r) for native FD", buf
, msg
);
1169 int r
= munmap(mapped
, msg
.size());
1171 return ReportError("munmap for native FD returned error", errno
);
1174 // Check mmap(2) for write with MAP_PRIVATE
1176 char* mapped
= reinterpret_cast<char*>(
1177 mmap(NULL
, msg
.size(), PROT_READ
| PROT_WRITE
, MAP_PRIVATE
, fd
, 0));
1178 if (mapped
== MAP_FAILED
)
1179 return ReportError("mmap(r) for native FD returned errno", errno
);
1180 // Make sure the file is not polluted by writing to privage mmap.
1181 strncpy(mapped
, "baz", 3);
1182 std::string read_buffer
;
1183 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd
, &read_buffer
));
1184 if (msg
!= read_buffer
)
1185 return ReportMismatch("file content != msg", read_buffer
, msg
);
1186 int r
= munmap(mapped
, msg
.size());
1188 return ReportError("munmap for native FD returned error", errno
);
1191 // Check mmap(2) for write with MAP_SHARED.
1193 char* mapped
= reinterpret_cast<char*>(
1194 mmap(NULL
, msg
.size(), PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0));
1195 if (mapped
== MAP_FAILED
)
1196 return ReportError("mmap(w) for native FD returned errno", errno
);
1198 strncpy(mapped
, "baz", 3);
1199 std::string read_buffer
;
1200 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd
, &read_buffer
));
1201 if (read_buffer
!= "bazbar")
1202 return ReportMismatch("file content != msg", read_buffer
, "bazbar");
1203 int r
= munmap(mapped
, msg
.size());
1205 return ReportError("munmap for native FD returned error", errno
);
1207 // END mmap(2) test with a file handle opened in READ-WRITE mode.
1210 return ReportError("close for native FD returned error", errno
);
1212 // BEGIN mmap(2) test with a file handle opened in READONLY mode.
1213 file_io
= pp::FileIO_Private(instance_
);
1214 callback
.WaitForResult(file_io
.Open(file_ref
,
1215 PP_FILEOPENFLAG_READ
,
1216 callback
.GetCallback()));
1217 ASSERT_EQ(PP_OK
, callback
.result());
1219 output_callback
= TestCompletionCallbackWithOutput
<pp::PassFileHandle
>(
1220 instance_
->pp_instance(), callback_type());
1221 output_callback
.WaitForResult(
1222 file_io
.RequestOSFileHandle(output_callback
.GetCallback()));
1223 handle
= output_callback
.output().Release();
1224 ASSERT_EQ(PP_OK
, output_callback
.result());
1226 if (handle
== PP_kInvalidFileHandle
)
1227 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1230 return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
1232 const std::string msg2
= "bazbar";
1234 // Check mmap(2) for read.
1236 char* mapped
= reinterpret_cast<char*>(
1237 mmap(NULL
, msg2
.size(), PROT_READ
, MAP_PRIVATE
, fd
, 0));
1238 if (mapped
== MAP_FAILED
)
1239 return ReportError("mmap(r) for native FD returned errno", errno
);
1240 // Make sure the buffer is cleared.
1241 std::string buf
= std::string(msg2
.size(), '\0');
1242 memcpy(&buf
[0], mapped
, msg2
.size());
1244 return ReportMismatch("mmap(r) for native FD", buf
, msg2
);
1245 int r
= munmap(mapped
, msg2
.size());
1247 return ReportError("munmap for native FD returned error", errno
);
1250 // Check mmap(2) for write with MAP_PRIVATE
1252 char* mapped
= reinterpret_cast<char*>(
1253 mmap(NULL
, msg2
.size(), PROT_READ
| PROT_WRITE
, MAP_PRIVATE
, fd
, 0));
1254 if (mapped
== MAP_FAILED
)
1255 return ReportError("mmap(r) for native FD returned errno", errno
);
1256 // Make sure the file is not polluted by writing to privage mmap.
1257 strncpy(mapped
, "baz", 3);
1258 std::string read_buffer
;
1259 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd
, &read_buffer
));
1260 if (msg2
!= read_buffer
)
1261 return ReportMismatch("file content != msg2", read_buffer
, msg2
);
1262 int r
= munmap(mapped
, msg2
.size());
1264 return ReportError("munmap for native FD returned error", errno
);
1267 // Check mmap(2) for write with MAP_SHARED.
1269 char* mapped
= reinterpret_cast<char*>(
1270 mmap(NULL
, msg2
.size(), PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0));
1271 if (mapped
!= MAP_FAILED
)
1272 return ReportError("mmap(w) for native FD must fail when opened readonly",
1275 // END mmap(2) test with a file handle opened in READONLY mode.
1278 return ReportError("close for native FD returned error", errno
);
1279 #endif // !defined(PPAPI_OS_WIN)
1284 std::string
TestFileIO::MatchOpenExpectations(pp::FileSystem
* file_system
,
1286 int32_t expectations
) {
1287 std::string bad_argument
=
1288 "TestFileIO::MatchOpenExpectations has invalid input arguments.";
1289 bool invalid_combination
= !!(expectations
& INVALID_FLAG_COMBINATION
);
1290 if (invalid_combination
) {
1291 if (expectations
!= INVALID_FLAG_COMBINATION
)
1292 return bad_argument
;
1294 // Validate that one and only one of <some_expectation> and
1295 // DONT_<some_expectation> is specified.
1296 for (size_t remains
= expectations
, end
= END_OF_OPEN_EXPECATION_PAIRS
;
1297 end
!= 0; remains
>>= 2, end
>>= 2) {
1298 if (!!(remains
& 1) == !!(remains
& 2))
1299 return bad_argument
;
1302 bool create_if_doesnt_exist
= !!(expectations
& CREATE_IF_DOESNT_EXIST
);
1303 bool open_if_exists
= !!(expectations
& OPEN_IF_EXISTS
);
1304 bool truncate_if_exists
= !!(expectations
& TRUNCATE_IF_EXISTS
);
1306 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1307 pp::FileRef
existent_file_ref(
1308 *file_system
, "/match_open_expectation_existent_non_empty_file");
1309 pp::FileRef
nonexistent_file_ref(
1310 *file_system
, "/match_open_expectation_nonexistent_file");
1312 // Setup files for test.
1314 callback
.WaitForResult(existent_file_ref
.Delete(callback
.GetCallback()));
1315 CHECK_CALLBACK_BEHAVIOR(callback
);
1316 ASSERT_TRUE(callback
.result() == PP_OK
||
1317 callback
.result() == PP_ERROR_FILENOTFOUND
);
1318 callback
.WaitForResult(nonexistent_file_ref
.Delete(callback
.GetCallback()));
1319 CHECK_CALLBACK_BEHAVIOR(callback
);
1320 ASSERT_TRUE(callback
.result() == PP_OK
||
1321 callback
.result() == PP_ERROR_FILENOTFOUND
);
1323 pp::FileIO
existent_file_io(instance_
);
1324 callback
.WaitForResult(existent_file_io
.Open(
1326 PP_FILEOPENFLAG_CREATE
| PP_FILEOPENFLAG_WRITE
,
1327 callback
.GetCallback()));
1328 CHECK_CALLBACK_BEHAVIOR(callback
);
1329 ASSERT_EQ(PP_OK
, callback
.result());
1330 int32_t rv
= WriteEntireBuffer(instance_
->pp_instance(), &existent_file_io
,
1331 0, "foobar", callback_type());
1332 ASSERT_EQ(PP_OK
, rv
);
1335 pp::FileIO
existent_file_io(instance_
);
1336 callback
.WaitForResult(existent_file_io
.Open(existent_file_ref
, open_flags
,
1337 callback
.GetCallback()));
1338 CHECK_CALLBACK_BEHAVIOR(callback
);
1339 if ((invalid_combination
&& callback
.result() == PP_OK
) ||
1340 (!invalid_combination
&&
1341 ((callback
.result() == PP_OK
) != open_if_exists
))) {
1342 return ReportOpenError(open_flags
);
1345 if (!invalid_combination
&& open_if_exists
) {
1347 callback
.WaitForResult(existent_file_io
.Query(&info
,
1348 callback
.GetCallback()));
1349 CHECK_CALLBACK_BEHAVIOR(callback
);
1350 ASSERT_EQ(PP_OK
, callback
.result());
1351 if (truncate_if_exists
!= (info
.size
== 0))
1352 return ReportOpenError(open_flags
);
1355 pp::FileIO
nonexistent_file_io(instance_
);
1356 callback
.WaitForResult(nonexistent_file_io
.Open(nonexistent_file_ref
,
1358 callback
.GetCallback()));
1359 CHECK_CALLBACK_BEHAVIOR(callback
);
1360 if ((invalid_combination
&& callback
.result() == PP_OK
) ||
1361 (!invalid_combination
&&
1362 ((callback
.result() == PP_OK
) != create_if_doesnt_exist
))) {
1363 return ReportOpenError(open_flags
);
1366 return std::string();
1369 // TODO(viettrungluu): Test Close(). crbug.com/69457