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

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, 2 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 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
282 // TODO(hidehiko): Implement the option's behavior. 286 // TODO(hidehiko): Implement the option's behavior.
283 CopyOrMoveOperationDelegate::CopyOrMoveOption option_; 287 CopyOrMoveOperationDelegate::CopyOrMoveOption option_;
284 CopyOrMoveFileValidatorFactory* validator_factory_; 288 CopyOrMoveFileValidatorFactory* validator_factory_;
285 scoped_ptr<CopyOrMoveFileValidator> validator_; 289 scoped_ptr<CopyOrMoveFileValidator> validator_;
286 FileSystemOperation::CopyFileProgressCallback file_progress_callback_; 290 FileSystemOperation::CopyFileProgressCallback file_progress_callback_;
287 291
288 base::WeakPtrFactory<SnapshotCopyOrMoveImpl> weak_factory_; 292 base::WeakPtrFactory<SnapshotCopyOrMoveImpl> weak_factory_;
289 DISALLOW_COPY_AND_ASSIGN(SnapshotCopyOrMoveImpl); 293 DISALLOW_COPY_AND_ASSIGN(SnapshotCopyOrMoveImpl);
290 }; 294 };
291 295
296 // The size of buffer for StreamCopyHelper.
297 const int kReadBufferSize = 32768;
298
299 // To avoid too many progress callbacks, it should be called less
300 // frequently than 50ms.
301 const int kMinProgressCallbackInvocationSpanInMilliseconds = 50;
302
303 // Specifically for cross file system copy/move operation, this class uses
304 // stream reader and writer for copying. Validator is not supported, so if
305 // necessary SnapshotCopyOrMoveImpl should be used.
306 class StreamCopyOrMoveImpl
307 : public CopyOrMoveOperationDelegate::CopyOrMoveImpl {
308 public:
309 StreamCopyOrMoveImpl(
310 FileSystemOperationRunner* operation_runner,
311 CopyOrMoveOperationDelegate::OperationType operation_type,
312 const FileSystemURL& src_url,
313 const FileSystemURL& dest_url,
314 scoped_ptr<webkit_blob::FileStreamReader> reader,
315 scoped_ptr<FileStreamWriter> writer,
316 const FileSystemOperation::CopyFileProgressCallback&
317 file_progress_callback)
318 : operation_runner_(operation_runner),
319 operation_type_(operation_type),
320 src_url_(src_url),
321 dest_url_(dest_url),
322 reader_(reader.Pass()),
323 writer_(writer.Pass()),
324 file_progress_callback_(file_progress_callback),
325 weak_factory_(this) {
326 }
327
328 virtual void Run(
329 const CopyOrMoveOperationDelegate::StatusCallback& callback) OVERRIDE {
330 // Reader can be created even if the entry does not exist or the entry is
331 // a directory. To check errors before destination file creation,
332 // check metadata first.
333 operation_runner_->GetMetadata(
334 src_url_,
335 base::Bind(&StreamCopyOrMoveImpl::RunAfterGetMetadataForSource,
336 weak_factory_.GetWeakPtr(), callback));
337 }
338
339 private:
340 void RunAfterGetMetadataForSource(
341 const CopyOrMoveOperationDelegate::StatusCallback& callback,
342 base::PlatformFileError error,
343 const base::PlatformFileInfo& file_info) {
344 if (error != base::PLATFORM_FILE_OK) {
345 callback.Run(error);
346 return;
347 }
348 if (file_info.is_directory) {
349 // If not a directory, failed with appropriate error code.
350 callback.Run(base::PLATFORM_FILE_ERROR_NOT_A_FILE);
351 return;
352 }
353
354 // To use FileStreamWriter, we need to ensure the destination file exists.
355 operation_runner_->CreateFile(
356 dest_url_, false /* exclusive */,
357 base::Bind(&StreamCopyOrMoveImpl::RunAfterCreateFileForDestination,
358 weak_factory_.GetWeakPtr(), callback));
359 }
360
361 void RunAfterCreateFileForDestination(
362 const CopyOrMoveOperationDelegate::StatusCallback& callback,
363 base::PlatformFileError error) {
364 if (error != base::PLATFORM_FILE_OK) {
365 callback.Run(error);
366 return;
367 }
368
369 DCHECK(!copy_helper_);
370 copy_helper_.reset(
371 new CopyOrMoveOperationDelegate::StreamCopyHelper(
372 reader_.Pass(), writer_.Pass(),
373 kReadBufferSize,
374 file_progress_callback_,
375 base::TimeDelta::FromMilliseconds(
376 kMinProgressCallbackInvocationSpanInMilliseconds)));
377 copy_helper_->Run(
378 base::Bind(&StreamCopyOrMoveImpl::RunAfterStreamCopy,
379 weak_factory_.GetWeakPtr(), callback));
380 }
381
382 void RunAfterStreamCopy(
383 const CopyOrMoveOperationDelegate::StatusCallback& callback,
384 base::PlatformFileError error) {
385 if (error != base::PLATFORM_FILE_OK) {
386 callback.Run(error);
387 return;
388 }
389
390 if (operation_type_ == CopyOrMoveOperationDelegate::OPERATION_COPY) {
391 callback.Run(base::PLATFORM_FILE_OK);
392 return;
393 }
394
395 DCHECK_EQ(CopyOrMoveOperationDelegate::OPERATION_MOVE, operation_type_);
396
397 // Remove the source for finalizing move operation.
398 operation_runner_->Remove(
399 src_url_, false /* recursive */,
400 base::Bind(&StreamCopyOrMoveImpl::RunAfterRemoveForMove,
401 weak_factory_.GetWeakPtr(), callback));
402 }
403
404 void RunAfterRemoveForMove(
405 const CopyOrMoveOperationDelegate::StatusCallback& callback,
406 base::PlatformFileError error) {
407 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND)
408 error = base::PLATFORM_FILE_OK;
409 callback.Run(error);
410 }
411
412 FileSystemOperationRunner* operation_runner_;
413 CopyOrMoveOperationDelegate::OperationType operation_type_;
414 FileSystemURL src_url_;
415 FileSystemURL dest_url_;
416 scoped_ptr<webkit_blob::FileStreamReader> reader_;
417 scoped_ptr<FileStreamWriter> writer_;
418 FileSystemOperation::CopyFileProgressCallback file_progress_callback_;
419 scoped_ptr<CopyOrMoveOperationDelegate::StreamCopyHelper> copy_helper_;
420
421 base::WeakPtrFactory<StreamCopyOrMoveImpl> weak_factory_;
422 DISALLOW_COPY_AND_ASSIGN(StreamCopyOrMoveImpl);
423 };
424
292 } // namespace 425 } // namespace
293 426
427 CopyOrMoveOperationDelegate::StreamCopyHelper::StreamCopyHelper(
428 scoped_ptr<webkit_blob::FileStreamReader> reader,
429 scoped_ptr<FileStreamWriter> writer,
430 int buffer_size,
431 const FileSystemOperation::CopyFileProgressCallback&
432 file_progress_callback,
433 const base::TimeDelta& min_progress_callback_invocation_span)
434 : reader_(reader.Pass()),
435 writer_(writer.Pass()),
436 file_progress_callback_(file_progress_callback),
437 io_buffer_(new net::IOBufferWithSize(buffer_size)),
438 num_copied_bytes_(0),
439 min_progress_callback_invocation_span_(
440 min_progress_callback_invocation_span),
441 weak_factory_(this) {
442 }
443
444 CopyOrMoveOperationDelegate::StreamCopyHelper::~StreamCopyHelper() {
445 }
446
447 void CopyOrMoveOperationDelegate::StreamCopyHelper::Run(
448 const StatusCallback& callback) {
449 file_progress_callback_.Run(0);
450 last_progress_callback_invocation_time_ = base::Time::Now();
451 Read(callback);
452 }
453
454 void CopyOrMoveOperationDelegate::StreamCopyHelper::Read(
455 const StatusCallback& callback) {
456 int result = reader_->Read(
457 io_buffer_.get(), io_buffer_->size(),
458 base::Bind(&StreamCopyHelper::DidRead,
459 weak_factory_.GetWeakPtr(), callback));
460 if (result != net::ERR_IO_PENDING)
461 DidRead(callback, result);
462 }
463
464 void CopyOrMoveOperationDelegate::StreamCopyHelper::DidRead(
465 const StatusCallback& callback, int result) {
466 if (result < 0) {
467 callback.Run(NetErrorToPlatformFileError(result));
468 return;
469 }
470
471 if (result == 0) {
472 // Here is the EOF.
473 callback.Run(base::PLATFORM_FILE_OK);
474 return;
475 }
476
477 Write(callback, new net::DrainableIOBuffer(io_buffer_.get(), result));
478 }
479
480 void CopyOrMoveOperationDelegate::StreamCopyHelper::Write(
481 const StatusCallback& callback,
482 scoped_refptr<net::DrainableIOBuffer> buffer) {
483 DCHECK_GT(buffer->BytesRemaining(), 0);
484
485 int result = writer_->Write(
486 buffer.get(), buffer->BytesRemaining(),
487 base::Bind(&StreamCopyHelper::DidWrite,
488 weak_factory_.GetWeakPtr(), callback, buffer));
489 if (result != net::ERR_IO_PENDING)
490 DidWrite(callback, buffer, result);
491 }
492
493 void CopyOrMoveOperationDelegate::StreamCopyHelper::DidWrite(
494 const StatusCallback& callback,
495 scoped_refptr<net::DrainableIOBuffer> buffer,
496 int result) {
497 if (result < 0) {
498 callback.Run(NetErrorToPlatformFileError(result));
499 return;
500 }
501
502 buffer->DidConsume(result);
503 num_copied_bytes_ += result;
504
505 // Check the elapsed time since last |file_progress_callback_| invocation.
506 base::Time now = base::Time::Now();
507 if (now - last_progress_callback_invocation_time_ >=
508 min_progress_callback_invocation_span_) {
509 file_progress_callback_.Run(num_copied_bytes_);
510 last_progress_callback_invocation_time_ = now;
511 }
512
513 if (buffer->BytesRemaining() > 0) {
514 Write(callback, buffer);
515 return;
516 }
517
518 Read(callback);
519 }
294 520
295 CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate( 521 CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate(
296 FileSystemContext* file_system_context, 522 FileSystemContext* file_system_context,
297 const FileSystemURL& src_root, 523 const FileSystemURL& src_root,
298 const FileSystemURL& dest_root, 524 const FileSystemURL& dest_root,
299 OperationType operation_type, 525 OperationType operation_type,
300 CopyOrMoveOption option, 526 CopyOrMoveOption option,
301 const CopyProgressCallback& progress_callback, 527 const CopyProgressCallback& progress_callback,
302 const StatusCallback& callback) 528 const StatusCallback& callback)
303 : RecursiveOperationDelegate(file_system_context), 529 : RecursiveOperationDelegate(file_system_context),
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 578
353 FileSystemURL dest_url = CreateDestURL(src_url); 579 FileSystemURL dest_url = CreateDestURL(src_url);
354 CopyOrMoveImpl* impl = NULL; 580 CopyOrMoveImpl* impl = NULL;
355 if (same_file_system_) { 581 if (same_file_system_) {
356 impl = new CopyOrMoveOnSameFileSystemImpl( 582 impl = new CopyOrMoveOnSameFileSystemImpl(
357 operation_runner(), operation_type_, src_url, dest_url, option_, 583 operation_runner(), operation_type_, src_url, dest_url, option_,
358 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, 584 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress,
359 weak_factory_.GetWeakPtr(), src_url)); 585 weak_factory_.GetWeakPtr(), src_url));
360 } else { 586 } else {
361 // Cross filesystem case. 587 // Cross filesystem case.
362 // TODO(hidehiko): Support stream based copy. crbug.com/279287.
363 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; 588 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
364 CopyOrMoveFileValidatorFactory* validator_factory = 589 CopyOrMoveFileValidatorFactory* validator_factory =
365 file_system_context()->GetCopyOrMoveFileValidatorFactory( 590 file_system_context()->GetCopyOrMoveFileValidatorFactory(
366 dest_root_.type(), &error); 591 dest_root_.type(), &error);
367 if (error != base::PLATFORM_FILE_OK) { 592 if (error != base::PLATFORM_FILE_OK) {
368 callback.Run(error); 593 callback.Run(error);
369 return; 594 return;
370 } 595 }
371 596
372 impl = new SnapshotCopyOrMoveImpl( 597 if (!validator_factory) {
373 operation_runner(), operation_type_, src_url, dest_url, option_, 598 scoped_ptr<webkit_blob::FileStreamReader> reader =
374 validator_factory, 599 file_system_context()->CreateFileStreamReader(
375 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, 600 src_url, 0, base::Time());
376 weak_factory_.GetWeakPtr(), src_url)); 601 scoped_ptr<FileStreamWriter> writer =
602 file_system_context()->CreateFileStreamWriter(dest_url, 0);
603 if (reader && writer) {
604 impl = new StreamCopyOrMoveImpl(
605 operation_runner(), operation_type_, src_url, dest_url,
606 reader.Pass(), writer.Pass(),
607 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress,
608 weak_factory_.GetWeakPtr(), src_url));
609 }
610 }
611
612 if (!impl) {
613 impl = new SnapshotCopyOrMoveImpl(
614 operation_runner(), operation_type_, src_url, dest_url, option_,
615 validator_factory,
616 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress,
617 weak_factory_.GetWeakPtr(), src_url));
618 }
377 } 619 }
378 620
379 // Register the running task. 621 // Register the running task.
380 running_copy_set_.insert(impl); 622 running_copy_set_.insert(impl);
381 impl->Run(base::Bind( 623 impl->Run(base::Bind(
382 &CopyOrMoveOperationDelegate::DidCopyOrMoveFile, 624 &CopyOrMoveOperationDelegate::DidCopyOrMoveFile,
383 weak_factory_.GetWeakPtr(), src_url, dest_url, callback, impl)); 625 weak_factory_.GetWeakPtr(), src_url, dest_url, callback, impl));
384 } 626 }
385 627
386 void CopyOrMoveOperationDelegate::ProcessDirectory( 628 void CopyOrMoveOperationDelegate::ProcessDirectory(
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 base::FilePath relative = dest_root_.virtual_path(); 751 base::FilePath relative = dest_root_.virtual_path();
510 src_root_.virtual_path().AppendRelativePath(src_url.virtual_path(), 752 src_root_.virtual_path().AppendRelativePath(src_url.virtual_path(),
511 &relative); 753 &relative);
512 return file_system_context()->CreateCrackedFileSystemURL( 754 return file_system_context()->CreateCrackedFileSystemURL(
513 dest_root_.origin(), 755 dest_root_.origin(),
514 dest_root_.mount_type(), 756 dest_root_.mount_type(),
515 relative); 757 relative);
516 } 758 }
517 759
518 } // namespace fileapi 760 } // namespace fileapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698