summaryrefslogtreecommitdiffstats
path: root/chromium/base/files/file_proxy.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/base/files/file_proxy.cc')
-rw-r--r--chromium/base/files/file_proxy.cc359
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