diff options
Diffstat (limited to 'chromium/base/files/file_proxy.cc')
-rw-r--r-- | chromium/base/files/file_proxy.cc | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/chromium/base/files/file_proxy.cc b/chromium/base/files/file_proxy.cc new file mode 100644 index 00000000000..291b98d1117 --- /dev/null +++ b/chromium/base/files/file_proxy.cc @@ -0,0 +1,359 @@ +// Copyright 2014 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 "base/files/file_proxy.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/file_util.h" +#include "base/files/file.h" +#include "base/location.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/task_runner.h" +#include "base/task_runner_util.h" + +namespace { + +void FileDeleter(base::File file) { +} + +} // namespace + +namespace base { + +class FileHelper { + public: + FileHelper(FileProxy* proxy, File file) + : file_(file.Pass()), + error_(File::FILE_ERROR_FAILED), + task_runner_(proxy->task_runner()), + proxy_(AsWeakPtr(proxy)) { + } + + void PassFile() { + if (proxy_) + proxy_->SetFile(file_.Pass()); + else if (file_.IsValid()) + task_runner_->PostTask(FROM_HERE, Bind(&FileDeleter, Passed(&file_))); + } + + protected: + File file_; + File::Error error_; + + private: + scoped_refptr<TaskRunner> task_runner_; + WeakPtr<FileProxy> proxy_; + DISALLOW_COPY_AND_ASSIGN(FileHelper); +}; + +namespace { + +class GenericFileHelper : public FileHelper { + public: + GenericFileHelper(FileProxy* proxy, File file) + : FileHelper(proxy, file.Pass()) { + } + + void Close() { + file_.Close(); + error_ = File::FILE_OK; + } + + void SetTimes(Time last_access_time, Time last_modified_time) { + bool rv = file_.SetTimes(last_access_time, last_modified_time); + error_ = rv ? File::FILE_OK : File::FILE_ERROR_FAILED; + } + + void SetLength(int64 length) { + if (file_.SetLength(length)) + error_ = File::FILE_OK; + } + + void Flush() { + if (file_.Flush()) + error_ = File::FILE_OK; + } + + void Reply(const FileProxy::StatusCallback& callback) { + PassFile(); + if (!callback.is_null()) + callback.Run(error_); + } + + private: + DISALLOW_COPY_AND_ASSIGN(GenericFileHelper); +}; + +class CreateOrOpenHelper : public FileHelper { + public: + CreateOrOpenHelper(FileProxy* proxy, File file) + : FileHelper(proxy, file.Pass()) { + } + + void RunWork(const FilePath& file_path, int file_flags) { + file_.Initialize(file_path, file_flags); + error_ = file_.IsValid() ? File::FILE_OK : file_.error_details(); + } + + void Reply(const FileProxy::StatusCallback& callback) { + DCHECK(!callback.is_null()); + PassFile(); + callback.Run(error_); + } + + private: + DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper); +}; + +class CreateTemporaryHelper : public FileHelper { + public: + CreateTemporaryHelper(FileProxy* proxy, File file) + : FileHelper(proxy, file.Pass()) { + } + + void RunWork(uint32 additional_file_flags) { + // TODO(darin): file_util should have a variant of CreateTemporaryFile + // that returns a FilePath and a File. + if (!CreateTemporaryFile(&file_path_)) { + // TODO(davidben): base::CreateTemporaryFile should preserve the error + // code. + error_ = File::FILE_ERROR_FAILED; + return; + } + + uint32 file_flags = File::FLAG_WRITE | + File::FLAG_TEMPORARY | + File::FLAG_CREATE_ALWAYS | + additional_file_flags; + + file_.Initialize(file_path_, file_flags); + if (file_.IsValid()) { + error_ = File::FILE_OK; + } else { + error_ = file_.error_details(); + DeleteFile(file_path_, false); + file_path_.clear(); + } + } + + void Reply(const FileProxy::CreateTemporaryCallback& callback) { + DCHECK(!callback.is_null()); + PassFile(); + callback.Run(error_, file_path_); + } + + private: + FilePath file_path_; + DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper); +}; + +class GetInfoHelper : public FileHelper { + public: + GetInfoHelper(FileProxy* proxy, File file) + : FileHelper(proxy, file.Pass()) { + } + + void RunWork() { + if (file_.GetInfo(&file_info_)) + error_ = File::FILE_OK; + } + + void Reply(const FileProxy::GetFileInfoCallback& callback) { + PassFile(); + DCHECK(!callback.is_null()); + callback.Run(error_, file_info_); + } + + private: + File::Info file_info_; + DISALLOW_COPY_AND_ASSIGN(GetInfoHelper); +}; + +class ReadHelper : public FileHelper { + public: + ReadHelper(FileProxy* proxy, File file, int bytes_to_read) + : FileHelper(proxy, file.Pass()), + buffer_(new char[bytes_to_read]), + bytes_to_read_(bytes_to_read), + bytes_read_(0) { + } + + void RunWork(int64 offset) { + bytes_read_ = file_.Read(offset, buffer_.get(), bytes_to_read_); + error_ = (bytes_read_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK; + } + + void Reply(const FileProxy::ReadCallback& callback) { + PassFile(); + DCHECK(!callback.is_null()); + callback.Run(error_, buffer_.get(), bytes_read_); + } + + private: + scoped_ptr<char[]> buffer_; + int bytes_to_read_; + int bytes_read_; + DISALLOW_COPY_AND_ASSIGN(ReadHelper); +}; + +class WriteHelper : public FileHelper { + public: + WriteHelper(FileProxy* proxy, + File file, + const char* buffer, int bytes_to_write) + : FileHelper(proxy, file.Pass()), + buffer_(new char[bytes_to_write]), + bytes_to_write_(bytes_to_write), + bytes_written_(0) { + memcpy(buffer_.get(), buffer, bytes_to_write); + } + + void RunWork(int64 offset) { + bytes_written_ = file_.Write(offset, buffer_.get(), bytes_to_write_); + error_ = (bytes_written_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK; + } + + void Reply(const FileProxy::WriteCallback& callback) { + PassFile(); + if (!callback.is_null()) + callback.Run(error_, bytes_written_); + } + + private: + scoped_ptr<char[]> buffer_; + int bytes_to_write_; + int bytes_written_; + DISALLOW_COPY_AND_ASSIGN(WriteHelper); +}; + +} // namespace + +FileProxy::FileProxy(TaskRunner* task_runner) : task_runner_(task_runner) { +} + +FileProxy::~FileProxy() { + if (file_.IsValid()) + task_runner_->PostTask(FROM_HERE, Bind(&FileDeleter, Passed(&file_))); +} + +bool FileProxy::CreateOrOpen(const FilePath& file_path, + uint32 file_flags, + const StatusCallback& callback) { + DCHECK(!file_.IsValid()); + CreateOrOpenHelper* helper = new CreateOrOpenHelper(this, File()); + return task_runner_->PostTaskAndReply( + FROM_HERE, + Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), file_path, + file_flags), + Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback)); +} + +bool FileProxy::CreateTemporary(uint32 additional_file_flags, + const CreateTemporaryCallback& callback) { + DCHECK(!file_.IsValid()); + CreateTemporaryHelper* helper = new CreateTemporaryHelper(this, File()); + return task_runner_->PostTaskAndReply( + FROM_HERE, + Bind(&CreateTemporaryHelper::RunWork, Unretained(helper), + additional_file_flags), + Bind(&CreateTemporaryHelper::Reply, Owned(helper), callback)); +} + +bool FileProxy::IsValid() const { + return file_.IsValid(); +} + +void FileProxy::SetFile(File file) { + DCHECK(!file_.IsValid()); + file_ = file.Pass(); +} + +File FileProxy::TakeFile() { + return file_.Pass(); +} + +PlatformFile FileProxy::GetPlatformFile() const { + return file_.GetPlatformFile(); +} + +bool FileProxy::Close(const StatusCallback& callback) { + DCHECK(file_.IsValid()); + GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass()); + return task_runner_->PostTaskAndReply( + FROM_HERE, + Bind(&GenericFileHelper::Close, Unretained(helper)), + Bind(&GenericFileHelper::Reply, Owned(helper), callback)); +} + +bool FileProxy::GetInfo(const GetFileInfoCallback& callback) { + DCHECK(file_.IsValid()); + GetInfoHelper* helper = new GetInfoHelper(this, file_.Pass()); + return task_runner_->PostTaskAndReply( + FROM_HERE, + Bind(&GetInfoHelper::RunWork, Unretained(helper)), + Bind(&GetInfoHelper::Reply, Owned(helper), callback)); +} + +bool FileProxy::Read(int64 offset, + int bytes_to_read, + const ReadCallback& callback) { + DCHECK(file_.IsValid()); + if (bytes_to_read < 0) + return false; + + ReadHelper* helper = new ReadHelper(this, file_.Pass(), bytes_to_read); + return task_runner_->PostTaskAndReply( + FROM_HERE, + Bind(&ReadHelper::RunWork, Unretained(helper), offset), + Bind(&ReadHelper::Reply, Owned(helper), callback)); +} + +bool FileProxy::Write(int64 offset, + const char* buffer, + int bytes_to_write, + const WriteCallback& callback) { + DCHECK(file_.IsValid()); + if (bytes_to_write <= 0 || buffer == NULL) + return false; + + WriteHelper* helper = + new WriteHelper(this, file_.Pass(), buffer, bytes_to_write); + return task_runner_->PostTaskAndReply( + FROM_HERE, + Bind(&WriteHelper::RunWork, Unretained(helper), offset), + Bind(&WriteHelper::Reply, Owned(helper), callback)); +} + +bool FileProxy::SetTimes(Time last_access_time, + Time last_modified_time, + const StatusCallback& callback) { + DCHECK(file_.IsValid()); + GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass()); + return task_runner_->PostTaskAndReply( + FROM_HERE, + Bind(&GenericFileHelper::SetTimes, Unretained(helper), last_access_time, + last_modified_time), + Bind(&GenericFileHelper::Reply, Owned(helper), callback)); +} + +bool FileProxy::SetLength(int64 length, const StatusCallback& callback) { + DCHECK(file_.IsValid()); + GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass()); + return task_runner_->PostTaskAndReply( + FROM_HERE, + Bind(&GenericFileHelper::SetLength, Unretained(helper), length), + Bind(&GenericFileHelper::Reply, Owned(helper), callback)); +} + +bool FileProxy::Flush(const StatusCallback& callback) { + DCHECK(file_.IsValid()); + GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass()); + return task_runner_->PostTaskAndReply( + FROM_HERE, + Bind(&GenericFileHelper::Flush, Unretained(helper)), + Bind(&GenericFileHelper::Reply, Owned(helper), callback)); +} + +} // namespace base |