diff options
Diffstat (limited to 'base/files/file_util_proxy.cc')
-rw-r--r-- | base/files/file_util_proxy.cc | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/base/files/file_util_proxy.cc b/base/files/file_util_proxy.cc new file mode 100644 index 0000000..f18d52b --- /dev/null +++ b/base/files/file_util_proxy.cc @@ -0,0 +1,426 @@ +// 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 "base/files/file_util_proxy.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/file_util.h" +#include "base/location.h" +#include "base/message_loop_proxy.h" +#include "base/task_runner.h" +#include "base/task_runner_util.h" + +namespace base { + +namespace { + +void CallWithTranslatedParameter(const FileUtilProxy::StatusCallback& callback, + bool value) { + DCHECK(!callback.is_null()); + callback.Run(value ? PLATFORM_FILE_OK : PLATFORM_FILE_ERROR_FAILED); +} + +// Helper classes or routines for individual methods. +class CreateOrOpenHelper { + public: + CreateOrOpenHelper(TaskRunner* task_runner, + const FileUtilProxy::CloseTask& close_task) + : task_runner_(task_runner), + close_task_(close_task), + file_handle_(kInvalidPlatformFileValue), + created_(false), + error_(PLATFORM_FILE_OK) {} + + ~CreateOrOpenHelper() { + if (file_handle_ != kInvalidPlatformFileValue) { + task_runner_->PostTask( + FROM_HERE, + base::Bind(base::IgnoreResult(close_task_), file_handle_)); + } + } + + void RunWork(const FileUtilProxy::CreateOrOpenTask& task) { + error_ = task.Run(&file_handle_, &created_); + } + + void Reply(const FileUtilProxy::CreateOrOpenCallback& callback) { + DCHECK(!callback.is_null()); + callback.Run(error_, PassPlatformFile(&file_handle_), created_); + } + + private: + scoped_refptr<TaskRunner> task_runner_; + FileUtilProxy::CloseTask close_task_; + PlatformFile file_handle_; + bool created_; + PlatformFileError error_; + DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper); +}; + +class CreateTemporaryHelper { + public: + explicit CreateTemporaryHelper(TaskRunner* task_runner) + : task_runner_(task_runner), + file_handle_(kInvalidPlatformFileValue), + error_(PLATFORM_FILE_OK) {} + + ~CreateTemporaryHelper() { + if (file_handle_ != kInvalidPlatformFileValue) { + FileUtilProxy::Close(task_runner_, file_handle_, + FileUtilProxy::StatusCallback()); + } + } + + void RunWork(int additional_file_flags) { + // TODO(darin): file_util should have a variant of CreateTemporaryFile + // that returns a FilePath and a PlatformFile. + file_util::CreateTemporaryFile(&file_path_); + + int file_flags = + PLATFORM_FILE_WRITE | + PLATFORM_FILE_TEMPORARY | + PLATFORM_FILE_CREATE_ALWAYS | + additional_file_flags; + + error_ = PLATFORM_FILE_OK; + file_handle_ = CreatePlatformFile(file_path_, file_flags, NULL, &error_); + } + + void Reply(const FileUtilProxy::CreateTemporaryCallback& callback) { + DCHECK(!callback.is_null()); + callback.Run(error_, PassPlatformFile(&file_handle_), file_path_); + } + + private: + scoped_refptr<TaskRunner> task_runner_; + PlatformFile file_handle_; + FilePath file_path_; + PlatformFileError error_; + DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper); +}; + +class GetFileInfoHelper { + public: + GetFileInfoHelper() + : error_(PLATFORM_FILE_OK) {} + + void RunWorkForFilePath(const FilePath& file_path) { + if (!file_util::PathExists(file_path)) { + error_ = PLATFORM_FILE_ERROR_NOT_FOUND; + return; + } + if (!file_util::GetFileInfo(file_path, &file_info_)) + error_ = PLATFORM_FILE_ERROR_FAILED; + } + + void RunWorkForPlatformFile(PlatformFile file) { + if (!GetPlatformFileInfo(file, &file_info_)) + error_ = PLATFORM_FILE_ERROR_FAILED; + } + + void Reply(const FileUtilProxy::GetFileInfoCallback& callback) { + if (!callback.is_null()) { + callback.Run(error_, file_info_); + } + } + + private: + PlatformFileError error_; + PlatformFileInfo file_info_; + DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper); +}; + +class ReadHelper { + public: + explicit ReadHelper(int bytes_to_read) + : buffer_(new char[bytes_to_read]), + bytes_to_read_(bytes_to_read), + bytes_read_(0) {} + + void RunWork(PlatformFile file, int64 offset) { + bytes_read_ = ReadPlatformFile(file, offset, buffer_.get(), bytes_to_read_); + } + + void Reply(const FileUtilProxy::ReadCallback& callback) { + if (!callback.is_null()) { + PlatformFileError error = + (bytes_read_ < 0) ? PLATFORM_FILE_ERROR_FAILED : PLATFORM_FILE_OK; + 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: + WriteHelper(const char* buffer, int bytes_to_write) + : buffer_(new char[bytes_to_write]), + bytes_to_write_(bytes_to_write), + bytes_written_(0) { + memcpy(buffer_.get(), buffer, bytes_to_write); + } + + void RunWork(PlatformFile file, int64 offset) { + bytes_written_ = WritePlatformFile(file, offset, buffer_.get(), + bytes_to_write_); + } + + void Reply(const FileUtilProxy::WriteCallback& callback) { + if (!callback.is_null()) { + PlatformFileError error = + (bytes_written_ < 0) ? PLATFORM_FILE_ERROR_FAILED : PLATFORM_FILE_OK; + callback.Run(error, bytes_written_); + } + } + + private: + scoped_ptr<char[]> buffer_; + int bytes_to_write_; + int bytes_written_; + DISALLOW_COPY_AND_ASSIGN(WriteHelper); +}; + + +PlatformFileError CreateOrOpenAdapter( + const FilePath& file_path, int file_flags, + PlatformFile* file_handle, bool* created) { + DCHECK(file_handle); + DCHECK(created); + if (!file_util::DirectoryExists(file_path.DirName())) { + // If its parent does not exist, should return NOT_FOUND error. + return PLATFORM_FILE_ERROR_NOT_FOUND; + } + PlatformFileError error = PLATFORM_FILE_OK; + *file_handle = CreatePlatformFile(file_path, file_flags, created, &error); + return error; +} + +PlatformFileError CloseAdapter(PlatformFile file_handle) { + if (!ClosePlatformFile(file_handle)) { + return PLATFORM_FILE_ERROR_FAILED; + } + return PLATFORM_FILE_OK; +} + +PlatformFileError DeleteAdapter(const FilePath& file_path, bool recursive) { + if (!file_util::PathExists(file_path)) { + return PLATFORM_FILE_ERROR_NOT_FOUND; + } + if (!file_util::Delete(file_path, recursive)) { + if (!recursive && !file_util::IsDirectoryEmpty(file_path)) { + return PLATFORM_FILE_ERROR_NOT_EMPTY; + } + return PLATFORM_FILE_ERROR_FAILED; + } + return PLATFORM_FILE_OK; +} + +} // namespace + +// static +bool FileUtilProxy::CreateOrOpen( + TaskRunner* task_runner, + const FilePath& file_path, int file_flags, + const CreateOrOpenCallback& callback) { + return RelayCreateOrOpen( + task_runner, + base::Bind(&CreateOrOpenAdapter, file_path, file_flags), + base::Bind(&CloseAdapter), + callback); +} + +// static +bool FileUtilProxy::CreateTemporary( + TaskRunner* task_runner, + int additional_file_flags, + const CreateTemporaryCallback& callback) { + CreateTemporaryHelper* helper = new CreateTemporaryHelper(task_runner); + return task_runner->PostTaskAndReply( + FROM_HERE, + Bind(&CreateTemporaryHelper::RunWork, Unretained(helper), + additional_file_flags), + Bind(&CreateTemporaryHelper::Reply, Owned(helper), callback)); +} + +// static +bool FileUtilProxy::Close( + TaskRunner* task_runner, + base::PlatformFile file_handle, + const StatusCallback& callback) { + return RelayClose( + task_runner, + base::Bind(&CloseAdapter), + file_handle, callback); +} + +// Retrieves the information about a file. It is invalid to pass NULL for the +// callback. +bool FileUtilProxy::GetFileInfo( + TaskRunner* task_runner, + const FilePath& file_path, + const GetFileInfoCallback& callback) { + GetFileInfoHelper* helper = new GetFileInfoHelper; + return task_runner->PostTaskAndReply( + FROM_HERE, + Bind(&GetFileInfoHelper::RunWorkForFilePath, + Unretained(helper), file_path), + Bind(&GetFileInfoHelper::Reply, Owned(helper), callback)); +} + +// static +bool FileUtilProxy::GetFileInfoFromPlatformFile( + TaskRunner* task_runner, + PlatformFile file, + const GetFileInfoCallback& callback) { + GetFileInfoHelper* helper = new GetFileInfoHelper; + return task_runner->PostTaskAndReply( + FROM_HERE, + Bind(&GetFileInfoHelper::RunWorkForPlatformFile, + Unretained(helper), file), + Bind(&GetFileInfoHelper::Reply, Owned(helper), callback)); +} + +// static +bool FileUtilProxy::Delete(TaskRunner* task_runner, + const FilePath& file_path, + bool recursive, + const StatusCallback& callback) { + return base::PostTaskAndReplyWithResult( + task_runner, FROM_HERE, + Bind(&DeleteAdapter, file_path, recursive), + callback); +} + +// static +bool FileUtilProxy::RecursiveDelete( + TaskRunner* task_runner, + const FilePath& file_path, + const StatusCallback& callback) { + return base::PostTaskAndReplyWithResult( + task_runner, FROM_HERE, + Bind(&DeleteAdapter, file_path, true /* recursive */), + callback); +} + +// static +bool FileUtilProxy::Read( + TaskRunner* task_runner, + PlatformFile file, + int64 offset, + int bytes_to_read, + const ReadCallback& callback) { + if (bytes_to_read < 0) { + return false; + } + ReadHelper* helper = new ReadHelper(bytes_to_read); + return task_runner->PostTaskAndReply( + FROM_HERE, + Bind(&ReadHelper::RunWork, Unretained(helper), file, offset), + Bind(&ReadHelper::Reply, Owned(helper), callback)); +} + +// static +bool FileUtilProxy::Write( + TaskRunner* task_runner, + PlatformFile file, + int64 offset, + const char* buffer, + int bytes_to_write, + const WriteCallback& callback) { + if (bytes_to_write <= 0 || buffer == NULL) { + return false; + } + WriteHelper* helper = new WriteHelper(buffer, bytes_to_write); + return task_runner->PostTaskAndReply( + FROM_HERE, + Bind(&WriteHelper::RunWork, Unretained(helper), file, offset), + Bind(&WriteHelper::Reply, Owned(helper), callback)); +} + +// static +bool FileUtilProxy::Touch( + TaskRunner* task_runner, + PlatformFile file, + const Time& last_access_time, + const Time& last_modified_time, + const StatusCallback& callback) { + return base::PostTaskAndReplyWithResult( + task_runner, + FROM_HERE, + Bind(&TouchPlatformFile, file, + last_access_time, last_modified_time), + Bind(&CallWithTranslatedParameter, callback)); +} + +// static +bool FileUtilProxy::Touch( + TaskRunner* task_runner, + const FilePath& file_path, + const Time& last_access_time, + const Time& last_modified_time, + const StatusCallback& callback) { + return base::PostTaskAndReplyWithResult( + task_runner, + FROM_HERE, + Bind(&file_util::TouchFile, file_path, + last_access_time, last_modified_time), + Bind(&CallWithTranslatedParameter, callback)); +} + +// static +bool FileUtilProxy::Truncate( + TaskRunner* task_runner, + PlatformFile file, + int64 length, + const StatusCallback& callback) { + return base::PostTaskAndReplyWithResult( + task_runner, + FROM_HERE, + Bind(&TruncatePlatformFile, file, length), + Bind(&CallWithTranslatedParameter, callback)); +} + +// static +bool FileUtilProxy::Flush( + TaskRunner* task_runner, + PlatformFile file, + const StatusCallback& callback) { + return base::PostTaskAndReplyWithResult( + task_runner, + FROM_HERE, + Bind(&FlushPlatformFile, file), + Bind(&CallWithTranslatedParameter, callback)); +} + +// static +bool FileUtilProxy::RelayCreateOrOpen( + TaskRunner* task_runner, + const CreateOrOpenTask& open_task, + const CloseTask& close_task, + const CreateOrOpenCallback& callback) { + CreateOrOpenHelper* helper = new CreateOrOpenHelper( + task_runner, close_task); + return task_runner->PostTaskAndReply( + FROM_HERE, + Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), open_task), + Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback)); +} + +// static +bool FileUtilProxy::RelayClose( + TaskRunner* task_runner, + const CloseTask& close_task, + PlatformFile file_handle, + const StatusCallback& callback) { + return base::PostTaskAndReplyWithResult( + task_runner, FROM_HERE, Bind(close_task, file_handle), callback); +} + +} // namespace base |