| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "webkit/fileapi/cross_file_util_helper.h" | |
| 6 | |
| 7 #include "webkit/fileapi/file_system_file_util.h" | |
| 8 #include "webkit/fileapi/file_system_operation_context.h" | |
| 9 #include "webkit/fileapi/file_system_path.h" | |
| 10 #include "webkit/fileapi/file_util_helper.h" | |
| 11 | |
| 12 using base::PlatformFileError; | |
| 13 | |
| 14 namespace fileapi { | |
| 15 | |
| 16 CrossFileUtilHelper::CrossFileUtilHelper( | |
| 17 FileSystemOperationContext* context, | |
| 18 FileSystemFileUtil* src_util, | |
| 19 FileSystemFileUtil* dest_util, | |
| 20 const FileSystemPath& src_path, | |
| 21 const FileSystemPath& dest_path, | |
| 22 Operation operation) | |
| 23 : context_(context), | |
| 24 src_util_(src_util), | |
| 25 dest_util_(dest_util), | |
| 26 src_root_path_(src_path), | |
| 27 dest_root_path_(dest_path), | |
| 28 operation_(operation) {} | |
| 29 | |
| 30 CrossFileUtilHelper::~CrossFileUtilHelper() {} | |
| 31 | |
| 32 base::PlatformFileError CrossFileUtilHelper::DoWork() { | |
| 33 base::PlatformFileError error = | |
| 34 PerformErrorCheckAndPreparationForMoveAndCopy(); | |
| 35 if (error != base::PLATFORM_FILE_OK) | |
| 36 return error; | |
| 37 if (src_util_->DirectoryExists(context_, src_root_path_)) { | |
| 38 return CopyOrMoveDirectory(src_root_path_, dest_root_path_); | |
| 39 } | |
| 40 return CopyOrMoveFile(src_root_path_, dest_root_path_); | |
| 41 } | |
| 42 | |
| 43 PlatformFileError | |
| 44 CrossFileUtilHelper::PerformErrorCheckAndPreparationForMoveAndCopy() { | |
| 45 // Exits earlier if the source path does not exist. | |
| 46 if (!src_util_->PathExists(context_, src_root_path_)) | |
| 47 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 48 | |
| 49 bool same_file_system = | |
| 50 (src_root_path_.origin() == dest_root_path_.origin()) && | |
| 51 (src_root_path_.type() == dest_root_path_.type()); | |
| 52 | |
| 53 // The parent of the |dest_root_path_| does not exist. | |
| 54 if (!ParentExists(dest_root_path_, dest_util_)) | |
| 55 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 56 | |
| 57 // It is an error to try to copy/move an entry into its child. | |
| 58 if (same_file_system && src_root_path_.IsParent(dest_root_path_)) | |
| 59 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | |
| 60 | |
| 61 // Now it is ok to return if the |dest_root_path_| does not exist. | |
| 62 if (!dest_util_->PathExists(context_, dest_root_path_)) | |
| 63 return base::PLATFORM_FILE_OK; | |
| 64 | |
| 65 // |src_root_path_| exists and is a directory. | |
| 66 // |dest_root_path_| exists and is a file. | |
| 67 bool src_is_directory = src_util_->DirectoryExists(context_, src_root_path_); | |
| 68 bool dest_is_directory = | |
| 69 dest_util_->DirectoryExists(context_, dest_root_path_); | |
| 70 | |
| 71 // Either one of |src_root_path_| or |dest_root_path_| is directory, | |
| 72 // while the other is not. | |
| 73 if (src_is_directory != dest_is_directory) | |
| 74 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | |
| 75 | |
| 76 // It is an error to copy/move an entry into the same path. | |
| 77 if (same_file_system && (src_root_path_.internal_path() == | |
| 78 dest_root_path_.internal_path())) | |
| 79 return base::PLATFORM_FILE_ERROR_EXISTS; | |
| 80 | |
| 81 if (dest_is_directory) { | |
| 82 // It is an error to copy/move an entry to a non-empty directory. | |
| 83 // Otherwise the copy/move attempt must overwrite the destination, but | |
| 84 // the file_util's Copy or Move method doesn't perform overwrite | |
| 85 // on all platforms, so we delete the destination directory here. | |
| 86 if (base::PLATFORM_FILE_OK != | |
| 87 dest_util_->DeleteSingleDirectory(context_, dest_root_path_)) { | |
| 88 if (!dest_util_->IsDirectoryEmpty(context_, dest_root_path_)) | |
| 89 return base::PLATFORM_FILE_ERROR_NOT_EMPTY; | |
| 90 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 91 } | |
| 92 } | |
| 93 return base::PLATFORM_FILE_OK; | |
| 94 } | |
| 95 | |
| 96 bool CrossFileUtilHelper::ParentExists( | |
| 97 const FileSystemPath& path, FileSystemFileUtil* file_util) { | |
| 98 // If path is in the root, path.DirName() will be ".", | |
| 99 // since we use paths with no leading '/'. | |
| 100 FilePath parent = path.internal_path().DirName(); | |
| 101 if (parent == FilePath(FILE_PATH_LITERAL("."))) | |
| 102 return true; | |
| 103 return file_util->DirectoryExists( | |
| 104 context_, path.WithInternalPath(parent)); | |
| 105 } | |
| 106 | |
| 107 PlatformFileError CrossFileUtilHelper::CopyOrMoveDirectory( | |
| 108 const FileSystemPath& src_path, | |
| 109 const FileSystemPath& dest_path) { | |
| 110 // At this point we must have gone through | |
| 111 // PerformErrorCheckAndPreparationForMoveAndCopy so this must be true. | |
| 112 DCHECK(!((src_path.origin() == dest_path.origin()) && | |
| 113 (src_path.type() == dest_path.type())) || | |
| 114 !src_path.IsParent(dest_path)); | |
| 115 | |
| 116 PlatformFileError error = dest_util_->CreateDirectory( | |
| 117 context_, dest_path, false, false); | |
| 118 if (error != base::PLATFORM_FILE_OK) | |
| 119 return error; | |
| 120 | |
| 121 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum( | |
| 122 src_util_->CreateFileEnumerator(context_, src_path, | |
| 123 true /* recursive */)); | |
| 124 FilePath src_file_path_each; | |
| 125 while (!(src_file_path_each = file_enum->Next()).empty()) { | |
| 126 FilePath dest_file_path_each(dest_path.internal_path()); | |
| 127 src_path.internal_path().AppendRelativePath( | |
| 128 src_file_path_each, &dest_file_path_each); | |
| 129 | |
| 130 if (file_enum->IsDirectory()) { | |
| 131 PlatformFileError error = dest_util_->CreateDirectory( | |
| 132 context_, | |
| 133 dest_path.WithInternalPath(dest_file_path_each), | |
| 134 true /* exclusive */, false /* recursive */); | |
| 135 if (error != base::PLATFORM_FILE_OK) | |
| 136 return error; | |
| 137 } else { | |
| 138 PlatformFileError error = CopyOrMoveFile( | |
| 139 src_path.WithInternalPath(src_file_path_each), | |
| 140 dest_path.WithInternalPath(dest_file_path_each)); | |
| 141 if (error != base::PLATFORM_FILE_OK) | |
| 142 return error; | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 if (operation_ == OPERATION_MOVE) { | |
| 147 PlatformFileError error = | |
| 148 FileUtilHelper::Delete(context_, src_util_, | |
| 149 src_path, true /* recursive */); | |
| 150 if (error != base::PLATFORM_FILE_OK) | |
| 151 return error; | |
| 152 } | |
| 153 | |
| 154 return base::PLATFORM_FILE_OK; | |
| 155 } | |
| 156 | |
| 157 PlatformFileError CrossFileUtilHelper::CopyOrMoveFile( | |
| 158 const FileSystemPath& src_path, | |
| 159 const FileSystemPath& dest_path) { | |
| 160 if ((src_path.origin() == dest_path.origin()) && | |
| 161 (src_path.type() == dest_path.type())) { | |
| 162 DCHECK(src_util_ == dest_util_); | |
| 163 // Source and destination are in the same FileSystemFileUtil; now we can | |
| 164 // safely call FileSystemFileUtil method on src_util_ (== dest_util_). | |
| 165 return src_util_->CopyOrMoveFile(context_, src_path, dest_path, | |
| 166 operation_ == OPERATION_COPY); | |
| 167 } | |
| 168 | |
| 169 // Resolve the src_path's underlying file path. | |
| 170 base::PlatformFileInfo file_info; | |
| 171 FilePath platform_file_path; | |
| 172 PlatformFileError error = src_util_->GetFileInfo( | |
| 173 context_, src_path, &file_info, &platform_file_path); | |
| 174 if (error != base::PLATFORM_FILE_OK) | |
| 175 return error; | |
| 176 | |
| 177 // Call CopyInForeignFile() on the dest_util_ with the resolved source path | |
| 178 // to perform limited cross-FileSystemFileUtil copy/move. | |
| 179 error = dest_util_->CopyInForeignFile( | |
| 180 context_, src_path.WithInternalPath(platform_file_path), dest_path); | |
| 181 | |
| 182 if (operation_ == OPERATION_COPY || error != base::PLATFORM_FILE_OK) | |
| 183 return error; | |
| 184 return src_util_->DeleteFile(context_, src_path); | |
| 185 } | |
| 186 | |
| 187 } // namespace fileapi | |
| OLD | NEW |