OLD | NEW |
---|---|
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 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/file_util_proxy.h" | 10 #include "base/file_util_proxy.h" |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
129 // http://code.google.com/p/chromium-os/issues/detail?id=15948 | 129 // http://code.google.com/p/chromium-os/issues/detail?id=15948 |
130 // This currently just prevents a file from showing up at all | 130 // This currently just prevents a file from showing up at all |
131 // if it's a link, hence preventing arbitary 'read' exploits. | 131 // if it's a link, hence preventing arbitary 'read' exploits. |
132 if (!file_util::IsLink(file_path.Append(entry.name))) | 132 if (!file_util::IsLink(file_path.Append(entry.name))) |
133 entries->push_back(entry); | 133 entries->push_back(entry); |
134 } | 134 } |
135 return base::PLATFORM_FILE_OK; | 135 return base::PLATFORM_FILE_OK; |
136 } | 136 } |
137 | 137 |
138 PlatformFileError FileSystemFileUtil::CreateDirectory( | 138 PlatformFileError FileSystemFileUtil::CreateDirectory( |
139 FileSystemOperationContext* fs_context, | 139 FileSystemOperationContext* unused, |
140 const FilePath& file_path, | 140 const FilePath& file_path, |
141 bool exclusive, | 141 bool exclusive, |
142 bool recursive) { | 142 bool recursive) { |
143 if (fs_context->do_not_write_actually()) | |
144 return base::PLATFORM_FILE_OK; | |
145 | |
146 // If parent dir of file doesn't exist. | 143 // If parent dir of file doesn't exist. |
147 if (!recursive && !file_util::PathExists(file_path.DirName())) | 144 if (!recursive && !file_util::PathExists(file_path.DirName())) |
148 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | 145 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
149 | 146 |
150 bool path_exists = file_util::PathExists(file_path); | 147 bool path_exists = file_util::PathExists(file_path); |
151 if (exclusive && path_exists) | 148 if (exclusive && path_exists) |
152 return base::PLATFORM_FILE_ERROR_EXISTS; | 149 return base::PLATFORM_FILE_ERROR_EXISTS; |
153 | 150 |
154 // If file exists at the path. | 151 // If file exists at the path. |
155 if (path_exists && !file_util::DirectoryExists(file_path)) | 152 if (path_exists && !file_util::DirectoryExists(file_path)) |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
246 PlatformFileError | 243 PlatformFileError |
247 FileSystemFileUtil::PerformCommonCheckAndPreparationForMoveAndCopy( | 244 FileSystemFileUtil::PerformCommonCheckAndPreparationForMoveAndCopy( |
248 FileSystemOperationContext* context, | 245 FileSystemOperationContext* context, |
249 const FilePath& src_file_path, | 246 const FilePath& src_file_path, |
250 const FilePath& dest_file_path) { | 247 const FilePath& dest_file_path) { |
251 bool same_file_system = | 248 bool same_file_system = |
252 (context->src_origin_url() == context->dest_origin_url()) && | 249 (context->src_origin_url() == context->dest_origin_url()) && |
253 (context->src_type() == context->dest_type()); | 250 (context->src_type() == context->dest_type()); |
254 FileSystemFileUtil* dest_util = context->dest_file_system_file_util(); | 251 FileSystemFileUtil* dest_util = context->dest_file_system_file_util(); |
255 DCHECK(dest_util); | 252 DCHECK(dest_util); |
256 if (same_file_system) | 253 scoped_ptr<FileSystemOperationContext> local_dest_context; |
254 FileSystemOperationContext* dest_context = NULL; | |
255 if (same_file_system) { | |
256 dest_context = context; | |
257 DCHECK(context->src_file_system_file_util() == | 257 DCHECK(context->src_file_system_file_util() == |
258 context->dest_file_system_file_util()); | 258 context->dest_file_system_file_util()); |
259 // All the single-path virtual FSFU methods expect the context information | 259 } else { |
260 // to be in the src_* variables, not the dest_* variables, so we have to | 260 local_dest_context.reset(context->CreateInheritedContextForDest()); |
261 // make a new context if we want to call them on the dest_file_path. | 261 // All the single-path virtual FSFU methods expect the context information |
262 scoped_ptr<FileSystemOperationContext> dest_context( | 262 // to be in the src_* variables, not the dest_* variables, so we have to |
263 context->CreateInheritedContextForDest()); | 263 // make a new context if we want to call them on the dest_file_path. |
264 dest_context = local_dest_context.get(); | |
265 } | |
264 | 266 |
265 // Exits earlier if the source path does not exist. | 267 // Exits earlier if the source path does not exist. |
266 if (!PathExists(context, src_file_path)) | 268 if (!PathExists(context, src_file_path)) |
267 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | 269 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
268 | 270 |
269 // The parent of the |dest_file_path| does not exist. | 271 // The parent of the |dest_file_path| does not exist. |
270 if (!ParentExists(dest_context.get(), dest_util, dest_file_path)) | 272 if (!ParentExists(dest_context, dest_util, dest_file_path)) |
271 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | 273 return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
272 | 274 |
273 // It is an error to try to copy/move an entry into its child. | 275 // It is an error to try to copy/move an entry into its child. |
274 if (same_file_system && src_file_path.IsParent(dest_file_path)) | 276 if (same_file_system && src_file_path.IsParent(dest_file_path)) |
275 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | 277 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
276 | 278 |
277 // Now it is ok to return if the |dest_file_path| does not exist. | 279 // Now it is ok to return if the |dest_file_path| does not exist. |
278 if (!dest_util->PathExists(dest_context.get(), dest_file_path)) | 280 if (!dest_util->PathExists(dest_context, dest_file_path)) |
279 return base::PLATFORM_FILE_OK; | 281 return base::PLATFORM_FILE_OK; |
280 | 282 |
281 // |src_file_path| exists and is a directory. | 283 // |src_file_path| exists and is a directory. |
282 // |dest_file_path| exists and is a file. | 284 // |dest_file_path| exists and is a file. |
283 bool src_is_directory = DirectoryExists(context, src_file_path); | 285 bool src_is_directory = DirectoryExists(context, src_file_path); |
284 bool dest_is_directory = | 286 bool dest_is_directory = |
285 dest_util->DirectoryExists(dest_context.get(), dest_file_path); | 287 dest_util->DirectoryExists(dest_context, dest_file_path); |
286 if (src_is_directory && !dest_is_directory) | 288 if (src_is_directory && !dest_is_directory) |
287 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | 289 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
288 | 290 |
289 // |src_file_path| exists and is a file. | 291 // |src_file_path| exists and is a file. |
290 // |dest_file_path| exists and is a directory. | 292 // |dest_file_path| exists and is a directory. |
291 if (!src_is_directory && dest_is_directory) | 293 if (!src_is_directory && dest_is_directory) |
292 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | 294 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
293 | 295 |
294 // It is an error to copy/move an entry into the same path. | 296 // It is an error to copy/move an entry into the same path. |
295 if (same_file_system && (src_file_path.value() == dest_file_path.value())) | 297 if (same_file_system && (src_file_path.value() == dest_file_path.value())) |
296 return base::PLATFORM_FILE_ERROR_EXISTS; | 298 return base::PLATFORM_FILE_ERROR_EXISTS; |
297 | 299 |
298 if (dest_is_directory) { | 300 if (dest_is_directory) { |
299 // It is an error to copy/move an entry to a non-empty directory. | 301 // It is an error to copy/move an entry to a non-empty directory. |
300 // Otherwise the copy/move attempt must overwrite the destination, but | 302 // Otherwise the copy/move attempt must overwrite the destination, but |
301 // the file_util's Copy or Move method doesn't perform overwrite | 303 // the file_util's Copy or Move method doesn't perform overwrite |
302 // on all platforms, so we delete the destination directory here. | 304 // on all platforms, so we delete the destination directory here. |
303 // TODO(kinuko): may be better to change the file_util::{Copy,Move}. | 305 // TODO(kinuko): may be better to change the file_util::{Copy,Move}. |
304 PlatformFileError error = dest_util->Delete( | 306 if (base::PLATFORM_FILE_OK != |
305 dest_context.get(), dest_file_path, false /* recursive */); | 307 dest_util->Delete(dest_context, dest_file_path, |
306 context->ImportAllowedBytesGrowth(*dest_context); | 308 false /* recursive */)) { |
307 if (base::PLATFORM_FILE_OK != error) { | 309 if (!dest_util->IsDirectoryEmpty(dest_context, dest_file_path)) |
308 if (!dest_util->IsDirectoryEmpty(dest_context.get(), dest_file_path)) | |
309 return base::PLATFORM_FILE_ERROR_NOT_EMPTY; | 310 return base::PLATFORM_FILE_ERROR_NOT_EMPTY; |
310 return base::PLATFORM_FILE_ERROR_FAILED; | 311 return base::PLATFORM_FILE_ERROR_FAILED; |
311 } | 312 } |
313 // Reflect changes in usage back to the original context. | |
314 if (!same_file_system) | |
315 context->set_allowed_bytes_growth(dest_context->allowed_bytes_growth()); | |
312 } | 316 } |
313 return base::PLATFORM_FILE_OK; | 317 return base::PLATFORM_FILE_OK; |
314 } | 318 } |
315 | 319 |
316 PlatformFileError FileSystemFileUtil::CopyOrMoveFile( | 320 PlatformFileError FileSystemFileUtil::CopyOrMoveFile( |
317 FileSystemOperationContext* unused, | 321 FileSystemOperationContext* unused, |
318 const FilePath& src_file_path, | 322 const FilePath& src_file_path, |
319 const FilePath& dest_file_path, | 323 const FilePath& dest_file_path, |
320 bool copy) { | 324 bool copy) { |
321 if (copy) { | 325 if (copy) { |
(...skipping 13 matching lines...) Expand all Loading... | |
335 const FilePath& dest_file_path) { | 339 const FilePath& dest_file_path) { |
336 return CopyOrMoveFile(context, src_file_path, dest_file_path, true); | 340 return CopyOrMoveFile(context, src_file_path, dest_file_path, true); |
337 } | 341 } |
338 | 342 |
339 PlatformFileError FileSystemFileUtil::CopyOrMoveDirectory( | 343 PlatformFileError FileSystemFileUtil::CopyOrMoveDirectory( |
340 FileSystemOperationContext* context, | 344 FileSystemOperationContext* context, |
341 const FilePath& src_file_path, | 345 const FilePath& src_file_path, |
342 const FilePath& dest_file_path, | 346 const FilePath& dest_file_path, |
343 bool copy) { | 347 bool copy) { |
344 FileSystemFileUtil* dest_util = context->dest_file_system_file_util(); | 348 FileSystemFileUtil* dest_util = context->dest_file_system_file_util(); |
349 // All the single-path virtual FSFU methods expect the context information to | |
350 // be in the src_* variables, not the dest_* variables, so we have to make a | |
351 // new context if we want to call them on the dest_file_path. | |
345 scoped_ptr<FileSystemOperationContext> dest_context( | 352 scoped_ptr<FileSystemOperationContext> dest_context( |
346 context->CreateInheritedContextForDest()); | 353 context->CreateInheritedContextForDest()); |
347 | 354 |
348 // Re-check PerformCommonCheckAndPreparationForMoveAndCopy() by DCHECK. | 355 // Re-check PerformCommonCheckAndPreparationForMoveAndCopy() by DCHECK. |
349 DCHECK(DirectoryExists(context, src_file_path)); | 356 DCHECK(DirectoryExists(context, src_file_path)); |
350 DCHECK(ParentExists(dest_context.get(), dest_util, dest_file_path)); | 357 DCHECK(ParentExists(dest_context.get(), dest_util, dest_file_path)); |
351 DCHECK(!dest_util->PathExists(dest_context.get(), dest_file_path)); | 358 DCHECK(!dest_util->PathExists(dest_context.get(), dest_file_path)); |
352 if ((context->src_origin_url() == context->dest_origin_url()) && | 359 if ((context->src_origin_url() == context->dest_origin_url()) && |
353 (context->src_type() == context->dest_type())) | 360 (context->src_type() == context->dest_type())) |
354 DCHECK(!src_file_path.IsParent(dest_file_path)); | 361 DCHECK(!src_file_path.IsParent(dest_file_path)); |
355 | 362 |
356 if (!dest_util->DirectoryExists(dest_context.get(), dest_file_path)) { | 363 if (!dest_util->DirectoryExists(dest_context.get(), dest_file_path)) { |
357 PlatformFileError error = dest_util->CreateDirectory(dest_context.get(), | 364 PlatformFileError error = dest_util->CreateDirectory(dest_context.get(), |
358 dest_file_path, false, false); | 365 dest_file_path, false, false); |
359 context->ImportAllowedBytesGrowth(*dest_context); | |
360 if (error != base::PLATFORM_FILE_OK) | 366 if (error != base::PLATFORM_FILE_OK) |
361 return error; | 367 return error; |
362 } | 368 } |
363 | 369 |
364 scoped_ptr<AbstractFileEnumerator> file_enum( | 370 scoped_ptr<AbstractFileEnumerator> file_enum( |
365 CreateFileEnumerator(context, src_file_path)); | 371 CreateFileEnumerator(context, src_file_path)); |
366 FilePath src_file_path_each; | 372 FilePath src_file_path_each; |
367 while (!(src_file_path_each = file_enum->Next()).empty()) { | 373 while (!(src_file_path_each = file_enum->Next()).empty()) { |
368 FilePath dest_file_path_each(dest_file_path); | 374 FilePath dest_file_path_each(dest_file_path); |
369 src_file_path.AppendRelativePath(src_file_path_each, &dest_file_path_each); | 375 src_file_path.AppendRelativePath(src_file_path_each, &dest_file_path_each); |
370 | 376 |
371 if (file_enum->IsDirectory()) { | 377 if (file_enum->IsDirectory()) { |
372 scoped_ptr<FileSystemOperationContext> new_directory_context( | 378 PlatformFileError error = dest_util->CreateDirectory(dest_context.get(), |
373 dest_context->CreateInheritedContextWithNewVirtualPaths( | 379 dest_file_path_each, false, false); |
Dai Mikurube (NOT FULLTIME)
2011/08/18 12:00:10
The dest_context should be reflected back in the w
ericu
2011/08/18 22:30:36
Ah, good catch--thanks!
Fixed.
| |
374 dest_file_path_each, FilePath())); | |
375 PlatformFileError error = dest_util->CreateDirectory( | |
376 new_directory_context.get(), dest_file_path_each, false, false); | |
377 context->ImportAllowedBytesGrowth(*new_directory_context); | |
378 if (error != base::PLATFORM_FILE_OK) | 380 if (error != base::PLATFORM_FILE_OK) |
379 return error; | 381 return error; |
380 } else { | 382 } else { |
381 scoped_ptr<FileSystemOperationContext> copy_context( | |
382 context->CreateInheritedContextWithNewVirtualPaths( | |
383 src_file_path_each, dest_file_path_each)); | |
384 PlatformFileError error = CopyOrMoveFileHelper( | 383 PlatformFileError error = CopyOrMoveFileHelper( |
385 copy_context.get(), src_file_path_each, dest_file_path_each, copy); | 384 context, src_file_path_each, dest_file_path_each, copy); |
386 context->ImportAllowedBytesGrowth(*copy_context); | |
387 if (error != base::PLATFORM_FILE_OK) | 385 if (error != base::PLATFORM_FILE_OK) |
388 return error; | 386 return error; |
389 } | 387 } |
390 } | 388 } |
391 | 389 |
392 if (!copy) { | 390 if (!copy) { |
393 PlatformFileError error = Delete(context, src_file_path, true); | 391 PlatformFileError error = Delete(context, src_file_path, true); |
394 if (error != base::PLATFORM_FILE_OK) | 392 if (error != base::PLATFORM_FILE_OK) |
395 return error; | 393 return error; |
396 } | 394 } |
395 | |
396 // Reflect changes in usage back to the original context. | |
397 context->set_allowed_bytes_growth(dest_context->allowed_bytes_growth()); | |
397 return base::PLATFORM_FILE_OK; | 398 return base::PLATFORM_FILE_OK; |
398 } | 399 } |
399 | 400 |
400 PlatformFileError FileSystemFileUtil::CopyOrMoveFileHelper( | 401 PlatformFileError FileSystemFileUtil::CopyOrMoveFileHelper( |
401 FileSystemOperationContext* context, | 402 FileSystemOperationContext* context, |
402 const FilePath& src_file_path, | 403 const FilePath& src_file_path, |
403 const FilePath& dest_file_path, | 404 const FilePath& dest_file_path, |
404 bool copy) { | 405 bool copy) { |
405 // CopyOrMoveFile here is the virtual overridden member function. | 406 // CopyOrMoveFile here is the virtual overridden member function. |
406 if ((context->src_origin_url() == context->dest_origin_url()) && | 407 if ((context->src_origin_url() == context->dest_origin_url()) && |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
462 scoped_ptr<AbstractFileEnumerator> file_enum( | 463 scoped_ptr<AbstractFileEnumerator> file_enum( |
463 CreateFileEnumerator(context, file_path)); | 464 CreateFileEnumerator(context, file_path)); |
464 FilePath file_path_each; | 465 FilePath file_path_each; |
465 | 466 |
466 std::stack<FilePath> directories; | 467 std::stack<FilePath> directories; |
467 while (!(file_path_each = file_enum->Next()).empty()) { | 468 while (!(file_path_each = file_enum->Next()).empty()) { |
468 if (file_enum->IsDirectory()) { | 469 if (file_enum->IsDirectory()) { |
469 directories.push(file_path_each); | 470 directories.push(file_path_each); |
470 } else { | 471 } else { |
471 // DeleteFile here is the virtual overridden member function. | 472 // DeleteFile here is the virtual overridden member function. |
472 scoped_ptr<FileSystemOperationContext> inherited_context( | 473 PlatformFileError error = DeleteFile(context, file_path_each); |
Dai Mikurube (NOT FULLTIME)
2011/08/18 12:00:10
file_path_each is better to be passed as src_virtu
ericu
2011/08/18 22:30:36
*_virtual_path is unused in all Delete/Remove call
| |
473 context->CreateInheritedContextWithNewVirtualPaths( | |
474 file_path_each, FilePath())); | |
475 PlatformFileError error = | |
476 DeleteFile(inherited_context.get(), file_path_each); | |
477 context->ImportAllowedBytesGrowth(*inherited_context); | |
478 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) | 474 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) |
479 return base::PLATFORM_FILE_ERROR_FAILED; | 475 return base::PLATFORM_FILE_ERROR_FAILED; |
480 else if (error != base::PLATFORM_FILE_OK) | 476 else if (error != base::PLATFORM_FILE_OK) |
481 return error; | 477 return error; |
482 } | 478 } |
483 } | 479 } |
484 | 480 |
485 while (!directories.empty()) { | 481 while (!directories.empty()) { |
486 scoped_ptr<FileSystemOperationContext> inherited_context( | 482 PlatformFileError error = DeleteSingleDirectory(context, directories.top()); |
487 context->CreateInheritedContextWithNewVirtualPaths( | |
488 directories.top(), FilePath())); | |
489 PlatformFileError error = | |
490 DeleteSingleDirectory(inherited_context.get(), directories.top()); | |
491 context->ImportAllowedBytesGrowth(*inherited_context); | |
492 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) | 483 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) |
493 return base::PLATFORM_FILE_ERROR_FAILED; | 484 return base::PLATFORM_FILE_ERROR_FAILED; |
494 else if (error != base::PLATFORM_FILE_OK) | 485 else if (error != base::PLATFORM_FILE_OK) |
495 return error; | 486 return error; |
496 directories.pop(); | 487 directories.pop(); |
497 } | 488 } |
498 return DeleteSingleDirectory(context, file_path); | 489 return DeleteSingleDirectory(context, file_path); |
499 } | 490 } |
500 | 491 |
501 bool FileSystemFileUtil::PathExists( | 492 bool FileSystemFileUtil::PathExists( |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
548 FileSystemFileUtil::CreateFileEnumerator( | 539 FileSystemFileUtil::CreateFileEnumerator( |
549 FileSystemOperationContext* unused, | 540 FileSystemOperationContext* unused, |
550 const FilePath& root_path) { | 541 const FilePath& root_path) { |
551 return new FileSystemFileEnumerator( | 542 return new FileSystemFileEnumerator( |
552 root_path, true, static_cast<file_util::FileEnumerator::FileType>( | 543 root_path, true, static_cast<file_util::FileEnumerator::FileType>( |
553 file_util::FileEnumerator::FILES | | 544 file_util::FileEnumerator::FILES | |
554 file_util::FileEnumerator::DIRECTORIES)); | 545 file_util::FileEnumerator::DIRECTORIES)); |
555 } | 546 } |
556 | 547 |
557 } // namespace fileapi | 548 } // namespace fileapi |
OLD | NEW |