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

Side by Side Diff: webkit/browser/fileapi/copy_or_move_operation_delegate.cc

Issue 23463048: Implement stream based cross file system copy. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 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) 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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698