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

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 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 does not exists or the entry is
kinuko 2013/09/23 22:10:20 nit: exists -> exist
hidehiko 2013/09/24 02:06:15 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
284 } // namespace 417 } // namespace
285 418
419 CopyOrMoveOperationDelegate::StreamCopyHelper::StreamCopyHelper(
420 scoped_ptr<webkit_blob::FileStreamReader> reader,
421 scoped_ptr<FileStreamWriter> writer,
422 int buffer_size,
423 const FileSystemOperation::CopyFileProgressCallback&
424 file_progress_callback,
425 const base::TimeDelta& min_progress_callback_invocation_span)
426 : reader_(reader.Pass()),
427 writer_(writer.Pass()),
428 file_progress_callback_(file_progress_callback),
429 io_buffer_(new net::IOBufferWithSize(buffer_size)),
430 num_copied_bytes_(0),
431 min_progress_callback_invocation_span_(
432 min_progress_callback_invocation_span),
433 weak_factory_(this) {
434 }
435
436 CopyOrMoveOperationDelegate::StreamCopyHelper::~StreamCopyHelper() {
437 }
438
439 void CopyOrMoveOperationDelegate::StreamCopyHelper::Run(
440 const StatusCallback& callback) {
441 file_progress_callback_.Run(0);
442 last_progress_callback_invocation_time_ = base::Time::Now();
443 Read(callback);
444 }
445
446 void CopyOrMoveOperationDelegate::StreamCopyHelper::Read(
447 const StatusCallback& callback) {
448 int result = reader_->Read(
449 io_buffer_.get(), io_buffer_->size(),
450 base::Bind(&StreamCopyHelper::DidRead,
451 weak_factory_.GetWeakPtr(), callback));
452 if (result != net::ERR_IO_PENDING)
453 DidRead(callback, result);
454 }
455
456 void CopyOrMoveOperationDelegate::StreamCopyHelper::DidRead(
457 const StatusCallback& callback, int result) {
458 if (result < 0) {
459 callback.Run(NetErrorToPlatformFileError(result));
460 return;
461 }
462
463 if (result == 0) {
464 // Here is the EOF.
465 callback.Run(base::PLATFORM_FILE_OK);
466 return;
467 }
468
469 Write(callback, new net::DrainableIOBuffer(io_buffer_.get(), result));
470 }
471
472 void CopyOrMoveOperationDelegate::StreamCopyHelper::Write(
473 const StatusCallback& callback,
474 scoped_refptr<net::DrainableIOBuffer> buffer) {
475 DCHECK_GT(buffer->BytesRemaining(), 0);
476
477 int result = writer_->Write(
478 buffer.get(), buffer->BytesRemaining(),
479 base::Bind(&StreamCopyHelper::DidWrite,
480 weak_factory_.GetWeakPtr(), callback, buffer));
481 if (result != net::ERR_IO_PENDING)
482 DidWrite(callback, buffer, result);
483 }
484
485 void CopyOrMoveOperationDelegate::StreamCopyHelper::DidWrite(
486 const StatusCallback& callback,
487 scoped_refptr<net::DrainableIOBuffer> buffer,
488 int result) {
489 if (result < 0) {
490 callback.Run(NetErrorToPlatformFileError(result));
491 return;
492 }
493
494 buffer->DidConsume(result);
495 num_copied_bytes_ += result;
496
497 // Check the elapsed time since last |file_progress_callback_| invocation.
498 base::Time now = base::Time::Now();
499 if (now - last_progress_callback_invocation_time_ >=
500 min_progress_callback_invocation_span_) {
501 file_progress_callback_.Run(num_copied_bytes_);
502 last_progress_callback_invocation_time_ = now;
503 }
504
505 if (buffer->BytesRemaining() > 0) {
506 Write(callback, buffer);
507 return;
508 }
509
510 Read(callback);
511 }
286 512
287 CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate( 513 CopyOrMoveOperationDelegate::CopyOrMoveOperationDelegate(
288 FileSystemContext* file_system_context, 514 FileSystemContext* file_system_context,
289 const FileSystemURL& src_root, 515 const FileSystemURL& src_root,
290 const FileSystemURL& dest_root, 516 const FileSystemURL& dest_root,
291 OperationType operation_type, 517 OperationType operation_type,
292 const CopyProgressCallback& progress_callback, 518 const CopyProgressCallback& progress_callback,
293 const StatusCallback& callback) 519 const StatusCallback& callback)
294 : RecursiveOperationDelegate(file_system_context), 520 : RecursiveOperationDelegate(file_system_context),
295 src_root_(src_root), 521 src_root_(src_root),
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 568
343 FileSystemURL dest_url = CreateDestURL(src_url); 569 FileSystemURL dest_url = CreateDestURL(src_url);
344 CopyOrMoveImpl* impl = NULL; 570 CopyOrMoveImpl* impl = NULL;
345 if (same_file_system_) { 571 if (same_file_system_) {
346 impl = new CopyOrMoveOnSameFileSystemImpl( 572 impl = new CopyOrMoveOnSameFileSystemImpl(
347 operation_runner(), operation_type_, src_url, dest_url, 573 operation_runner(), operation_type_, src_url, dest_url,
348 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, 574 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress,
349 weak_factory_.GetWeakPtr(), src_url)); 575 weak_factory_.GetWeakPtr(), src_url));
350 } else { 576 } else {
351 // Cross filesystem case. 577 // Cross filesystem case.
352 // TODO(hidehiko): Support stream based copy. crbug.com/279287.
353 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; 578 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
354 CopyOrMoveFileValidatorFactory* validator_factory = 579 CopyOrMoveFileValidatorFactory* validator_factory =
355 file_system_context()->GetCopyOrMoveFileValidatorFactory( 580 file_system_context()->GetCopyOrMoveFileValidatorFactory(
356 dest_root_.type(), &error); 581 dest_root_.type(), &error);
357 if (error != base::PLATFORM_FILE_OK) { 582 if (error != base::PLATFORM_FILE_OK) {
358 callback.Run(error); 583 callback.Run(error);
359 return; 584 return;
360 } 585 }
361 586
362 impl = new SnapshotCopyOrMoveImpl( 587 if (!validator_factory) {
363 operation_runner(), operation_type_, src_url, dest_url, 588 scoped_ptr<webkit_blob::FileStreamReader> reader =
364 validator_factory, 589 file_system_context()->CreateFileStreamReader(
365 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress, 590 src_url, 0, base::Time());
366 weak_factory_.GetWeakPtr(), src_url)); 591 scoped_ptr<FileStreamWriter> writer =
592 file_system_context()->CreateFileStreamWriter(dest_url, 0);
593 if (reader && writer) {
594 impl = new StreamCopyOrMoveImpl(
595 operation_runner(), operation_type_, src_url, dest_url,
596 reader.Pass(), writer.Pass(),
597 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress,
598 weak_factory_.GetWeakPtr(), src_url));
599 }
600 }
601
602 if (!impl) {
603 impl = new SnapshotCopyOrMoveImpl(
604 operation_runner(), operation_type_, src_url, dest_url,
605 validator_factory,
606 base::Bind(&CopyOrMoveOperationDelegate::OnCopyFileProgress,
607 weak_factory_.GetWeakPtr(), src_url));
608 }
367 } 609 }
368 610
369 // Register the running task. 611 // Register the running task.
370 running_copy_set_.insert(impl); 612 running_copy_set_.insert(impl);
371 impl->Run(base::Bind( 613 impl->Run(base::Bind(
372 &CopyOrMoveOperationDelegate::DidCopyOrMoveFile, 614 &CopyOrMoveOperationDelegate::DidCopyOrMoveFile,
373 weak_factory_.GetWeakPtr(), src_url, dest_url, callback, impl)); 615 weak_factory_.GetWeakPtr(), src_url, dest_url, callback, impl));
374 } 616 }
375 617
376 void CopyOrMoveOperationDelegate::ProcessDirectory( 618 void CopyOrMoveOperationDelegate::ProcessDirectory(
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
499 base::FilePath relative = dest_root_.virtual_path(); 741 base::FilePath relative = dest_root_.virtual_path();
500 src_root_.virtual_path().AppendRelativePath(src_url.virtual_path(), 742 src_root_.virtual_path().AppendRelativePath(src_url.virtual_path(),
501 &relative); 743 &relative);
502 return file_system_context()->CreateCrackedFileSystemURL( 744 return file_system_context()->CreateCrackedFileSystemURL(
503 dest_root_.origin(), 745 dest_root_.origin(),
504 dest_root_.mount_type(), 746 dest_root_.mount_type(),
505 relative); 747 relative);
506 } 748 }
507 749
508 } // namespace fileapi 750 } // namespace fileapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698