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 3 // found in the LICENSE file. 4 5 #include "webkit/browser/fileapi/recursive_operation_delegate.h" 6 7 #include "base/bind.h" 8 #include "webkit/browser/fileapi/file_system_context.h" 9 #include "webkit/browser/fileapi/file_system_operation_runner.h" 10 11 namespace fileapi { 12 13 namespace { 14 // Don't start too many inflight operations. 15 const int kMaxInflightOperations = 5; 16 } 17 18 RecursiveOperationDelegate::RecursiveOperationDelegate( 19 FileSystemContext* file_system_context) 20 : file_system_context_(file_system_context), 21 inflight_operations_(0) { 22 } 23 24 RecursiveOperationDelegate::~RecursiveOperationDelegate() { 25 } 26 27 void RecursiveOperationDelegate::StartRecursiveOperation( 28 const FileSystemURL& root, 29 const StatusCallback& callback) { 30 callback_ = callback; 31 pending_directories_.push(root); 32 ProcessNextDirectory(); 33 } 34 35 FileSystemOperationRunner* RecursiveOperationDelegate::operation_runner() { 36 return file_system_context_->operation_runner(); 37 } 38 39 void RecursiveOperationDelegate::ProcessNextDirectory() { 40 DCHECK(pending_files_.empty()); 41 if (inflight_operations_ > 0) 42 return; 43 if (pending_directories_.empty()) { 44 callback_.Run(base::PLATFORM_FILE_OK); 45 return; 46 } 47 FileSystemURL url = pending_directories_.front(); 48 pending_directories_.pop(); 49 inflight_operations_++; 50 ProcessDirectory( 51 url, base::Bind(&RecursiveOperationDelegate::DidProcessDirectory, 52 AsWeakPtr(), url)); 53 } 54 55 void RecursiveOperationDelegate::ProcessPendingFiles() { 56 if (pending_files_.empty()) { 57 ProcessNextDirectory(); 58 return; 59 } 60 while (!pending_files_.empty() && 61 inflight_operations_ < kMaxInflightOperations) { 62 FileSystemURL url = pending_files_.front(); 63 pending_files_.pop(); 64 inflight_operations_++; 65 base::MessageLoopProxy::current()->PostTask( 66 FROM_HERE, 67 base::Bind(&RecursiveOperationDelegate::ProcessFile, 68 AsWeakPtr(), url, 69 base::Bind(&RecursiveOperationDelegate::DidProcessFile, 70 AsWeakPtr()))); 71 } 72 } 73 74 void RecursiveOperationDelegate::DidProcessFile(base::PlatformFileError error) { 75 inflight_operations_--; 76 DCHECK_GE(inflight_operations_, 0); 77 if (error != base::PLATFORM_FILE_OK) { 78 callback_.Run(error); 79 return; 80 } 81 ProcessPendingFiles(); 82 } 83 84 void RecursiveOperationDelegate::DidProcessDirectory( 85 const FileSystemURL& url, 86 base::PlatformFileError error) { 87 if (error != base::PLATFORM_FILE_OK) { 88 callback_.Run(error); 89 return; 90 } 91 operation_runner()->ReadDirectory( 92 url, base::Bind(&RecursiveOperationDelegate::DidReadDirectory, 93 AsWeakPtr(), url)); 94 } 95 96 void RecursiveOperationDelegate::DidReadDirectory( 97 const FileSystemURL& parent, 98 base::PlatformFileError error, 99 const FileEntryList& entries, 100 bool has_more) { 101 if (error != base::PLATFORM_FILE_OK) { 102 if (error == base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY) { 103 // The given path may have been a file, so try RemoveFile now. 104 ProcessFile(parent, 105 base::Bind(&RecursiveOperationDelegate::DidTryProcessFile, 106 AsWeakPtr(), error)); 107 return; 108 } 109 callback_.Run(error); 110 return; 111 } 112 for (size_t i = 0; i < entries.size(); i++) { 113 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL( 114 parent.origin(), 115 parent.mount_type(), 116 parent.virtual_path().Append(entries[i].name)); 117 if (entries[i].is_directory) 118 pending_directories_.push(url); 119 else 120 pending_files_.push(url); 121 } 122 if (has_more) 123 return; 124 125 inflight_operations_--; 126 DCHECK_GE(inflight_operations_, 0); 127 ProcessPendingFiles(); 128 } 129 130 void RecursiveOperationDelegate::DidTryProcessFile( 131 base::PlatformFileError previous_error, 132 base::PlatformFileError error) { 133 if (error == base::PLATFORM_FILE_ERROR_NOT_A_FILE) { 134 // It wasn't a file either; returns with the previous error. 135 callback_.Run(previous_error); 136 return; 137 } 138 DidProcessFile(error); 139 } 140 141 } // namespace fileapi 142