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

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

Issue 12051010: (For-try) Divide recursive Copy/Move into multiple async tasks (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: test fix Created 7 years, 11 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
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 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_) {
ericu 2013/01/23 19:27:23 I'm getting a bit lost in all the redirection. If
146 if (operation_type_ == OPERATION_MOVE)
147 src_operation->MoveLocalFile(src, dest, callback);
148 else
149 src_operation->CopyLocalFile(src, dest, callback);
150 return;
151 }
152
153 // Cross filesystem case.
154 // Performs 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 oepration.
ericu 2013/01/23 19:27:23 typo: 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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698