12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ppapi/tests/test_file_io.h"
- #include <errno.h>
- #include <fcntl.h>
- #include <stddef.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <algorithm>
- #include <vector>
- #include "ppapi/c/pp_errors.h"
- #include "ppapi/c/ppb_file_io.h"
- #include "ppapi/c/private/pp_file_handle.h"
- #include "ppapi/c/private/ppb_testing_private.h"
- #include "ppapi/cpp/file_io.h"
- #include "ppapi/cpp/file_ref.h"
- #include "ppapi/cpp/file_system.h"
- #include "ppapi/cpp/instance.h"
- #include "ppapi/cpp/module.h"
- #include "ppapi/cpp/private/file_io_private.h"
- #include "ppapi/cpp/private/pass_file_handle.h"
- #include "ppapi/tests/test_utils.h"
- #include "ppapi/tests/testing_instance.h"
- #if defined(PPAPI_OS_WIN)
- # include <io.h>
- # include <windows.h>
- // TODO(hamaji): Use standard windows APIs instead of compatibility layer?
- # define lseek _lseek
- # define read _read
- # define write _write
- # define ssize_t int
- #else
- # include <sys/mman.h>
- # include <unistd.h>
- #endif
- REGISTER_TEST_CASE(FileIO);
- namespace {
- std::string ReportMismatch(const std::string& method_name,
- const std::string& returned_result,
- const std::string& expected_result) {
- return method_name + " returned '" + returned_result + "'; '" +
- expected_result + "' expected.";
- }
- std::string ReportOpenError(int32_t open_flags) {
- static const char* kFlagNames[] = {
- "PP_FILEOPENFLAG_READ",
- "PP_FILEOPENFLAG_WRITE",
- "PP_FILEOPENFLAG_CREATE",
- "PP_FILEOPENFLAG_TRUNCATE",
- "PP_FILEOPENFLAG_EXCLUSIVE"
- };
- std::string result = "FileIO:Open had unexpected behavior with flags: ";
- bool first_flag = true;
- for (int32_t mask = 1, index = 0; mask <= PP_FILEOPENFLAG_EXCLUSIVE;
- mask <<= 1, ++index) {
- if (mask & open_flags) {
- if (first_flag) {
- first_flag = false;
- } else {
- result += " | ";
- }
- result += kFlagNames[index];
- }
- }
- if (first_flag)
- result += "[None]";
- return result;
- }
- int32_t ReadEntireFile(PP_Instance instance,
- pp::FileIO* file_io,
- int32_t offset,
- std::string* data,
- CallbackType callback_type) {
- TestCompletionCallback callback(instance, callback_type);
- char buf[256];
- int32_t read_offset = offset;
- for (;;) {
- callback.WaitForResult(
- file_io->Read(read_offset, buf, sizeof(buf), callback.GetCallback()));
- if (callback.result() < 0)
- return callback.result();
- if (callback.result() == 0)
- break;
- read_offset += callback.result();
- data->append(buf, callback.result());
- }
- return PP_OK;
- }
- int32_t ReadToArrayEntireFile(PP_Instance instance,
- pp::FileIO* file_io,
- int32_t offset,
- std::string* data,
- CallbackType callback_type) {
- TestCompletionCallbackWithOutput< std::vector<char> > callback(
- instance, callback_type);
- for (;;) {
- callback.WaitForResult(file_io->Read(offset, 256, callback.GetCallback()));
- int32_t rv = callback.result();
- if (rv < 0)
- return rv;
- if (rv == 0)
- break;
- const std::vector<char>& output = callback.output();
- assert(rv == static_cast<int32_t>(output.size()));
- offset += rv;
- data->append(output.begin(), output.end());
- }
- return PP_OK;
- }
- #if !defined(PPAPI_OS_WIN)
- bool ReadEntireFileFromFileHandle(int fd, std::string* data) {
- if (lseek(fd, 0, SEEK_SET) < 0)
- return false;
- data->clear();
- int ret;
- do {
- char buf[8192];
- ret = read(fd, buf, sizeof(buf));
- if (ret > 0)
- data->append(buf, ret);
- } while (ret > 0);
- return ret == 0;
- }
- #endif // !defined(PPAPI_OS_WIN)
- int32_t WriteEntireBuffer(PP_Instance instance,
- pp::FileIO* file_io,
- int32_t offset,
- const std::string& data,
- CallbackType callback_type) {
- TestCompletionCallback callback(instance, callback_type);
- int32_t write_offset = offset;
- const char* buf = data.c_str();
- int32_t size = static_cast<int32_t>(data.size());
- while (write_offset < offset + size) {
- callback.WaitForResult(file_io->Write(write_offset,
- &buf[write_offset - offset],
- size - write_offset + offset,
- callback.GetCallback()));
- if (callback.result() < 0)
- return callback.result();
- if (callback.result() == 0)
- return PP_ERROR_FAILED;
- write_offset += callback.result();
- }
- return PP_OK;
- }
- } // namespace
- bool TestFileIO::Init() {
- return CheckTestingInterface() && EnsureRunningOverHTTP();
- }
- void TestFileIO::RunTests(const std::string& filter) {
- RUN_CALLBACK_TEST(TestFileIO, Open, filter);
- RUN_CALLBACK_TEST(TestFileIO, OpenDirectory, filter);
- RUN_CALLBACK_TEST(TestFileIO, ReadWriteSetLength, filter);
- RUN_CALLBACK_TEST(TestFileIO, ReadToArrayWriteSetLength, filter);
- RUN_CALLBACK_TEST(TestFileIO, TouchQuery, filter);
- RUN_CALLBACK_TEST(TestFileIO, AbortCalls, filter);
- RUN_CALLBACK_TEST(TestFileIO, ParallelReads, filter);
- RUN_CALLBACK_TEST(TestFileIO, ParallelWrites, filter);
- RUN_CALLBACK_TEST(TestFileIO, NotAllowMixedReadWrite, filter);
- RUN_CALLBACK_TEST(TestFileIO, RequestOSFileHandle, filter);
- RUN_CALLBACK_TEST(TestFileIO, RequestOSFileHandleWithOpenExclusive, filter);
- RUN_CALLBACK_TEST(TestFileIO, Mmap, filter);
- // TODO(viettrungluu): add tests:
- // - that PP_ERROR_PENDING is correctly returned
- // - that operations respect the file open modes (flags)
- }
- std::string TestFileIO::TestOpen() {
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
- pp::FileRef file_ref(file_system, "/file_open");
- callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- std::string result;
- result = MatchOpenExpectations(
- &file_system,
- PP_FILEOPENFLAG_READ,
- DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS);
- if (!result.empty())
- return result;
- // Test the behavior of the power set of
- // { PP_FILEOPENFLAG_CREATE,
- // PP_FILEOPENFLAG_TRUNCATE,
- // PP_FILEOPENFLAG_EXCLUSIVE }.
- // First of all, none of them are specified.
- result = MatchOpenExpectations(
- &file_system,
- PP_FILEOPENFLAG_WRITE,
- DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS);
- if (!result.empty())
- return result;
- result = MatchOpenExpectations(
- &file_system,
- PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE,
- CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS);
- if (!result.empty())
- return result;
- result = MatchOpenExpectations(
- &file_system,
- PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_EXCLUSIVE,
- DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS);
- if (!result.empty())
- return result;
- result = MatchOpenExpectations(
- &file_system,
- PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_TRUNCATE,
- DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | TRUNCATE_IF_EXISTS);
- if (!result.empty())
- return result;
- result = MatchOpenExpectations(
- &file_system,
- PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE |
- PP_FILEOPENFLAG_EXCLUSIVE,
- CREATE_IF_DOESNT_EXIST | DONT_OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS);
- if (!result.empty())
- return result;
- result = MatchOpenExpectations(
- &file_system,
- PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_TRUNCATE,
- CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | TRUNCATE_IF_EXISTS);
- if (!result.empty())
- return result;
- result = MatchOpenExpectations(
- &file_system,
- PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_EXCLUSIVE |
- PP_FILEOPENFLAG_TRUNCATE,
- DONT_CREATE_IF_DOESNT_EXIST | OPEN_IF_EXISTS | TRUNCATE_IF_EXISTS);
- if (!result.empty())
- return result;
- result = MatchOpenExpectations(
- &file_system,
- PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE |
- PP_FILEOPENFLAG_EXCLUSIVE | PP_FILEOPENFLAG_TRUNCATE,
- CREATE_IF_DOESNT_EXIST | DONT_OPEN_IF_EXISTS | DONT_TRUNCATE_IF_EXISTS);
- if (!result.empty())
- return result;
- // Invalid combination: PP_FILEOPENFLAG_TRUNCATE without
- // PP_FILEOPENFLAG_WRITE.
- result = MatchOpenExpectations(
- &file_system,
- PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_TRUNCATE,
- INVALID_FLAG_COMBINATION);
- if (!result.empty())
- return result;
- PASS();
- }
- std::string TestFileIO::TestOpenDirectory() {
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
- callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- // Make a directory.
- pp::FileRef dir_ref(file_system, "/test_dir_open_directory");
- callback.WaitForResult(dir_ref.MakeDirectory(
- PP_MAKEDIRECTORYFLAG_NONE, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- // Open the directory. This is expected to fail since directories cannot be
- // opened.
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(dir_ref, PP_FILEOPENFLAG_READ,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_ERROR_NOTAFILE, callback.result());
- PASS();
- }
- std::string TestFileIO::TestReadWriteSetLength() {
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
- pp::FileRef file_ref(file_system, "/file_read_write_setlength");
- callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref,
- PP_FILEOPENFLAG_CREATE |
- PP_FILEOPENFLAG_TRUNCATE |
- PP_FILEOPENFLAG_READ |
- PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- // Write something to the file.
- int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0,
- "test_test", callback_type());
- ASSERT_EQ(PP_OK, rv);
- // Attempt to read a negative number of bytes; it should fail.
- char buf[256];
- callback.WaitForResult(file_io.Read(0,
- buf,
- -1,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_ERROR_FAILED, callback.result());
- // Read the entire file.
- std::string read_buffer;
- rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer,
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("test_test"), read_buffer);
- // Truncate the file.
- callback.WaitForResult(file_io.SetLength(4, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- // Check the file contents.
- read_buffer.clear();
- rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer,
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("test"), read_buffer);
- // Try to read past the end of the file.
- read_buffer.clear();
- rv = ReadEntireFile(instance_->pp_instance(), &file_io, 100, &read_buffer,
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_TRUE(read_buffer.empty());
- // Write past the end of the file. The file should be zero-padded.
- rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 8, "test",
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- // Check the contents of the file.
- read_buffer.clear();
- rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer,
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("test\0\0\0\0test", 12), read_buffer);
- // Extend the file.
- callback.WaitForResult(file_io.SetLength(16, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- // Check the contents of the file.
- read_buffer.clear();
- rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer,
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("test\0\0\0\0test\0\0\0\0", 16), read_buffer);
- // Write in the middle of the file.
- rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 4, "test",
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- // Check the contents of the file.
- read_buffer.clear();
- rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0, &read_buffer,
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("testtesttest\0\0\0\0", 16), read_buffer);
- // Read from the middle of the file.
- read_buffer.clear();
- rv = ReadEntireFile(instance_->pp_instance(), &file_io, 4, &read_buffer,
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("testtest\0\0\0\0", 12), read_buffer);
- // Append to the end of the file.
- pp::FileIO file_io2(instance_);
- callback.WaitForResult(file_io2.Open(file_ref,
- PP_FILEOPENFLAG_CREATE |
- PP_FILEOPENFLAG_READ |
- PP_FILEOPENFLAG_APPEND,
- callback.GetCallback()));
- rv = WriteEntireBuffer(instance_->pp_instance(), &file_io2, 0, "appended",
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- read_buffer.clear();
- rv = ReadEntireFile(instance_->pp_instance(), &file_io2, 0, &read_buffer,
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("testtesttest\0\0\0\0appended", 24), read_buffer);
- PASS();
- }
- // This is basically a copy of TestReadWriteSetLength, but with the new Read
- // API. With this test case, we can make sure the two Read's have the same
- // behavior.
- std::string TestFileIO::TestReadToArrayWriteSetLength() {
- if (callback_type() == PP_BLOCKING) {
- // This test does not make sense for blocking callbacks.
- PASS();
- }
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
- pp::FileRef file_ref(file_system, "/file_read_write_setlength");
- callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref,
- PP_FILEOPENFLAG_CREATE |
- PP_FILEOPENFLAG_TRUNCATE |
- PP_FILEOPENFLAG_READ |
- PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- // Write something to the file.
- int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0,
- "test_test", callback_type());
- ASSERT_EQ(PP_OK, rv);
- TestCompletionCallbackWithOutput< std::vector<char> > callback2(
- instance_->pp_instance(), callback_type());
- // Attempt to read a negative number of bytes; it should fail.
- callback2.WaitForResult(file_io.Read(0, -1, callback2.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback2);
- ASSERT_EQ(PP_ERROR_FAILED, callback2.result());
- // Read the entire file.
- std::string read_buffer;
- read_buffer.reserve(10);
- rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
- &read_buffer, callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("test_test"), read_buffer);
- // Truncate the file.
- callback.WaitForResult(file_io.SetLength(4, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, rv);
- // Check the file contents.
- read_buffer.clear();
- rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
- &read_buffer, callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("test"), read_buffer);
- // Try to read past the end of the file.
- read_buffer.clear();
- rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 100,
- &read_buffer, callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_TRUE(read_buffer.empty());
- // Write past the end of the file. The file should be zero-padded.
- rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 8, "test",
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- // Check the contents of the file.
- read_buffer.clear();
- rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
- &read_buffer, callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("test\0\0\0\0test", 12), read_buffer);
- // Extend the file.
- callback.WaitForResult(file_io.SetLength(16, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- // Check the contents of the file.
- read_buffer.clear();
- rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
- &read_buffer, callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("test\0\0\0\0test\0\0\0\0", 16), read_buffer);
- // Write in the middle of the file.
- rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 4, "test",
- callback_type());
- ASSERT_EQ(PP_OK, rv);
- // Check the contents of the file.
- read_buffer.clear();
- rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
- &read_buffer, callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("testtesttest\0\0\0\0", 16), read_buffer);
- // Read from the middle of the file.
- read_buffer.clear();
- rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 4,
- &read_buffer, callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("testtest\0\0\0\0", 12), read_buffer);
- PASS();
- }
- std::string TestFileIO::TestTouchQuery() {
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
- callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- pp::FileRef file_ref(file_system, "/file_touch");
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref,
- PP_FILEOPENFLAG_CREATE |
- PP_FILEOPENFLAG_TRUNCATE |
- PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- // Write some data to have a non-zero file size.
- callback.WaitForResult(file_io.Write(0, "test", 4, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(4, callback.result());
- const PP_Time last_access_time = 123 * 24 * 3600.0;
- // last_modified_time's granularity is 2 seconds
- // NOTE: In NaCl on Windows, NaClDescIO uses _fstat64 to retrieve file info.
- // This function returns strange values for very small time values (near the
- // Unix Epoch). For a value like 246.0, it returns -1. For larger values, it
- // returns values that are exactly an hour less. The value below is handled
- // correctly, and is only 100 days after the start of Unix time.
- const PP_Time last_modified_time = 100 * 24 * 3600.0;
- callback.WaitForResult(file_io.Touch(last_access_time, last_modified_time,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- PP_FileInfo info;
- callback.WaitForResult(file_io.Query(&info, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- if ((info.size != 4) ||
- (info.type != PP_FILETYPE_REGULAR) ||
- (info.system_type != PP_FILESYSTEMTYPE_LOCALTEMPORARY))
- // Disabled due to DST-related failure: crbug.com/314579
- //(info.last_access_time != last_access_time) ||
- //(info.last_modified_time != last_modified_time))
- return "FileIO::Query() has returned bad data.";
- // Call |Query()| again, to make sure it works a second time.
- callback.WaitForResult(file_io.Query(&info, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- PASS();
- }
- std::string TestFileIO::TestAbortCalls() {
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
- pp::FileRef file_ref(file_system, "/file_abort_calls");
- callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- int32_t rv = PP_ERROR_FAILED;
- // First, create a file on which to do ops.
- {
- pp::FileIO file_io(instance_);
- callback.WaitForResult(
- file_io.Open(file_ref,
- PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- // N.B.: Should write at least 3 bytes.
- rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0,
- "foobarbazquux", callback_type());
- ASSERT_EQ(PP_OK, rv);
- }
- // Abort |Open()|.
- {
- rv = pp::FileIO(instance_)
- .Open(file_ref, PP_FILEOPENFLAG_READ, callback.GetCallback());
- }
- callback.WaitForAbortResult(rv);
- CHECK_CALLBACK_BEHAVIOR(callback);
- // Abort |Query()|.
- {
- PP_FileInfo info = { 0 };
- // Save a copy and make sure |info| doesn't get written to if it is aborted.
- PP_FileInfo info_copy;
- memcpy(&info_copy, &info, sizeof(info));
- {
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_READ,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- rv = file_io.Query(&info, callback.GetCallback());
- } // Destroy |file_io|.
- callback.WaitForResult(rv);
- CHECK_CALLBACK_BEHAVIOR(callback);
- if (callback_type() == PP_BLOCKING) {
- ASSERT_EQ(PP_OK, callback.result());
- // The operation completed synchronously, so |info| should have changed.
- ASSERT_NE(0, memcmp(&info_copy, &info, sizeof(info)));
- } else {
- ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
- ASSERT_EQ(0, memcmp(&info_copy, &info, sizeof(info)));
- }
- }
- // Abort |Touch()|.
- {
- {
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- rv = file_io.Touch(0, 0, callback.GetCallback());
- } // Destroy |file_io|.
- callback.WaitForAbortResult(rv);
- CHECK_CALLBACK_BEHAVIOR(callback);
- }
- // Abort |Read()|.
- {
- char buf[3] = { 0 };
- {
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_READ,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- rv = file_io.Read(0, buf, sizeof(buf), callback.GetCallback());
- } // Destroy |file_io|.
- // Save a copy to make sure buf isn't written to in the async case.
- char buf_copy[3];
- memcpy(&buf_copy, &buf, sizeof(buf));
- callback.WaitForResult(rv);
- CHECK_CALLBACK_BEHAVIOR(callback);
- if (callback_type() == PP_BLOCKING) {
- ASSERT_EQ(callback.result(), sizeof(buf));
- } else {
- ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
- ASSERT_EQ(0, memcmp(&buf_copy, &buf, sizeof(buf)));
- }
- }
- // Abort |Write()|.
- {
- char buf[3] = { 0 };
- {
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- rv = file_io.Write(0, buf, sizeof(buf), callback.GetCallback());
- } // Destroy |file_io|.
- callback.WaitForResult(rv);
- CHECK_CALLBACK_BEHAVIOR(callback);
- if (callback_type() == PP_BLOCKING)
- ASSERT_EQ(callback.result(), sizeof(buf));
- else
- ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
- }
- // Abort |SetLength()|.
- {
- {
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- rv = file_io.SetLength(3, callback.GetCallback());
- } // Destroy |file_io|.
- callback.WaitForAbortResult(rv);
- CHECK_CALLBACK_BEHAVIOR(callback);
- }
- // Abort |Flush|.
- {
- {
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- rv = file_io.Flush(callback.GetCallback());
- } // Destroy |file_io|.
- callback.WaitForAbortResult(rv);
- CHECK_CALLBACK_BEHAVIOR(callback);
- }
- PASS();
- }
- std::string TestFileIO::TestParallelReads() {
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
- pp::FileRef file_ref(file_system, "/file_parallel_reads");
- callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref,
- PP_FILEOPENFLAG_CREATE |
- PP_FILEOPENFLAG_TRUNCATE |
- PP_FILEOPENFLAG_READ |
- PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- // Set up testing contents.
- int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0,
- "abcdefghijkl", callback_type());
- ASSERT_EQ(PP_OK, rv);
- // Parallel read operations.
- const char* border = "__border__";
- const int32_t border_size = static_cast<int32_t>(strlen(border));
- TestCompletionCallback callback_1(instance_->pp_instance(), callback_type());
- int32_t read_offset_1 = 0;
- int32_t size_1 = 3;
- std::vector<char> extended_buf_1(border_size * 2 + size_1);
- char* buf_1 = &extended_buf_1[border_size];
- memcpy(&extended_buf_1[0], border, border_size);
- memcpy(buf_1 + size_1, border, border_size);
- TestCompletionCallback callback_2(instance_->pp_instance(), callback_type());
- int32_t read_offset_2 = size_1;
- int32_t size_2 = 9;
- std::vector<char> extended_buf_2(border_size * 2 + size_2);
- char* buf_2 = &extended_buf_2[border_size];
- memcpy(&extended_buf_2[0], border, border_size);
- memcpy(buf_2 + size_2, border, border_size);
- int32_t rv_1 = PP_OK;
- int32_t rv_2 = PP_OK;
- while (size_1 >= 0 && size_2 >= 0 && size_1 + size_2 > 0) {
- if (size_1 > 0) {
- rv_1 = file_io.Read(read_offset_1, buf_1, size_1,
- callback_1.GetCallback());
- }
- if (size_2 > 0) {
- rv_2 = file_io.Read(read_offset_2, buf_2, size_2,
- callback_2.GetCallback());
- }
- if (size_1 > 0) {
- callback_1.WaitForResult(rv_1);
- CHECK_CALLBACK_BEHAVIOR(callback_1);
- ASSERT_TRUE(callback_1.result() > 0);
- read_offset_1 += callback_1.result();
- buf_1 += callback_1.result();
- size_1 -= callback_1.result();
- }
- if (size_2 > 0) {
- callback_2.WaitForResult(rv_2);
- CHECK_CALLBACK_BEHAVIOR(callback_2);
- ASSERT_TRUE(callback_2.result() > 0);
- read_offset_2 += callback_2.result();
- buf_2 += callback_2.result();
- size_2 -= callback_2.result();
- }
- }
- // If |size_1| or |size_2| is not 0, we have invoked wrong callback(s).
- ASSERT_EQ(0, size_1);
- ASSERT_EQ(0, size_2);
- // Make sure every read operation writes into the correct buffer.
- const char expected_result_1[] = "__border__abc__border__";
- const char expected_result_2[] = "__border__defghijkl__border__";
- ASSERT_TRUE(strncmp(&extended_buf_1[0], expected_result_1,
- strlen(expected_result_1)) == 0);
- ASSERT_TRUE(strncmp(&extended_buf_2[0], expected_result_2,
- strlen(expected_result_2)) == 0);
- PASS();
- }
- std::string TestFileIO::TestParallelWrites() {
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
- pp::FileRef file_ref(file_system, "/file_parallel_writes");
- callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref,
- PP_FILEOPENFLAG_CREATE |
- PP_FILEOPENFLAG_TRUNCATE |
- PP_FILEOPENFLAG_READ |
- PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- // Parallel write operations.
- TestCompletionCallback callback_1(instance_->pp_instance(), callback_type());
- int32_t write_offset_1 = 0;
- const char* buf_1 = "abc";
- int32_t size_1 = static_cast<int32_t>(strlen(buf_1));
- TestCompletionCallback callback_2(instance_->pp_instance(), callback_type());
- int32_t write_offset_2 = size_1;
- const char* buf_2 = "defghijkl";
- int32_t size_2 = static_cast<int32_t>(strlen(buf_2));
- int32_t rv_1 = PP_OK;
- int32_t rv_2 = PP_OK;
- while (size_1 >= 0 && size_2 >= 0 && size_1 + size_2 > 0) {
- if (size_1 > 0) {
- // Copy the buffer so we can erase it below.
- std::string str_1(buf_1);
- rv_1 = file_io.Write(
- write_offset_1, &str_1[0], static_cast<int32_t>(str_1.size()),
- callback_1.GetCallback());
- // Erase the buffer to test that async writes copy it.
- std::fill(str_1.begin(), str_1.end(), 0);
- }
- if (size_2 > 0) {
- // Copy the buffer so we can erase it below.
- std::string str_2(buf_2);
- rv_2 = file_io.Write(
- write_offset_2, &str_2[0], static_cast<int32_t>(str_2.size()),
- callback_2.GetCallback());
- // Erase the buffer to test that async writes copy it.
- std::fill(str_2.begin(), str_2.end(), 0);
- }
- if (size_1 > 0) {
- callback_1.WaitForResult(rv_1);
- CHECK_CALLBACK_BEHAVIOR(callback_1);
- ASSERT_TRUE(callback_1.result() > 0);
- write_offset_1 += callback_1.result();
- buf_1 += callback_1.result();
- size_1 -= callback_1.result();
- }
- if (size_2 > 0) {
- callback_2.WaitForResult(rv_2);
- CHECK_CALLBACK_BEHAVIOR(callback_2);
- ASSERT_TRUE(callback_2.result() > 0);
- write_offset_2 += callback_2.result();
- buf_2 += callback_2.result();
- size_2 -= callback_2.result();
- }
- }
- // If |size_1| or |size_2| is not 0, we have invoked wrong callback(s).
- ASSERT_EQ(0, size_1);
- ASSERT_EQ(0, size_2);
- // Check the file contents.
- std::string read_buffer;
- int32_t rv = ReadEntireFile(instance_->pp_instance(), &file_io, 0,
- &read_buffer, callback_type());
- ASSERT_EQ(PP_OK, rv);
- ASSERT_EQ(std::string("abcdefghijkl"), read_buffer);
- PASS();
- }
- std::string TestFileIO::TestNotAllowMixedReadWrite() {
- if (callback_type() == PP_BLOCKING) {
- // This test does not make sense for blocking callbacks.
- PASS();
- }
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
- pp::FileRef file_ref(file_system, "/file_not_allow_mixed_read_write");
- callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- pp::FileIO file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref,
- PP_FILEOPENFLAG_CREATE |
- PP_FILEOPENFLAG_TRUNCATE |
- PP_FILEOPENFLAG_READ |
- PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- TestCompletionCallback callback_1(instance_->pp_instance(), PP_REQUIRED);
- int32_t write_offset_1 = 0;
- const char* buf_1 = "mnopqrstuvw";
- int32_t rv_1 = file_io.Write(write_offset_1, buf_1,
- static_cast<int32_t>(strlen(buf_1)),
- callback_1.GetCallback());
- ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1);
- TestCompletionCallback callback_2(instance_->pp_instance(), callback_type());
- int32_t read_offset_2 = 4;
- char buf_2[3];
- callback_2.WaitForResult(file_io.Read(read_offset_2, buf_2, sizeof(buf_2),
- callback_2.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback_2);
- ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
- callback_1.WaitForResult(rv_1);
- CHECK_CALLBACK_BEHAVIOR(callback_1);
- // Cannot query while a write is pending.
- rv_1 = file_io.Write(write_offset_1, buf_1,
- static_cast<int32_t>(strlen(buf_1)),
- callback_1.GetCallback());
- ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1);
- PP_FileInfo info;
- callback_2.WaitForResult(file_io.Query(&info, callback_2.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback_2);
- ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
- callback_1.WaitForResult(rv_1);
- CHECK_CALLBACK_BEHAVIOR(callback_1);
- // Cannot touch while a write is pending.
- rv_1 = file_io.Write(write_offset_1, buf_1,
- static_cast<int32_t>(strlen(buf_1)),
- callback_1.GetCallback());
- ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1);
- callback_2.WaitForResult(file_io.Touch(1234.0, 5678.0,
- callback_2.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback_2);
- ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
- callback_1.WaitForResult(rv_1);
- CHECK_CALLBACK_BEHAVIOR(callback_1);
- // Cannot set length while a write is pending.
- rv_1 = file_io.Write(write_offset_1, buf_1,
- static_cast<int32_t>(strlen(buf_1)),
- callback_1.GetCallback());
- ASSERT_EQ(PP_OK_COMPLETIONPENDING, rv_1);
- callback_2.WaitForResult(file_io.SetLength(123, callback_2.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback_2);
- ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
- callback_1.WaitForResult(rv_1);
- CHECK_CALLBACK_BEHAVIOR(callback_1);
- PASS();
- }
- std::string TestFileIO::TestRequestOSFileHandle() {
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
- pp::FileRef file_ref(file_system, "/file_os_fd");
- callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
- ASSERT_EQ(PP_OK, callback.result());
- pp::FileIO_Private file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref,
- PP_FILEOPENFLAG_CREATE |
- PP_FILEOPENFLAG_TRUNCATE |
- PP_FILEOPENFLAG_READ |
- PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- ASSERT_EQ(PP_OK, callback.result());
- TestCompletionCallbackWithOutput<pp::PassFileHandle> output_callback(
- instance_->pp_instance(), callback_type());
- output_callback.WaitForResult(
- file_io.RequestOSFileHandle(output_callback.GetCallback()));
- PP_FileHandle handle = output_callback.output().Release();
- ASSERT_EQ(PP_OK, output_callback.result());
- if (handle == PP_kInvalidFileHandle)
- return "FileIO::RequestOSFileHandle() returned a bad file handle.";
- #if defined(PPAPI_OS_WIN)
- int fd = _open_osfhandle(reinterpret_cast<intptr_t>(handle),
- _O_RDWR | _O_BINARY);
- #else
- int fd = handle;
- #endif
- if (fd < 0)
- return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
- // Check write(2) for the native FD.
- const std::string msg = "foobar";
- ssize_t cnt = write(fd, msg.data(), static_cast<unsigned>(msg.size()));
- if (cnt < 0)
- return ReportError("write for native FD returned error", errno);
- if (cnt != static_cast<ssize_t>(msg.size()))
- return ReportError("write for native FD count mismatch", cnt);
- // Check lseek(2) for the native FD.
- off_t off = lseek(fd, 0, SEEK_CUR);
- if (off == static_cast<off_t>(-1))
- return ReportError("lseek for native FD returned error", errno);
- if (off != static_cast<off_t>(msg.size()))
- return ReportError("lseek for native FD offset mismatch", off);
- off = lseek(fd, 0, SEEK_SET);
- if (off == static_cast<off_t>(-1))
- return ReportError("lseek for native FD returned error", errno);
- if (off != 0)
- return ReportError("lseek for native FD offset mismatch", off);
- // Check read(2) for the native FD.
- std::string buf(msg.size(), '\0');
- cnt = read(fd, &buf[0], static_cast<unsigned>(msg.size()));
- if (cnt < 0)
- return ReportError("read for native FD returned error", errno);
- if (cnt != static_cast<ssize_t>(msg.size()))
- return ReportError("read for native FD count mismatch", cnt);
- if (msg != buf)
- return ReportMismatch("read for native FD", buf, msg);
- PASS();
- }
- // Calling RequestOSFileHandle with the FileIO that is opened with
- // PP_FILEOPENFLAG_EXCLUSIVE used to cause NaCl module to crash while loading.
- // This is a regression test for crbug.com/243241.
- std::string TestFileIO::TestRequestOSFileHandleWithOpenExclusive() {
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
- pp::FileRef file_ref(file_system, "/file_os_fd2");
- callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
- ASSERT_EQ(PP_OK, callback.result());
- // Open with PP_FILEOPENFLAG_CREATE and PP_FILEOPENFLAG_EXCLUSIVE will fail
- // if the file already exists. Delete it here to make sure it does not.
- callback.WaitForResult(file_ref.Delete(callback.GetCallback()));
- pp::FileIO_Private file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref,
- PP_FILEOPENFLAG_CREATE |
- PP_FILEOPENFLAG_READ |
- PP_FILEOPENFLAG_WRITE |
- PP_FILEOPENFLAG_EXCLUSIVE,
- callback.GetCallback()));
- ASSERT_EQ(PP_OK, callback.result());
- TestCompletionCallbackWithOutput<pp::PassFileHandle> output_callback(
- instance_->pp_instance(), callback_type());
- output_callback.WaitForResult(
- file_io.RequestOSFileHandle(output_callback.GetCallback()));
- PP_FileHandle handle = output_callback.output().Release();
- if (handle == PP_kInvalidFileHandle)
- return "FileIO::RequestOSFileHandle() returned a bad file handle.";
- ASSERT_EQ(PP_OK, output_callback.result());
- PASS();
- }
- std::string TestFileIO::TestMmap() {
- #if !defined(PPAPI_OS_WIN)
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
- pp::FileRef file_ref(file_system, "/file_os_fd");
- callback.WaitForResult(file_system.Open(1024, callback.GetCallback()));
- ASSERT_EQ(PP_OK, callback.result());
- pp::FileIO_Private file_io(instance_);
- callback.WaitForResult(file_io.Open(file_ref,
- PP_FILEOPENFLAG_CREATE |
- PP_FILEOPENFLAG_TRUNCATE |
- PP_FILEOPENFLAG_READ |
- PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- ASSERT_EQ(PP_OK, callback.result());
- TestCompletionCallbackWithOutput<pp::PassFileHandle> output_callback(
- instance_->pp_instance(), callback_type());
- output_callback.WaitForResult(
- file_io.RequestOSFileHandle(output_callback.GetCallback()));
- PP_FileHandle handle = output_callback.output().Release();
- ASSERT_EQ(PP_OK, output_callback.result());
- if (handle == PP_kInvalidFileHandle)
- return "FileIO::RequestOSFileHandle() returned a bad file handle.";
- int fd = handle;
- if (fd < 0)
- return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
- // Check write(2) for the native FD.
- const std::string msg = "foobar";
- ssize_t cnt = write(fd, msg.data(), msg.size());
- if (cnt < 0)
- return ReportError("write for native FD returned error", errno);
- if (cnt != static_cast<ssize_t>(msg.size()))
- return ReportError("write for native FD count mismatch", cnt);
- // BEGIN mmap(2) test with a file handle opened in READ-WRITE mode.
- // Check mmap(2) for read.
- {
- char* mapped = reinterpret_cast<char*>(
- mmap(NULL, msg.size(), PROT_READ, MAP_PRIVATE, fd, 0));
- if (mapped == MAP_FAILED)
- return ReportError("mmap(r) for native FD returned errno", errno);
- // Make sure the buffer is cleared.
- std::string buf = std::string(msg.size(), '\0');
- memcpy(&buf[0], mapped, msg.size());
- if (msg != buf)
- return ReportMismatch("mmap(r) for native FD", buf, msg);
- int r = munmap(mapped, msg.size());
- if (r < 0)
- return ReportError("munmap for native FD returned error", errno);
- }
- // Check mmap(2) for write with MAP_PRIVATE
- {
- char* mapped = reinterpret_cast<char*>(
- mmap(NULL, msg.size(), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0));
- if (mapped == MAP_FAILED)
- return ReportError("mmap(r) for native FD returned errno", errno);
- // Make sure the file is not polluted by writing to privage mmap.
- strncpy(mapped, "baz", 3);
- std::string read_buffer;
- ASSERT_TRUE(ReadEntireFileFromFileHandle(fd, &read_buffer));
- if (msg != read_buffer)
- return ReportMismatch("file content != msg", read_buffer, msg);
- int r = munmap(mapped, msg.size());
- if (r < 0)
- return ReportError("munmap for native FD returned error", errno);
- }
- // Check mmap(2) for write with MAP_SHARED.
- {
- char* mapped = reinterpret_cast<char*>(
- mmap(NULL, msg.size(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
- if (mapped == MAP_FAILED)
- return ReportError("mmap(w) for native FD returned errno", errno);
- // s/foo/baz/
- strncpy(mapped, "baz", 3);
- std::string read_buffer;
- ASSERT_TRUE(ReadEntireFileFromFileHandle(fd, &read_buffer));
- if (read_buffer != "bazbar")
- return ReportMismatch("file content != msg", read_buffer, "bazbar");
- int r = munmap(mapped, msg.size());
- if (r < 0)
- return ReportError("munmap for native FD returned error", errno);
- }
- // END mmap(2) test with a file handle opened in READ-WRITE mode.
- if (close(fd) < 0)
- return ReportError("close for native FD returned error", errno);
- // BEGIN mmap(2) test with a file handle opened in READONLY mode.
- file_io = pp::FileIO_Private(instance_);
- callback.WaitForResult(file_io.Open(file_ref,
- PP_FILEOPENFLAG_READ,
- callback.GetCallback()));
- ASSERT_EQ(PP_OK, callback.result());
- output_callback = TestCompletionCallbackWithOutput<pp::PassFileHandle>(
- instance_->pp_instance(), callback_type());
- output_callback.WaitForResult(
- file_io.RequestOSFileHandle(output_callback.GetCallback()));
- handle = output_callback.output().Release();
- ASSERT_EQ(PP_OK, output_callback.result());
- if (handle == PP_kInvalidFileHandle)
- return "FileIO::RequestOSFileHandle() returned a bad file handle.";
- fd = handle;
- if (fd < 0)
- return "FileIO::RequestOSFileHandle() returned a bad file descriptor.";
- const std::string msg2 = "bazbar";
- // Check mmap(2) for read.
- {
- char* mapped = reinterpret_cast<char*>(
- mmap(NULL, msg2.size(), PROT_READ, MAP_PRIVATE, fd, 0));
- if (mapped == MAP_FAILED)
- return ReportError("mmap(r) for native FD returned errno", errno);
- // Make sure the buffer is cleared.
- std::string buf = std::string(msg2.size(), '\0');
- memcpy(&buf[0], mapped, msg2.size());
- if (msg2 != buf)
- return ReportMismatch("mmap(r) for native FD", buf, msg2);
- int r = munmap(mapped, msg2.size());
- if (r < 0)
- return ReportError("munmap for native FD returned error", errno);
- }
- // Check mmap(2) for write with MAP_PRIVATE
- {
- char* mapped = reinterpret_cast<char*>(
- mmap(NULL, msg2.size(), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0));
- if (mapped == MAP_FAILED)
- return ReportError("mmap(r) for native FD returned errno", errno);
- // Make sure the file is not polluted by writing to privage mmap.
- strncpy(mapped, "baz", 3);
- std::string read_buffer;
- ASSERT_TRUE(ReadEntireFileFromFileHandle(fd, &read_buffer));
- if (msg2 != read_buffer)
- return ReportMismatch("file content != msg2", read_buffer, msg2);
- int r = munmap(mapped, msg2.size());
- if (r < 0)
- return ReportError("munmap for native FD returned error", errno);
- }
- // Check mmap(2) for write with MAP_SHARED.
- {
- char* mapped = reinterpret_cast<char*>(
- mmap(NULL, msg2.size(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
- if (mapped != MAP_FAILED)
- return ReportError("mmap(w) for native FD must fail when opened readonly",
- -1);
- }
- // END mmap(2) test with a file handle opened in READONLY mode.
- if (close(fd) < 0)
- return ReportError("close for native FD returned error", errno);
- #endif // !defined(PPAPI_OS_WIN)
- PASS();
- }
- std::string TestFileIO::MatchOpenExpectations(pp::FileSystem* file_system,
- int32_t open_flags,
- int32_t expectations) {
- std::string bad_argument =
- "TestFileIO::MatchOpenExpectations has invalid input arguments.";
- bool invalid_combination = !!(expectations & INVALID_FLAG_COMBINATION);
- if (invalid_combination) {
- if (expectations != INVALID_FLAG_COMBINATION)
- return bad_argument;
- } else {
- // Validate that one and only one of <some_expectation> and
- // DONT_<some_expectation> is specified.
- for (size_t remains = expectations, end = END_OF_OPEN_EXPECATION_PAIRS;
- end != 0; remains >>= 2, end >>= 2) {
- if (!!(remains & 1) == !!(remains & 2))
- return bad_argument;
- }
- }
- bool create_if_doesnt_exist = !!(expectations & CREATE_IF_DOESNT_EXIST);
- bool open_if_exists = !!(expectations & OPEN_IF_EXISTS);
- bool truncate_if_exists = !!(expectations & TRUNCATE_IF_EXISTS);
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- pp::FileRef existent_file_ref(
- *file_system, "/match_open_expectation_existent_non_empty_file");
- pp::FileRef nonexistent_file_ref(
- *file_system, "/match_open_expectation_nonexistent_file");
- // Setup files for test.
- {
- callback.WaitForResult(existent_file_ref.Delete(callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_TRUE(callback.result() == PP_OK ||
- callback.result() == PP_ERROR_FILENOTFOUND);
- callback.WaitForResult(nonexistent_file_ref.Delete(callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_TRUE(callback.result() == PP_OK ||
- callback.result() == PP_ERROR_FILENOTFOUND);
- pp::FileIO existent_file_io(instance_);
- callback.WaitForResult(existent_file_io.Open(
- existent_file_ref,
- PP_FILEOPENFLAG_CREATE | PP_FILEOPENFLAG_WRITE,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- int32_t rv = WriteEntireBuffer(instance_->pp_instance(), &existent_file_io,
- 0, "foobar", callback_type());
- ASSERT_EQ(PP_OK, rv);
- }
- pp::FileIO existent_file_io(instance_);
- callback.WaitForResult(existent_file_io.Open(existent_file_ref, open_flags,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- if ((invalid_combination && callback.result() == PP_OK) ||
- (!invalid_combination &&
- ((callback.result() == PP_OK) != open_if_exists))) {
- return ReportOpenError(open_flags);
- }
- if (!invalid_combination && open_if_exists) {
- PP_FileInfo info;
- callback.WaitForResult(existent_file_io.Query(&info,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- if (truncate_if_exists != (info.size == 0))
- return ReportOpenError(open_flags);
- }
- pp::FileIO nonexistent_file_io(instance_);
- callback.WaitForResult(nonexistent_file_io.Open(nonexistent_file_ref,
- open_flags,
- callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- if ((invalid_combination && callback.result() == PP_OK) ||
- (!invalid_combination &&
- ((callback.result() == PP_OK) != create_if_doesnt_exist))) {
- return ReportOpenError(open_flags);
- }
- return std::string();
- }
- // TODO(viettrungluu): Test Close(). crbug.com/69457
|