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

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

Issue 7066033: Enable cross-filesystem moves and copies. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rolled in Michael's feedback; removed unnecessary unlimited quota flag. Created 9 years, 7 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
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/fileapi/file_system_file_util.h" 5 #include "webkit/fileapi/file_system_file_util.h"
6 6
7 #include <stack> 7 #include <stack>
8 8
9 #include "base/file_util_proxy.h" 9 #include "base/file_util_proxy.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/scoped_ptr.h" 11 #include "base/scoped_ptr.h"
12 #include "webkit/fileapi/file_system_operation_context.h" 12 #include "webkit/fileapi/file_system_operation_context.h"
13 13
14 namespace fileapi { 14 namespace fileapi {
15 15
16 namespace {
17
18 // This assumes that the root exists.
19 bool ParentExists(FileSystemOperationContext* context,
20 FileSystemFileUtil* file_util, const FilePath& file_path) {
21 // If file_path is in the root, file_path.DirName() will be ".",
22 // since we use paths with no leading '/'.
23 FilePath parent = file_path.DirName();
24 if (parent != FilePath(FILE_PATH_LITERAL(".")) &&
25 !file_util->DirectoryExists(context, parent))
26 return false;
michaeln 2011/05/25 20:30:11 nit: maybe could be more readable... FilePath par
ericu 2011/05/25 21:51:58 Done.
27 return true;
28 }
29
30 }
31
16 // static 32 // static
17 FileSystemFileUtil* FileSystemFileUtil::GetInstance() { 33 FileSystemFileUtil* FileSystemFileUtil::GetInstance() {
18 return Singleton<FileSystemFileUtil>::get(); 34 return Singleton<FileSystemFileUtil>::get();
19 } 35 }
20 36
21 PlatformFileError FileSystemFileUtil::CreateOrOpen( 37 PlatformFileError FileSystemFileUtil::CreateOrOpen(
22 FileSystemOperationContext* unused, 38 FileSystemOperationContext* unused,
23 const FilePath& file_path, int file_flags, 39 const FilePath& file_path, int file_flags,
24 PlatformFile* file_handle, bool* created) { 40 PlatformFile* file_handle, bool* created) {
25 if (!file_util::DirectoryExists(file_path.DirName())) { 41 if (!file_util::DirectoryExists(file_path.DirName())) {
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 PlatformFileError error_code; 157 PlatformFileError error_code;
142 error_code = 158 error_code =
143 PerformCommonCheckAndPreparationForMoveAndCopy( 159 PerformCommonCheckAndPreparationForMoveAndCopy(
144 context, src_file_path, dest_file_path); 160 context, src_file_path, dest_file_path);
145 if (error_code != base::PLATFORM_FILE_OK) 161 if (error_code != base::PLATFORM_FILE_OK)
146 return error_code; 162 return error_code;
147 163
148 if (DirectoryExists(context, src_file_path)) 164 if (DirectoryExists(context, src_file_path))
149 return CopyOrMoveDirectory(context, src_file_path, dest_file_path, 165 return CopyOrMoveDirectory(context, src_file_path, dest_file_path,
150 true /* copy */); 166 true /* copy */);
151 else 167 return CopyOrMoveFileHelper(context, src_file_path, dest_file_path,
152 return CopyOrMoveFile(context, src_file_path, dest_file_path, 168 true /* copy */);
153 true /* copy */);
154 } 169 }
155 170
156 PlatformFileError FileSystemFileUtil::Move( 171 PlatformFileError FileSystemFileUtil::Move(
157 FileSystemOperationContext* context, 172 FileSystemOperationContext* context,
158 const FilePath& src_file_path, 173 const FilePath& src_file_path,
159 const FilePath& dest_file_path) { 174 const FilePath& dest_file_path) {
160 PlatformFileError error_code; 175 PlatformFileError error_code;
161 error_code = 176 error_code =
162 PerformCommonCheckAndPreparationForMoveAndCopy( 177 PerformCommonCheckAndPreparationForMoveAndCopy(
163 context, src_file_path, dest_file_path); 178 context, src_file_path, dest_file_path);
164 if (error_code != base::PLATFORM_FILE_OK) 179 if (error_code != base::PLATFORM_FILE_OK)
165 return error_code; 180 return error_code;
166 181
167 // TODO(dmikurube): ReplaceFile if in the same domain and filesystem type. 182 // TODO(dmikurube): ReplaceFile if in the same domain and filesystem type.
168 if (DirectoryExists(context, src_file_path)) 183 if (DirectoryExists(context, src_file_path))
169 return CopyOrMoveDirectory(context, src_file_path, dest_file_path, 184 return CopyOrMoveDirectory(context, src_file_path, dest_file_path,
170 false /* copy */); 185 false /* copy */);
171 else 186 return CopyOrMoveFileHelper(context, src_file_path, dest_file_path,
172 return CopyOrMoveFile(context, src_file_path, dest_file_path, 187 false /* copy */);
173 false /* copy */);
174 } 188 }
175 189
176 PlatformFileError FileSystemFileUtil::Delete( 190 PlatformFileError FileSystemFileUtil::Delete(
177 FileSystemOperationContext* context, 191 FileSystemOperationContext* context,
178 const FilePath& file_path, 192 const FilePath& file_path,
179 bool recursive) { 193 bool recursive) {
180 if (DirectoryExists(context, file_path)) { 194 if (DirectoryExists(context, file_path)) {
181 if (!recursive) 195 if (!recursive)
182 return DeleteSingleDirectory(context, file_path); 196 return DeleteSingleDirectory(context, file_path);
183 else 197 else
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 error_code = base::PLATFORM_FILE_ERROR_FAILED; 229 error_code = base::PLATFORM_FILE_ERROR_FAILED;
216 base::ClosePlatformFile(file); 230 base::ClosePlatformFile(file);
217 return error_code; 231 return error_code;
218 } 232 }
219 233
220 PlatformFileError 234 PlatformFileError
221 FileSystemFileUtil::PerformCommonCheckAndPreparationForMoveAndCopy( 235 FileSystemFileUtil::PerformCommonCheckAndPreparationForMoveAndCopy(
222 FileSystemOperationContext* context, 236 FileSystemOperationContext* context,
223 const FilePath& src_file_path, 237 const FilePath& src_file_path,
224 const FilePath& dest_file_path) { 238 const FilePath& dest_file_path) {
239 bool same_file_system =
240 (context->src_origin_url() == context->dest_origin_url()) &&
241 (context->src_type() == context->dest_type());
242 FileSystemFileUtil* dest_util = context->dest_file_system_file_util();
243 DCHECK(dest_util);
244 FileSystemOperationContext local_dest_context(
245 context->file_system_context(), dest_util);
246 FileSystemOperationContext* dest_context;
247 if (same_file_system) {
248 dest_context = context;
249 DCHECK(context->src_file_system_file_util() ==
250 context->dest_file_system_file_util());
251 } else {
252 // All the single-path virtual FSFU methods expect the context information
253 // to be in the src_* variables, not the dest_* variables, so we have to
254 // make a new context if we want to call them on the dest_file_path.
255 dest_context = &local_dest_context;
256 dest_context->set_src_type(context->dest_type());
257 dest_context->set_src_origin_url(context->dest_origin_url());
258 dest_context->set_src_virtual_path(context->dest_virtual_path());
259 dest_context->set_allowed_bytes_growth(context->allowed_bytes_growth());
260 }
261
225 // Exits earlier if the source path does not exist. 262 // Exits earlier if the source path does not exist.
226 if (!PathExists(context, src_file_path)) 263 if (!PathExists(context, src_file_path))
227 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 264 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
228 265
229 // The parent of the |dest_file_path| does not exist. 266 // The parent of the |dest_file_path| does not exist.
230 if (!DirectoryExists(context, dest_file_path.DirName())) 267 if (!ParentExists(dest_context, dest_util, dest_file_path))
231 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 268 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
232 269
233 // It is an error to try to copy/move an entry into its child. 270 // It is an error to try to copy/move an entry into its child.
234 if (src_file_path.IsParent(dest_file_path)) 271 if (same_file_system && src_file_path.IsParent(dest_file_path))
235 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; 272 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
236 273
237 // Now it is ok to return if the |dest_file_path| does not exist. 274 // Now it is ok to return if the |dest_file_path| does not exist.
238 if (!PathExists(context, dest_file_path)) 275 if (!dest_util->PathExists(dest_context, dest_file_path))
239 return base::PLATFORM_FILE_OK; 276 return base::PLATFORM_FILE_OK;
240 277
241 // |src_file_path| exists and is a directory. 278 // |src_file_path| exists and is a directory.
242 // |dest_file_path| exists and is a file. 279 // |dest_file_path| exists and is a file.
243 bool src_is_directory = DirectoryExists(context, src_file_path); 280 bool src_is_directory = DirectoryExists(context, src_file_path);
244 bool dest_is_directory = DirectoryExists(context, dest_file_path); 281 bool dest_is_directory =
282 dest_util->DirectoryExists(dest_context, dest_file_path);
245 if (src_is_directory && !dest_is_directory) 283 if (src_is_directory && !dest_is_directory)
246 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; 284 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
247 285
248 // |src_file_path| exists and is a file. 286 // |src_file_path| exists and is a file.
249 // |dest_file_path| exists and is a directory. 287 // |dest_file_path| exists and is a directory.
250 if (!src_is_directory && dest_is_directory) 288 if (!src_is_directory && dest_is_directory)
251 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; 289 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
252 290
253 // It is an error to copy/move an entry into the same path. 291 // It is an error to copy/move an entry into the same path.
254 if (src_file_path.value() == dest_file_path.value()) 292 if (same_file_system && (src_file_path.value() == dest_file_path.value()))
255 return base::PLATFORM_FILE_ERROR_EXISTS; 293 return base::PLATFORM_FILE_ERROR_EXISTS;
256 294
257 if (dest_is_directory) { 295 if (dest_is_directory) {
258 // It is an error to copy/move an entry to a non-empty directory. 296 // It is an error to copy/move an entry to a non-empty directory.
259 // Otherwise the copy/move attempt must overwrite the destination, but 297 // Otherwise the copy/move attempt must overwrite the destination, but
260 // the file_util's Copy or Move method doesn't perform overwrite 298 // the file_util's Copy or Move method doesn't perform overwrite
261 // on all platforms, so we delete the destination directory here. 299 // on all platforms, so we delete the destination directory here.
262 // TODO(kinuko): may be better to change the file_util::{Copy,Move}. 300 // TODO(kinuko): may be better to change the file_util::{Copy,Move}.
263 if (base::PLATFORM_FILE_OK != 301 if (base::PLATFORM_FILE_OK !=
264 Delete(context, dest_file_path, false /* recursive */)) { 302 dest_util->Delete(dest_context, dest_file_path,
265 if (!IsDirectoryEmpty(context, dest_file_path)) 303 false /* recursive */)) {
304 if (!dest_util->IsDirectoryEmpty(dest_context, dest_file_path))
266 return base::PLATFORM_FILE_ERROR_NOT_EMPTY; 305 return base::PLATFORM_FILE_ERROR_NOT_EMPTY;
267 return base::PLATFORM_FILE_ERROR_FAILED; 306 return base::PLATFORM_FILE_ERROR_FAILED;
268 } 307 }
269 } 308 }
270 return base::PLATFORM_FILE_OK; 309 return base::PLATFORM_FILE_OK;
271 } 310 }
272 311
273 PlatformFileError FileSystemFileUtil::CopyOrMoveFile( 312 PlatformFileError FileSystemFileUtil::CopyOrMoveFile(
274 FileSystemOperationContext* unused, 313 FileSystemOperationContext* unused,
275 const FilePath& src_file_path, 314 const FilePath& src_file_path,
276 const FilePath& dest_file_path, 315 const FilePath& dest_file_path,
277 bool copy) { 316 bool copy) {
278 if (copy) { 317 if (copy) {
279 if (file_util::CopyFile(src_file_path, dest_file_path)) 318 if (file_util::CopyFile(src_file_path, dest_file_path))
280 return base::PLATFORM_FILE_OK; 319 return base::PLATFORM_FILE_OK;
281 } else { 320 } else {
282 DCHECK(!file_util::DirectoryExists(src_file_path)); 321 DCHECK(!file_util::DirectoryExists(src_file_path));
283 if (file_util::Move(src_file_path, dest_file_path)) 322 if (file_util::Move(src_file_path, dest_file_path))
284 return base::PLATFORM_FILE_OK; 323 return base::PLATFORM_FILE_OK;
285 } 324 }
286 return base::PLATFORM_FILE_ERROR_FAILED; 325 return base::PLATFORM_FILE_ERROR_FAILED;
287 } 326 }
288 327
328 PlatformFileError FileSystemFileUtil::CopyInForeignFile(
329 FileSystemOperationContext* context,
330 const FilePath& src_file_path,
331 const FilePath& dest_file_path) {
332 return CopyOrMoveFile(context, src_file_path, dest_file_path, true);
333 }
334
289 PlatformFileError FileSystemFileUtil::CopyOrMoveDirectory( 335 PlatformFileError FileSystemFileUtil::CopyOrMoveDirectory(
290 FileSystemOperationContext* context, 336 FileSystemOperationContext* context,
291 const FilePath& src_file_path, 337 const FilePath& src_file_path,
292 const FilePath& dest_file_path, 338 const FilePath& dest_file_path,
293 bool copy) { 339 bool copy) {
340 FileSystemFileUtil* dest_util = context->dest_file_system_file_util();
341 FileSystemOperationContext dest_context(
342 context->file_system_context(), dest_util);
343 // All the single-path virtual FSFU methods expect the context information to
344 // be in the src_* variables, not the dest_* variables, so we have to make a
345 // new context if we want to call them on the dest_file_path.
346 dest_context.set_src_type(context->dest_type());
347 dest_context.set_src_origin_url(context->dest_origin_url());
348 dest_context.set_src_virtual_path(context->dest_virtual_path());
349 dest_context.set_allowed_bytes_growth(context->allowed_bytes_growth());
350
294 // Re-check PerformCommonCheckAndPreparationForMoveAndCopy() by DCHECK. 351 // Re-check PerformCommonCheckAndPreparationForMoveAndCopy() by DCHECK.
295 DCHECK(DirectoryExists(context, src_file_path)); 352 DCHECK(DirectoryExists(context, src_file_path));
296 DCHECK(DirectoryExists(context, dest_file_path.DirName())); 353 DCHECK(ParentExists(&dest_context, dest_util, dest_file_path));
297 DCHECK(!src_file_path.IsParent(dest_file_path)); 354 DCHECK(!dest_util->PathExists(&dest_context, dest_file_path));
298 DCHECK(!PathExists(context, dest_file_path)); 355 if ((context->src_origin_url() == context->dest_origin_url()) &&
356 (context->src_type() == context->dest_type()))
357 DCHECK(!src_file_path.IsParent(dest_file_path));
299 358
300 if (!DirectoryExists(context, dest_file_path)) { 359 if (!dest_util->DirectoryExists(&dest_context, dest_file_path)) {
301 PlatformFileError error = CreateDirectory(context, 360 PlatformFileError error = dest_util->CreateDirectory(&dest_context,
302 dest_file_path, false, false); 361 dest_file_path, false, false);
303 if (error != base::PLATFORM_FILE_OK) 362 if (error != base::PLATFORM_FILE_OK)
304 return error; 363 return error;
305 } 364 }
306 365
307 scoped_ptr<AbstractFileEnumerator> file_enum( 366 scoped_ptr<AbstractFileEnumerator> file_enum(
308 CreateFileEnumerator(context, src_file_path)); 367 CreateFileEnumerator(context, src_file_path));
309 FilePath src_file_path_each; 368 FilePath src_file_path_each;
310 while (!(src_file_path_each = file_enum->Next()).empty()) { 369 while (!(src_file_path_each = file_enum->Next()).empty()) {
311 FilePath dest_file_path_each(dest_file_path); 370 FilePath dest_file_path_each(dest_file_path);
312 src_file_path.AppendRelativePath(src_file_path_each, &dest_file_path_each); 371 src_file_path.AppendRelativePath(src_file_path_each, &dest_file_path_each);
313 372
314 if (file_enum->IsDirectory()) { 373 if (file_enum->IsDirectory()) {
315 PlatformFileError error = CreateDirectory(context, 374 PlatformFileError error = dest_util->CreateDirectory(&dest_context,
316 dest_file_path_each, false, false); 375 dest_file_path_each, false, false);
317 if (error != base::PLATFORM_FILE_OK) 376 if (error != base::PLATFORM_FILE_OK)
318 return error; 377 return error;
319 } else { 378 } else {
320 // CopyOrMoveFile here is the virtual overridden member function. 379 PlatformFileError error = CopyOrMoveFileHelper(
321 PlatformFileError error = CopyOrMoveFile(
322 context, src_file_path_each, dest_file_path_each, copy); 380 context, src_file_path_each, dest_file_path_each, copy);
323 if (error != base::PLATFORM_FILE_OK) 381 if (error != base::PLATFORM_FILE_OK)
324 return error; 382 return error;
325 } 383 }
326 } 384 }
327 385
328 if (!copy) { 386 if (!copy) {
329 PlatformFileError error = Delete(context, src_file_path, true); 387 PlatformFileError error = Delete(context, src_file_path, true);
330 if (error != base::PLATFORM_FILE_OK) 388 if (error != base::PLATFORM_FILE_OK)
331 return error; 389 return error;
332 } 390 }
333 return base::PLATFORM_FILE_OK; 391 return base::PLATFORM_FILE_OK;
334 } 392 }
335 393
394 PlatformFileError FileSystemFileUtil::CopyOrMoveFileHelper(
395 FileSystemOperationContext* context,
396 const FilePath& src_file_path,
397 const FilePath& dest_file_path,
398 bool copy) {
399 // CopyOrMoveFile here is the virtual overridden member function.
400 if ((context->src_origin_url() == context->dest_origin_url()) &&
401 (context->src_type() == context->dest_type())) {
402 DCHECK(context->src_file_system_file_util() ==
403 context->dest_file_system_file_util());
404 return CopyOrMoveFile(context, src_file_path, dest_file_path, copy);
405 }
406 base::PlatformFileInfo file_info;
407 FilePath platform_file_path;
408 PlatformFileError error_code;
409 error_code =
410 GetFileInfo(context, src_file_path, &file_info, &platform_file_path);
411 if (error_code != base::PLATFORM_FILE_OK)
412 return error_code;
413
414 DCHECK(context->dest_file_system_file_util());
415 error_code = context->dest_file_system_file_util()->CopyInForeignFile(
416 context, platform_file_path, dest_file_path);
417 if (copy || error_code != base::PLATFORM_FILE_OK)
418 return error_code;
419 return DeleteFile(context, src_file_path);
420 }
421
422
336 PlatformFileError FileSystemFileUtil::DeleteFile( 423 PlatformFileError FileSystemFileUtil::DeleteFile(
337 FileSystemOperationContext* unused, 424 FileSystemOperationContext* unused,
338 const FilePath& file_path) { 425 const FilePath& file_path) {
339 if (!file_util::PathExists(file_path)) 426 if (!file_util::PathExists(file_path))
340 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 427 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
341 if (file_util::DirectoryExists(file_path)) 428 if (file_util::DirectoryExists(file_path))
342 return base::PLATFORM_FILE_ERROR_NOT_A_FILE; 429 return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
343 if (!file_util::Delete(file_path, false)) 430 if (!file_util::Delete(file_path, false))
344 return base::PLATFORM_FILE_ERROR_FAILED; 431 return base::PLATFORM_FILE_ERROR_FAILED;
345 return base::PLATFORM_FILE_OK; 432 return base::PLATFORM_FILE_OK;
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
445 FileSystemFileUtil::CreateFileEnumerator( 532 FileSystemFileUtil::CreateFileEnumerator(
446 FileSystemOperationContext* unused, 533 FileSystemOperationContext* unused,
447 const FilePath& root_path) { 534 const FilePath& root_path) {
448 return new FileSystemFileEnumerator( 535 return new FileSystemFileEnumerator(
449 root_path, true, static_cast<file_util::FileEnumerator::FILE_TYPE>( 536 root_path, true, static_cast<file_util::FileEnumerator::FILE_TYPE>(
450 file_util::FileEnumerator::FILES | 537 file_util::FileEnumerator::FILES |
451 file_util::FileEnumerator::DIRECTORIES)); 538 file_util::FileEnumerator::DIRECTORIES));
452 } 539 }
453 540
454 } // namespace fileapi 541 } // namespace fileapi
OLDNEW
« no previous file with comments | « webkit/fileapi/file_system_file_util.h ('k') | webkit/fileapi/file_system_file_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698