| 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/cross_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_context.h" | 11 #include "webkit/browser/fileapi/file_system_operation_context.h" |
| 12 #include "webkit/browser/fileapi/file_system_url.h" | 12 #include "webkit/browser/fileapi/file_system_url.h" |
| 13 #include "webkit/browser/fileapi/local_file_system_operation.h" | 13 #include "webkit/browser/fileapi/local_file_system_operation.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 CrossOperationDelegate::CrossOperationDelegate( | 19 CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate( |
| 20 FileSystemContext* file_system_context, | 20 FileSystemContext* file_system_context, |
| 21 scoped_ptr<LocalFileSystemOperation> src_root_operation, | 21 scoped_ptr<LocalFileSystemOperation> src_root_operation, |
| 22 LocalFileSystemOperation* dest_root_operation, | 22 LocalFileSystemOperation* dest_root_operation, |
| 23 const FileSystemURL& src_root, | 23 const FileSystemURL& src_root, |
| 24 const FileSystemURL& dest_root, | 24 const FileSystemURL& dest_root, |
| 25 OperationType operation_type, | 25 OperationType operation_type, |
| 26 const StatusCallback& callback) | 26 const StatusCallback& callback) |
| 27 : RecursiveOperationDelegate(file_system_context, dest_root_operation), | 27 : RecursiveOperationDelegate(file_system_context, dest_root_operation), |
| 28 src_root_(src_root), | 28 src_root_(src_root), |
| 29 dest_root_(dest_root), | 29 dest_root_(dest_root), |
| 30 operation_type_(operation_type), | 30 operation_type_(operation_type), |
| 31 callback_(callback), | 31 callback_(callback), |
| 32 src_root_operation_(src_root_operation.Pass()) { | 32 src_root_operation_(src_root_operation.Pass()) { |
| 33 same_file_system_ = src_root_.IsInSameFileSystem(dest_root_); | 33 same_file_system_ = src_root_.IsInSameFileSystem(dest_root_); |
| 34 } | 34 } |
| 35 | 35 |
| 36 CrossOperationDelegate::~CrossOperationDelegate() { | 36 CopyOrMoveOperationDelegate::~CopyOrMoveOperationDelegate() { |
| 37 } | 37 } |
| 38 | 38 |
| 39 void CrossOperationDelegate::Run() { | 39 void CopyOrMoveOperationDelegate::Run() { |
| 40 // Not supported; this should never be called. | 40 // Not supported; this should never be called. |
| 41 NOTREACHED(); | 41 NOTREACHED(); |
| 42 } | 42 } |
| 43 | 43 |
| 44 void CrossOperationDelegate::RunRecursively() { | 44 void CopyOrMoveOperationDelegate::RunRecursively() { |
| 45 // Perform light-weight checks first. | 45 // Perform light-weight checks first. |
| 46 | 46 |
| 47 // It is an error to try to copy/move an entry into its child. | 47 // It is an error to try to copy/move an entry into its child. |
| 48 if (same_file_system_ && src_root_.path().IsParent(dest_root_.path())) { | 48 if (same_file_system_ && src_root_.path().IsParent(dest_root_.path())) { |
| 49 callback_.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); | 49 callback_.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); |
| 50 return; | 50 return; |
| 51 } | 51 } |
| 52 | 52 |
| 53 // It is an error to copy/move an entry into the same path. | 53 // It is an error to copy/move an entry into the same path. |
| 54 if (same_file_system_ && src_root_.path() == dest_root_.path()) { | 54 if (same_file_system_ && src_root_.path() == dest_root_.path()) { |
| 55 callback_.Run(base::PLATFORM_FILE_ERROR_EXISTS); | 55 callback_.Run(base::PLATFORM_FILE_ERROR_EXISTS); |
| 56 return; | 56 return; |
| 57 } | 57 } |
| 58 | 58 |
| 59 // First try to copy/move it as a file. | 59 // First try to copy/move it as a file. |
| 60 CopyOrMoveFile(URLPair(src_root_, dest_root_), | 60 CopyOrMoveFile(URLPair(src_root_, dest_root_), |
| 61 base::Bind(&CrossOperationDelegate::DidTryCopyOrMoveFile, | 61 base::Bind(&CopyOrMoveOperationDelegate::DidTryCopyOrMoveFile, |
| 62 AsWeakPtr())); | 62 AsWeakPtr())); |
| 63 } | 63 } |
| 64 | 64 |
| 65 void CrossOperationDelegate::ProcessFile(const FileSystemURL& src_url, | 65 void CopyOrMoveOperationDelegate::ProcessFile(const FileSystemURL& src_url, |
| 66 const StatusCallback& callback) { | 66 const StatusCallback& callback) { |
| 67 CopyOrMoveFile(URLPair(src_url, CreateDestURL(src_url)), callback); | 67 CopyOrMoveFile(URLPair(src_url, CreateDestURL(src_url)), callback); |
| 68 } | 68 } |
| 69 | 69 |
| 70 void CrossOperationDelegate::ProcessDirectory(const FileSystemURL& src_url, | 70 void CopyOrMoveOperationDelegate::ProcessDirectory(const FileSystemURL& src_url, |
| 71 const StatusCallback& callback) { | 71 const StatusCallback& callback) { |
| 72 FileSystemURL dest_url = CreateDestURL(src_url); | 72 FileSystemURL dest_url = CreateDestURL(src_url); |
| 73 | 73 |
| 74 // If operation_type == Move we may need to record directories and | 74 // If operation_type == Move we may need to record directories and |
| 75 // restore directory timestamps in the end, though it may have | 75 // restore directory timestamps in the end, though it may have |
| 76 // negative performance impact. | 76 // negative performance impact. |
| 77 // See http://crbug.com/171284 for more details. | 77 // See http://crbug.com/171284 for more details. |
| 78 NewDestOperation()->CreateDirectory( | 78 NewDestOperation()->CreateDirectory( |
| 79 dest_url, false /* exclusive */, false /* recursive */, callback); | 79 dest_url, false /* exclusive */, false /* recursive */, callback); |
| 80 } | 80 } |
| 81 | 81 |
| 82 void CrossOperationDelegate::DidTryCopyOrMoveFile( | 82 void CopyOrMoveOperationDelegate::DidTryCopyOrMoveFile( |
| 83 base::PlatformFileError error) { | 83 base::PlatformFileError error) { |
| 84 if (error == base::PLATFORM_FILE_OK || | 84 if (error == base::PLATFORM_FILE_OK || |
| 85 error != base::PLATFORM_FILE_ERROR_NOT_A_FILE) { | 85 error != base::PLATFORM_FILE_ERROR_NOT_A_FILE) { |
| 86 callback_.Run(error); | 86 callback_.Run(error); |
| 87 return; | 87 return; |
| 88 } | 88 } |
| 89 | 89 |
| 90 // The src_root_ looks to be a directory. | 90 // The src_root_ looks to be a directory. |
| 91 // Try removing the dest_root_ to see if it exists and/or it is an | 91 // Try removing the dest_root_ to see if it exists and/or it is an |
| 92 // empty directory. | 92 // empty directory. |
| 93 NewDestOperation()->RemoveDirectory( | 93 NewDestOperation()->RemoveDirectory( |
| 94 dest_root_, base::Bind(&CrossOperationDelegate::DidTryRemoveDestRoot, | 94 dest_root_, base::Bind(&CopyOrMoveOperationDelegate::DidTryRemoveDestRoot, |
| 95 AsWeakPtr())); | 95 AsWeakPtr())); |
| 96 } | 96 } |
| 97 | 97 |
| 98 void CrossOperationDelegate::DidTryRemoveDestRoot( | 98 void CopyOrMoveOperationDelegate::DidTryRemoveDestRoot( |
| 99 base::PlatformFileError error) { | 99 base::PlatformFileError error) { |
| 100 if (error == base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY) { | 100 if (error == base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY) { |
| 101 callback_.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); | 101 callback_.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); |
| 102 return; | 102 return; |
| 103 } | 103 } |
| 104 if (error != base::PLATFORM_FILE_OK && | 104 if (error != base::PLATFORM_FILE_OK && |
| 105 error != base::PLATFORM_FILE_ERROR_NOT_FOUND) { | 105 error != base::PLATFORM_FILE_ERROR_NOT_FOUND) { |
| 106 callback_.Run(error); | 106 callback_.Run(error); |
| 107 return; | 107 return; |
| 108 } | 108 } |
| 109 | 109 |
| 110 // Start to process the source directory recursively. | 110 // Start to process the source directory recursively. |
| 111 // TODO(kinuko): This could be too expensive for same_file_system_==true | 111 // TODO(kinuko): This could be too expensive for same_file_system_==true |
| 112 // and operation==MOVE case, probably we can just rename the root directory. | 112 // and operation==MOVE case, probably we can just rename the root directory. |
| 113 // http://crbug.com/172187 | 113 // http://crbug.com/172187 |
| 114 StartRecursiveOperation( | 114 StartRecursiveOperation( |
| 115 src_root_, base::Bind(&CrossOperationDelegate::DidFinishCopy, | 115 src_root_, base::Bind(&CopyOrMoveOperationDelegate::DidFinishCopy, |
| 116 AsWeakPtr(), src_root_, callback_)); | 116 AsWeakPtr(), src_root_, callback_)); |
| 117 } | 117 } |
| 118 | 118 |
| 119 void CrossOperationDelegate::CopyOrMoveFile(const URLPair& url_pair, | 119 void CopyOrMoveOperationDelegate::CopyOrMoveFile(const URLPair& url_pair, |
| 120 const StatusCallback& callback) { | 120 const StatusCallback& callback) { |
| 121 // Same filesystem case. | 121 // Same filesystem case. |
| 122 if (same_file_system_) { | 122 if (same_file_system_) { |
| 123 if (operation_type_ == OPERATION_MOVE) { | 123 if (operation_type_ == OPERATION_MOVE) { |
| 124 NewSourceOperation()->MoveFileLocal(url_pair.src, url_pair.dest, | 124 NewSourceOperation()->MoveFileLocal(url_pair.src, url_pair.dest, |
| 125 callback); | 125 callback); |
| 126 } else { | 126 } else { |
| 127 NewSourceOperation()->CopyFileLocal(url_pair.src, url_pair.dest, | 127 NewSourceOperation()->CopyFileLocal(url_pair.src, url_pair.dest, |
| 128 callback); | 128 callback); |
| 129 } | 129 } |
| 130 return; | 130 return; |
| 131 } | 131 } |
| 132 | 132 |
| 133 // Cross filesystem case. | 133 // Cross filesystem case. |
| 134 // Perform CreateSnapshotFile, CopyInForeignFile and then calls | 134 // Perform CreateSnapshotFile, CopyInForeignFile and then calls |
| 135 // copy_callback which removes the source file if operation_type == MOVE. | 135 // copy_callback which removes the source file if operation_type == MOVE. |
| 136 StatusCallback copy_callback = | 136 StatusCallback copy_callback = |
| 137 base::Bind(&CrossOperationDelegate::DidFinishCopy, AsWeakPtr(), | 137 base::Bind(&CopyOrMoveOperationDelegate::DidFinishCopy, AsWeakPtr(), |
| 138 url_pair.src, callback); | 138 url_pair.src, callback); |
| 139 NewSourceOperation()->CreateSnapshotFile( | 139 NewSourceOperation()->CreateSnapshotFile( |
| 140 url_pair.src, | 140 url_pair.src, |
| 141 base::Bind(&CrossOperationDelegate::DidCreateSnapshot, AsWeakPtr(), | 141 base::Bind(&CopyOrMoveOperationDelegate::DidCreateSnapshot, AsWeakPtr(), |
| 142 url_pair, copy_callback)); | 142 url_pair, copy_callback)); |
| 143 } | 143 } |
| 144 | 144 |
| 145 void CrossOperationDelegate::DidCreateSnapshot( | 145 void CopyOrMoveOperationDelegate::DidCreateSnapshot( |
| 146 const URLPair& url_pair, | 146 const URLPair& url_pair, |
| 147 const StatusCallback& callback, | 147 const StatusCallback& callback, |
| 148 base::PlatformFileError error, | 148 base::PlatformFileError error, |
| 149 const base::PlatformFileInfo& file_info, | 149 const base::PlatformFileInfo& file_info, |
| 150 const base::FilePath& platform_path, | 150 const base::FilePath& platform_path, |
| 151 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { | 151 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { |
| 152 if (error != base::PLATFORM_FILE_OK) { | 152 if (error != base::PLATFORM_FILE_OK) { |
| 153 callback.Run(error); | 153 callback.Run(error); |
| 154 return; | 154 return; |
| 155 } | 155 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 167 return; | 167 return; |
| 168 } | 168 } |
| 169 if (!factory) { | 169 if (!factory) { |
| 170 DidValidateFile(url_pair.dest, callback, file_info, platform_path, error); | 170 DidValidateFile(url_pair.dest, callback, file_info, platform_path, error); |
| 171 return; | 171 return; |
| 172 } | 172 } |
| 173 | 173 |
| 174 validator_.reset( | 174 validator_.reset( |
| 175 factory->CreateCopyOrMoveFileValidator(url_pair.src, platform_path)); | 175 factory->CreateCopyOrMoveFileValidator(url_pair.src, platform_path)); |
| 176 validator_->StartValidation( | 176 validator_->StartValidation( |
| 177 base::Bind(&CrossOperationDelegate::DidValidateFile, AsWeakPtr(), | 177 base::Bind(&CopyOrMoveOperationDelegate::DidValidateFile, AsWeakPtr(), |
| 178 url_pair.dest, callback, file_info, platform_path)); | 178 url_pair.dest, callback, file_info, platform_path)); |
| 179 } | 179 } |
| 180 | 180 |
| 181 void CrossOperationDelegate::DidValidateFile( | 181 void CopyOrMoveOperationDelegate::DidValidateFile( |
| 182 const FileSystemURL& dest, | 182 const FileSystemURL& dest, |
| 183 const StatusCallback& callback, | 183 const StatusCallback& callback, |
| 184 const base::PlatformFileInfo& file_info, | 184 const base::PlatformFileInfo& file_info, |
| 185 const base::FilePath& platform_path, | 185 const base::FilePath& platform_path, |
| 186 base::PlatformFileError error) { | 186 base::PlatformFileError error) { |
| 187 if (error != base::PLATFORM_FILE_OK) { | 187 if (error != base::PLATFORM_FILE_OK) { |
| 188 callback.Run(error); | 188 callback.Run(error); |
| 189 return; | 189 return; |
| 190 } | 190 } |
| 191 | 191 |
| 192 NewDestOperation()->CopyInForeignFile(platform_path, dest, callback); | 192 NewDestOperation()->CopyInForeignFile(platform_path, dest, callback); |
| 193 } | 193 } |
| 194 | 194 |
| 195 void CrossOperationDelegate::DidFinishCopy( | 195 void CopyOrMoveOperationDelegate::DidFinishCopy( |
| 196 const FileSystemURL& src, | 196 const FileSystemURL& src, |
| 197 const StatusCallback& callback, | 197 const StatusCallback& callback, |
| 198 base::PlatformFileError error) { | 198 base::PlatformFileError error) { |
| 199 if (error != base::PLATFORM_FILE_OK || | 199 if (error != base::PLATFORM_FILE_OK || |
| 200 operation_type_ == OPERATION_COPY) { | 200 operation_type_ == OPERATION_COPY) { |
| 201 callback.Run(error); | 201 callback.Run(error); |
| 202 return; | 202 return; |
| 203 } | 203 } |
| 204 | 204 |
| 205 DCHECK_EQ(OPERATION_MOVE, operation_type_); | 205 DCHECK_EQ(OPERATION_MOVE, operation_type_); |
| 206 | 206 |
| 207 // Remove the source for finalizing move operation. | 207 // Remove the source for finalizing move operation. |
| 208 NewSourceOperation()->Remove( | 208 NewSourceOperation()->Remove( |
| 209 src, true /* recursive */, | 209 src, true /* recursive */, |
| 210 base::Bind(&CrossOperationDelegate::DidRemoveSourceForMove, | 210 base::Bind(&CopyOrMoveOperationDelegate::DidRemoveSourceForMove, |
| 211 AsWeakPtr(), callback)); | 211 AsWeakPtr(), callback)); |
| 212 } | 212 } |
| 213 | 213 |
| 214 void CrossOperationDelegate::DidRemoveSourceForMove( | 214 void CopyOrMoveOperationDelegate::DidRemoveSourceForMove( |
| 215 const StatusCallback& callback, | 215 const StatusCallback& callback, |
| 216 base::PlatformFileError error) { | 216 base::PlatformFileError error) { |
| 217 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) | 217 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) |
| 218 error = base::PLATFORM_FILE_OK; | 218 error = base::PLATFORM_FILE_OK; |
| 219 callback.Run(error); | 219 callback.Run(error); |
| 220 } | 220 } |
| 221 | 221 |
| 222 FileSystemURL CrossOperationDelegate::CreateDestURL( | 222 FileSystemURL CopyOrMoveOperationDelegate::CreateDestURL( |
| 223 const FileSystemURL& src_url) const { | 223 const FileSystemURL& src_url) const { |
| 224 DCHECK_EQ(src_root_.type(), src_url.type()); | 224 DCHECK_EQ(src_root_.type(), src_url.type()); |
| 225 DCHECK_EQ(src_root_.origin(), src_url.origin()); | 225 DCHECK_EQ(src_root_.origin(), src_url.origin()); |
| 226 | 226 |
| 227 base::FilePath relative = dest_root_.virtual_path(); | 227 base::FilePath relative = dest_root_.virtual_path(); |
| 228 src_root_.virtual_path().AppendRelativePath(src_url.virtual_path(), | 228 src_root_.virtual_path().AppendRelativePath(src_url.virtual_path(), |
| 229 &relative); | 229 &relative); |
| 230 return file_system_context()->CreateCrackedFileSystemURL( | 230 return file_system_context()->CreateCrackedFileSystemURL( |
| 231 dest_root_.origin(), | 231 dest_root_.origin(), |
| 232 dest_root_.mount_type(), | 232 dest_root_.mount_type(), |
| 233 relative); | 233 relative); |
| 234 } | 234 } |
| 235 | 235 |
| 236 LocalFileSystemOperation* CrossOperationDelegate::NewDestOperation() { | 236 LocalFileSystemOperation* CopyOrMoveOperationDelegate::NewDestOperation() { |
| 237 return NewNestedOperation(); | 237 return NewNestedOperation(); |
| 238 } | 238 } |
| 239 | 239 |
| 240 LocalFileSystemOperation* CrossOperationDelegate::NewSourceOperation() { | 240 LocalFileSystemOperation* CopyOrMoveOperationDelegate::NewSourceOperation() { |
| 241 if (same_file_system_) | 241 if (same_file_system_) |
| 242 return NewDestOperation(); | 242 return NewDestOperation(); |
| 243 return src_root_operation_->CreateNestedOperation(); | 243 return src_root_operation_->CreateNestedOperation(); |
| 244 } | 244 } |
| 245 | 245 |
| 246 } // namespace fileapi | 246 } // namespace fileapi |
| OLD | NEW |