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 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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |