Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(781)

Side by Side Diff: webkit/fileapi/cross_operation_delegate.cc

Issue 12036022: Split recursive Copy/Move into async tasks and support cross operation (in local case) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/fileapi/cross_operation_delegate.h ('k') | webkit/fileapi/file_system_file_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
129
130 // Start to process the source directory recursively.
131 // TODO(kinuko): This could be too expensive for same_file_system_==true
132 // and operation==MOVE case, probably we can just rename the root directory.
133 // http://crbug.com/172187
134 StartRecursiveOperation(
135 src_root_, base::Bind(&CrossOperationDelegate::DidFinishCopy,
136 AsWeakPtr(), src_root_, callback_));
137 }
138
139 void CrossOperationDelegate::CopyOrMoveFile(
140 const FileSystemURL& src,
141 const FileSystemURL& dest,
142 const StatusCallback& callback) {
143 LocalFileSystemOperation* src_operation = NewSourceOperation(src);
144 if (!src_operation)
145 return;
146
147 // Same filesystem case.
148 if (same_file_system_) {
149 if (operation_type_ == OPERATION_MOVE)
150 src_operation->MoveFileLocal(src, dest, callback);
151 else
152 src_operation->CopyFileLocal(src, dest, callback);
153 return;
154 }
155
156 // Cross filesystem case.
157 // Perform CreateSnapshotFile, CopyInForeignFile and then calls
158 // copy_callback which removes the source file if operation_type == MOVE.
159 StatusCallback copy_callback =
160 base::Bind(&CrossOperationDelegate::DidFinishCopy, AsWeakPtr(),
161 src, callback);
162 src_operation->CreateSnapshotFile(
163 src, base::Bind(&CrossOperationDelegate::DidCreateSnapshot, AsWeakPtr(),
164 dest, copy_callback));
165 }
166
167 void CrossOperationDelegate::DidCreateSnapshot(
168 const FileSystemURL& dest,
169 const StatusCallback& callback,
170 base::PlatformFileError error,
171 const base::PlatformFileInfo& file_info,
172 const FilePath& platform_path,
173 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
174 if (error != base::PLATFORM_FILE_OK) {
175 callback.Run(error);
176 return;
177 }
178 current_file_ref_ = file_ref;
179
180 // For now we assume CreateSnapshotFile always return a valid local file path.
181 // TODO(kinuko): Otherwise create a FileStreamReader to perform a copy/move.
182 DCHECK(!platform_path.empty());
183
184 LocalFileSystemOperation* dest_operation = NewDestOperation(dest);
185 if (!dest_operation)
186 return;
187 dest_operation->CopyInForeignFile(platform_path, dest, callback);
188 }
189
190 void CrossOperationDelegate::DidFinishCopy(
191 const FileSystemURL& src,
192 const StatusCallback& callback,
193 base::PlatformFileError error) {
194 if (error != base::PLATFORM_FILE_OK ||
195 operation_type_ == OPERATION_COPY) {
196 callback.Run(error);
197 return;
198 }
199
200 DCHECK_EQ(OPERATION_MOVE, operation_type_);
201
202 // Remove the source for finalizing move operation.
203 LocalFileSystemOperation* src_operation = NewSourceOperation(src);
204 if (!src_operation)
205 return;
206 src_operation->Remove(
207 src_root_, true /* recursive */,
208 base::Bind(&CrossOperationDelegate::DidRemoveSourceForMove,
209 AsWeakPtr(), callback));
210 }
211
212 void CrossOperationDelegate::DidRemoveSourceForMove(
213 const StatusCallback& callback,
214 base::PlatformFileError error) {
215 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND)
216 error = base::PLATFORM_FILE_OK;
217 callback.Run(error);
218 }
219
220 FileSystemURL CrossOperationDelegate::CreateDestURL(
221 const FileSystemURL& src_url) const {
222 DCHECK_EQ(src_root_.type(), src_url.type());
223 DCHECK_EQ(src_root_.origin(), src_url.origin());
224
225 FilePath path = dest_root_.path();
226 src_root_.path().AppendRelativePath(src_url.path(), &path);
227 return dest_root_.WithPath(path);
228 }
229
230 LocalFileSystemOperation* CrossOperationDelegate::NewDestOperation(
231 const FileSystemURL& url) {
232 base::PlatformFileError error = base::PLATFORM_FILE_OK;
233 LocalFileSystemOperation* operation =
234 RecursiveOperationDelegate::NewOperation(url, &error);
235 if (!operation) {
236 DCHECK_NE(base::PLATFORM_FILE_OK, error);
237 callback_.Run(error);
238 return NULL;
239 }
240 return operation;
241 }
242
243 LocalFileSystemOperation* CrossOperationDelegate::NewSourceOperation(
244 const FileSystemURL& url) {
245 if (same_file_system_)
246 return NewDestOperation(url);
247
248 base::PlatformFileError error = base::PLATFORM_FILE_OK;
249 FileSystemOperation* operation = file_system_context()->
250 CreateFileSystemOperation(url, &error);
251 if (!operation) {
252 DCHECK_NE(base::PLATFORM_FILE_OK, error);
253 callback_.Run(error);
254 return NULL;
255 }
256 LocalFileSystemOperation* local_operation =
257 operation->AsLocalFileSystemOperation();
258 DCHECK(local_operation);
259 DCHECK(src_root_operation_);
260
261 // Let the new operation inherit from the root operation.
262 local_operation->set_overriding_operation_context(
263 src_root_operation_->operation_context());
264 return local_operation;
265 }
266
267 } // namespace fileapi
OLDNEW
« no previous file with comments | « webkit/fileapi/cross_operation_delegate.h ('k') | webkit/fileapi/file_system_file_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698