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