diff options
author | kkanetkar@chromium.org <kkanetkar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-02 03:43:36 +0000 |
---|---|---|
committer | kkanetkar@chromium.org <kkanetkar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-02 03:43:36 +0000 |
commit | 61da1dbbe85912d3b21310b5e934ddcc273e5cb1 (patch) | |
tree | 4a8e50420f8583b860db847d2f3ea79e907bfdaa /base | |
parent | 6470a9eb1c4fdcfb45b504e9b6ce57941ff956de (diff) | |
download | chromium_src-61da1dbbe85912d3b21310b5e934ddcc273e5cb1.zip chromium_src-61da1dbbe85912d3b21310b5e934ddcc273e5cb1.tar.gz chromium_src-61da1dbbe85912d3b21310b5e934ddcc273e5cb1.tar.bz2 |
Changes for browser-side implementation for file api.
BUG=32277
TEST=Separate CL for unit test.
Review URL: http://codereview.chromium.org/3212002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58312 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/file_util_proxy.cc | 249 | ||||
-rw-r--r-- | base/file_util_proxy.h | 75 | ||||
-rw-r--r-- | base/platform_file.h | 5 |
3 files changed, 303 insertions, 26 deletions
diff --git a/base/file_util_proxy.cc b/base/file_util_proxy.cc index de16b10..e7c0263 100644 --- a/base/file_util_proxy.cc +++ b/base/file_util_proxy.cc @@ -4,7 +4,6 @@ #include "base/file_util_proxy.h" -#include "base/file_util.h" #include "base/message_loop_proxy.h" // TODO(jianli): Move the code from anonymous namespace to base namespace so @@ -16,7 +15,7 @@ class MessageLoopRelay public: MessageLoopRelay() : origin_message_loop_proxy_( - base::MessageLoopProxy::CreateForCurrentThread()), + base::MessageLoopProxy::CreateForCurrentThread()), error_code_(base::PLATFORM_FILE_OK) { } @@ -200,8 +199,17 @@ class RelayDelete : public RelayWithStatusCallback { protected: virtual void RunWork() { - if (!file_util::Delete(file_path_, recursive_)) + if (!file_util::PathExists(file_path_)) { + set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); + return; + } + if (!file_util::Delete(file_path_, recursive_)) { + if (!recursive_ && !file_util::IsDirectoryEmpty(file_path_)) { + set_error_code(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); + return; + } set_error_code(base::PLATFORM_FILE_ERROR_FAILED); + } } private: @@ -209,6 +217,185 @@ class RelayDelete : public RelayWithStatusCallback { bool recursive_; }; +class RelayCopy : public RelayWithStatusCallback { + public: + RelayCopy(const FilePath& src_file_path, + const FilePath& dest_file_path, + base::FileUtilProxy::StatusCallback* callback) + : RelayWithStatusCallback(callback), + src_file_path_(src_file_path), + dest_file_path_(dest_file_path) { + } + + protected: + virtual void RunWork() { + bool dest_path_exists = file_util::PathExists(dest_file_path_); + if (!dest_path_exists && + !file_util::DirectoryExists(dest_file_path_.DirName())) { + set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); + return; + } + // |src_file_path| exists and is a directory. + // |dest_file_path| exists and is a file. + if (file_util::DirectoryExists(src_file_path_) && + dest_path_exists && !file_util::DirectoryExists(dest_file_path_)) { + set_error_code(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY); + return; + } + if (file_util::ContainsPath(src_file_path_, dest_file_path_)) { + set_error_code(base::PLATFORM_FILE_ERROR_FAILED); + return; + } + if (!file_util::CopyDirectory(src_file_path_, dest_file_path_, + true /* recursive */)) { + if (!file_util::PathExists(src_file_path_)) { + set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); + return; + } + if (src_file_path_.value() == dest_file_path_.value()) { + set_error_code(base::PLATFORM_FILE_ERROR_EXISTS); + return; + } + // Something else went wrong. + set_error_code(base::PLATFORM_FILE_ERROR_FAILED); + } + } + + private: + FilePath src_file_path_; + FilePath dest_file_path_; +}; + +class RelayMove : public RelayWithStatusCallback { + public: + RelayMove(const FilePath& src_file_path, + const FilePath& dest_file_path, + base::FileUtilProxy::StatusCallback* callback) + : RelayWithStatusCallback(callback), + src_file_path_(src_file_path), + dest_file_path_(dest_file_path) { + } + + protected: + virtual void RunWork() { + bool dest_path_exists = file_util::PathExists(dest_file_path_); + if (!dest_path_exists && + !file_util::DirectoryExists(dest_file_path_.DirName())) { + set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); + return; + } + // |src_file_path| exists and is a directory. + // |dest_file_path| exists and is a file. + if (file_util::DirectoryExists(src_file_path_) && + dest_path_exists && + !file_util::DirectoryExists(dest_file_path_)) { + set_error_code(base::PLATFORM_FILE_ERROR_EXISTS); + return; + } + if (file_util::ContainsPath(src_file_path_, dest_file_path_)) { + set_error_code(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); + return; + } + if (!file_util::Move(src_file_path_, dest_file_path_)) { + if (!file_util::PathExists(src_file_path_)) { + set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); + return; + } + if (src_file_path_.value() == dest_file_path_.value()) { + set_error_code(base::PLATFORM_FILE_ERROR_EXISTS); + return; + } + // Something else went wrong. + set_error_code(base::PLATFORM_FILE_ERROR_FAILED); + } + } + + private: + FilePath src_file_path_; + FilePath dest_file_path_; +}; + +class RelayCreateDirectory : public RelayWithStatusCallback { + public: + RelayCreateDirectory( + const FilePath& file_path, + bool exclusive, + base::FileUtilProxy::StatusCallback* callback) + : RelayWithStatusCallback(callback), + file_path_(file_path), + exclusive_(exclusive) { + } + + protected: + virtual void RunWork() { + bool path_exists = file_util::PathExists(file_path_); + // If parent dir of file doesn't exist. + if (!file_util::PathExists(file_path_.DirName())) { + set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); + return; + } + if (exclusive_ && path_exists) { + set_error_code(base::PLATFORM_FILE_ERROR_EXISTS); + return; + } + // If file exists at the path. + if (path_exists && !file_util::DirectoryExists(file_path_)) { + set_error_code(base::PLATFORM_FILE_ERROR_EXISTS); + return; + } + if (!file_util::CreateDirectory(file_path_)) + set_error_code(base::PLATFORM_FILE_ERROR_FAILED); + } + + private: + FilePath file_path_; + bool exclusive_; +}; + +class RelayReadDirectory : public MessageLoopRelay { + public: + RelayReadDirectory(const FilePath& file_path, + base::FileUtilProxy::ReadDirectoryCallback* callback) + : callback_(callback), file_path_(file_path) { + DCHECK(callback); + } + + protected: + virtual void RunWork() { + // TODO(kkanetkar): Implement directory read in multiple chunks. + if (!file_util::DirectoryExists(file_path_)) { + set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); + return; + } + + 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::file_util_proxy::Entry entry; + file_util::FileEnumerator::FindInfo info; + file_enum.GetFindInfo(&info); + entry.isDirectory = 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); + } + } + + virtual void RunCallback() { + callback_->Run(error_code(), entries_); + delete callback_; + } + + private: + base::FileUtilProxy::ReadDirectoryCallback* callback_; + FilePath file_path_; + std::vector<base::file_util_proxy::Entry> entries_; +}; + class RelayGetFileInfo : public MessageLoopRelay { public: RelayGetFileInfo(const FilePath& file_path, @@ -220,6 +407,10 @@ class RelayGetFileInfo : public MessageLoopRelay { protected: virtual void RunWork() { + if (!file_util::PathExists(file_path_)) { + set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND); + return; + } if (!file_util::GetFileInfo(file_path_, &file_info_)) set_error_code(base::PLATFORM_FILE_ERROR_FAILED); } @@ -263,6 +454,16 @@ bool FileUtilProxy::CreateTemporary( } // static +bool FileUtilProxy::CreateDirectory( + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + bool exclusive, + StatusCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, new RelayCreateDirectory( + file_path, exclusive, callback)); +} + +// static bool FileUtilProxy::Close(scoped_refptr<MessageLoopProxy> message_loop_proxy, base::PlatformFile file_handle, StatusCallback* callback) { @@ -279,21 +480,49 @@ bool FileUtilProxy::Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy, } // static -bool FileUtilProxy::RecursiveDelete( - scoped_refptr<MessageLoopProxy> message_loop_proxy, - const FilePath& file_path, - StatusCallback* callback) { +bool FileUtilProxy::Copy(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 RelayDelete(file_path, true, callback)); + new RelayCopy(src_file_path, dest_file_path, callback)); +} + +// static +bool FileUtilProxy::Move(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(src_file_path, dest_file_path, callback)); } // static +bool FileUtilProxy::ReadDirectory( + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + ReadDirectoryCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, new RelayReadDirectory( + file_path, callback)); +} + +// Retrieves the information about a file. It is invalid to pass NULL for the +// callback. bool FileUtilProxy::GetFileInfo( scoped_refptr<MessageLoopProxy> message_loop_proxy, const FilePath& file_path, GetFileInfoCallback* callback) { + return Start(FROM_HERE, message_loop_proxy, new RelayGetFileInfo( + file_path, callback)); +} + +// static +bool FileUtilProxy::RecursiveDelete( + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + StatusCallback* callback) { return Start(FROM_HERE, message_loop_proxy, - new RelayGetFileInfo(file_path, callback)); + new RelayDelete(file_path, true, callback)); } -} // namespace base +} // namespace base diff --git a/base/file_util_proxy.h b/base/file_util_proxy.h index 9899c77..dec06e3 100644 --- a/base/file_util_proxy.h +++ b/base/file_util_proxy.h @@ -2,10 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef BASE_FILE_SYSTEM_PROXY_H_ -#define BASE_FILE_SYSTEM_PROXY_H_ +#ifndef BASE_FILE_UTIL_PROXY_H_ +#define BASE_FILE_UTIL_PROXY_H_ + +#include <vector> #include "base/callback.h" +#include "base/file_path.h" +#include "base/file_util.h" #include "base/platform_file.h" #include "base/ref_counted.h" #include "base/tracked_objects.h" @@ -16,6 +20,14 @@ struct FileInfo; namespace base { +namespace file_util_proxy { + // Holds metadata for file or directory entry. +struct Entry { + FilePath::StringType name; + bool isDirectory; +}; +} // namespace file_util_proxy + class MessageLoopProxy; // This class provides asynchronous access to common file routines. @@ -51,31 +63,66 @@ class FileUtilProxy { base::PlatformFile, StatusCallback* callback); + // Retrieves the information about a file. It is invalid to pass NULL for the + // callback. + typedef Callback2<base::PlatformFileError /* error code */, + const file_util::FileInfo& /*file_info*/ + >::Type GetFileInfoCallback; + static bool GetFileInfo( + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + GetFileInfoCallback* callback); + + typedef Callback2<base::PlatformFileError /* error code */, + const std::vector<base::file_util_proxy::Entry>& + >::Type ReadDirectoryCallback; + static bool ReadDirectory(scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + ReadDirectoryCallback* 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 is a parent of destination. + // If source doesn't exists. + static bool Copy(scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& src_file_path, + const FilePath& dest_file_path, + StatusCallback* callback); + + // Creates directory at given path. It's an error to create + // if |exclusive| is true and dir already exists. + static bool CreateDirectory( + scoped_refptr<MessageLoopProxy> message_loop_proxy, + const FilePath& file_path, + bool exclusive, + StatusCallback* callback); + // Deletes a file or empty directory. static bool Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy, const FilePath& file_path, StatusCallback* callback); - // Deletes a directory and all of its contents. - static bool RecursiveDelete( + // 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( scoped_refptr<MessageLoopProxy> message_loop_proxy, - const FilePath& file_path, + const FilePath& src_file_path, + const FilePath& dest_file_path, StatusCallback* callback); - // Retrieves the information about a file. It is invalid to pass NULL for the - // callback. - typedef Callback2<base::PlatformFileError /* error code */, - const file_util::FileInfo& /*file_info*/ - >::Type GetFileInfoCallback; - static bool GetFileInfo( + // Deletes a directory and all of its contents. + static bool RecursiveDelete( scoped_refptr<MessageLoopProxy> message_loop_proxy, const FilePath& file_path, - GetFileInfoCallback* callback); + StatusCallback* callback); private: DISALLOW_IMPLICIT_CONSTRUCTORS(FileUtilProxy); }; -} // namespace base +} // namespace base -#endif // BASE_FILE_SYSTEM_PROXY_H_ +#endif // BASE_FILE_UTIL_PROXY_H_ diff --git a/base/platform_file.h b/base/platform_file.h index 70ed0f1..0e4d05c 100644 --- a/base/platform_file.h +++ b/base/platform_file.h @@ -50,8 +50,9 @@ enum PlatformFileError { PLATFORM_FILE_ERROR_ACCESS_DENIED = -5, PLATFORM_FILE_ERROR_TOO_MANY_OPENED = -6, PLATFORM_FILE_ERROR_NO_MEMORY = -7, - PLATFORM_FILE_ERROR_NO_SPACE = -7, - PLATFORM_FILE_ERROR_NOT_A_DIRECTORY = -9 + PLATFORM_FILE_ERROR_NO_SPACE = -8, + PLATFORM_FILE_ERROR_NOT_A_DIRECTORY = -9, + PLATFORM_FILE_ERROR_INVALID_OPERATION = -10 }; // Creates or opens the given file. If PLATFORM_FILE_OPEN_ALWAYS is used, and |