Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "webkit/fileapi/cross_operation_delegate.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "webkit/blob/shareable_file_reference.h" | |
| 9 #include "webkit/fileapi/file_system_context.h" | |
| 10 #include "webkit/fileapi/file_system_operation_context.h" | |
| 11 #include "webkit/fileapi/local_file_system_operation.h" | |
| 12 | |
| 13 namespace fileapi { | |
| 14 | |
| 15 CrossOperationDelegate::CrossOperationDelegate( | |
| 16 LocalFileSystemOperation* original_operation, | |
| 17 const FileSystemURL& src_root, | |
| 18 const FileSystemURL& dest_root, | |
| 19 OperationType operation_type, | |
| 20 const StatusCallback& callback) | |
| 21 : RecursiveOperationDelegate(original_operation), | |
| 22 src_root_(src_root), | |
| 23 dest_root_(dest_root), | |
| 24 operation_type_(operation_type), | |
| 25 callback_(callback), | |
| 26 src_root_operation_(NULL) { | |
| 27 same_file_system_ = | |
| 28 src_root_.origin() == dest_root_.origin() && | |
| 29 src_root_.type() == dest_root_.type(); | |
| 30 } | |
| 31 | |
| 32 CrossOperationDelegate::~CrossOperationDelegate() { | |
| 33 if (src_root_operation_) | |
| 34 delete src_root_operation_; | |
| 35 } | |
| 36 | |
| 37 void CrossOperationDelegate::Run() { | |
| 38 // Not supported; this should never be called. | |
| 39 NOTREACHED(); | |
| 40 } | |
| 41 | |
| 42 void CrossOperationDelegate::RunRecursively() { | |
| 43 // Perform light-weight checks first. | |
| 44 | |
| 45 // 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())) { | |
| 47 callback_.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); | |
| 48 return; | |
| 49 } | |
| 50 | |
| 51 // It is an error to copy/move an entry into the same path. | |
| 52 if (same_file_system_ && src_root_.path() == dest_root_.path()) { | |
| 53 callback_.Run(base::PLATFORM_FILE_ERROR_EXISTS); | |
| 54 return; | |
| 55 } | |
| 56 | |
| 57 // Initialize the src_root_operation_ for the src root URL. | |
| 58 DCHECK(!src_root_operation_); | |
| 59 if (!same_file_system_) { | |
| 60 base::PlatformFileError error = base::PLATFORM_FILE_OK; | |
| 61 FileSystemOperation* operation = file_system_context()-> | |
| 62 CreateFileSystemOperation(src_root_, &error); | |
| 63 if (error != base::PLATFORM_FILE_OK) { | |
| 64 DCHECK(!operation); | |
| 65 callback_.Run(error); | |
| 66 return; | |
| 67 } | |
| 68 src_root_operation_ = operation->AsLocalFileSystemOperation(); | |
| 69 DCHECK(src_root_operation_); | |
| 70 } | |
| 71 | |
| 72 // First try to copy/move it as a file. | |
| 73 CopyOrMoveFile(src_root_, dest_root_, | |
| 74 base::Bind(&CrossOperationDelegate::DidTryCopyOrMoveFile, | |
| 75 AsWeakPtr())); | |
| 76 } | |
| 77 | |
| 78 void CrossOperationDelegate::ProcessFile(const FileSystemURL& src_url, | |
| 79 const StatusCallback& callback) { | |
| 80 CopyOrMoveFile(src_url, CreateDestURL(src_url), callback); | |
| 81 } | |
| 82 | |
| 83 void CrossOperationDelegate::ProcessDirectory(const FileSystemURL& src_url, | |
| 84 const StatusCallback& callback) { | |
| 85 FileSystemURL dest_url = CreateDestURL(src_url); | |
| 86 LocalFileSystemOperation* dest_operation = NewDestOperation(dest_url); | |
| 87 if (!dest_operation) { | |
| 88 return; | |
| 89 } | |
| 90 | |
| 91 // If operation_type == Move we may need to record directories and | |
| 92 // restore directory timestamps in the end, though it may have | |
| 93 // negative performance impact. | |
| 94 // See http://crbug.com/171284 for more details. | |
| 95 dest_operation->CreateDirectory( | |
| 96 dest_url, false /* exclusive */, false /* recursive */, callback); | |
| 97 } | |
| 98 | |
| 99 void CrossOperationDelegate::DidTryCopyOrMoveFile( | |
| 100 base::PlatformFileError error) { | |
| 101 if (error == base::PLATFORM_FILE_OK || | |
| 102 error != base::PLATFORM_FILE_ERROR_NOT_A_FILE) { | |
| 103 callback_.Run(error); | |
| 104 return; | |
| 105 } | |
| 106 | |
| 107 // The src_root_ looks to be a directory. | |
| 108 // Try removing the dest_root_ to see if it exists and/or it is an | |
| 109 // empty directory. | |
| 110 LocalFileSystemOperation* dest_operation = NewDestOperation(dest_root_); | |
| 111 if (!dest_operation) | |
| 112 return; | |
| 113 dest_operation->RemoveDirectory( | |
| 114 dest_root_, base::Bind(&CrossOperationDelegate::DidTryRemoveDestRoot, | |
| 115 AsWeakPtr())); | |
| 116 } | |
| 117 | |
| 118 void CrossOperationDelegate::DidTryRemoveDestRoot( | |
| 119 base::PlatformFileError error) { | |
| 120 if (error == base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY) { | |
| 121 callback_.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); | |
| 122 return; | |
| 123 } | |
| 124 if (error != base::PLATFORM_FILE_OK && | |
| 125 error != base::PLATFORM_FILE_ERROR_NOT_FOUND) { | |
| 126 callback_.Run(error); | |
| 127 return; | |
| 128 } | |
|
tzik
2013/01/24 05:19:24
For same_file_system && operation_type == MOVE cas
kinuko
2013/01/25 04:31:43
Done.
| |
| 129 | |
| 130 // Start to process the source directory recursively. | |
| 131 StartRecursiveOperation( | |
| 132 src_root_, base::Bind(&CrossOperationDelegate::DidFinishCopy, | |
| 133 AsWeakPtr(), src_root_, callback_)); | |
| 134 } | |
| 135 | |
| 136 void CrossOperationDelegate::CopyOrMoveFile( | |
| 137 const FileSystemURL& src, | |
| 138 const FileSystemURL& dest, | |
| 139 const StatusCallback& callback) { | |
| 140 LocalFileSystemOperation* src_operation = NewSourceOperation(src); | |
| 141 if (!src_operation) | |
| 142 return; | |
| 143 | |
| 144 // Same filesystem case. | |
| 145 if (same_file_system_) { | |
| 146 if (operation_type_ == OPERATION_MOVE) | |
| 147 src_operation->MoveFileLocal(src, dest, callback); | |
| 148 else | |
| 149 src_operation->CopyFileLocal(src, dest, callback); | |
| 150 return; | |
| 151 } | |
| 152 | |
| 153 // Cross filesystem case. | |
| 154 // Perform CreateSnapshotFile, CopyInForeignFile and then calls | |
| 155 // copy_callback which removes the source file if operation_type == MOVE. | |
| 156 StatusCallback copy_callback = | |
| 157 base::Bind(&CrossOperationDelegate::DidFinishCopy, AsWeakPtr(), | |
| 158 src, callback); | |
| 159 src_operation->CreateSnapshotFile( | |
| 160 src, base::Bind(&CrossOperationDelegate::DidCreateSnapshot, AsWeakPtr(), | |
| 161 dest, copy_callback)); | |
| 162 } | |
| 163 | |
| 164 void CrossOperationDelegate::DidCreateSnapshot( | |
| 165 const FileSystemURL& dest, | |
| 166 const StatusCallback& callback, | |
| 167 base::PlatformFileError error, | |
| 168 const base::PlatformFileInfo& file_info, | |
| 169 const FilePath& platform_path, | |
| 170 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { | |
| 171 if (error != base::PLATFORM_FILE_OK) { | |
| 172 callback.Run(error); | |
| 173 return; | |
| 174 } | |
| 175 current_file_ref_ = file_ref; | |
| 176 | |
| 177 // For now we assume CreateSnapshotFile always return a valid local file path. | |
| 178 // TODO(kinuko): Otherwise create a FileStreamReader to perform a copy/move. | |
| 179 DCHECK(!platform_path.empty()); | |
| 180 | |
| 181 LocalFileSystemOperation* dest_operation = NewDestOperation(dest); | |
| 182 if (!dest_operation) | |
| 183 return; | |
| 184 dest_operation->CopyInForeignFile(platform_path, dest, callback); | |
| 185 } | |
| 186 | |
| 187 void CrossOperationDelegate::DidFinishCopy( | |
| 188 const FileSystemURL& src, | |
| 189 const StatusCallback& callback, | |
| 190 base::PlatformFileError error) { | |
| 191 if (error != base::PLATFORM_FILE_OK || | |
| 192 operation_type_ == OPERATION_COPY) { | |
| 193 callback.Run(error); | |
| 194 return; | |
| 195 } | |
| 196 | |
| 197 DCHECK_EQ(OPERATION_MOVE, operation_type_); | |
| 198 | |
| 199 // Remove the source for finalizing move operation. | |
| 200 LocalFileSystemOperation* src_operation = NewSourceOperation(src); | |
| 201 if (!src_operation) | |
| 202 return; | |
| 203 src_operation->Remove( | |
| 204 src_root_, true /* recursive */, | |
| 205 base::Bind(&CrossOperationDelegate::DidRemoveSourceForMove, | |
| 206 AsWeakPtr(), callback)); | |
| 207 } | |
| 208 | |
| 209 void CrossOperationDelegate::DidRemoveSourceForMove( | |
| 210 const StatusCallback& callback, | |
| 211 base::PlatformFileError error) { | |
| 212 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) | |
| 213 error = base::PLATFORM_FILE_OK; | |
| 214 callback.Run(error); | |
| 215 } | |
| 216 | |
| 217 FileSystemURL CrossOperationDelegate::CreateDestURL( | |
| 218 const FileSystemURL& src_url) const { | |
| 219 DCHECK_EQ(src_root_.type(), src_url.type()); | |
| 220 DCHECK_EQ(src_root_.origin(), src_url.origin()); | |
| 221 | |
| 222 FilePath path = dest_root_.path(); | |
| 223 src_root_.path().AppendRelativePath(src_url.path(), &path); | |
| 224 return dest_root_.WithPath(path); | |
| 225 } | |
| 226 | |
| 227 LocalFileSystemOperation* CrossOperationDelegate::NewDestOperation( | |
| 228 const FileSystemURL& url) { | |
| 229 base::PlatformFileError error = base::PLATFORM_FILE_OK; | |
| 230 LocalFileSystemOperation* operation = | |
| 231 RecursiveOperationDelegate::NewOperation(url, &error); | |
| 232 if (!operation) { | |
| 233 DCHECK_NE(base::PLATFORM_FILE_OK, error); | |
| 234 callback_.Run(error); | |
| 235 return NULL; | |
| 236 } | |
| 237 return operation; | |
| 238 } | |
| 239 | |
| 240 LocalFileSystemOperation* CrossOperationDelegate::NewSourceOperation( | |
| 241 const FileSystemURL& url) { | |
| 242 if (same_file_system_) | |
| 243 return NewDestOperation(url); | |
| 244 | |
| 245 base::PlatformFileError error = base::PLATFORM_FILE_OK; | |
| 246 FileSystemOperation* operation = file_system_context()-> | |
| 247 CreateFileSystemOperation(url, &error); | |
| 248 if (!operation) { | |
| 249 DCHECK_NE(base::PLATFORM_FILE_OK, error); | |
| 250 callback_.Run(error); | |
| 251 return NULL; | |
| 252 } | |
| 253 LocalFileSystemOperation* local_operation = | |
| 254 operation->AsLocalFileSystemOperation(); | |
| 255 DCHECK(local_operation); | |
| 256 DCHECK(src_root_operation_); | |
| 257 | |
| 258 // Let the new operation inherit from the root operation. | |
| 259 local_operation->set_overriding_operation_context( | |
| 260 src_root_operation_->operation_context()); | |
| 261 return local_operation; | |
| 262 } | |
| 263 | |
| 264 } // namespace fileapi | |
| OLD | NEW |