Commit 47a6da61 authored by gcasto's avatar gcasto Committed by Commit bot

Revert of mojo filesystem: Simplify full file reading/writing. (patchset #5...

Revert of mojo filesystem: Simplify full file reading/writing. (patchset #5 id:80001 of https://codereview.chromium.org/1634293002/ )

Reason for revert:
Broke the Windows build.

https://build.chromium.org/p/chromium.win/builders/Win%20x64%20GN/builds/10430/steps/compile/logs/stdio

FAILED: ninja -t msvc -e environment.x64 -- E:\b\build\goma/gomacc.exe "E:\b\depot_tools\win_toolchain\vs2013_files\VC\bin\amd64/cl.exe" /nologo /showIncludes /FC @obj/components/filesystem/lib/directory_impl.obj.rsp /c ../../components/filesystem/directory_impl.cc /Foobj/components/filesystem/lib/directory_impl.obj /Fdobj/components/filesystem/lib_cc.pdb
e:\b\build\slave\win_x64_gn\build\src\components\filesystem\directory_impl.cc(274) : error C2220: warning treated as error - no 'object' file generated
e:\b\build\slave\win_x64_gn\build\src\components\filesystem\directory_impl.cc(274) : warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data
ninja: build stopped: subcommand failed.

Original issue's description:
> mojo filesystem: Simplify full file reading/writing.
>
> One common pattern that's coming up multiple times is that we want to
> read or write the full contents of a file. The first attempt at an
> interface to that had was put on the File object.
>
> However, file seeking behaviour differs between platforms. Performing a
> seek on an empty file is safe on posix and errors on Windows. And when
> dealing with arbitrary File objects, we want to seek to the beginning
> just in case there was any previous usage on the File object.
>
> It was also cumbersome. The user was still responsible for opening the
> file and closing it once they were done with it. Putting these
> operations on Directory not only removes a bug, but also simplifies the
> interface.
>
> BUG=557405
>
> Committed: https://crrev.com/fd918ae590f61f145d75c800abb8eb050ca32b06
> Cr-Commit-Position: refs/heads/master@{#371845}

TBR=sky@chromium.org,erg@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=557405

Review URL: https://codereview.chromium.org/1643733002

Cr-Commit-Position: refs/heads/master@{#371863}
parent eee4f0ab
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "components/filesystem/file_impl.h" #include "components/filesystem/file_impl.h"
#include "components/filesystem/util.h" #include "components/filesystem/util.h"
#include "mojo/common/common_type_converters.h"
namespace filesystem { namespace filesystem {
...@@ -65,7 +64,7 @@ void DirectoryImpl::OpenFile(const mojo::String& raw_path, ...@@ -65,7 +64,7 @@ void DirectoryImpl::OpenFile(const mojo::String& raw_path,
#if defined(OS_WIN) #if defined(OS_WIN)
// On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory. // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
if (base::DirectoryExists(path)) if (DirectoryExists(path))
open_flags |= base::File::FLAG_BACKUP_SEMANTICS; open_flags |= base::File::FLAG_BACKUP_SEMANTICS;
#endif // OS_WIN #endif // OS_WIN
...@@ -216,68 +215,4 @@ void DirectoryImpl::Flush(const FlushCallback& callback) { ...@@ -216,68 +215,4 @@ void DirectoryImpl::Flush(const FlushCallback& callback) {
callback.Run(FileError::OK); callback.Run(FileError::OK);
} }
void DirectoryImpl::ReadEntireFile(const mojo::String& raw_path,
const ReadEntireFileCallback& callback) {
base::FilePath path;
FileError error = ValidatePath(raw_path, directory_path_, &path);
if (error != FileError::OK) {
callback.Run(error, mojo::Array<uint8_t>(0));
return;
}
if (base::DirectoryExists(path)) {
callback.Run(FileError::NOT_A_FILE, mojo::Array<uint8_t>(0));
return;
}
base::File base_file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!base_file.IsValid()) {
callback.Run(GetError(base_file), mojo::Array<uint8_t>(0));
return;
}
std::string contents;
const int kBufferSize = 1 << 16;
scoped_ptr<char[]> buf(new char[kBufferSize]);
int len;
while ((len = base_file.ReadAtCurrentPos(buf.get(), kBufferSize)) > 0)
contents.append(buf.get(), len);
callback.Run(FileError::OK, mojo::Array<uint8_t>::From(contents));
}
void DirectoryImpl::WriteFile(const mojo::String& raw_path,
mojo::Array<uint8_t> data,
const WriteFileCallback& callback) {
base::FilePath path;
FileError error = ValidatePath(raw_path, directory_path_, &path);
if (error != FileError::OK) {
callback.Run(error);
return;
}
if (base::DirectoryExists(path)) {
callback.Run(FileError::NOT_A_FILE);
return;
}
base::File base_file(path,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
if (!base_file.IsValid()) {
callback.Run(GetError(base_file));
return;
}
// If we're given empty data, we don't write and just truncate the file.
if (data.size()) {
if (base_file.Write(0, reinterpret_cast<char*>(&data.front()),
data.size()) == -1) {
callback.Run(GetError(base_file));
return;
}
}
callback.Run(FileError::OK);
}
} // namespace filesystem } // namespace filesystem
...@@ -55,11 +55,6 @@ class DirectoryImpl : public Directory { ...@@ -55,11 +55,6 @@ class DirectoryImpl : public Directory {
void IsWritable(const mojo::String& path, void IsWritable(const mojo::String& path,
const IsWritableCallback& callback) override; const IsWritableCallback& callback) override;
void Flush(const FlushCallback& callback) override; void Flush(const FlushCallback& callback) override;
void ReadEntireFile(const mojo::String& path,
const ReadEntireFileCallback& callback) override;
void WriteFile(const mojo::String& path,
mojo::Array<uint8_t> data,
const WriteFileCallback& callback) override;
private: private:
mojo::StrongBinding<Directory> binding_; mojo::StrongBinding<Directory> binding_;
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "base/macros.h" #include "base/macros.h"
#include "components/filesystem/files_test_base.h" #include "components/filesystem/files_test_base.h"
#include "mojo/common/common_type_converters.h"
#include "mojo/util/capture_util.h" #include "mojo/util/capture_util.h"
using mojo::Capture; using mojo::Capture;
...@@ -154,93 +153,6 @@ TEST_F(DirectoryImplTest, CantOpenDirectoriesAsFiles) { ...@@ -154,93 +153,6 @@ TEST_F(DirectoryImplTest, CantOpenDirectoriesAsFiles) {
} }
} }
TEST_F(DirectoryImplTest, WriteFileReadFile) {
DirectoryPtr directory;
GetTemporaryRoot(&directory);
FileError error;
std::string data("one two three");
{
directory->WriteFile("data", mojo::Array<uint8_t>::From(data),
Capture(&error));
ASSERT_TRUE(directory.WaitForIncomingResponse());
EXPECT_EQ(FileError::OK, error);
}
{
mojo::Array<uint8_t> file_contents;
directory->ReadEntireFile("data", Capture(&error, &file_contents));
ASSERT_TRUE(directory.WaitForIncomingResponse());
EXPECT_EQ(FileError::OK, error);
EXPECT_EQ(data, file_contents.To<std::string>());
}
}
TEST_F(DirectoryImplTest, ReadEmptyFileIsNotFoundError) {
DirectoryPtr directory;
GetTemporaryRoot(&directory);
FileError error;
{
mojo::Array<uint8_t> file_contents;
directory->ReadEntireFile("doesnt_exist", Capture(&error, &file_contents));
ASSERT_TRUE(directory.WaitForIncomingResponse());
EXPECT_EQ(FileError::NOT_FOUND, error);
}
}
TEST_F(DirectoryImplTest, CantReadEntireFileOnADirectory) {
DirectoryPtr directory;
GetTemporaryRoot(&directory);
FileError error;
// Create a directory
{
DirectoryPtr my_file_directory;
error = FileError::FAILED;
directory->OpenDirectory(
"my_dir", GetProxy(&my_file_directory),
kFlagRead | kFlagWrite | kFlagCreate,
Capture(&error));
ASSERT_TRUE(directory.WaitForIncomingResponse());
EXPECT_EQ(FileError::OK, error);
}
// Try to read it as a file
{
mojo::Array<uint8_t> file_contents;
directory->ReadEntireFile("my_dir", Capture(&error, &file_contents));
ASSERT_TRUE(directory.WaitForIncomingResponse());
EXPECT_EQ(FileError::NOT_A_FILE, error);
}
}
TEST_F(DirectoryImplTest, CantWriteFileOnADirectory) {
DirectoryPtr directory;
GetTemporaryRoot(&directory);
FileError error;
// Create a directory
{
DirectoryPtr my_file_directory;
error = FileError::FAILED;
directory->OpenDirectory(
"my_dir", GetProxy(&my_file_directory),
kFlagRead | kFlagWrite | kFlagCreate,
Capture(&error));
ASSERT_TRUE(directory.WaitForIncomingResponse());
EXPECT_EQ(FileError::OK, error);
}
{
std::string data("one two three");
directory->WriteFile("my_dir", mojo::Array<uint8_t>::From(data),
Capture(&error));
ASSERT_TRUE(directory.WaitForIncomingResponse());
EXPECT_EQ(FileError::NOT_A_FILE, error);
}
}
// TODO(vtl): Test delete flags. // TODO(vtl): Test delete flags.
......
...@@ -94,6 +94,28 @@ void FileImpl::Read(uint32_t num_bytes_to_read, ...@@ -94,6 +94,28 @@ void FileImpl::Read(uint32_t num_bytes_to_read,
callback.Run(FileError::OK, std::move(bytes_read)); callback.Run(FileError::OK, std::move(bytes_read));
} }
void FileImpl::ReadEntireFile(const ReadEntireFileCallback& callback) {
if (!file_.IsValid()) {
callback.Run(GetError(file_), mojo::Array<uint8_t>());
return;
}
// Seek to the front of the file.
if (file_.Seek(base::File::FROM_BEGIN, 0) == -1) {
callback.Run(FileError::FAILED, mojo::Array<uint8_t>());
return;
}
std::string contents;
const int kBufferSize = 1 << 16;
scoped_ptr<char[]> buf(new char[kBufferSize]);
size_t len;
while ((len = file_.ReadAtCurrentPos(buf.get(), kBufferSize)) > 0)
contents.append(buf.get(), len);
callback.Run(FileError::OK, mojo::Array<uint8_t>::From(contents));
}
// TODO(vtl): Move the implementation to a thread pool. // TODO(vtl): Move the implementation to a thread pool.
void FileImpl::Write(mojo::Array<uint8_t> bytes_to_write, void FileImpl::Write(mojo::Array<uint8_t> bytes_to_write,
int64_t offset, int64_t offset,
......
...@@ -34,6 +34,7 @@ class FileImpl : public File { ...@@ -34,6 +34,7 @@ class FileImpl : public File {
int64_t offset, int64_t offset,
Whence whence, Whence whence,
const ReadCallback& callback) override; const ReadCallback& callback) override;
void ReadEntireFile(const ReadEntireFileCallback& callback) override;
void Write(mojo::Array<uint8_t> bytes_to_write, void Write(mojo::Array<uint8_t> bytes_to_write,
int64_t offset, int64_t offset,
Whence whence, Whence whence,
......
...@@ -348,6 +348,17 @@ void FilesystemJsonPrefStore::OnOpenFilesystem(base::Closure callback, ...@@ -348,6 +348,17 @@ void FilesystemJsonPrefStore::OnOpenFilesystem(base::Closure callback,
} }
void FilesystemJsonPrefStore::OnTempFileWriteStart() { void FilesystemJsonPrefStore::OnTempFileWriteStart() {
// Open up a temporary file and truncate it.
directory_->OpenFile(
"tmp", GetProxy(&temporary_file_), kFlagWrite | kFlagCreate,
Bind(&FilesystemJsonPrefStore::OnTempFileOpened, AsWeakPtr()));
}
void FilesystemJsonPrefStore::OnTempFileOpened(FileError err) {
// TODO(erg): Error handling. The JsonPrefStore code assumes that writing the
// file can never fail.
CHECK_EQ(FileError::OK, err);
// Calculate what we want to write, and then write to the temporary file. // Calculate what we want to write, and then write to the temporary file.
pending_lossy_write_ = false; pending_lossy_write_ = false;
...@@ -359,29 +370,50 @@ void FilesystemJsonPrefStore::OnTempFileWriteStart() { ...@@ -359,29 +370,50 @@ void FilesystemJsonPrefStore::OnTempFileWriteStart() {
serializer.set_pretty_print(false); serializer.set_pretty_print(false);
serializer.Serialize(*prefs_); serializer.Serialize(*prefs_);
directory_->WriteFile( temporary_file_->Write(
"tmp", mojo::Array<uint8_t>::From(output), 0, Whence::FROM_CURRENT,
mojo::Array<uint8_t>::From(output),
Bind(&FilesystemJsonPrefStore::OnTempFileWrite, AsWeakPtr())); Bind(&FilesystemJsonPrefStore::OnTempFileWrite, AsWeakPtr()));
} }
void FilesystemJsonPrefStore::OnTempFileWrite(FileError err) { void FilesystemJsonPrefStore::OnTempFileWrite(FileError err,
uint32_t num_bytes_written) {
// TODO(erg): Error handling. The JsonPrefStore code assumes that writing the
// file can never fail.
CHECK_EQ(FileError::OK, err);
// Now that we've written the file, close it.
temporary_file_->Close(
Bind(&FilesystemJsonPrefStore::OnTempFileClosed, AsWeakPtr()));
}
void FilesystemJsonPrefStore::OnTempFileClosed(FileError err) {
// TODO(erg): Error handling. The JsonPrefStore code assumes that writing the // TODO(erg): Error handling. The JsonPrefStore code assumes that writing the
// file can never fail. // file can never fail.
CHECK_EQ(FileError::OK, err); CHECK_EQ(FileError::OK, err);
temporary_file_.reset();
directory_->Rename( directory_->Rename(
"tmp", path_, "tmp", path_,
Bind(&FilesystemJsonPrefStore::OnTempFileRenamed, AsWeakPtr())); Bind(&FilesystemJsonPrefStore::OnTempFileRenamed, AsWeakPtr()));
} }
void FilesystemJsonPrefStore::OnTempFileRenamed(FileError err) { void FilesystemJsonPrefStore::OnTempFileRenamed(FileError err) {}
}
void FilesystemJsonPrefStore::OnPreferencesReadStart() { void FilesystemJsonPrefStore::OnPreferencesReadStart() {
directory_->ReadEntireFile( // TODO(erg): implement me.
path_, directory_->OpenFile(
Bind(&FilesystemJsonPrefStore::OnPreferencesFileRead, AsWeakPtr())); path_, GetProxy(&preferences_file_), kFlagRead | kFlagOpen,
Bind(&FilesystemJsonPrefStore::OnPreferencesFileOpened, AsWeakPtr()));
}
void FilesystemJsonPrefStore::OnPreferencesFileOpened(FileError err) {
// TODO(erg): Error handling.
if (err == FileError::OK) {
preferences_file_->ReadEntireFile(
Bind(&FilesystemJsonPrefStore::OnPreferencesFileRead, AsWeakPtr()));
} else {
OnPreferencesFileRead(err, mojo::Array<uint8_t>());
}
} }
void FilesystemJsonPrefStore::OnPreferencesFileRead( void FilesystemJsonPrefStore::OnPreferencesFileRead(
...@@ -391,13 +423,12 @@ void FilesystemJsonPrefStore::OnPreferencesFileRead( ...@@ -391,13 +423,12 @@ void FilesystemJsonPrefStore::OnPreferencesFileRead(
new FilesystemJsonPrefStore::ReadResult); new FilesystemJsonPrefStore::ReadResult);
// TODO(erg): Needs even better error handling. // TODO(erg): Needs even better error handling.
switch (err) { switch (err) {
case FileError::FAILED:
case FileError::IN_USE: case FileError::IN_USE:
case FileError::ACCESS_DENIED: case FileError::ACCESS_DENIED: {
case FileError::NOT_A_FILE: {
read_only_ = true; read_only_ = true;
break; break;
} }
case FileError::FAILED:
case FileError::NOT_FOUND: { case FileError::NOT_FOUND: {
// If the file just doesn't exist, maybe this is the first run. Just // If the file just doesn't exist, maybe this is the first run. Just
// don't pass a value. // don't pass a value.
...@@ -414,6 +445,8 @@ void FilesystemJsonPrefStore::OnPreferencesFileRead( ...@@ -414,6 +445,8 @@ void FilesystemJsonPrefStore::OnPreferencesFileRead(
} }
} }
preferences_file_.reset();
OnFileRead(std::move(read_result)); OnFileRead(std::move(read_result));
} }
......
...@@ -140,11 +140,14 @@ class FilesystemJsonPrefStore ...@@ -140,11 +140,14 @@ class FilesystemJsonPrefStore
// Asynchronous implementation details of PerformWrite(). // Asynchronous implementation details of PerformWrite().
void OnTempFileWriteStart(); void OnTempFileWriteStart();
void OnTempFileWrite(FileError err); void OnTempFileOpened(FileError err);
void OnTempFileWrite(FileError err, uint32_t num_bytes_written);
void OnTempFileClosed(FileError err);
void OnTempFileRenamed(FileError err); void OnTempFileRenamed(FileError err);
// Asynchronous implementation details of ReadPrefsAsync(). // Asynchronous implementation details of ReadPrefsAsync().
void OnPreferencesReadStart(); void OnPreferencesReadStart();
void OnPreferencesFileOpened(FileError err);
void OnPreferencesFileRead(FileError err, mojo::Array<uint8_t> contents); void OnPreferencesFileRead(FileError err, mojo::Array<uint8_t> contents);
const std::string path_; const std::string path_;
...@@ -155,6 +158,9 @@ class FilesystemJsonPrefStore ...@@ -155,6 +158,9 @@ class FilesystemJsonPrefStore
// |filesystem. See OpenFilesystem(). // |filesystem. See OpenFilesystem().
DirectoryPtr directory_; DirectoryPtr directory_;
FilePtr preferences_file_;
FilePtr temporary_file_;
scoped_ptr<base::DictionaryValue> prefs_; scoped_ptr<base::DictionaryValue> prefs_;
bool read_only_; bool read_only_;
......
...@@ -52,12 +52,6 @@ interface Directory { ...@@ -52,12 +52,6 @@ interface Directory {
// fsync()/FlushFileBuffers(). // fsync()/FlushFileBuffers().
Flush() => (FileError error); Flush() => (FileError error);
// Reads the contents of an entire file.
ReadEntireFile(string path) => (FileError error, array<uint8> data);
// Writes |data| to |path|, overwriting the file if it already exists.
WriteFile(string path, array<uint8> data) => (FileError error);
// TODO(vtl): directory "streaming"? // TODO(vtl): directory "streaming"?
// TODO(vtl): "make root" (i.e., prevent cd-ing, etc., to parent); note that // TODO(vtl): "make root" (i.e., prevent cd-ing, etc., to parent); note that
// this would require a much more complicated implementation (e.g., it needs // this would require a much more complicated implementation (e.g., it needs
......
...@@ -27,6 +27,10 @@ interface File { ...@@ -27,6 +27,10 @@ interface File {
Read(uint32 num_bytes_to_read, int64 offset, Whence whence) Read(uint32 num_bytes_to_read, int64 offset, Whence whence)
=> (FileError error, array<uint8>? bytes_read); => (FileError error, array<uint8>? bytes_read);
// Returns the entire contents of the file as an array of bytes. The mojo
// equivalent of base::ReadFileToString().
ReadEntireFile() => (FileError error, array<uint8>? bytes_read);
// Writes |bytes_to_write| to the location specified by |offset|/|whence|. // Writes |bytes_to_write| to the location specified by |offset|/|whence|.
// TODO(vtl): Clarify behavior when |num_bytes_written| is less than the size // TODO(vtl): Clarify behavior when |num_bytes_written| is less than the size
// of |bytes_to_write|. // of |bytes_to_write|.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment