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
= 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
= 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
= 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
= 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], str_1
.size(), callback_1
.GetCallback());
883 // Erase the buffer to test that async writes copy it.
884 std::fill(str_1
.begin(), str_1
.end(), 0);
887 // Copy the buffer so we can erase it below.
888 std::string
str_2(buf_2
);
889 rv_2
= file_io
.Write(
890 write_offset_2
, &str_2
[0], str_2
.size(), callback_2
.GetCallback());
891 // Erase the buffer to test that async writes copy it.
892 std::fill(str_2
.begin(), str_2
.end(), 0);
896 callback_1
.WaitForResult(rv_1
);
897 CHECK_CALLBACK_BEHAVIOR(callback_1
);
898 ASSERT_TRUE(callback_1
.result() > 0);
899 write_offset_1
+= callback_1
.result();
900 buf_1
+= callback_1
.result();
901 size_1
-= callback_1
.result();
905 callback_2
.WaitForResult(rv_2
);
906 CHECK_CALLBACK_BEHAVIOR(callback_2
);
907 ASSERT_TRUE(callback_2
.result() > 0);
908 write_offset_2
+= callback_2
.result();
909 buf_2
+= callback_2
.result();
910 size_2
-= callback_2
.result();
914 // If |size_1| or |size_2| is not 0, we have invoked wrong callback(s).
915 ASSERT_EQ(0, size_1
);
916 ASSERT_EQ(0, size_2
);
918 // Check the file contents.
919 std::string read_buffer
;
920 int32_t rv
= ReadEntireFile(instance_
->pp_instance(), &file_io
, 0,
921 &read_buffer
, callback_type());
922 ASSERT_EQ(PP_OK
, rv
);
923 ASSERT_EQ(std::string("abcdefghijkl"), read_buffer
);
928 std::string
TestFileIO::TestNotAllowMixedReadWrite() {
929 if (callback_type() == PP_BLOCKING
) {
930 // This test does not make sense for blocking callbacks.
933 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
935 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
936 pp::FileRef
file_ref(file_system
, "/file_not_allow_mixed_read_write");
937 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
938 CHECK_CALLBACK_BEHAVIOR(callback
);
939 ASSERT_EQ(PP_OK
, callback
.result());
941 pp::FileIO
file_io(instance_
);
942 callback
.WaitForResult(file_io
.Open(file_ref
,
943 PP_FILEOPENFLAG_CREATE
|
944 PP_FILEOPENFLAG_TRUNCATE
|
945 PP_FILEOPENFLAG_READ
|
946 PP_FILEOPENFLAG_WRITE
,
947 callback
.GetCallback()));
948 CHECK_CALLBACK_BEHAVIOR(callback
);
949 ASSERT_EQ(PP_OK
, callback
.result());
951 TestCompletionCallback
callback_1(instance_
->pp_instance(), PP_REQUIRED
);
952 int32_t write_offset_1
= 0;
953 const char* buf_1
= "mnopqrstuvw";
954 int32_t rv_1
= file_io
.Write(write_offset_1
, buf_1
, strlen(buf_1
),
955 callback_1
.GetCallback());
956 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, rv_1
);
958 TestCompletionCallback
callback_2(instance_
->pp_instance(), callback_type());
959 int32_t read_offset_2
= 4;
961 callback_2
.WaitForResult(file_io
.Read(read_offset_2
, buf_2
, sizeof(buf_2
),
962 callback_2
.GetCallback()));
963 CHECK_CALLBACK_BEHAVIOR(callback_2
);
964 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback_2
.result());
965 callback_1
.WaitForResult(rv_1
);
966 CHECK_CALLBACK_BEHAVIOR(callback_1
);
968 // Cannot query while a write is pending.
969 rv_1
= file_io
.Write(write_offset_1
, buf_1
, strlen(buf_1
),
970 callback_1
.GetCallback());
971 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, rv_1
);
973 callback_2
.WaitForResult(file_io
.Query(&info
, callback_2
.GetCallback()));
974 CHECK_CALLBACK_BEHAVIOR(callback_2
);
975 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback_2
.result());
976 callback_1
.WaitForResult(rv_1
);
977 CHECK_CALLBACK_BEHAVIOR(callback_1
);
979 // Cannot touch while a write is pending.
980 rv_1
= file_io
.Write(write_offset_1
, buf_1
, strlen(buf_1
),
981 callback_1
.GetCallback());
982 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, rv_1
);
983 callback_2
.WaitForResult(file_io
.Touch(1234.0, 5678.0,
984 callback_2
.GetCallback()));
985 CHECK_CALLBACK_BEHAVIOR(callback_2
);
986 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback_2
.result());
987 callback_1
.WaitForResult(rv_1
);
988 CHECK_CALLBACK_BEHAVIOR(callback_1
);
990 // Cannot set length while a write is pending.
991 rv_1
= file_io
.Write(write_offset_1
, buf_1
, strlen(buf_1
),
992 callback_1
.GetCallback());
993 ASSERT_EQ(PP_OK_COMPLETIONPENDING
, rv_1
);
994 callback_2
.WaitForResult(file_io
.SetLength(123, callback_2
.GetCallback()));
995 CHECK_CALLBACK_BEHAVIOR(callback_2
);
996 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback_2
.result());
997 callback_1
.WaitForResult(rv_1
);
998 CHECK_CALLBACK_BEHAVIOR(callback_1
);
1003 std::string
TestFileIO::TestRequestOSFileHandle() {
1004 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1006 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
1007 pp::FileRef
file_ref(file_system
, "/file_os_fd");
1009 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
1010 ASSERT_EQ(PP_OK
, callback
.result());
1012 pp::FileIO_Private
file_io(instance_
);
1013 callback
.WaitForResult(file_io
.Open(file_ref
,
1014 PP_FILEOPENFLAG_CREATE
|
1015 PP_FILEOPENFLAG_TRUNCATE
|
1016 PP_FILEOPENFLAG_READ
|
1017 PP_FILEOPENFLAG_WRITE
,
1018 callback
.GetCallback()));
1019 ASSERT_EQ(PP_OK
, callback
.result());
1021 TestCompletionCallbackWithOutput
<pp::PassFileHandle
> output_callback(
1022 instance_
->pp_instance(), callback_type());
1023 output_callback
.WaitForResult(
1024 file_io
.RequestOSFileHandle(output_callback
.GetCallback()));
1025 PP_FileHandle handle
= output_callback
.output().Release();
1026 ASSERT_EQ(PP_OK
, output_callback
.result());
1028 if (handle
== PP_kInvalidFileHandle
)
1029 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1030 #if defined(PPAPI_OS_WIN)
1031 int fd
= _open_osfhandle(reinterpret_cast<intptr_t>(handle
),
1032 _O_RDWR
| _O_BINARY
);
1037 return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
1039 // Check write(2) for the native FD.
1040 const std::string msg
= "foobar";
1041 ssize_t cnt
= write(fd
, msg
.data(), msg
.size());
1043 return ReportError("write for native FD returned error", errno
);
1044 if (cnt
!= static_cast<ssize_t
>(msg
.size()))
1045 return ReportError("write for native FD count mismatch", cnt
);
1047 // Check lseek(2) for the native FD.
1048 off_t off
= lseek(fd
, 0, SEEK_CUR
);
1049 if (off
== static_cast<off_t
>(-1))
1050 return ReportError("lseek for native FD returned error", errno
);
1051 if (off
!= static_cast<off_t
>(msg
.size()))
1052 return ReportError("lseek for native FD offset mismatch", off
);
1054 off
= lseek(fd
, 0, SEEK_SET
);
1055 if (off
== static_cast<off_t
>(-1))
1056 return ReportError("lseek for native FD returned error", errno
);
1058 return ReportError("lseek for native FD offset mismatch", off
);
1060 // Check read(2) for the native FD.
1061 std::string
buf(msg
.size(), '\0');
1062 cnt
= read(fd
, &buf
[0], msg
.size());
1064 return ReportError("read for native FD returned error", errno
);
1065 if (cnt
!= static_cast<ssize_t
>(msg
.size()))
1066 return ReportError("read for native FD count mismatch", cnt
);
1068 return ReportMismatch("read for native FD", buf
, msg
);
1072 // Calling RequestOSFileHandle with the FileIO that is opened with
1073 // PP_FILEOPENFLAG_EXCLUSIVE used to cause NaCl module to crash while loading.
1074 // This is a regression test for crbug.com/243241.
1075 std::string
TestFileIO::TestRequestOSFileHandleWithOpenExclusive() {
1076 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1078 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
1079 pp::FileRef
file_ref(file_system
, "/file_os_fd2");
1081 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
1082 ASSERT_EQ(PP_OK
, callback
.result());
1084 // Open with PP_FILEOPENFLAG_CREATE and PP_FILEOPENFLAG_EXCLUSIVE will fail
1085 // if the file already exists. Delete it here to make sure it does not.
1086 callback
.WaitForResult(file_ref
.Delete(callback
.GetCallback()));
1088 pp::FileIO_Private
file_io(instance_
);
1089 callback
.WaitForResult(file_io
.Open(file_ref
,
1090 PP_FILEOPENFLAG_CREATE
|
1091 PP_FILEOPENFLAG_READ
|
1092 PP_FILEOPENFLAG_WRITE
|
1093 PP_FILEOPENFLAG_EXCLUSIVE
,
1094 callback
.GetCallback()));
1095 ASSERT_EQ(PP_OK
, callback
.result());
1097 TestCompletionCallbackWithOutput
<pp::PassFileHandle
> output_callback(
1098 instance_
->pp_instance(), callback_type());
1099 output_callback
.WaitForResult(
1100 file_io
.RequestOSFileHandle(output_callback
.GetCallback()));
1101 PP_FileHandle handle
= output_callback
.output().Release();
1102 if (handle
== PP_kInvalidFileHandle
)
1103 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1104 ASSERT_EQ(PP_OK
, output_callback
.result());
1109 std::string
TestFileIO::TestMmap() {
1110 #if !defined(PPAPI_OS_WIN)
1111 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1113 pp::FileSystem
file_system(instance_
, PP_FILESYSTEMTYPE_LOCALTEMPORARY
);
1114 pp::FileRef
file_ref(file_system
, "/file_os_fd");
1116 callback
.WaitForResult(file_system
.Open(1024, callback
.GetCallback()));
1117 ASSERT_EQ(PP_OK
, callback
.result());
1119 pp::FileIO_Private
file_io(instance_
);
1120 callback
.WaitForResult(file_io
.Open(file_ref
,
1121 PP_FILEOPENFLAG_CREATE
|
1122 PP_FILEOPENFLAG_TRUNCATE
|
1123 PP_FILEOPENFLAG_READ
|
1124 PP_FILEOPENFLAG_WRITE
,
1125 callback
.GetCallback()));
1126 ASSERT_EQ(PP_OK
, callback
.result());
1128 TestCompletionCallbackWithOutput
<pp::PassFileHandle
> output_callback(
1129 instance_
->pp_instance(), callback_type());
1130 output_callback
.WaitForResult(
1131 file_io
.RequestOSFileHandle(output_callback
.GetCallback()));
1132 PP_FileHandle handle
= output_callback
.output().Release();
1133 ASSERT_EQ(PP_OK
, output_callback
.result());
1135 if (handle
== PP_kInvalidFileHandle
)
1136 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1139 return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
1141 // Check write(2) for the native FD.
1142 const std::string msg
= "foobar";
1143 ssize_t cnt
= write(fd
, msg
.data(), msg
.size());
1145 return ReportError("write for native FD returned error", errno
);
1146 if (cnt
!= static_cast<ssize_t
>(msg
.size()))
1147 return ReportError("write for native FD count mismatch", cnt
);
1149 // BEGIN mmap(2) test with a file handle opened in READ-WRITE mode.
1150 // Check mmap(2) for read.
1152 char* mapped
= reinterpret_cast<char*>(
1153 mmap(NULL
, msg
.size(), PROT_READ
, MAP_PRIVATE
, fd
, 0));
1154 if (mapped
== MAP_FAILED
)
1155 return ReportError("mmap(r) for native FD returned errno", errno
);
1156 // Make sure the buffer is cleared.
1157 std::string buf
= std::string(msg
.size(), '\0');
1158 memcpy(&buf
[0], mapped
, msg
.size());
1160 return ReportMismatch("mmap(r) for native FD", buf
, msg
);
1161 int r
= munmap(mapped
, msg
.size());
1163 return ReportError("munmap for native FD returned error", errno
);
1166 // Check mmap(2) for write with MAP_PRIVATE
1168 char* mapped
= reinterpret_cast<char*>(
1169 mmap(NULL
, msg
.size(), PROT_READ
| PROT_WRITE
, MAP_PRIVATE
, fd
, 0));
1170 if (mapped
== MAP_FAILED
)
1171 return ReportError("mmap(r) for native FD returned errno", errno
);
1172 // Make sure the file is not polluted by writing to privage mmap.
1173 strncpy(mapped
, "baz", 3);
1174 std::string read_buffer
;
1175 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd
, &read_buffer
));
1176 if (msg
!= read_buffer
)
1177 return ReportMismatch("file content != msg", read_buffer
, msg
);
1178 int r
= munmap(mapped
, msg
.size());
1180 return ReportError("munmap for native FD returned error", errno
);
1183 // Check mmap(2) for write with MAP_SHARED.
1185 char* mapped
= reinterpret_cast<char*>(
1186 mmap(NULL
, msg
.size(), PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0));
1187 if (mapped
== MAP_FAILED
)
1188 return ReportError("mmap(w) for native FD returned errno", errno
);
1190 strncpy(mapped
, "baz", 3);
1191 std::string read_buffer
;
1192 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd
, &read_buffer
));
1193 if (read_buffer
!= "bazbar")
1194 return ReportMismatch("file content != msg", read_buffer
, "bazbar");
1195 int r
= munmap(mapped
, msg
.size());
1197 return ReportError("munmap for native FD returned error", errno
);
1199 // END mmap(2) test with a file handle opened in READ-WRITE mode.
1202 return ReportError("close for native FD returned error", errno
);
1204 // BEGIN mmap(2) test with a file handle opened in READONLY mode.
1205 file_io
= pp::FileIO_Private(instance_
);
1206 callback
.WaitForResult(file_io
.Open(file_ref
,
1207 PP_FILEOPENFLAG_READ
,
1208 callback
.GetCallback()));
1209 ASSERT_EQ(PP_OK
, callback
.result());
1211 output_callback
= TestCompletionCallbackWithOutput
<pp::PassFileHandle
>(
1212 instance_
->pp_instance(), callback_type());
1213 output_callback
.WaitForResult(
1214 file_io
.RequestOSFileHandle(output_callback
.GetCallback()));
1215 handle
= output_callback
.output().Release();
1216 ASSERT_EQ(PP_OK
, output_callback
.result());
1218 if (handle
== PP_kInvalidFileHandle
)
1219 return "FileIO::RequestOSFileHandle() returned a bad file handle.";
1222 return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
1224 const std::string msg2
= "bazbar";
1226 // Check mmap(2) for read.
1228 char* mapped
= reinterpret_cast<char*>(
1229 mmap(NULL
, msg2
.size(), PROT_READ
, MAP_PRIVATE
, fd
, 0));
1230 if (mapped
== MAP_FAILED
)
1231 return ReportError("mmap(r) for native FD returned errno", errno
);
1232 // Make sure the buffer is cleared.
1233 std::string buf
= std::string(msg2
.size(), '\0');
1234 memcpy(&buf
[0], mapped
, msg2
.size());
1236 return ReportMismatch("mmap(r) for native FD", buf
, msg2
);
1237 int r
= munmap(mapped
, msg2
.size());
1239 return ReportError("munmap for native FD returned error", errno
);
1242 // Check mmap(2) for write with MAP_PRIVATE
1244 char* mapped
= reinterpret_cast<char*>(
1245 mmap(NULL
, msg2
.size(), PROT_READ
| PROT_WRITE
, MAP_PRIVATE
, fd
, 0));
1246 if (mapped
== MAP_FAILED
)
1247 return ReportError("mmap(r) for native FD returned errno", errno
);
1248 // Make sure the file is not polluted by writing to privage mmap.
1249 strncpy(mapped
, "baz", 3);
1250 std::string read_buffer
;
1251 ASSERT_TRUE(ReadEntireFileFromFileHandle(fd
, &read_buffer
));
1252 if (msg2
!= read_buffer
)
1253 return ReportMismatch("file content != msg2", read_buffer
, msg2
);
1254 int r
= munmap(mapped
, msg2
.size());
1256 return ReportError("munmap for native FD returned error", errno
);
1259 // Check mmap(2) for write with MAP_SHARED.
1261 char* mapped
= reinterpret_cast<char*>(
1262 mmap(NULL
, msg2
.size(), PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0));
1263 if (mapped
!= MAP_FAILED
)
1264 return ReportError("mmap(w) for native FD must fail when opened readonly",
1267 // END mmap(2) test with a file handle opened in READONLY mode.
1270 return ReportError("close for native FD returned error", errno
);
1271 #endif // !defined(PPAPI_OS_WIN)
1276 std::string
TestFileIO::MatchOpenExpectations(pp::FileSystem
* file_system
,
1278 size_t expectations
) {
1279 std::string bad_argument
=
1280 "TestFileIO::MatchOpenExpectations has invalid input arguments.";
1281 bool invalid_combination
= !!(expectations
& INVALID_FLAG_COMBINATION
);
1282 if (invalid_combination
) {
1283 if (expectations
!= INVALID_FLAG_COMBINATION
)
1284 return bad_argument
;
1286 // Validate that one and only one of <some_expectation> and
1287 // DONT_<some_expectation> is specified.
1288 for (size_t remains
= expectations
, end
= END_OF_OPEN_EXPECATION_PAIRS
;
1289 end
!= 0; remains
>>= 2, end
>>= 2) {
1290 if (!!(remains
& 1) == !!(remains
& 2))
1291 return bad_argument
;
1294 bool create_if_doesnt_exist
= !!(expectations
& CREATE_IF_DOESNT_EXIST
);
1295 bool open_if_exists
= !!(expectations
& OPEN_IF_EXISTS
);
1296 bool truncate_if_exists
= !!(expectations
& TRUNCATE_IF_EXISTS
);
1298 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
1299 pp::FileRef
existent_file_ref(
1300 *file_system
, "/match_open_expectation_existent_non_empty_file");
1301 pp::FileRef
nonexistent_file_ref(
1302 *file_system
, "/match_open_expectation_nonexistent_file");
1304 // Setup files for test.
1306 callback
.WaitForResult(existent_file_ref
.Delete(callback
.GetCallback()));
1307 CHECK_CALLBACK_BEHAVIOR(callback
);
1308 ASSERT_TRUE(callback
.result() == PP_OK
||
1309 callback
.result() == PP_ERROR_FILENOTFOUND
);
1310 callback
.WaitForResult(nonexistent_file_ref
.Delete(callback
.GetCallback()));
1311 CHECK_CALLBACK_BEHAVIOR(callback
);
1312 ASSERT_TRUE(callback
.result() == PP_OK
||
1313 callback
.result() == PP_ERROR_FILENOTFOUND
);
1315 pp::FileIO
existent_file_io(instance_
);
1316 callback
.WaitForResult(existent_file_io
.Open(
1318 PP_FILEOPENFLAG_CREATE
| PP_FILEOPENFLAG_WRITE
,
1319 callback
.GetCallback()));
1320 CHECK_CALLBACK_BEHAVIOR(callback
);
1321 ASSERT_EQ(PP_OK
, callback
.result());
1322 int32_t rv
= WriteEntireBuffer(instance_
->pp_instance(), &existent_file_io
,
1323 0, "foobar", callback_type());
1324 ASSERT_EQ(PP_OK
, rv
);
1327 pp::FileIO
existent_file_io(instance_
);
1328 callback
.WaitForResult(existent_file_io
.Open(existent_file_ref
, open_flags
,
1329 callback
.GetCallback()));
1330 CHECK_CALLBACK_BEHAVIOR(callback
);
1331 if ((invalid_combination
&& callback
.result() == PP_OK
) ||
1332 (!invalid_combination
&&
1333 ((callback
.result() == PP_OK
) != open_if_exists
))) {
1334 return ReportOpenError(open_flags
);
1337 if (!invalid_combination
&& open_if_exists
) {
1339 callback
.WaitForResult(existent_file_io
.Query(&info
,
1340 callback
.GetCallback()));
1341 CHECK_CALLBACK_BEHAVIOR(callback
);
1342 ASSERT_EQ(PP_OK
, callback
.result());
1343 if (truncate_if_exists
!= (info
.size
== 0))
1344 return ReportOpenError(open_flags
);
1347 pp::FileIO
nonexistent_file_io(instance_
);
1348 callback
.WaitForResult(nonexistent_file_io
.Open(nonexistent_file_ref
,
1350 callback
.GetCallback()));
1351 CHECK_CALLBACK_BEHAVIOR(callback
);
1352 if ((invalid_combination
&& callback
.result() == PP_OK
) ||
1353 (!invalid_combination
&&
1354 ((callback
.result() == PP_OK
) != create_if_doesnt_exist
))) {
1355 return ReportOpenError(open_flags
);
1358 return std::string();
1361 // TODO(viettrungluu): Test Close(). crbug.com/69457