| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "webkit/browser/fileapi/copy_or_move_operation_delegate.h" | 5 #include "webkit/browser/fileapi/copy_or_move_operation_delegate.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
| 9 #include "webkit/browser/fileapi/copy_or_move_file_validator.h" | 9 #include "webkit/browser/fileapi/copy_or_move_file_validator.h" |
| 10 #include "webkit/browser/fileapi/file_system_context.h" | 10 #include "webkit/browser/fileapi/file_system_context.h" |
| 11 #include "webkit/browser/fileapi/file_system_operation_runner.h" | 11 #include "webkit/browser/fileapi/file_system_operation_runner.h" |
| 12 #include "webkit/browser/fileapi/file_system_url.h" | 12 #include "webkit/browser/fileapi/file_system_url.h" |
| 13 #include "webkit/browser/fileapi/recursive_operation_delegate.h" | 13 #include "webkit/browser/fileapi/recursive_operation_delegate.h" |
| 14 #include "webkit/common/blob/shareable_file_reference.h" | 14 #include "webkit/common/blob/shareable_file_reference.h" |
| 15 #include "webkit/common/fileapi/file_system_util.h" | 15 #include "webkit/common/fileapi/file_system_util.h" |
| 16 | 16 |
| 17 namespace fileapi { | 17 namespace fileapi { |
| 18 | 18 |
| 19 class CopyOrMoveOperationDelegate::CopyOrMoveImpl { |
| 20 public: |
| 21 virtual ~CopyOrMoveImpl() {} |
| 22 virtual void Run( |
| 23 const CopyOrMoveOperationDelegate::StatusCallback& callback) = 0; |
| 24 protected: |
| 25 CopyOrMoveImpl() {} |
| 26 DISALLOW_COPY_AND_ASSIGN(CopyOrMoveImpl); |
| 27 }; |
| 28 |
| 29 namespace { |
| 30 |
| 31 // Copies a file on a (same) file system. Just delegate the operation to |
| 32 // |operation_runner|. |
| 33 class CopyOrMoveOnSameFileSystemImpl |
| 34 : public CopyOrMoveOperationDelegate::CopyOrMoveImpl { |
| 35 public: |
| 36 CopyOrMoveOnSameFileSystemImpl( |
| 37 FileSystemOperationRunner* operation_runner, |
| 38 CopyOrMoveOperationDelegate::OperationType operation_type, |
| 39 const FileSystemURL& src_url, |
| 40 const FileSystemURL& dest_url) |
| 41 : operation_runner_(operation_runner), |
| 42 operation_type_(operation_type), |
| 43 src_url_(src_url), |
| 44 dest_url_(dest_url) { |
| 45 } |
| 46 |
| 47 virtual void Run( |
| 48 const CopyOrMoveOperationDelegate::StatusCallback& callback) OVERRIDE { |
| 49 if (operation_type_ == CopyOrMoveOperationDelegate::OPERATION_MOVE) { |
| 50 operation_runner_->MoveFileLocal(src_url_, dest_url_, callback); |
| 51 } else { |
| 52 // TODO(hidehiko): Support progress callback. |
| 53 operation_runner_->CopyFileLocal( |
| 54 src_url_, dest_url_, |
| 55 FileSystemOperationRunner::CopyFileProgressCallback(), callback); |
| 56 } |
| 57 } |
| 58 |
| 59 private: |
| 60 FileSystemOperationRunner* operation_runner_; |
| 61 CopyOrMoveOperationDelegate::OperationType operation_type_; |
| 62 FileSystemURL src_url_; |
| 63 FileSystemURL dest_url_; |
| 64 DISALLOW_COPY_AND_ASSIGN(CopyOrMoveOnSameFileSystemImpl); |
| 65 }; |
| 66 |
| 67 // Specifically for cross file system copy/move operation, this class creates |
| 68 // a snapshot file, validates it if necessary, runs copying process, |
| 69 // validates the created file, and removes source file for move (noop for |
| 70 // copy). |
| 71 class SnapshotCopyOrMoveImpl |
| 72 : public CopyOrMoveOperationDelegate::CopyOrMoveImpl { |
| 73 public: |
| 74 SnapshotCopyOrMoveImpl( |
| 75 FileSystemOperationRunner* operation_runner, |
| 76 CopyOrMoveOperationDelegate::OperationType operation_type, |
| 77 const FileSystemURL& src_url, |
| 78 const FileSystemURL& dest_url, |
| 79 CopyOrMoveFileValidatorFactory* validator_factory) |
| 80 : operation_runner_(operation_runner), |
| 81 operation_type_(operation_type), |
| 82 src_url_(src_url), |
| 83 dest_url_(dest_url), |
| 84 validator_factory_(validator_factory), |
| 85 weak_factory_(this) { |
| 86 } |
| 87 |
| 88 virtual void Run( |
| 89 const CopyOrMoveOperationDelegate::StatusCallback& callback) OVERRIDE { |
| 90 operation_runner_->CreateSnapshotFile( |
| 91 src_url_, |
| 92 base::Bind(&SnapshotCopyOrMoveImpl::RunAfterCreateSnapshot, |
| 93 weak_factory_.GetWeakPtr(), callback)); |
| 94 } |
| 95 |
| 96 private: |
| 97 void RunAfterCreateSnapshot( |
| 98 const CopyOrMoveOperationDelegate::StatusCallback& callback, |
| 99 base::PlatformFileError error, |
| 100 const base::PlatformFileInfo& file_info, |
| 101 const base::FilePath& platform_path, |
| 102 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { |
| 103 if (error != base::PLATFORM_FILE_OK) { |
| 104 callback.Run(error); |
| 105 return; |
| 106 } |
| 107 |
| 108 // For now we assume CreateSnapshotFile always return a valid local file |
| 109 // path. |
| 110 DCHECK(!platform_path.empty()); |
| 111 |
| 112 if (!validator_factory_) { |
| 113 // No validation is needed. |
| 114 RunAfterPreWriteValidation( |
| 115 platform_path, file_ref, callback, base::PLATFORM_FILE_OK); |
| 116 return; |
| 117 } |
| 118 |
| 119 // Run pre write validation. |
| 120 PreWriteValidation( |
| 121 platform_path, |
| 122 base::Bind(&SnapshotCopyOrMoveImpl::RunAfterPreWriteValidation, |
| 123 weak_factory_.GetWeakPtr(), |
| 124 platform_path, file_ref, callback)); |
| 125 } |
| 126 |
| 127 void RunAfterPreWriteValidation( |
| 128 const base::FilePath& platform_path, |
| 129 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref, |
| 130 const CopyOrMoveOperationDelegate::StatusCallback& callback, |
| 131 base::PlatformFileError error) { |
| 132 if (error != base::PLATFORM_FILE_OK) { |
| 133 callback.Run(error); |
| 134 return; |
| 135 } |
| 136 |
| 137 // |file_ref| is unused but necessary to keep the file alive until |
| 138 // CopyInForeignFile() is completed. |
| 139 operation_runner_->CopyInForeignFile( |
| 140 platform_path, dest_url_, |
| 141 base::Bind(&SnapshotCopyOrMoveImpl::RunAfterCopyInForeignFile, |
| 142 weak_factory_.GetWeakPtr(), file_ref, callback)); |
| 143 } |
| 144 |
| 145 void RunAfterCopyInForeignFile( |
| 146 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref, |
| 147 const CopyOrMoveOperationDelegate::StatusCallback& callback, |
| 148 base::PlatformFileError error) { |
| 149 if (error != base::PLATFORM_FILE_OK) { |
| 150 callback.Run(error); |
| 151 return; |
| 152 } |
| 153 |
| 154 // |validator_| is NULL when the destination filesystem does not do |
| 155 // validation. |
| 156 if (!validator_) { |
| 157 // No validation is needed. |
| 158 RunAfterPostWriteValidation(callback, base::PLATFORM_FILE_OK); |
| 159 return; |
| 160 } |
| 161 |
| 162 PostWriteValidation( |
| 163 base::Bind(&SnapshotCopyOrMoveImpl::RunAfterPostWriteValidation, |
| 164 weak_factory_.GetWeakPtr(), callback)); |
| 165 } |
| 166 |
| 167 void RunAfterPostWriteValidation( |
| 168 const CopyOrMoveOperationDelegate::StatusCallback& callback, |
| 169 base::PlatformFileError error) { |
| 170 if (error != base::PLATFORM_FILE_OK) { |
| 171 // Failed to validate. Remove the destination file. |
| 172 operation_runner_->Remove( |
| 173 dest_url_, true /* recursive */, |
| 174 base::Bind(&SnapshotCopyOrMoveImpl::DidRemoveDestForError, |
| 175 weak_factory_.GetWeakPtr(), error, callback)); |
| 176 return; |
| 177 } |
| 178 |
| 179 if (operation_type_ == CopyOrMoveOperationDelegate::OPERATION_COPY) { |
| 180 callback.Run(base::PLATFORM_FILE_OK); |
| 181 return; |
| 182 } |
| 183 |
| 184 DCHECK_EQ(CopyOrMoveOperationDelegate::OPERATION_MOVE, operation_type_); |
| 185 |
| 186 // Remove the source for finalizing move operation. |
| 187 operation_runner_->Remove( |
| 188 src_url_, true /* recursive */, |
| 189 base::Bind(&SnapshotCopyOrMoveImpl::RunAfterRemoveSourceForMove, |
| 190 weak_factory_.GetWeakPtr(), callback)); |
| 191 } |
| 192 |
| 193 void RunAfterRemoveSourceForMove( |
| 194 const CopyOrMoveOperationDelegate::StatusCallback& callback, |
| 195 base::PlatformFileError error) { |
| 196 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) |
| 197 error = base::PLATFORM_FILE_OK; |
| 198 callback.Run(error); |
| 199 } |
| 200 |
| 201 void DidRemoveDestForError( |
| 202 base::PlatformFileError prior_error, |
| 203 const CopyOrMoveOperationDelegate::StatusCallback& callback, |
| 204 base::PlatformFileError error) { |
| 205 if (error != base::PLATFORM_FILE_OK) { |
| 206 VLOG(1) << "Error removing destination file after validation error: " |
| 207 << error; |
| 208 } |
| 209 callback.Run(prior_error); |
| 210 } |
| 211 |
| 212 // Runs pre-write validation. |
| 213 void PreWriteValidation( |
| 214 const base::FilePath& platform_path, |
| 215 const CopyOrMoveOperationDelegate::StatusCallback& callback) { |
| 216 DCHECK(validator_factory_); |
| 217 validator_.reset( |
| 218 validator_factory_->CreateCopyOrMoveFileValidator( |
| 219 src_url_, platform_path)); |
| 220 validator_->StartPreWriteValidation(callback); |
| 221 } |
| 222 |
| 223 // Runs post-write validation. |
| 224 void PostWriteValidation( |
| 225 const CopyOrMoveOperationDelegate::StatusCallback& callback) { |
| 226 operation_runner_->CreateSnapshotFile( |
| 227 dest_url_, |
| 228 base::Bind( |
| 229 &SnapshotCopyOrMoveImpl::PostWriteValidationAfterCreateSnapshotFile, |
| 230 weak_factory_.GetWeakPtr(), callback)); |
| 231 } |
| 232 |
| 233 void PostWriteValidationAfterCreateSnapshotFile( |
| 234 const CopyOrMoveOperationDelegate::StatusCallback& callback, |
| 235 base::PlatformFileError error, |
| 236 const base::PlatformFileInfo& file_info, |
| 237 const base::FilePath& platform_path, |
| 238 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { |
| 239 if (error != base::PLATFORM_FILE_OK) { |
| 240 callback.Run(error); |
| 241 return; |
| 242 } |
| 243 |
| 244 DCHECK(validator_); |
| 245 // Note: file_ref passed here to keep the file alive until after |
| 246 // the StartPostWriteValidation operation finishes. |
| 247 validator_->StartPostWriteValidation( |
| 248 platform_path, |
| 249 base::Bind(&SnapshotCopyOrMoveImpl::DidPostWriteValidation, |
| 250 weak_factory_.GetWeakPtr(), file_ref, callback)); |
| 251 } |
| 252 |
| 253 // |file_ref| is unused; it is passed here to make sure the reference is |
| 254 // alive until after post-write validation is complete. |
| 255 void DidPostWriteValidation( |
| 256 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref, |
| 257 const CopyOrMoveOperationDelegate::StatusCallback& callback, |
| 258 base::PlatformFileError error) { |
| 259 callback.Run(error); |
| 260 } |
| 261 |
| 262 FileSystemOperationRunner* operation_runner_; |
| 263 CopyOrMoveOperationDelegate::OperationType operation_type_; |
| 264 FileSystemURL src_url_; |
| 265 FileSystemURL dest_url_; |
| 266 CopyOrMoveFileValidatorFactory* validator_factory_; |
| 267 scoped_ptr<CopyOrMoveFileValidator> validator_; |
| 268 |
| 269 base::WeakPtrFactory<SnapshotCopyOrMoveImpl> weak_factory_; |
| 270 DISALLOW_COPY_AND_ASSIGN(SnapshotCopyOrMoveImpl); |
| 271 }; |
| 272 |
| 273 } // namespace |
| 274 |
| 275 |
| 19 CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate( | 276 CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate( |
| 20 FileSystemContext* file_system_context, | 277 FileSystemContext* file_system_context, |
| 21 const FileSystemURL& src_root, | 278 const FileSystemURL& src_root, |
| 22 const FileSystemURL& dest_root, | 279 const FileSystemURL& dest_root, |
| 23 OperationType operation_type, | 280 OperationType operation_type, |
| 24 const StatusCallback& callback) | 281 const StatusCallback& callback) |
| 25 : RecursiveOperationDelegate(file_system_context), | 282 : RecursiveOperationDelegate(file_system_context), |
| 26 src_root_(src_root), | 283 src_root_(src_root), |
| 27 dest_root_(dest_root), | 284 dest_root_(dest_root), |
| 28 operation_type_(operation_type), | 285 operation_type_(operation_type), |
| 29 callback_(callback), | 286 callback_(callback), |
| 30 weak_factory_(this) { | 287 weak_factory_(this) { |
| 31 same_file_system_ = src_root_.IsInSameFileSystem(dest_root_); | 288 same_file_system_ = src_root_.IsInSameFileSystem(dest_root_); |
| 32 } | 289 } |
| 33 | 290 |
| 34 CopyOrMoveOperationDelegate::~CopyOrMoveOperationDelegate() { | 291 CopyOrMoveOperationDelegate::~CopyOrMoveOperationDelegate() { |
| 292 STLDeleteElements(&running_copy_set_); |
| 35 } | 293 } |
| 36 | 294 |
| 37 void CopyOrMoveOperationDelegate::Run() { | 295 void CopyOrMoveOperationDelegate::Run() { |
| 38 // Not supported; this should never be called. | 296 // Not supported; this should never be called. |
| 39 NOTREACHED(); | 297 NOTREACHED(); |
| 40 } | 298 } |
| 41 | 299 |
| 42 void CopyOrMoveOperationDelegate::RunRecursively() { | 300 void CopyOrMoveOperationDelegate::RunRecursively() { |
| 43 // Perform light-weight checks first. | 301 // Perform light-weight checks first. |
| 44 | 302 |
| 45 // It is an error to try to copy/move an entry into its child. | 303 // It is an error to try to copy/move an entry into its child. |
| 46 if (same_file_system_ && src_root_.path().IsParent(dest_root_.path())) { | 304 if (same_file_system_ && src_root_.path().IsParent(dest_root_.path())) { |
| 47 callback_.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); | 305 callback_.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); |
| 48 return; | 306 return; |
| 49 } | 307 } |
| 50 | 308 |
| 51 // It is an error to copy/move an entry into the same path. | 309 // It is an error to copy/move an entry into the same path. |
| 52 if (same_file_system_ && src_root_.path() == dest_root_.path()) { | 310 if (same_file_system_ && src_root_.path() == dest_root_.path()) { |
| 53 callback_.Run(base::PLATFORM_FILE_ERROR_EXISTS); | 311 callback_.Run(base::PLATFORM_FILE_ERROR_EXISTS); |
| 54 return; | 312 return; |
| 55 } | 313 } |
| 56 | 314 |
| 57 // First try to copy/move it as a file. | 315 // First try to copy/move it as a file. |
| 58 CopyOrMoveFile(URLPair(src_root_, dest_root_), | 316 CopyOrMoveFile(src_root_, dest_root_, |
| 59 base::Bind(&CopyOrMoveOperationDelegate::DidTryCopyOrMoveFile, | 317 base::Bind(&CopyOrMoveOperationDelegate::DidTryCopyOrMoveFile, |
| 60 weak_factory_.GetWeakPtr())); | 318 weak_factory_.GetWeakPtr())); |
| 61 } | 319 } |
| 62 | 320 |
| 63 void CopyOrMoveOperationDelegate::ProcessFile(const FileSystemURL& src_url, | 321 void CopyOrMoveOperationDelegate::ProcessFile(const FileSystemURL& src_url, |
| 64 const StatusCallback& callback) { | 322 const StatusCallback& callback) { |
| 65 CopyOrMoveFile(URLPair(src_url, CreateDestURL(src_url)), callback); | 323 CopyOrMoveFile(src_url, CreateDestURL(src_url), callback); |
| 66 } | 324 } |
| 67 | 325 |
| 68 void CopyOrMoveOperationDelegate::ProcessDirectory(const FileSystemURL& src_url, | 326 void CopyOrMoveOperationDelegate::ProcessDirectory(const FileSystemURL& src_url, |
| 69 const StatusCallback& callback) { | 327 const StatusCallback& callback) { |
| 70 FileSystemURL dest_url = CreateDestURL(src_url); | 328 FileSystemURL dest_url = CreateDestURL(src_url); |
| 71 | 329 |
| 72 // If operation_type == Move we may need to record directories and | 330 // If operation_type == Move we may need to record directories and |
| 73 // restore directory timestamps in the end, though it may have | 331 // restore directory timestamps in the end, though it may have |
| 74 // negative performance impact. | 332 // negative performance impact. |
| 75 // See http://crbug.com/171284 for more details. | 333 // See http://crbug.com/171284 for more details. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 // Start to process the source directory recursively. | 367 // Start to process the source directory recursively. |
| 110 // TODO(kinuko): This could be too expensive for same_file_system_==true | 368 // TODO(kinuko): This could be too expensive for same_file_system_==true |
| 111 // and operation==MOVE case, probably we can just rename the root directory. | 369 // and operation==MOVE case, probably we can just rename the root directory. |
| 112 // http://crbug.com/172187 | 370 // http://crbug.com/172187 |
| 113 StartRecursiveOperation( | 371 StartRecursiveOperation( |
| 114 src_root_, | 372 src_root_, |
| 115 base::Bind(&CopyOrMoveOperationDelegate::DidFinishRecursiveCopyDir, | 373 base::Bind(&CopyOrMoveOperationDelegate::DidFinishRecursiveCopyDir, |
| 116 weak_factory_.GetWeakPtr(), src_root_, callback_)); | 374 weak_factory_.GetWeakPtr(), src_root_, callback_)); |
| 117 } | 375 } |
| 118 | 376 |
| 119 void CopyOrMoveOperationDelegate::CopyOrMoveFile( | |
| 120 const URLPair& url_pair, | |
| 121 const StatusCallback& callback) { | |
| 122 // Same filesystem case. | |
| 123 if (same_file_system_) { | |
| 124 if (operation_type_ == OPERATION_MOVE) { | |
| 125 operation_runner()->MoveFileLocal(url_pair.src, url_pair.dest, callback); | |
| 126 } else { | |
| 127 // TODO(hidehiko): Support progress callback. | |
| 128 operation_runner()->CopyFileLocal( | |
| 129 url_pair.src, url_pair.dest, | |
| 130 FileSystemOperationRunner::CopyFileProgressCallback(), callback); | |
| 131 } | |
| 132 return; | |
| 133 } | |
| 134 | |
| 135 // Cross filesystem case. | |
| 136 // Perform CreateSnapshotFile, CopyInForeignFile and then calls | |
| 137 // copy_callback which removes the source file if operation_type == MOVE. | |
| 138 StatusCallback copy_callback = | |
| 139 base::Bind(&CopyOrMoveOperationDelegate::DidFinishCopy, | |
| 140 weak_factory_.GetWeakPtr(), url_pair, callback); | |
| 141 operation_runner()->CreateSnapshotFile( | |
| 142 url_pair.src, | |
| 143 base::Bind(&CopyOrMoveOperationDelegate::DidCreateSnapshot, | |
| 144 weak_factory_.GetWeakPtr(), url_pair, copy_callback)); | |
| 145 } | |
| 146 | |
| 147 void CopyOrMoveOperationDelegate::DidCreateSnapshot( | |
| 148 const URLPair& url_pair, | |
| 149 const StatusCallback& callback, | |
| 150 base::PlatformFileError error, | |
| 151 const base::PlatformFileInfo& file_info, | |
| 152 const base::FilePath& platform_path, | |
| 153 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { | |
| 154 if (error != base::PLATFORM_FILE_OK) { | |
| 155 callback.Run(error); | |
| 156 return; | |
| 157 } | |
| 158 current_file_ref_ = file_ref; | |
| 159 | |
| 160 // For now we assume CreateSnapshotFile always return a valid local file path. | |
| 161 // TODO(kinuko): Otherwise create a FileStreamReader to perform a copy/move. | |
| 162 DCHECK(!platform_path.empty()); | |
| 163 | |
| 164 CopyOrMoveFileValidatorFactory* factory = | |
| 165 file_system_context()->GetCopyOrMoveFileValidatorFactory( | |
| 166 dest_root_.type(), &error); | |
| 167 if (error != base::PLATFORM_FILE_OK) { | |
| 168 callback.Run(error); | |
| 169 return; | |
| 170 } | |
| 171 if (!factory) { | |
| 172 DidValidateFile(url_pair.dest, callback, file_info, platform_path, error); | |
| 173 return; | |
| 174 } | |
| 175 | |
| 176 validator_.reset( | |
| 177 factory->CreateCopyOrMoveFileValidator(url_pair.src, platform_path)); | |
| 178 validator_->StartPreWriteValidation( | |
| 179 base::Bind(&CopyOrMoveOperationDelegate::DidValidateFile, | |
| 180 weak_factory_.GetWeakPtr(), | |
| 181 url_pair.dest, callback, file_info, platform_path)); | |
| 182 } | |
| 183 | |
| 184 void CopyOrMoveOperationDelegate::DidValidateFile( | |
| 185 const FileSystemURL& dest, | |
| 186 const StatusCallback& callback, | |
| 187 const base::PlatformFileInfo& file_info, | |
| 188 const base::FilePath& platform_path, | |
| 189 base::PlatformFileError error) { | |
| 190 if (error != base::PLATFORM_FILE_OK) { | |
| 191 callback.Run(error); | |
| 192 return; | |
| 193 } | |
| 194 | |
| 195 operation_runner()->CopyInForeignFile(platform_path, dest, callback); | |
| 196 } | |
| 197 | |
| 198 void CopyOrMoveOperationDelegate::DidFinishRecursiveCopyDir( | 377 void CopyOrMoveOperationDelegate::DidFinishRecursiveCopyDir( |
| 199 const FileSystemURL& src, | 378 const FileSystemURL& src, |
| 200 const StatusCallback& callback, | 379 const StatusCallback& callback, |
| 201 base::PlatformFileError error) { | 380 base::PlatformFileError error) { |
| 202 if (error != base::PLATFORM_FILE_OK || | 381 if (error != base::PLATFORM_FILE_OK || |
| 203 operation_type_ == OPERATION_COPY) { | 382 operation_type_ == OPERATION_COPY) { |
| 204 callback.Run(error); | 383 callback.Run(error); |
| 205 return; | 384 return; |
| 206 } | 385 } |
| 207 | 386 |
| 208 DCHECK_EQ(OPERATION_MOVE, operation_type_); | 387 DCHECK_EQ(OPERATION_MOVE, operation_type_); |
| 209 | 388 |
| 210 // Remove the source for finalizing move operation. | 389 // Remove the source for finalizing move operation. |
| 211 operation_runner()->Remove( | 390 operation_runner()->Remove( |
| 212 src, true /* recursive */, | 391 src, true /* recursive */, |
| 213 base::Bind(&CopyOrMoveOperationDelegate::DidRemoveSourceForMove, | 392 base::Bind(&CopyOrMoveOperationDelegate::DidRemoveSourceForMove, |
| 214 weak_factory_.GetWeakPtr(), callback)); | 393 weak_factory_.GetWeakPtr(), callback)); |
| 215 } | 394 } |
| 216 | 395 |
| 217 void CopyOrMoveOperationDelegate::DidFinishCopy( | |
| 218 const URLPair& url_pair, | |
| 219 const StatusCallback& callback, | |
| 220 base::PlatformFileError error) { | |
| 221 if (error != base::PLATFORM_FILE_OK) { | |
| 222 callback.Run(error); | |
| 223 return; | |
| 224 } | |
| 225 | |
| 226 // |validator_| is NULL in the same-filesystem case or when the destination | |
| 227 // filesystem does not do validation. | |
| 228 if (!validator_.get()) { | |
| 229 scoped_refptr<webkit_blob::ShareableFileReference> file_ref; | |
| 230 DidPostWriteValidation(url_pair, callback, file_ref, | |
| 231 base::PLATFORM_FILE_OK); | |
| 232 return; | |
| 233 } | |
| 234 | |
| 235 DCHECK(!same_file_system_); | |
| 236 operation_runner()->CreateSnapshotFile( | |
| 237 url_pair.dest, | |
| 238 base::Bind(&CopyOrMoveOperationDelegate::DoPostWriteValidation, | |
| 239 weak_factory_.GetWeakPtr(), url_pair, callback)); | |
| 240 } | |
| 241 | |
| 242 void CopyOrMoveOperationDelegate::DoPostWriteValidation( | |
| 243 const URLPair& url_pair, | |
| 244 const StatusCallback& callback, | |
| 245 base::PlatformFileError error, | |
| 246 const base::PlatformFileInfo& file_info, | |
| 247 const base::FilePath& platform_path, | |
| 248 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { | |
| 249 if (error != base::PLATFORM_FILE_OK) { | |
| 250 operation_runner()->Remove( | |
| 251 url_pair.dest, true, | |
| 252 base::Bind(&CopyOrMoveOperationDelegate::DidRemoveDestForError, | |
| 253 weak_factory_.GetWeakPtr(), error, callback)); | |
| 254 return; | |
| 255 } | |
| 256 | |
| 257 DCHECK(validator_.get()); | |
| 258 // Note: file_ref passed here to keep the file alive until after | |
| 259 // the StartPostWriteValidation operation finishes. | |
| 260 validator_->StartPostWriteValidation( | |
| 261 platform_path, | |
| 262 base::Bind(&CopyOrMoveOperationDelegate::DidPostWriteValidation, | |
| 263 weak_factory_.GetWeakPtr(), url_pair, callback, file_ref)); | |
| 264 } | |
| 265 | |
| 266 // |file_ref| is unused; it is passed here to make sure the reference is | |
| 267 // alive until after post-write validation is complete. | |
| 268 void CopyOrMoveOperationDelegate::DidPostWriteValidation( | |
| 269 const URLPair& url_pair, | |
| 270 const StatusCallback& callback, | |
| 271 const scoped_refptr<webkit_blob::ShareableFileReference>& /*file_ref*/, | |
| 272 base::PlatformFileError error) { | |
| 273 if (error != base::PLATFORM_FILE_OK) { | |
| 274 operation_runner()->Remove( | |
| 275 url_pair.dest, true, | |
| 276 base::Bind(&CopyOrMoveOperationDelegate::DidRemoveDestForError, | |
| 277 weak_factory_.GetWeakPtr(), error, callback)); | |
| 278 return; | |
| 279 } | |
| 280 | |
| 281 if (operation_type_ == OPERATION_COPY) { | |
| 282 callback.Run(error); | |
| 283 return; | |
| 284 } | |
| 285 | |
| 286 DCHECK_EQ(OPERATION_MOVE, operation_type_); | |
| 287 | |
| 288 // Remove the source for finalizing move operation. | |
| 289 operation_runner()->Remove( | |
| 290 url_pair.src, true /* recursive */, | |
| 291 base::Bind(&CopyOrMoveOperationDelegate::DidRemoveSourceForMove, | |
| 292 weak_factory_.GetWeakPtr(), callback)); | |
| 293 } | |
| 294 | |
| 295 void CopyOrMoveOperationDelegate::DidRemoveSourceForMove( | 396 void CopyOrMoveOperationDelegate::DidRemoveSourceForMove( |
| 296 const StatusCallback& callback, | 397 const StatusCallback& callback, |
| 297 base::PlatformFileError error) { | 398 base::PlatformFileError error) { |
| 298 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) | 399 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) |
| 299 error = base::PLATFORM_FILE_OK; | 400 error = base::PLATFORM_FILE_OK; |
| 300 callback.Run(error); | 401 callback.Run(error); |
| 301 } | 402 } |
| 302 | 403 |
| 404 void CopyOrMoveOperationDelegate::CopyOrMoveFile( |
| 405 const FileSystemURL& src_url, |
| 406 const FileSystemURL& dest_url, |
| 407 const StatusCallback& callback) { |
| 408 CopyOrMoveImpl* impl = NULL; |
| 409 if (same_file_system_) { |
| 410 impl = new CopyOrMoveOnSameFileSystemImpl( |
| 411 operation_runner(), operation_type_, src_url, dest_url); |
| 412 } else { |
| 413 // Cross filesystem case. |
| 414 // TODO(hidehiko): Support stream based copy. crbug.com/279287. |
| 415 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; |
| 416 CopyOrMoveFileValidatorFactory* validator_factory = |
| 417 file_system_context()->GetCopyOrMoveFileValidatorFactory( |
| 418 dest_root_.type(), &error); |
| 419 if (error != base::PLATFORM_FILE_OK) { |
| 420 callback.Run(error); |
| 421 return; |
| 422 } |
| 423 |
| 424 impl = new SnapshotCopyOrMoveImpl( |
| 425 operation_runner(), operation_type_, src_url, dest_url, |
| 426 validator_factory); |
| 427 } |
| 428 |
| 429 // Register the running task. |
| 430 running_copy_set_.insert(impl); |
| 431 impl->Run(base::Bind(&CopyOrMoveOperationDelegate::DidCopyOrMoveFile, |
| 432 weak_factory_.GetWeakPtr(), impl, callback)); |
| 433 } |
| 434 |
| 435 void CopyOrMoveOperationDelegate::DidCopyOrMoveFile( |
| 436 CopyOrMoveImpl* impl, |
| 437 const StatusCallback& callback, |
| 438 base::PlatformFileError error) { |
| 439 running_copy_set_.erase(impl); |
| 440 delete impl; |
| 441 callback.Run(error); |
| 442 } |
| 443 |
| 303 FileSystemURL CopyOrMoveOperationDelegate::CreateDestURL( | 444 FileSystemURL CopyOrMoveOperationDelegate::CreateDestURL( |
| 304 const FileSystemURL& src_url) const { | 445 const FileSystemURL& src_url) const { |
| 305 DCHECK_EQ(src_root_.type(), src_url.type()); | 446 DCHECK_EQ(src_root_.type(), src_url.type()); |
| 306 DCHECK_EQ(src_root_.origin(), src_url.origin()); | 447 DCHECK_EQ(src_root_.origin(), src_url.origin()); |
| 307 | 448 |
| 308 base::FilePath relative = dest_root_.virtual_path(); | 449 base::FilePath relative = dest_root_.virtual_path(); |
| 309 src_root_.virtual_path().AppendRelativePath(src_url.virtual_path(), | 450 src_root_.virtual_path().AppendRelativePath(src_url.virtual_path(), |
| 310 &relative); | 451 &relative); |
| 311 return file_system_context()->CreateCrackedFileSystemURL( | 452 return file_system_context()->CreateCrackedFileSystemURL( |
| 312 dest_root_.origin(), | 453 dest_root_.origin(), |
| 313 dest_root_.mount_type(), | 454 dest_root_.mount_type(), |
| 314 relative); | 455 relative); |
| 315 } | 456 } |
| 316 | 457 |
| 317 void CopyOrMoveOperationDelegate::DidRemoveDestForError( | |
| 318 base::PlatformFileError prior_error, | |
| 319 const StatusCallback& callback, | |
| 320 base::PlatformFileError error) { | |
| 321 if (error != base::PLATFORM_FILE_OK) { | |
| 322 VLOG(1) << "Error removing destination file after validation error: " | |
| 323 << error; | |
| 324 } | |
| 325 callback.Run(prior_error); | |
| 326 } | |
| 327 | |
| 328 } // namespace fileapi | 458 } // namespace fileapi |
| OLD | NEW |