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