diff options
author | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-04 04:14:04 +0000 |
---|---|---|
committer | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-04 04:14:04 +0000 |
commit | d5233ef41f16c99bb80f74c23d9c8f3425945222 (patch) | |
tree | 7b5f4609a8ab000ea1012319a03be6b57f7a278d /webkit/fileapi | |
parent | 034714b8c7421fa955acc4ac03b281e935bbae1b (diff) | |
download | chromium_src-d5233ef41f16c99bb80f74c23d9c8f3425945222.zip chromium_src-d5233ef41f16c99bb80f74c23d9c8f3425945222.tar.gz chromium_src-d5233ef41f16c99bb80f74c23d9c8f3425945222.tar.bz2 |
Introduce FileSystemFileUtil and -Proxy to decorate base::file_util in webkit/fileapi.
BUG=74841
TEST=none
Review URL: http://codereview.chromium.org/6604020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76875 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/fileapi')
-rw-r--r-- | webkit/fileapi/file_system_context.h | 2 | ||||
-rw-r--r-- | webkit/fileapi/file_system_file_util.cc | 253 | ||||
-rw-r--r-- | webkit/fileapi/file_system_file_util.h | 135 | ||||
-rw-r--r-- | webkit/fileapi/file_system_file_util_proxy.cc | 527 | ||||
-rw-r--r-- | webkit/fileapi/file_system_file_util_proxy.h | 150 | ||||
-rw-r--r-- | webkit/fileapi/file_system_operation.cc | 73 | ||||
-rw-r--r-- | webkit/fileapi/file_system_operation.h | 4 | ||||
-rw-r--r-- | webkit/fileapi/file_system_operation_context.h | 30 | ||||
-rw-r--r-- | webkit/fileapi/webkit_fileapi.gypi | 4 |
9 files changed, 1150 insertions, 28 deletions
diff --git a/webkit/fileapi/file_system_context.h b/webkit/fileapi/file_system_context.h index f37c428..0da1d99 100644 --- a/webkit/fileapi/file_system_context.h +++ b/webkit/fileapi/file_system_context.h @@ -22,9 +22,9 @@ class SpecialStoragePolicy; namespace fileapi { +class FileSystemContext; class FileSystemPathManager; class FileSystemUsageTracker; -class FileSystemContext; struct DefaultContextDeleter; diff --git a/webkit/fileapi/file_system_file_util.cc b/webkit/fileapi/file_system_file_util.cc new file mode 100644 index 0000000..52f2c70 --- /dev/null +++ b/webkit/fileapi/file_system_file_util.cc @@ -0,0 +1,253 @@ +// Copyright (c) 2011 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 "webkit/fileapi/file_system_file_util.h" + +#include "base/file_util_proxy.h" + +// This also removes the destination directory if it's non-empty and all other +// checks are passed (so that the copy/move correctly overwrites the +// destination). +// TODO(ericu, dmikurube): This method won't work with obfuscation and quota +// since all (file_util::) operations should consider obfuscation and quota. +// We will need to virtualize all these calls. We should do that by making this +// method a non-virtual member of FileSystemFileUtil, but changing all of its +// file_util calls to be FileSystemFileUtil calls. That way when we override +// them for obfuscation or quota, it'll just work. +static base::PlatformFileError PerformCommonCheckAndPreparationForMoveAndCopy( + const FilePath& src_file_path, + const FilePath& dest_file_path) { + // Exits earlier if the source path does not exist. + if (!file_util::PathExists(src_file_path)) + return base::PLATFORM_FILE_ERROR_NOT_FOUND; + + // The parent of the |dest_file_path| does not exist. + if (!file_util::DirectoryExists(dest_file_path.DirName())) + return base::PLATFORM_FILE_ERROR_NOT_FOUND; + + // It is an error to try to copy/move an entry into its child. + if (src_file_path.IsParent(dest_file_path)) + return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; + + // Now it is ok to return if the |dest_file_path| does not exist. + if (!file_util::PathExists(dest_file_path)) + return base::PLATFORM_FILE_OK; + + // |src_file_path| exists and is a directory. + // |dest_file_path| exists and is a file. + bool src_is_directory = file_util::DirectoryExists(src_file_path); + bool dest_is_directory = file_util::DirectoryExists(dest_file_path); + if (src_is_directory && !dest_is_directory) + return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; + + // |src_file_path| exists and is a file. + // |dest_file_path| exists and is a directory. + if (!src_is_directory && dest_is_directory) + return base::PLATFORM_FILE_ERROR_NOT_A_FILE; + + // It is an error to copy/move an entry into the same path. + if (src_file_path.value() == dest_file_path.value()) + return base::PLATFORM_FILE_ERROR_EXISTS; + + if (dest_is_directory) { + // It is an error to copy/move an entry to a non-empty directory. + // Otherwise the copy/move attempt must overwrite the destination, but + // the file_util's Copy or Move method doesn't perform overwrite + // on all platforms, so we delete the destination directory here. + // TODO(kinuko): may be better to change the file_util::{Copy,Move}. + if (!file_util::Delete(dest_file_path, false /* recursive */)) { + if (!file_util::IsDirectoryEmpty(dest_file_path)) + return base::PLATFORM_FILE_ERROR_NOT_EMPTY; + return base::PLATFORM_FILE_ERROR_FAILED; + } + } + return base::PLATFORM_FILE_OK; +} + +namespace fileapi { + +FileSystemFileUtil* FileSystemFileUtil::GetInstance() { + return Singleton<FileSystemFileUtil>::get(); +} + +PlatformFileError FileSystemFileUtil::CreateOrOpen( + FileSystemOperationContext* unused, + const FilePath& file_path, int file_flags, + PlatformFile* file_handle, bool* created) { + if (!file_util::DirectoryExists(file_path.DirName())) { + // If its parent does not exist, should return NOT_FOUND error. + return base::PLATFORM_FILE_ERROR_NOT_FOUND; + } + PlatformFileError error_code = base::PLATFORM_FILE_OK; + *file_handle = base::CreatePlatformFile(file_path, file_flags, + created, &error_code); + return error_code; +} + +PlatformFileError FileSystemFileUtil::Close( + FileSystemOperationContext* unused, + PlatformFile file_handle) { + if (!base::ClosePlatformFile(file_handle)) + return base::PLATFORM_FILE_ERROR_FAILED; + return base::PLATFORM_FILE_OK; +} + +PlatformFileError FileSystemFileUtil::EnsureFileExists( + FileSystemOperationContext* unused, + const FilePath& file_path, + bool* created) { + if (!file_util::DirectoryExists(file_path.DirName())) + // If its parent does not exist, should return NOT_FOUND error. + return base::PLATFORM_FILE_ERROR_NOT_FOUND; + PlatformFileError error_code = base::PLATFORM_FILE_OK; + // Tries to create the |file_path| exclusively. This should fail + // with base::PLATFORM_FILE_ERROR_EXISTS if the path already exists. + PlatformFile handle = base::CreatePlatformFile( + file_path, + base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ, + created, &error_code); + if (error_code == base::PLATFORM_FILE_ERROR_EXISTS) { + // Make sure created_ is false. + *created = false; + error_code = base::PLATFORM_FILE_OK; + } + if (handle != base::kInvalidPlatformFileValue) + base::ClosePlatformFile(handle); + return error_code; +} + +PlatformFileError FileSystemFileUtil::GetFileInfo( + FileSystemOperationContext* unused, + const FilePath& file_path, + base::PlatformFileInfo* file_info) { + if (!file_util::PathExists(file_path)) + return base::PLATFORM_FILE_ERROR_NOT_FOUND; + if (!file_util::GetFileInfo(file_path, file_info)) + return base::PLATFORM_FILE_ERROR_FAILED; + return base::PLATFORM_FILE_OK; +} + +PlatformFileError FileSystemFileUtil::ReadDirectory( + FileSystemOperationContext* unused, + const FilePath& file_path, + std::vector<base::FileUtilProxy::Entry>* entries) { + // TODO(kkanetkar): Implement directory read in multiple chunks. + if (!file_util::DirectoryExists(file_path)) + return base::PLATFORM_FILE_ERROR_NOT_FOUND; + + file_util::FileEnumerator file_enum( + file_path, false, static_cast<file_util::FileEnumerator::FILE_TYPE>( + file_util::FileEnumerator::FILES | + file_util::FileEnumerator::DIRECTORIES)); + FilePath current; + while (!(current = file_enum.Next()).empty()) { + base::FileUtilProxy::Entry entry; + file_util::FileEnumerator::FindInfo info; + file_enum.GetFindInfo(&info); + entry.is_directory = file_enum.IsDirectory(info); + // This will just give the entry's name instead of entire path + // if we use current.value(). + entry.name = file_util::FileEnumerator::GetFilename(info).value(); + entries->push_back(entry); + } + return base::PLATFORM_FILE_OK; +} + +PlatformFileError FileSystemFileUtil::CreateDirectory( + FileSystemOperationContext* unused, + const FilePath& file_path, + bool exclusive) { + bool path_exists = file_util::PathExists(file_path); + if (!file_util::PathExists(file_path.DirName())) + return base::PLATFORM_FILE_ERROR_NOT_FOUND; + // If parent dir of file doesn't exist. + if (exclusive && path_exists) + return base::PLATFORM_FILE_ERROR_EXISTS; + // If file exists at the path. + if (path_exists && !file_util::DirectoryExists(file_path)) + return base::PLATFORM_FILE_ERROR_EXISTS; + if (!file_util::CreateDirectory(file_path)) + return base::PLATFORM_FILE_ERROR_FAILED; + return base::PLATFORM_FILE_OK; +} + +PlatformFileError FileSystemFileUtil::Copy( + FileSystemOperationContext* unused, + const FilePath& src_file_path, + const FilePath& dest_file_path) { + PlatformFileError error_code; + error_code = + PerformCommonCheckAndPreparationForMoveAndCopy( + src_file_path, dest_file_path); + if (error_code != base::PLATFORM_FILE_OK) + return error_code; + if (!file_util::CopyDirectory(src_file_path, dest_file_path, + true /* recursive */)) + return base::PLATFORM_FILE_ERROR_FAILED; + return base::PLATFORM_FILE_OK; +} + +PlatformFileError FileSystemFileUtil::Move( + FileSystemOperationContext* unused, + const FilePath& src_file_path, + const FilePath& dest_file_path) { + PlatformFileError error_code; + error_code = + PerformCommonCheckAndPreparationForMoveAndCopy( + src_file_path, dest_file_path); + if (error_code != base::PLATFORM_FILE_OK) + return error_code; + if (!file_util::Move(src_file_path, dest_file_path)) + return base::PLATFORM_FILE_ERROR_FAILED; + return base::PLATFORM_FILE_OK; +} + +PlatformFileError FileSystemFileUtil::Delete( + FileSystemOperationContext* unused, + const FilePath& file_path, + bool recursive) { + if (!file_util::PathExists(file_path)) { + return base::PLATFORM_FILE_ERROR_NOT_FOUND; + } + if (!file_util::Delete(file_path, recursive)) { + if (!recursive && !file_util::IsDirectoryEmpty(file_path)) { + return base::PLATFORM_FILE_ERROR_NOT_EMPTY; + } + return base::PLATFORM_FILE_ERROR_FAILED; + } + return base::PLATFORM_FILE_OK; +} + +PlatformFileError FileSystemFileUtil::Touch( + FileSystemOperationContext* unused, + const FilePath& file_path, + const base::Time& last_access_time, + const base::Time& last_modified_time) { + if (!file_util::TouchFile( + file_path, last_access_time, last_modified_time)) + return base::PLATFORM_FILE_ERROR_FAILED; + return base::PLATFORM_FILE_OK; +} + +PlatformFileError FileSystemFileUtil::Truncate( + FileSystemOperationContext* unused, + const FilePath& file_path, + int64 length) { + PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED); + PlatformFile file = + base::CreatePlatformFile( + file_path, + base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, + NULL, + &error_code); + if (error_code != base::PLATFORM_FILE_OK) { + return error_code; + } + if (!base::TruncatePlatformFile(file, length)) + error_code = base::PLATFORM_FILE_ERROR_FAILED; + base::ClosePlatformFile(file); + return error_code; +} + +} // namespace fileapi diff --git a/webkit/fileapi/file_system_file_util.h b/webkit/fileapi/file_system_file_util.h new file mode 100644 index 0000000..433c0bc --- /dev/null +++ b/webkit/fileapi/file_system_file_util.h @@ -0,0 +1,135 @@ +// Copyright (c) 2011 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. + +#ifndef WEBKIT_FILEAPI_FILE_SYSTEM_FILE_UTIL_H_ +#define WEBKIT_FILEAPI_FILE_SYSTEM_FILE_UTIL_H_ + +#include "base/callback.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/file_util_proxy.h" +#include "base/platform_file.h" +#include "base/ref_counted.h" +#include "base/singleton.h" +#include "base/tracked_objects.h" + +namespace base { +struct PlatformFileInfo; +class MessageLoopProxy; +class Time; +} + +namespace fileapi { + +using base::PlatformFile; +using base::PlatformFileError; + +class FileSystemOperationContext; + +// A large part of this implementation is taken from base::FileUtilProxy. +// TODO(dmikurube, kinuko): Clean up base::FileUtilProxy to factor out common +// routines. It includes dropping FileAPI-specific routines from FileUtilProxy. +class FileSystemFileUtil { + public: + static FileSystemFileUtil* GetInstance(); + + // Creates or opens a file with the given flags. It is invalid to pass NULL + // for the callback. + // If PLATFORM_FILE_CREATE is set in |file_flags| it always tries to create + // a new file at the given |file_path| and calls back with + // PLATFORM_FILE_ERROR_FILE_EXISTS if the |file_path| already exists. + virtual PlatformFileError CreateOrOpen( + FileSystemOperationContext* context, + const FilePath& file_path, + int file_flags, + PlatformFile* file_handle, + bool* created); + + // Close the given file handle. + virtual PlatformFileError Close( + FileSystemOperationContext* context, + PlatformFile); + + // Ensures that the given |file_path| exist. This creates a empty new file + // at |file_path| if the |file_path| does not exist. + // If a new file han not existed and is created at the |file_path|, + // |created| of the callback argument is set true and |error code| + // is set PLATFORM_FILE_OK. + // If the file already exists, |created| is set false and |error code| + // is set PLATFORM_FILE_OK. + // If the file hasn't existed but it couldn't be created for some other + // reasons, |created| is set false and |error code| indicates the error. + virtual PlatformFileError EnsureFileExists( + FileSystemOperationContext* context, + const FilePath& file_path, bool* created); + + // Retrieves the information about a file. It is invalid to pass NULL for the + // callback. + virtual PlatformFileError GetFileInfo( + FileSystemOperationContext* context, + const FilePath& file_, base::PlatformFileInfo* file_info); + + virtual PlatformFileError ReadDirectory( + FileSystemOperationContext* context, + const FilePath& file_path, + std::vector<base::FileUtilProxy::Entry>* entries); + + // Creates directory at given path. It's an error to create + // if |exclusive| is true and dir already exists. + virtual PlatformFileError CreateDirectory( + FileSystemOperationContext* context, + const FilePath& file_path, + bool exclusive); + + // Copies a file or a directory from |src_file_path| to |dest_file_path| + // Error cases: + // If destination file doesn't exist or destination's parent + // doesn't exists. + // If source dir exists but destination path is an existing file. + // If source file exists but destination path is an existing directory. + // If source is a parent of destination. + // If source doesn't exists. + virtual PlatformFileError Copy( + FileSystemOperationContext* context, + const FilePath& src_file_path, + const FilePath& dest_file_path); + + // Moves a file or a directory from src_file_path to dest_file_path. + // Error cases are similar to Copy method's error cases. + virtual PlatformFileError Move( + FileSystemOperationContext* context, + const FilePath& src_file_path, + const FilePath& dest_file_path); + + // Deletes a file or a directory. + // It is an error to delete a non-empty directory with recursive=false. + virtual PlatformFileError Delete( + FileSystemOperationContext* context, + const FilePath& file_path, + bool recursive); + + // Touches a file. The callback can be NULL. + virtual PlatformFileError Touch( + FileSystemOperationContext* context, + const FilePath& file_path, + const base::Time& last_access_time, + const base::Time& last_modified_time); + + // Truncates a file to the given length. If |length| is greater than the + // current length of the file, the file will be extended with zeroes. + // The callback can be NULL. + virtual PlatformFileError Truncate( + FileSystemOperationContext* context, + const FilePath& path, + int64 length); + + protected: + FileSystemFileUtil() { } + friend struct DefaultSingletonTraits<FileSystemFileUtil>; + DISALLOW_COPY_AND_ASSIGN(FileSystemFileUtil); +}; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_FILE_SYSTEM_FILE_UTIL_H_ diff --git a/webkit/fileapi/file_system_file_util_proxy.cc b/webkit/fileapi/file_system_file_util_proxy.cc new file mode 100644 index 0000000..3b14e16 --- /dev/null +++ b/webkit/fileapi/file_system_file_util_proxy.cc @@ -0,0 +1,527 @@ +// Copyright (c) 2010 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 "webkit/fileapi/file_system_file_util_proxy.h" + +#include "base/message_loop_proxy.h" +#include "webkit/fileapi/file_system_context.h" +#include "webkit/fileapi/file_system_file_util.h" +#include "webkit/fileapi/file_system_operation_context.h" + +namespace { + +class MessageLoopRelay + : public base::RefCountedThreadSafe<MessageLoopRelay> { + public: + // FileSystemOperationContext is passed by value from the IO thread to the + // File thread. + explicit MessageLoopRelay(const fileapi::FileSystemOperationContext& context) + : origin_message_loop_proxy_( + base::MessageLoopProxy::CreateForCurrentThread()), + error_code_(base::PLATFORM_FILE_OK), + context_(context) { + } + + bool Start(scoped_refptr<base::MessageLoopProxy> message_loop_proxy, + const tracked_objects::Location& from_here) { + return message_loop_proxy->PostTask( + from_here, + NewRunnableMethod(this, &MessageLoopRelay::ProcessOnTargetThread)); + } + + protected: + friend class base::RefCountedThreadSafe<MessageLoopRelay>; + virtual ~MessageLoopRelay() {} + + // Called to perform work on the FILE thread. + virtual void RunWork() = 0; + + // Called to notify the callback on the origin thread. + virtual void RunCallback() = 0; + + void set_error_code(base::PlatformFileError error_code) { + error_code_ = error_code; + } + + base::PlatformFileError error_code() const { + return error_code_; + } + + fileapi::FileSystemOperationContext* context() { + return &context_; + } + + fileapi::FileSystemFileUtil* file_system_file_util() const { + return context_.file_system_file_util(); + } + + private: + void ProcessOnTargetThread() { + RunWork(); + origin_message_loop_proxy_->PostTask( + FROM_HERE, + NewRunnableMethod(this, &MessageLoopRelay::RunCallback)); + } + + scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_; + base::PlatformFileError error_code_; + fileapi::FileSystemOperationContext context_; + fileapi::FileSystemFileUtil* file_system_file_util_; +}; + +class RelayCreateOrOpen : public MessageLoopRelay { + public: + RelayCreateOrOpen( + const fileapi::FileSystemOperationContext& context, + scoped_refptr<base::MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + int file_flags, + fileapi::FileSystemFileUtilProxy::CreateOrOpenCallback* callback) + : MessageLoopRelay(context), + message_loop_proxy_(message_loop_proxy), + file_path_(file_path), + file_flags_(file_flags), + callback_(callback), + file_handle_(base::kInvalidPlatformFileValue), + created_(false) { + DCHECK(callback); + } + + protected: + virtual ~RelayCreateOrOpen() { + if (file_handle_ != base::kInvalidPlatformFileValue) + fileapi::FileSystemFileUtilProxy::Close(*context(), + message_loop_proxy_, file_handle_, NULL); + } + + virtual void RunWork() { + set_error_code( + file_system_file_util()->CreateOrOpen( + context(), file_path_, file_flags_, &file_handle_, &created_)); + } + + virtual void RunCallback() { + callback_->Run(error_code(), base::PassPlatformFile(&file_handle_), + created_); + delete callback_; + } + + private: + scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; + FilePath file_path_; + int file_flags_; + fileapi::FileSystemFileUtilProxy::CreateOrOpenCallback* callback_; + base::PlatformFile file_handle_; + bool created_; +}; + +class RelayWithStatusCallback : public MessageLoopRelay { + public: + RelayWithStatusCallback( + const fileapi::FileSystemOperationContext& context, + fileapi::FileSystemFileUtilProxy::StatusCallback* callback) + : MessageLoopRelay(context), + callback_(callback) { + // It is OK for callback to be NULL. + } + + protected: + virtual void RunCallback() { + // The caller may not have been interested in the result. + if (callback_) { + callback_->Run(error_code()); + delete callback_; + } + } + + private: + fileapi::FileSystemFileUtilProxy::StatusCallback* callback_; +}; + +class RelayClose : public RelayWithStatusCallback { + public: + RelayClose(const fileapi::FileSystemOperationContext& context, + base::PlatformFile file_handle, + fileapi::FileSystemFileUtilProxy::StatusCallback* callback) + : RelayWithStatusCallback(context, callback), + file_handle_(file_handle) { + } + + protected: + virtual void RunWork() { + set_error_code( + file_system_file_util()->Close(context(), file_handle_)); + } + + private: + base::PlatformFile file_handle_; +}; + +class RelayEnsureFileExists : public MessageLoopRelay { + public: + RelayEnsureFileExists( + const fileapi::FileSystemOperationContext& context, + scoped_refptr<base::MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + fileapi::FileSystemFileUtilProxy::EnsureFileExistsCallback* callback) + : MessageLoopRelay(context), + message_loop_proxy_(message_loop_proxy), + file_path_(file_path), + callback_(callback), + created_(false) { + DCHECK(callback); + } + + protected: + virtual void RunWork() { + set_error_code( + file_system_file_util()->EnsureFileExists( + context(), file_path_, &created_)); + } + + virtual void RunCallback() { + callback_->Run(error_code(), created_); + delete callback_; + } + + private: + scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; + FilePath file_path_; + fileapi::FileSystemFileUtilProxy::EnsureFileExistsCallback* callback_; + bool created_; +}; + +class RelayGetFileInfo : public MessageLoopRelay { + public: + RelayGetFileInfo( + const fileapi::FileSystemOperationContext& context, + const FilePath& file_path, + fileapi::FileSystemFileUtilProxy::GetFileInfoCallback* callback) + : MessageLoopRelay(context), + callback_(callback), + file_path_(file_path) { + DCHECK(callback); + } + + protected: + virtual void RunWork() { + set_error_code( + file_system_file_util()->GetFileInfo( + context(), file_path_, &file_info_)); + } + + virtual void RunCallback() { + callback_->Run(error_code(), file_info_); + delete callback_; + } + + private: + fileapi::FileSystemFileUtilProxy::GetFileInfoCallback* callback_; + FilePath file_path_; + base::PlatformFileInfo file_info_; +}; + +class RelayReadDirectory : public MessageLoopRelay { + public: + RelayReadDirectory( + const fileapi::FileSystemOperationContext& context, + const FilePath& file_path, + fileapi::FileSystemFileUtilProxy::ReadDirectoryCallback* callback) + : MessageLoopRelay(context), + callback_(callback), file_path_(file_path) { + DCHECK(callback); + } + + protected: + virtual void RunWork() { + // TODO(kkanetkar): Implement directory read in multiple chunks. + set_error_code( + file_system_file_util()->ReadDirectory( + context(), file_path_, &entries_)); + } + + virtual void RunCallback() { + callback_->Run(error_code(), entries_); + delete callback_; + } + + private: + fileapi::FileSystemFileUtilProxy::ReadDirectoryCallback* callback_; + FilePath file_path_; + std::vector<base::FileUtilProxy::Entry> entries_; +}; + +class RelayCreateDirectory : public RelayWithStatusCallback { + public: + RelayCreateDirectory( + const fileapi::FileSystemOperationContext& context, + const FilePath& file_path, + bool exclusive, + fileapi::FileSystemFileUtilProxy::StatusCallback* callback) + : RelayWithStatusCallback(context, callback), + file_path_(file_path), + exclusive_(exclusive) { + } + + protected: + virtual void RunWork() { + set_error_code( + file_system_file_util()->CreateDirectory( + context(), file_path_, exclusive_)); + } + + private: + FilePath file_path_; + bool exclusive_; +}; + +class RelayCopy : public RelayWithStatusCallback { + public: + RelayCopy(const fileapi::FileSystemOperationContext& context, + const FilePath& src_file_path, + const FilePath& dest_file_path, + fileapi::FileSystemFileUtilProxy::StatusCallback* callback) + : RelayWithStatusCallback(context, callback), + src_file_path_(src_file_path), + dest_file_path_(dest_file_path) { + } + + protected: + virtual void RunWork() { + set_error_code( + file_system_file_util()->Copy( + context(), src_file_path_, dest_file_path_)); + } + + private: + FilePath src_file_path_; + FilePath dest_file_path_; +}; + +class RelayMove : public RelayWithStatusCallback { + public: + RelayMove(const fileapi::FileSystemOperationContext& context, + const FilePath& src_file_path, + const FilePath& dest_file_path, + fileapi::FileSystemFileUtilProxy::StatusCallback* callback) + : RelayWithStatusCallback(context, callback), + src_file_path_(src_file_path), + dest_file_path_(dest_file_path) { + } + + protected: + virtual void RunWork() { + set_error_code( + file_system_file_util()->Move( + context(), src_file_path_, dest_file_path_)); + } + + private: + FilePath src_file_path_; + FilePath dest_file_path_; +}; + +class RelayDelete : public RelayWithStatusCallback { + public: + RelayDelete(const fileapi::FileSystemOperationContext& context, + const FilePath& file_path, + bool recursive, + fileapi::FileSystemFileUtilProxy::StatusCallback* callback) + : RelayWithStatusCallback(context, callback), + file_path_(file_path), + recursive_(recursive) { + } + + protected: + virtual void RunWork() { + set_error_code( + file_system_file_util()->Delete( + context(), file_path_, recursive_)); + } + + private: + FilePath file_path_; + bool recursive_; +}; + +class RelayTouchFilePath : public RelayWithStatusCallback { + public: + RelayTouchFilePath(const fileapi::FileSystemOperationContext& context, + const FilePath& file_path, + const base::Time& last_access_time, + const base::Time& last_modified_time, + fileapi::FileSystemFileUtilProxy::StatusCallback* callback) + : RelayWithStatusCallback(context, callback), + file_path_(file_path), + last_access_time_(last_access_time), + last_modified_time_(last_modified_time) { + } + + protected: + virtual void RunWork() { + set_error_code( + file_system_file_util()->Touch( + context(), file_path_, last_access_time_, last_modified_time_)); + } + + private: + FilePath file_path_; + base::Time last_access_time_; + base::Time last_modified_time_; +}; + +class RelayTruncate : public RelayWithStatusCallback { + public: + RelayTruncate(const fileapi::FileSystemOperationContext& context, + const FilePath& file_path, + int64 length, + fileapi::FileSystemFileUtilProxy::StatusCallback* callback) + : RelayWithStatusCallback(context, callback), + file_path_(file_path), + length_(length) { + } + + protected: + virtual void RunWork() { + set_error_code( + file_system_file_util()->Truncate(context(), file_path_, length_)); + } + + private: + FilePath file_path_; + int64 length_; +}; + +bool Start(const tracked_objects::Location& from_here, + scoped_refptr<base::MessageLoopProxy> message_loop_proxy, + scoped_refptr<MessageLoopRelay> relay) { + return relay->Start(message_loop_proxy, from_here); +} + +} // namespace + +namespace fileapi { + +// static +bool FileSystemFileUtilProxy::CreateOrOpen( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, int file_flags, + CreateOrOpenCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, new RelayCreateOrOpen(context, + message_loop_proxy, file_path, file_flags, callback)); +} + +// static +bool FileSystemFileUtilProxy::Close( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + base::PlatformFile file_handle, + StatusCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, + new RelayClose(context, file_handle, callback)); +} + +// static +bool FileSystemFileUtilProxy::EnsureFileExists( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + EnsureFileExistsCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, new RelayEnsureFileExists( + context, message_loop_proxy, file_path, callback)); +} + +// Retrieves the information about a file. It is invalid to pass NULL for the +// callback. +bool FileSystemFileUtilProxy::GetFileInfo( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + GetFileInfoCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, new RelayGetFileInfo(context, + file_path, callback)); +} + +// static +bool FileSystemFileUtilProxy::ReadDirectory( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + ReadDirectoryCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, new RelayReadDirectory(context, + file_path, callback)); +} + +// static +bool FileSystemFileUtilProxy::CreateDirectory( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + bool exclusive, + StatusCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, new RelayCreateDirectory( + context, file_path, exclusive, callback)); +} + +// static +bool FileSystemFileUtilProxy::Copy( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& src_file_path, + const FilePath& dest_file_path, + StatusCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, + new RelayCopy(context, src_file_path, dest_file_path, + callback)); +} + +// static +bool FileSystemFileUtilProxy::Move( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& src_file_path, + const FilePath& dest_file_path, + StatusCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, + new RelayMove(context, src_file_path, dest_file_path, + callback)); +} + +// static +bool FileSystemFileUtilProxy::Delete( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + bool recursive, + StatusCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, + new RelayDelete(context, file_path, recursive, callback)); +} + +// static +bool FileSystemFileUtilProxy::Touch( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + const base::Time& last_access_time, + const base::Time& last_modified_time, + StatusCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, + new RelayTouchFilePath(context, file_path, last_access_time, + last_modified_time, callback)); +} + +// static +bool FileSystemFileUtilProxy::Truncate( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& path, + int64 length, + StatusCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, + new RelayTruncate(context, path, length, callback)); +} + +} // namespace fileapi diff --git a/webkit/fileapi/file_system_file_util_proxy.h b/webkit/fileapi/file_system_file_util_proxy.h new file mode 100644 index 0000000..0f10507 --- /dev/null +++ b/webkit/fileapi/file_system_file_util_proxy.h @@ -0,0 +1,150 @@ +// Copyright (c) 2011 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. + +#ifndef WEBKIT_FILEAPI_FILE_SYSTEM_FILE_UTIL_PROXY_H_ +#define WEBKIT_FILEAPI_FILE_SYSTEM_FILE_UTIL_PROXY_H_ + +#include <vector> + +#include "base/callback.h" +#include "base/file_path.h" +#include "base/file_util_proxy.h" +#include "base/platform_file.h" +#include "base/ref_counted.h" +#include "base/tracked_objects.h" + +namespace base { +class MessageLoopProxy; +class Time; +} + +namespace fileapi { + +class FileSystemOperationContext; + +using base::MessageLoopProxy; +using base::PlatformFile; + +// This class provides asynchronous access to common file routines for the +// FileSystem API. +class FileSystemFileUtilProxy { + public: + typedef base::FileUtilProxy::StatusCallback StatusCallback; + typedef base::FileUtilProxy::CreateOrOpenCallback CreateOrOpenCallback; + typedef base::FileUtilProxy::EnsureFileExistsCallback + EnsureFileExistsCallback; + typedef base::FileUtilProxy::GetFileInfoCallback GetFileInfoCallback; + typedef base::FileUtilProxy::ReadDirectoryCallback ReadDirectoryCallback; + + // Creates or opens a file with the given flags. It is invalid to pass NULL + // for the callback. + // If PLATFORM_FILE_CREATE is set in |file_flags| it always tries to create + // a new file at the given |file_path| and calls back with + // PLATFORM_FILE_ERROR_FILE_EXISTS if the |file_path| already exists. + static bool CreateOrOpen(const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + int file_flags, + CreateOrOpenCallback* callback); + + // Close the given file handle. + static bool Close(const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + PlatformFile, + StatusCallback* callback); + + // Ensures that the given |file_path| exist. This creates a empty new file + // at |file_path| if the |file_path| does not exist. + // If a new file han not existed and is created at the |file_path|, + // |created| of the callback argument is set true and |error code| + // is set PLATFORM_FILE_OK. + // If the file already exists, |created| is set false and |error code| + // is set PLATFORM_FILE_OK. + // If the file hasn't existed but it couldn't be created for some other + // reasons, |created| is set false and |error code| indicates the error. + static bool EnsureFileExists( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + EnsureFileExistsCallback* callback); + + // Retrieves the information about a file. It is invalid to pass NULL for the + // callback. + static bool GetFileInfo( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + GetFileInfoCallback* callback); + + static bool ReadDirectory(const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + ReadDirectoryCallback* callback); + + // Creates directory at given path. It's an error to create + // if |exclusive| is true and dir already exists. + static bool CreateDirectory( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + bool exclusive, + StatusCallback* callback); + + // Copies a file or a directory from |src_file_path| to |dest_file_path| + // Error cases: + // If destination file doesn't exist or destination's parent + // doesn't exists. + // If source dir exists but destination path is an existing file. + // If source file exists but destination path is an existing directory. + // If source is a parent of destination. + // If source doesn't exists. + static bool Copy(const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& src_file_path, + const FilePath& dest_file_path, + StatusCallback* callback); + + // Moves a file or a directory from src_file_path to dest_file_path. + // Error cases are similar to Copy method's error cases. + static bool Move( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& src_file_path, + const FilePath& dest_file_path, + StatusCallback* callback); + + // Deletes a file or a directory. + // It is an error to delete a non-empty directory with recursive=false. + static bool Delete(const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + bool recursive, + StatusCallback* callback); + + // Touches a file. The callback can be NULL. + static bool Touch( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + const base::Time& last_access_time, + const base::Time& last_modified_time, + StatusCallback* callback); + + // Truncates a file to the given length. If |length| is greater than the + // current length of the file, the file will be extended with zeroes. + // The callback can be NULL. + static bool Truncate( + const FileSystemOperationContext& context, + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& path, + int64 length, + StatusCallback* callback); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(FileSystemFileUtilProxy); +}; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_FILE_SYSTEM_FILE_UTIL_PROXY_H_ diff --git a/webkit/fileapi/file_system_operation.cc b/webkit/fileapi/file_system_operation.cc index d3d4908..ec3ea7e 100644 --- a/webkit/fileapi/file_system_operation.cc +++ b/webkit/fileapi/file_system_operation.cc @@ -8,6 +8,8 @@ #include "net/url_request/url_request_context.h" #include "webkit/fileapi/file_system_callback_dispatcher.h" #include "webkit/fileapi/file_system_context.h" +#include "webkit/fileapi/file_system_file_util_proxy.h" +#include "webkit/fileapi/file_system_operation_context.h" #include "webkit/fileapi/file_system_path_manager.h" #include "webkit/fileapi/file_writer_delegate.h" @@ -20,6 +22,7 @@ FileSystemOperation::FileSystemOperation( : proxy_(proxy), dispatcher_(dispatcher), file_system_context_(file_system_context), + file_system_operation_context_(FileSystemFileUtil::GetInstance()), callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { DCHECK(dispatcher); #ifndef NDEBUG @@ -29,7 +32,9 @@ FileSystemOperation::FileSystemOperation( FileSystemOperation::~FileSystemOperation() { if (file_writer_delegate_.get()) - base::FileUtilProxy::Close(proxy_, file_writer_delegate_->file(), NULL); + FileSystemFileUtilProxy::Close( + file_system_operation_context_, + proxy_, file_writer_delegate_->file(), NULL); } void FileSystemOperation::OpenFileSystem( @@ -57,26 +62,29 @@ void FileSystemOperation::CreateFile(const FilePath& path, delete this; return; } - base::FileUtilProxy::EnsureFileExists( - proxy_, path, callback_factory_.NewCallback( - exclusive ? &FileSystemOperation::DidEnsureFileExistsExclusive - : &FileSystemOperation::DidEnsureFileExistsNonExclusive)); + FileSystemFileUtilProxy::EnsureFileExists( + file_system_operation_context_, + proxy_, path, callback_factory_.NewCallback( + exclusive ? &FileSystemOperation::DidEnsureFileExistsExclusive + : &FileSystemOperation::DidEnsureFileExistsNonExclusive)); } void FileSystemOperation::CreateDirectory(const FilePath& path, bool exclusive, - bool recursive) { + bool unused) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationCreateDirectory; #endif + DCHECK(!unused); if (!VerifyFileSystemPathForWrite(path, true /* create */)) { delete this; return; } - base::FileUtilProxy::CreateDirectory( - proxy_, path, exclusive, recursive, callback_factory_.NewCallback( + FileSystemFileUtilProxy::CreateDirectory( + file_system_operation_context_, + proxy_, path, exclusive, callback_factory_.NewCallback( &FileSystemOperation::DidFinishFileOperation)); } @@ -92,8 +100,9 @@ void FileSystemOperation::Copy(const FilePath& src_path, delete this; return; } - base::FileUtilProxy::Copy(proxy_, src_path, dest_path, - callback_factory_.NewCallback( + FileSystemFileUtilProxy::Copy( + file_system_operation_context_, + proxy_, src_path, dest_path, callback_factory_.NewCallback( &FileSystemOperation::DidFinishFileOperation)); } @@ -109,8 +118,9 @@ void FileSystemOperation::Move(const FilePath& src_path, delete this; return; } - base::FileUtilProxy::Move(proxy_, src_path, dest_path, - callback_factory_.NewCallback( + FileSystemFileUtilProxy::Move( + file_system_operation_context_, + proxy_, src_path, dest_path, callback_factory_.NewCallback( &FileSystemOperation::DidFinishFileOperation)); } @@ -124,8 +134,10 @@ void FileSystemOperation::DirectoryExists(const FilePath& path) { delete this; return; } - base::FileUtilProxy::GetFileInfo(proxy_, path, callback_factory_.NewCallback( - &FileSystemOperation::DidDirectoryExists)); + FileSystemFileUtilProxy::GetFileInfo( + file_system_operation_context_, + proxy_, path, callback_factory_.NewCallback( + &FileSystemOperation::DidDirectoryExists)); } void FileSystemOperation::FileExists(const FilePath& path) { @@ -138,8 +150,10 @@ void FileSystemOperation::FileExists(const FilePath& path) { delete this; return; } - base::FileUtilProxy::GetFileInfo(proxy_, path, callback_factory_.NewCallback( - &FileSystemOperation::DidFileExists)); + FileSystemFileUtilProxy::GetFileInfo( + file_system_operation_context_, + proxy_, path, callback_factory_.NewCallback( + &FileSystemOperation::DidFileExists)); } void FileSystemOperation::GetMetadata(const FilePath& path) { @@ -152,8 +166,10 @@ void FileSystemOperation::GetMetadata(const FilePath& path) { delete this; return; } - base::FileUtilProxy::GetFileInfo(proxy_, path, callback_factory_.NewCallback( - &FileSystemOperation::DidGetMetadata)); + FileSystemFileUtilProxy::GetFileInfo( + file_system_operation_context_, + proxy_, path, callback_factory_.NewCallback( + &FileSystemOperation::DidGetMetadata)); } void FileSystemOperation::ReadDirectory(const FilePath& path) { @@ -166,8 +182,9 @@ void FileSystemOperation::ReadDirectory(const FilePath& path) { delete this; return; } - base::FileUtilProxy::ReadDirectory(proxy_, path, - callback_factory_.NewCallback( + FileSystemFileUtilProxy::ReadDirectory( + file_system_operation_context_, + proxy_, path, callback_factory_.NewCallback( &FileSystemOperation::DidReadDirectory)); } @@ -181,8 +198,9 @@ void FileSystemOperation::Remove(const FilePath& path, bool recursive) { delete this; return; } - base::FileUtilProxy::Delete(proxy_, path, recursive, - callback_factory_.NewCallback( + FileSystemFileUtilProxy::Delete( + file_system_operation_context_, + proxy_, path, recursive, callback_factory_.NewCallback( &FileSystemOperation::DidFinishFileOperation)); } @@ -204,7 +222,8 @@ void FileSystemOperation::Write( blob_request_.reset( new net::URLRequest(blob_url, file_writer_delegate_.get())); blob_request_->set_context(url_request_context); - base::FileUtilProxy::CreateOrOpen( + FileSystemFileUtilProxy::CreateOrOpen( + file_system_operation_context_, proxy_, path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE | @@ -222,8 +241,9 @@ void FileSystemOperation::Truncate(const FilePath& path, int64 length) { delete this; return; } - base::FileUtilProxy::Truncate(proxy_, path, length, - callback_factory_.NewCallback( + FileSystemFileUtilProxy::Truncate( + file_system_operation_context_, + proxy_, path, length, callback_factory_.NewCallback( &FileSystemOperation::DidFinishFileOperation)); } @@ -239,7 +259,8 @@ void FileSystemOperation::TouchFile(const FilePath& path, delete this; return; } - base::FileUtilProxy::Touch( + FileSystemFileUtilProxy::Touch( + file_system_operation_context_, proxy_, path, last_access_time, last_modified_time, callback_factory_.NewCallback(&FileSystemOperation::DidTouchFile)); } diff --git a/webkit/fileapi/file_system_operation.h b/webkit/fileapi/file_system_operation.h index 4630fe7..9fa2db4 100644 --- a/webkit/fileapi/file_system_operation.h +++ b/webkit/fileapi/file_system_operation.h @@ -16,6 +16,7 @@ #include "base/scoped_ptr.h" #include "googleurl/src/gurl.h" #include "webkit/fileapi/file_system_types.h" +#include "webkit/fileapi/file_system_operation_context.h" namespace base { class Time; @@ -55,7 +56,7 @@ class FileSystemOperation { bool exclusive); void CreateDirectory(const FilePath& path, bool exclusive, - bool recursive); + bool unused); void Copy(const FilePath& src_path, const FilePath& dest_path); void Move(const FilePath& src_path, @@ -170,6 +171,7 @@ class FileSystemOperation { scoped_ptr<FileSystemCallbackDispatcher> dispatcher_; scoped_refptr<FileSystemContext> file_system_context_; + FileSystemOperationContext file_system_operation_context_; base::ScopedCallbackFactory<FileSystemOperation> callback_factory_; diff --git a/webkit/fileapi/file_system_operation_context.h b/webkit/fileapi/file_system_operation_context.h new file mode 100644 index 0000000..68f5e47 --- /dev/null +++ b/webkit/fileapi/file_system_operation_context.h @@ -0,0 +1,30 @@ +// Copyright (c) 2011 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. + +#ifndef WEBKIT_FILEAPI_FILE_SYSTEM_OPERATION_CONTEXT_H_ +#define WEBKIT_FILEAPI_FILE_SYSTEM_OPERATION_CONTEXT_H_ + +#include "webkit/fileapi/file_system_file_util.h" + +namespace fileapi { + +class FileSystemOperationContext { + public: + FileSystemOperationContext(FileSystemFileUtil* file_system_file_util) + : file_system_file_util_(file_system_file_util) { + } + + FileSystemFileUtil* file_system_file_util() const { + return file_system_file_util_; + } + + private: + // This file_system_file_util_ is not "owned" by FileSystemOperationContext. + // It is supposed to be a pointer to a singleton. + FileSystemFileUtil* file_system_file_util_; +}; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_FILE_SYSTEM_OPERATION_CONTEXT_H_ diff --git a/webkit/fileapi/webkit_fileapi.gypi b/webkit/fileapi/webkit_fileapi.gypi index 564b1b7..f1191c6 100644 --- a/webkit/fileapi/webkit_fileapi.gypi +++ b/webkit/fileapi/webkit_fileapi.gypi @@ -19,6 +19,10 @@ 'file_system_context.h', 'file_system_dir_url_request_job.cc', 'file_system_dir_url_request_job.h', + 'file_system_file_util.cc', + 'file_system_file_util.h', + 'file_system_file_util_proxy.cc', + 'file_system_file_util_proxy.h', 'file_system_operation.cc', 'file_system_operation.h', 'file_system_path_manager.cc', |