diff options
author | tzik@chromium.org <tzik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-08 04:56:21 +0000 |
---|---|---|
committer | tzik@chromium.org <tzik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-08 04:56:21 +0000 |
commit | c3d5d25e9f3128c693debcfc457e71d2d6b880d5 (patch) | |
tree | 49cf3150ea64fcbccc826bb359ec555d680a88c5 /webkit/fileapi/file_util_helper.cc | |
parent | 1bc85b268333b7c8eec62d4d5324067978fafc98 (diff) | |
download | chromium_src-c3d5d25e9f3128c693debcfc457e71d2d6b880d5.zip chromium_src-c3d5d25e9f3128c693debcfc457e71d2d6b880d5.tar.gz chromium_src-c3d5d25e9f3128c693debcfc457e71d2d6b880d5.tar.bz2 |
Merge CrossFileUtilHelper to FileUtilHelper as Copy() and Move().
BUG=114732
TEST="existing tests"
Review URL: http://codereview.chromium.org/9616033
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125558 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/fileapi/file_util_helper.cc')
-rw-r--r-- | webkit/fileapi/file_util_helper.cc | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/webkit/fileapi/file_util_helper.cc b/webkit/fileapi/file_util_helper.cc index 1310f18..b2885de 100644 --- a/webkit/fileapi/file_util_helper.cc +++ b/webkit/fileapi/file_util_helper.cc @@ -12,6 +12,253 @@ using base::PlatformFileError; namespace fileapi { +namespace { + +// A helper class for cross-FileUtil Copy/Move operations. +class CrossFileUtilHelper { + public: + enum Operation { + OPERATION_COPY, + OPERATION_MOVE + }; + + CrossFileUtilHelper(FileSystemOperationContext* context, + FileSystemFileUtil* src_util, + FileSystemFileUtil* dest_util, + const FileSystemPath& src_path, + const FileSystemPath& dest_path, + Operation operation); + ~CrossFileUtilHelper(); + + base::PlatformFileError DoWork(); + + private: + // Performs common pre-operation check and preparation. + // This may delete the destination directory if it's empty. + base::PlatformFileError PerformErrorCheckAndPreparation(); + + // This assumes that the root exists. + bool ParentExists(const FileSystemPath& path, FileSystemFileUtil* file_util); + + // Performs recursive copy or move by calling CopyOrMoveFile for individual + // files. Operations for recursive traversal are encapsulated in this method. + // It assumes src_path and dest_path have passed + // PerformErrorCheckAndPreparationForMoveAndCopy(). + base::PlatformFileError CopyOrMoveDirectory( + const FileSystemPath& src_path, + const FileSystemPath& dest_path); + + // Determines whether a simple same-filesystem move or copy can be done. If + // so, it delegates to CopyOrMoveFile. Otherwise it looks up the true + // platform path of the source file, delegates to CopyInForeignFile, and [for + // move] calls DeleteFile on the source file. + base::PlatformFileError CopyOrMoveFile( + const FileSystemPath& src_path, + const FileSystemPath& dest_path); + + FileSystemOperationContext* context_; + FileSystemFileUtil* src_util_; // Not owned. + FileSystemFileUtil* dest_util_; // Not owned. + const FileSystemPath& src_root_path_; + const FileSystemPath& dest_root_path_; + Operation operation_; + bool same_file_system_; + + DISALLOW_COPY_AND_ASSIGN(CrossFileUtilHelper); +}; + +CrossFileUtilHelper::CrossFileUtilHelper( + FileSystemOperationContext* context, + FileSystemFileUtil* src_util, + FileSystemFileUtil* dest_util, + const FileSystemPath& src_path, + const FileSystemPath& dest_path, + Operation operation) + : context_(context), + src_util_(src_util), + dest_util_(dest_util), + src_root_path_(src_path), + dest_root_path_(dest_path), + operation_(operation) { + same_file_system_ = + src_root_path_.origin() == dest_root_path_.origin() && + src_root_path_.type() == dest_root_path_.type(); +} + +CrossFileUtilHelper::~CrossFileUtilHelper() {} + +base::PlatformFileError CrossFileUtilHelper::DoWork() { + base::PlatformFileError error = PerformErrorCheckAndPreparation(); + if (error != base::PLATFORM_FILE_OK) + return error; + if (src_util_->DirectoryExists(context_, src_root_path_)) + return CopyOrMoveDirectory(src_root_path_, dest_root_path_); + return CopyOrMoveFile(src_root_path_, dest_root_path_); +} + +PlatformFileError CrossFileUtilHelper::PerformErrorCheckAndPreparation() { + // Exits earlier if the source path does not exist. + if (!src_util_->PathExists(context_, src_root_path_)) + return base::PLATFORM_FILE_ERROR_NOT_FOUND; + + // The parent of the |dest_root_path_| does not exist. + if (!ParentExists(dest_root_path_, dest_util_)) + return base::PLATFORM_FILE_ERROR_NOT_FOUND; + + // It is an error to try to copy/move an entry into its child. + if (same_file_system_ && src_root_path_.IsParent(dest_root_path_)) + return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; + + // Now it is ok to return if the |dest_root_path_| does not exist. + if (!dest_util_->PathExists(context_, dest_root_path_)) + return base::PLATFORM_FILE_OK; + + // |src_root_path_| exists and is a directory. + // |dest_root_path_| exists and is a file. + bool src_is_directory = src_util_->DirectoryExists(context_, src_root_path_); + bool dest_is_directory = + dest_util_->DirectoryExists(context_, dest_root_path_); + + // Either one of |src_root_path_| or |dest_root_path_| is directory, + // while the other is not. + if (src_is_directory != dest_is_directory) + return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; + + // It is an error to copy/move an entry into the same path. + if (same_file_system_ && + src_root_path_.internal_path() == dest_root_path_.internal_path()) + 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. + if (base::PLATFORM_FILE_OK != + dest_util_->DeleteSingleDirectory(context_, dest_root_path_)) { + if (!dest_util_->IsDirectoryEmpty(context_, dest_root_path_)) + return base::PLATFORM_FILE_ERROR_NOT_EMPTY; + return base::PLATFORM_FILE_ERROR_FAILED; + } + } + return base::PLATFORM_FILE_OK; +} + +bool CrossFileUtilHelper::ParentExists( + const FileSystemPath& path, FileSystemFileUtil* file_util) { + // If path is in the root, path.DirName() will be ".", + // since we use paths with no leading '/'. + FilePath parent = path.internal_path().DirName(); + if (parent == FilePath(FILE_PATH_LITERAL("."))) + return true; + return file_util->DirectoryExists( + context_, path.WithInternalPath(parent)); +} + +PlatformFileError CrossFileUtilHelper::CopyOrMoveDirectory( + const FileSystemPath& src_path, + const FileSystemPath& dest_path) { + // At this point we must have gone through + // PerformErrorCheckAndPreparationForMoveAndCopy so this must be true. + DCHECK(!same_file_system_ || + !src_path.IsParent(dest_path)); + + PlatformFileError error = dest_util_->CreateDirectory( + context_, dest_path, false, false); + if (error != base::PLATFORM_FILE_OK) + return error; + + scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum( + src_util_->CreateFileEnumerator(context_, src_path, true)); + FilePath src_file_path_each; + while (!(src_file_path_each = file_enum->Next()).empty()) { + FilePath dest_file_path_each(dest_path.internal_path()); + src_path.internal_path().AppendRelativePath( + src_file_path_each, &dest_file_path_each); + + if (file_enum->IsDirectory()) { + PlatformFileError error = dest_util_->CreateDirectory( + context_, + dest_path.WithInternalPath(dest_file_path_each), + true /* exclusive */, false /* recursive */); + if (error != base::PLATFORM_FILE_OK) + return error; + } else { + PlatformFileError error = CopyOrMoveFile( + src_path.WithInternalPath(src_file_path_each), + dest_path.WithInternalPath(dest_file_path_each)); + if (error != base::PLATFORM_FILE_OK) + return error; + } + } + + if (operation_ == OPERATION_MOVE) { + PlatformFileError error = + FileUtilHelper::Delete(context_, src_util_, + src_path, true /* recursive */); + if (error != base::PLATFORM_FILE_OK) + return error; + } + + return base::PLATFORM_FILE_OK; +} + +PlatformFileError CrossFileUtilHelper::CopyOrMoveFile( + const FileSystemPath& src_path, + const FileSystemPath& dest_path) { + if (same_file_system_) { + DCHECK(src_util_ == dest_util_); + // Source and destination are in the same FileSystemFileUtil; now we can + // safely call FileSystemFileUtil method on src_util_ (== dest_util_). + return src_util_->CopyOrMoveFile(context_, src_path, dest_path, + operation_ == OPERATION_COPY); + } + + // Resolve the src_path's underlying file path. + base::PlatformFileInfo file_info; + FilePath platform_file_path; + PlatformFileError error = src_util_->GetFileInfo( + context_, src_path, &file_info, &platform_file_path); + if (error != base::PLATFORM_FILE_OK) + return error; + + // Call CopyInForeignFile() on the dest_util_ with the resolved source path + // to perform limited cross-FileSystemFileUtil copy/move. + error = dest_util_->CopyInForeignFile( + context_, src_path.WithInternalPath(platform_file_path), dest_path); + + if (operation_ == OPERATION_COPY || error != base::PLATFORM_FILE_OK) + return error; + return src_util_->DeleteFile(context_, src_path); +} + +} // anonymous namespace + +// static +base::PlatformFileError FileUtilHelper::Copy( + FileSystemOperationContext* context, + FileSystemFileUtil* src_file_util, + FileSystemFileUtil* dest_file_util, + const FileSystemPath& src_root_path, + const FileSystemPath& dest_root_path) { + return CrossFileUtilHelper(context, src_file_util, dest_file_util, + src_root_path, dest_root_path, + CrossFileUtilHelper::OPERATION_COPY).DoWork(); +} + +// static +base::PlatformFileError FileUtilHelper::Move( + FileSystemOperationContext* context, + FileSystemFileUtil* src_file_util, + FileSystemFileUtil* dest_file_util, + const FileSystemPath& src_root_path, + const FileSystemPath& dest_root_path) { + return CrossFileUtilHelper(context, src_file_util, dest_file_util, + src_root_path, dest_root_path, + CrossFileUtilHelper::OPERATION_MOVE).DoWork(); +} + +// static base::PlatformFileError FileUtilHelper::Delete( FileSystemOperationContext* context, FileSystemFileUtil* file_util, @@ -27,6 +274,7 @@ base::PlatformFileError FileUtilHelper::Delete( } } +// static base::PlatformFileError FileUtilHelper::DeleteDirectoryRecursive( FileSystemOperationContext* context, FileSystemFileUtil* file_util, |