Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 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/browser/fileapi/copy_or_move_operation_delegate.h" | 5 #include "webkit/browser/fileapi/copy_or_move_operation_delegate.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
| 9 #include "net/base/io_buffer.h" | |
| 10 #include "net/base/net_errors.h" | |
| 11 #include "webkit/browser/blob/file_stream_reader.h" | |
| 9 #include "webkit/browser/fileapi/copy_or_move_file_validator.h" | 12 #include "webkit/browser/fileapi/copy_or_move_file_validator.h" |
| 13 #include "webkit/browser/fileapi/file_stream_writer.h" | |
| 10 #include "webkit/browser/fileapi/file_system_context.h" | 14 #include "webkit/browser/fileapi/file_system_context.h" |
| 11 #include "webkit/browser/fileapi/file_system_operation_runner.h" | 15 #include "webkit/browser/fileapi/file_system_operation_runner.h" |
| 12 #include "webkit/browser/fileapi/file_system_url.h" | 16 #include "webkit/browser/fileapi/file_system_url.h" |
| 13 #include "webkit/browser/fileapi/recursive_operation_delegate.h" | 17 #include "webkit/browser/fileapi/recursive_operation_delegate.h" |
| 14 #include "webkit/common/blob/shareable_file_reference.h" | 18 #include "webkit/common/blob/shareable_file_reference.h" |
| 15 #include "webkit/common/fileapi/file_system_util.h" | 19 #include "webkit/common/fileapi/file_system_util.h" |
| 16 | 20 |
| 17 namespace fileapi { | 21 namespace fileapi { |
| 18 | 22 |
| 19 class CopyOrMoveOperationDelegate::CopyOrMoveImpl { | 23 class CopyOrMoveOperationDelegate::CopyOrMoveImpl { |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 274 FileSystemURL src_url_; | 278 FileSystemURL src_url_; |
| 275 FileSystemURL dest_url_; | 279 FileSystemURL dest_url_; |
| 276 CopyOrMoveFileValidatorFactory* validator_factory_; | 280 CopyOrMoveFileValidatorFactory* validator_factory_; |
| 277 scoped_ptr<CopyOrMoveFileValidator> validator_; | 281 scoped_ptr<CopyOrMoveFileValidator> validator_; |
| 278 FileSystemOperation::CopyFileProgressCallback file_progress_callback_; | 282 FileSystemOperation::CopyFileProgressCallback file_progress_callback_; |
| 279 | 283 |
| 280 base::WeakPtrFactory<SnapshotCopyOrMoveImpl> weak_factory_; | 284 base::WeakPtrFactory<SnapshotCopyOrMoveImpl> weak_factory_; |
| 281 DISALLOW_COPY_AND_ASSIGN(SnapshotCopyOrMoveImpl); | 285 DISALLOW_COPY_AND_ASSIGN(SnapshotCopyOrMoveImpl); |
| 282 }; | 286 }; |
| 283 | 287 |
| 288 // The size of buffer for StreamCopyHelper. | |
| 289 const int kReadBufferSize = 32768; | |
| 290 | |
| 291 // To avoid too many progress callbacks, it should be called less | |
| 292 // frequently than 50ms. | |
| 293 const int kMinProgressCallbackInvocationSpanInMilliseconds = 50; | |
| 294 | |
| 295 // Specifically for cross file system copy/move operation, this class uses | |
| 296 // stream reader and writer for copying. Validator is not supported, so if | |
| 297 // necessary SnapshotCopyOrMoveImpl should be used. | |
| 298 class StreamCopyOrMoveImpl | |
| 299 : public CopyOrMoveOperationDelegate::CopyOrMoveImpl { | |
| 300 public: | |
| 301 StreamCopyOrMoveImpl( | |
| 302 FileSystemOperationRunner* operation_runner, | |
| 303 CopyOrMoveOperationDelegate::OperationType operation_type, | |
| 304 const FileSystemURL& src_url, | |
| 305 const FileSystemURL& dest_url, | |
| 306 scoped_ptr<webkit_blob::FileStreamReader> reader, | |
| 307 scoped_ptr<FileStreamWriter> writer, | |
| 308 const FileSystemOperation::CopyFileProgressCallback& | |
| 309 file_progress_callback) | |
| 310 : operation_runner_(operation_runner), | |
| 311 operation_type_(operation_type), | |
| 312 src_url_(src_url), | |
| 313 dest_url_(dest_url), | |
| 314 reader_(reader.Pass()), | |
| 315 writer_(writer.Pass()), | |
| 316 file_progress_callback_(file_progress_callback), | |
| 317 weak_factory_(this) { | |
| 318 } | |
| 319 | |
| 320 virtual void Run( | |
| 321 const CopyOrMoveOperationDelegate::StatusCallback& callback) OVERRIDE { | |
| 322 // Reader can be created even if the entry is not exists or the entry is | |
|
kinuko
2013/09/21 10:44:36
nit: is not exists -> does not exist
hidehiko
2013/09/23 08:18:10
Oops Done.
| |
| 323 // a directory. To check errors before destination file creation, | |
| 324 // check metadata first. | |
| 325 operation_runner_->GetMetadata( | |
| 326 src_url_, | |
| 327 base::Bind(&StreamCopyOrMoveImpl::RunAfterGetMetadataForSource, | |
| 328 weak_factory_.GetWeakPtr(), callback)); | |
| 329 } | |
| 330 | |
| 331 private: | |
| 332 void RunAfterGetMetadataForSource( | |
| 333 const CopyOrMoveOperationDelegate::StatusCallback& callback, | |
| 334 base::PlatformFileError error, | |
| 335 const base::PlatformFileInfo& file_info) { | |
| 336 if (error != base::PLATFORM_FILE_OK) { | |
| 337 callback.Run(error); | |
| 338 return; | |
| 339 } | |
| 340 if (file_info.is_directory) { | |
| 341 // If not a directory, failed with appropriate error code. | |
| 342 callback.Run(base::PLATFORM_FILE_ERROR_NOT_A_FILE); | |
| 343 return; | |
| 344 } | |
| 345 | |
| 346 // To use FileStreamWriter, we need to ensure the destination file exists. | |
| 347 operation_runner_->CreateFile( | |
| 348 dest_url_, false /* exclusive */, | |
| 349 base::Bind(&StreamCopyOrMoveImpl::RunAfterCreateFileForDestination, | |
| 350 weak_factory_.GetWeakPtr(), callback)); | |
| 351 } | |
| 352 | |
| 353 void RunAfterCreateFileForDestination( | |
| 354 const CopyOrMoveOperationDelegate::StatusCallback& callback, | |
| 355 base::PlatformFileError error) { | |
| 356 if (error != base::PLATFORM_FILE_OK) { | |
| 357 callback.Run(error); | |
| 358 return; | |
| 359 } | |
| 360 | |
| 361 DCHECK(!copy_helper_); | |
| 362 copy_helper_.reset( | |
| 363 new CopyOrMoveOperationDelegate::StreamCopyHelper( | |
| 364 reader_.Pass(), writer_.Pass(), | |
| 365 kReadBufferSize, | |
| 366 file_progress_callback_, | |
| 367 base::TimeDelta::FromMilliseconds( | |
| 368 kMinProgressCallbackInvocationSpanInMilliseconds))); | |
| 369 copy_helper_->Run( | |
| 370 base::Bind(&StreamCopyOrMoveImpl::RunAfterStreamCopy, | |
| 371 weak_factory_.GetWeakPtr(), callback)); | |
| 372 } | |
| 373 | |
| 374 void RunAfterStreamCopy( | |
| 375 const CopyOrMoveOperationDelegate::StatusCallback& callback, | |
| 376 base::PlatformFileError error) { | |
| 377 if (error != base::PLATFORM_FILE_OK) { | |
| 378 callback.Run(error); | |
| 379 return; | |
| 380 } | |
| 381 | |
| 382 if (operation_type_ == CopyOrMoveOperationDelegate::OPERATION_COPY) { | |
| 383 callback.Run(base::PLATFORM_FILE_OK); | |
| 384 return; | |
| 385 } | |
| 386 | |
| 387 DCHECK_EQ(CopyOrMoveOperationDelegate::OPERATION_MOVE, operation_type_); | |
| 388 | |
| 389 // Remove the source for finalizing move operation. | |
| 390 operation_runner_->Remove( | |
| 391 src_url_, false /* recursive */, | |
| 392 base::Bind(&StreamCopyOrMoveImpl::RunAfterRemoveForMove, | |
| 393 weak_factory_.GetWeakPtr(), callback)); | |
| 394 } | |
| 395 | |
| 396 void RunAfterRemoveForMove( | |
| 397 const CopyOrMoveOperationDelegate::StatusCallback& callback, | |
| 398 base::PlatformFileError error) { | |
| 399 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) | |
| 400 error = base::PLATFORM_FILE_OK; | |
| 401 callback.Run(error); | |
| 402 } | |
| 403 | |
| 404 FileSystemOperationRunner* operation_runner_; | |
| 405 CopyOrMoveOperationDelegate::OperationType operation_type_; | |
| 406 FileSystemURL src_url_; | |
| 407 FileSystemURL dest_url_; | |
| 408 scoped_ptr<webkit_blob::FileStreamReader> reader_; | |
| 409 scoped_ptr<FileStreamWriter> writer_; | |
| 410 FileSystemOperation::CopyFileProgressCallback file_progress_callback_; | |
| 411 scoped_ptr<CopyOrMoveOperationDelegate::StreamCopyHelper> copy_helper_; | |
| 412 | |
| 413 base::WeakPtrFactory<StreamCopyOrMoveImpl> weak_factory_; | |
| 414 DISALLOW_COPY_AND_ASSIGN(StreamCopyOrMoveImpl); | |
| 415 }; | |
| 416 | |
| 417 // Translates the net::Error to base::PlatformFileError. | |
| 418 base::PlatformFileError NetErrorToPlatformFileError(int error) { | |
|
kinuko
2013/09/21 10:44:36
Hmm.. could this be moved to webkit/common/fileapi
hidehiko
2013/09/23 08:18:10
Done.
| |
| 419 switch (error) { | |
| 420 case net::OK: | |
| 421 return base::PLATFORM_FILE_OK; | |
| 422 case net::ERR_ADDRESS_IN_USE: | |
| 423 return base::PLATFORM_FILE_ERROR_IN_USE; | |
| 424 case net::ERR_FILE_EXISTS: | |
| 425 return base::PLATFORM_FILE_ERROR_EXISTS; | |
| 426 case net::ERR_FILE_NOT_FOUND: | |
| 427 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 428 case net::ERR_ACCESS_DENIED: | |
| 429 return base::PLATFORM_FILE_ERROR_ACCESS_DENIED; | |
| 430 case net::ERR_TOO_MANY_SOCKET_STREAMS: | |
| 431 return base::PLATFORM_FILE_ERROR_TOO_MANY_OPENED; | |
| 432 case net::ERR_OUT_OF_MEMORY: | |
| 433 return base::PLATFORM_FILE_ERROR_NO_MEMORY; | |
| 434 case net::ERR_FILE_NO_SPACE: | |
| 435 return base::PLATFORM_FILE_ERROR_NO_SPACE; | |
| 436 case net::ERR_INVALID_ARGUMENT: | |
| 437 case net::ERR_INVALID_HANDLE: | |
| 438 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | |
| 439 case net::ERR_ABORTED: | |
| 440 case net::ERR_CONNECTION_ABORTED: | |
| 441 return base::PLATFORM_FILE_ERROR_ABORT; | |
| 442 case net::ERR_ADDRESS_INVALID: | |
| 443 case net::ERR_INVALID_URL: | |
| 444 return base::PLATFORM_FILE_ERROR_INVALID_URL; | |
| 445 default: | |
| 446 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 447 } | |
| 448 } | |
| 449 | |
| 284 } // namespace | 450 } // namespace |
| 285 | 451 |
| 452 CopyOrMoveOperationDelegate::StreamCopyHelper::StreamCopyHelper( | |
| 453 scoped_ptr<webkit_blob::FileStreamReader> reader, | |
| 454 scoped_ptr<FileStreamWriter> writer, | |
| 455 int buffer_size, | |
| 456 const FileSystemOperation::CopyFileProgressCallback& | |
| 457 file_progress_callback, | |
| 458 const base::TimeDelta& min_progress_callback_invocation_span) | |
| 459 : reader_(reader.Pass()), | |
| 460 writer_(writer.Pass()), | |
| 461 file_progress_callback_(file_progress_callback), | |
| 462 io_buffer_(new net::IOBufferWithSize(buffer_size)), | |
| 463 num_copied_bytes_(0), | |
| 464 min_progress_callback_invocation_span_( | |
| 465 min_progress_callback_invocation_span), | |
| 466 weak_factory_(this) { | |
| 467 } | |
| 468 | |
| 469 CopyOrMoveOperationDelegate::StreamCopyHelper::~StreamCopyHelper() { | |
| 470 } | |
| 471 | |
| 472 void CopyOrMoveOperationDelegate::StreamCopyHelper::Run( | |
| 473 const StatusCallback& callback) { | |
| 474 file_progress_callback_.Run(0); | |
| 475 last_progress_callback_invocation_time_ = base::Time::Now(); | |
| 476 Read(callback); | |
| 477 } | |
| 478 | |
| 479 void CopyOrMoveOperationDelegate::StreamCopyHelper::Read( | |
| 480 const StatusCallback& callback) { | |
| 481 int result = reader_->Read( | |
| 482 io_buffer_.get(), io_buffer_->size(), | |
| 483 base::Bind(&StreamCopyHelper::DidRead, | |
| 484 weak_factory_.GetWeakPtr(), callback)); | |
| 485 if (result != net::ERR_IO_PENDING) | |
| 486 DidRead(callback, result); | |
| 487 } | |
| 488 | |
| 489 void CopyOrMoveOperationDelegate::StreamCopyHelper::DidRead( | |
| 490 const StatusCallback& callback, int result) { | |
| 491 if (result < 0) { | |
| 492 callback.Run(NetErrorToPlatformFileError(result)); | |
| 493 return; | |
| 494 } | |
| 495 | |
| 496 if (result == 0) { | |
| 497 // Here is the EOF. | |
| 498 callback.Run(base::PLATFORM_FILE_OK); | |
| 499 return; | |
| 500 } | |
| 501 | |
| 502 Write(callback, new net::DrainableIOBuffer(io_buffer_.get(), result)); | |
| 503 } | |
| 504 | |
| 505 void CopyOrMoveOperationDelegate::StreamCopyHelper::Write( | |
| 506 const StatusCallback& callback, | |
| 507 scoped_refptr<net::DrainableIOBuffer> buffer) { | |
| 508 DCHECK_GT(buffer->BytesRemaining(), 0); | |
| 509 | |
| 510 int result = writer_->Write( | |
| 511 buffer.get(), buffer->BytesRemaining(), | |
| 512 base::Bind(&StreamCopyHelper::DidWrite, | |
| 513 weak_factory_.GetWeakPtr(), callback, buffer)); | |
| 514 if (result != net::ERR_IO_PENDING) | |
| 515 DidWrite(callback, buffer, result); | |
| 516 } | |
| 517 | |
| 518 void CopyOrMoveOperationDelegate::StreamCopyHelper::DidWrite( | |
| 519 const StatusCallback& callback, | |
| 520 scoped_refptr<net::DrainableIOBuffer> buffer, | |
| 521 int result) { | |
| 522 if (result < 0) { | |
| 523 callback.Run(NetErrorToPlatformFileError(result)); | |
| 524 return; | |
| 525 } | |
| 526 | |
| 527 buffer->DidConsume(result); | |
| 528 num_copied_bytes_ += result; | |
| 529 | |
| 530 // Check the elapsed time since last |file_progress_callback_| invocation. | |
| 531 base::Time now = base::Time::Now(); | |
| 532 if (now - last_progress_callback_invocation_time_ >= | |
| 533 min_progress_callback_invocation_span_) { | |
| 534 file_progress_callback_.Run(num_copied_bytes_); | |
| 535 last_progress_callback_invocation_time_ = now; | |
| 536 } | |
| 537 | |
| 538 if (buffer->BytesRemaining() > 0) { | |
| 539 Write(callback, buffer); | |
| 540 return; | |
| 541 } | |
| 542 | |
| 543 Read(callback); | |
| 544 } | |
| 286 | 545 |
| 287 CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate( | 546 CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate( |
| 288 FileSystemContext* file_system_context, | 547 FileSystemContext* file_system_context, |
| 289 const FileSystemURL& src_root, | 548 const FileSystemURL& src_root, |
| 290 const FileSystemURL& dest_root, | 549 const FileSystemURL& dest_root, |
| 291 OperationType operation_type, | 550 OperationType operation_type, |
| 292 const CopyProgressCallback& progress_callback, | 551 const CopyProgressCallback& progress_callback, |
| 293 const StatusCallback& callback) | 552 const StatusCallback& callback) |
| 294 : RecursiveOperationDelegate(file_system_context), | 553 : RecursiveOperationDelegate(file_system_context), |
| 295 src_root_(src_root), | 554 src_root_(src_root), |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 342 | 601 |
| 343 FileSystemURL dest_url = CreateDestURL(src_url); | 602 FileSystemURL dest_url = CreateDestURL(src_url); |
| 344 CopyOrMoveImpl* impl = NULL; | 603 CopyOrMoveImpl* impl = NULL; |
| 345 if (same_file_system_) { | 604 if (same_file_system_) { |
| 346 impl = new CopyOrMoveOnSameFileSystemImpl( | 605 impl = new CopyOrMoveOnSameFileSystemImpl( |
| 347 operation_runner(), operation_type_, src_url, dest_url, | 606 operation_runner(), operation_type_, src_url, dest_url, |
| 348 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, | 607 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, |
| 349 weak_factory_.GetWeakPtr(), src_url)); | 608 weak_factory_.GetWeakPtr(), src_url)); |
| 350 } else { | 609 } else { |
| 351 // Cross filesystem case. | 610 // Cross filesystem case. |
| 352 // TODO(hidehiko): Support stream based copy. crbug.com/279287. | |
| 353 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; | 611 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; |
| 354 CopyOrMoveFileValidatorFactory* validator_factory = | 612 CopyOrMoveFileValidatorFactory* validator_factory = |
| 355 file_system_context()->GetCopyOrMoveFileValidatorFactory( | 613 file_system_context()->GetCopyOrMoveFileValidatorFactory( |
| 356 dest_root_.type(), &error); | 614 dest_root_.type(), &error); |
| 357 if (error != base::PLATFORM_FILE_OK) { | 615 if (error != base::PLATFORM_FILE_OK) { |
| 358 callback.Run(error); | 616 callback.Run(error); |
| 359 return; | 617 return; |
| 360 } | 618 } |
| 361 | 619 |
| 362 impl = new SnapshotCopyOrMoveImpl( | 620 if (!validator_factory) { |
| 363 operation_runner(), operation_type_, src_url, dest_url, | 621 scoped_ptr<webkit_blob::FileStreamReader> reader = |
| 364 validator_factory, | 622 file_system_context()->CreateFileStreamReader( |
| 365 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, | 623 src_url, 0, base::Time()); |
| 366 weak_factory_.GetWeakPtr(), src_url)); | 624 scoped_ptr<FileStreamWriter> writer = |
| 625 file_system_context()->CreateFileStreamWriter(dest_url, 0); | |
| 626 if (reader && writer) { | |
| 627 impl = new StreamCopyOrMoveImpl( | |
| 628 operation_runner(), operation_type_, src_url, dest_url, | |
| 629 reader.Pass(), writer.Pass(), | |
| 630 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, | |
| 631 weak_factory_.GetWeakPtr(), src_url)); | |
| 632 } | |
| 633 } | |
| 634 | |
| 635 if (!impl) { | |
| 636 impl = new SnapshotCopyOrMoveImpl( | |
| 637 operation_runner(), operation_type_, src_url, dest_url, | |
| 638 validator_factory, | |
| 639 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, | |
| 640 weak_factory_.GetWeakPtr(), src_url)); | |
| 641 } | |
| 367 } | 642 } |
| 368 | 643 |
| 369 // Register the running task. | 644 // Register the running task. |
| 370 running_copy_set_.insert(impl); | 645 running_copy_set_.insert(impl); |
| 371 impl->Run(base::Bind( | 646 impl->Run(base::Bind( |
| 372 &CopyOrMoveOperationDelegate::DidCopyOrMoveFile, | 647 &CopyOrMoveOperationDelegate::DidCopyOrMoveFile, |
| 373 weak_factory_.GetWeakPtr(), src_url, dest_url, callback, impl)); | 648 weak_factory_.GetWeakPtr(), src_url, dest_url, callback, impl)); |
| 374 } | 649 } |
| 375 | 650 |
| 376 void CopyOrMoveOperationDelegate::ProcessDirectory( | 651 void CopyOrMoveOperationDelegate::ProcessDirectory( |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 499 base::FilePath relative = dest_root_.virtual_path(); | 774 base::FilePath relative = dest_root_.virtual_path(); |
| 500 src_root_.virtual_path().AppendRelativePath(src_url.virtual_path(), | 775 src_root_.virtual_path().AppendRelativePath(src_url.virtual_path(), |
| 501 &relative); | 776 &relative); |
| 502 return file_system_context()->CreateCrackedFileSystemURL( | 777 return file_system_context()->CreateCrackedFileSystemURL( |
| 503 dest_root_.origin(), | 778 dest_root_.origin(), |
| 504 dest_root_.mount_type(), | 779 dest_root_.mount_type(), |
| 505 relative); | 780 relative); |
| 506 } | 781 } |
| 507 | 782 |
| 508 } // namespace fileapi | 783 } // namespace fileapi |
| OLD | NEW |