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 bool ReadEntireFileFromFileHandle(int fd
, std::string
* data
) {
131 if (lseek(fd
, 0, SEEK_SET
) < 0)
138 ret
= read(fd
, buf
, sizeof(buf
));
140 data
->append(buf
, ret
);
145 int32_t WriteEntireBuffer(PP_Instance instance
,
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();
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());
206 result
= MatchOpenExpectations(
208 PP_FILEOPENFLAG_READ
,
209 DONT_CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| DONT_TRUNCATE_IF_EXISTS
);
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(
221 PP_FILEOPENFLAG_WRITE
,
222 DONT_CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| DONT_TRUNCATE_IF_EXISTS
);
226 result
= MatchOpenExpectations(
228 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_CREATE
,
229 CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| DONT_TRUNCATE_IF_EXISTS
);
233 result
= MatchOpenExpectations(
235 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_EXCLUSIVE
,
236 DONT_CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| DONT_TRUNCATE_IF_EXISTS
);
240 result
= MatchOpenExpectations(
242 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_TRUNCATE
,
243 DONT_CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| TRUNCATE_IF_EXISTS
);
247 result
= MatchOpenExpectations(
249 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_CREATE
|
250 PP_FILEOPENFLAG_EXCLUSIVE
,
251 CREATE_IF_DOESNT_EXIST
| DONT_OPEN_IF_EXISTS
| DONT_TRUNCATE_IF_EXISTS
);
255 result
= MatchOpenExpectations(
257 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_CREATE
| PP_FILEOPENFLAG_TRUNCATE
,
258 CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| TRUNCATE_IF_EXISTS
);
262 result
= MatchOpenExpectations(
264 PP_FILEOPENFLAG_WRITE
| PP_FILEOPENFLAG_EXCLUSIVE
|
265 PP_FILEOPENFLAG_TRUNCATE
,
266 DONT_CREATE_IF_DOESNT_EXIST
| OPEN_IF_EXISTS
| TRUNCATE_IF_EXISTS
);
270 result
= MatchOpenExpectations(
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
);
278 // Invalid combination: PP_FILEOPENFLAG_TRUNCATE without
279 // PP_FILEOPENFLAG_WRITE.
280 result
= MatchOpenExpectations(
282 PP_FILEOPENFLAG_READ
| PP_FILEOPENFLAG_TRUNCATE
,
283 INVALID_FLAG_COMBINATION
);
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());
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
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());
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.
342 callback
.WaitForResult(file_io
.Read(0,
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
,
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.
363 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 0, &read_buffer
,
365 ASSERT_EQ(PP_OK
, rv
);
366 ASSERT_EQ(std::string("test"), read_buffer
);
368 // Try to read past the end of the file.
370 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 100, &read_buffer
,
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",
378 ASSERT_EQ(PP_OK
, rv
);
380 // Check the contents of the file.
382 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 0, &read_buffer
,
384 ASSERT_EQ(PP_OK
, rv
);
385 ASSERT_EQ(std::string("test\0\0\0\0test", 12), read_buffer
);
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.
394 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 0, &read_buffer
,
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",
402 ASSERT_EQ(PP_OK
, rv
);
404 // Check the contents of the file.
406 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 0, &read_buffer
,
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.
413 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 4, &read_buffer
,
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",
427 ASSERT_EQ(PP_OK
, rv
);
429 rv
= ReadEntireFile(instance_
->pp_instance(), &file_io2
, 0, &read_buffer
,
431 ASSERT_EQ(PP_OK
, rv
);
432 ASSERT_EQ(std::string("testtesttest\0\0\0\0appended", 24), read_buffer
);
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
440 std::string
TestFileIO::TestReadToArrayWriteSetLength() {
441 if (callback_type() == PP_BLOCKING
) {
442 // This test does not make sense for blocking callbacks.
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.
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.
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",
505 ASSERT_EQ(PP_OK
, rv
);
507 // Check the contents of the file.
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
);
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.
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",
529 ASSERT_EQ(PP_OK
, rv
);
531 // Check the contents of the file.
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.
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
);
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());
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());
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
);
633 rv
= pp::FileIO(instance_
)
634 .Open(file_ref
, PP_FILEOPENFLAG_READ
, callback
.GetCallback());
636 callback
.WaitForAbortResult(rv
);
637 CHECK_CALLBACK_BEHAVIOR(callback
);
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
)));
661 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
662 ASSERT_EQ(0, memcmp(&info_copy
, &info
, sizeof(info
)));
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
);
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.
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
));
701 ASSERT_EQ(PP_ERROR_ABORTED
, callback
.result());
702 ASSERT_EQ(0, memcmp(&buf_copy
, &buf
, sizeof(buf
)));
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
));
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
);
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
);
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;
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
;
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) {
806 rv_1
= file_io
.Read(read_offset_1
, buf_1
, size_1
,
807 callback_1
.GetCallback());
810 rv_2
= file_io
.Read(read_offset_2
, buf_2
, size_2
,
811 callback_2
.GetCallback());
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();
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);
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) {
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);
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);
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();
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
);
930 std::string
TestFileIO::TestNotAllowMixedReadWrite() {
931 if (callback_type() == PP_BLOCKING
) {
932 // This test does not make sense for blocking callbacks.
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;
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
);
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
);
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
);
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()));
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
);
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()));
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
);
1074 return ReportMismatch("read for native FD", buf
, msg
);
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());
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.";
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());
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());
1166 return ReportMismatch("mmap(r) for native FD", buf
, msg
);
1167 int r
= munmap(mapped
, msg
.size());
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());
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
);
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());
1203 return ReportError("munmap for native FD returned error", errno
);
1205 // END mmap(2) test with a file handle opened in READ-WRITE mode.
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.";
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());
1242 return ReportMismatch("mmap(r) for native FD", buf
, msg2
);
1243 int r
= munmap(mapped
, msg2
.size());
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());
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",
1273 // END mmap(2) test with a file handle opened in READONLY mode.
1276 return ReportError("close for native FD returned error", errno
);
1277 #endif // !defined(PPAPI_OS_WIN)
1282 std::string
TestFileIO::MatchOpenExpectations(pp::FileSystem
* file_system
,
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
;
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(
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
) {
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
,
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