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.
5 #include "webkit/fileapi/recursive_operation_delegate.h"
8 #include "webkit/fileapi/file_system_context.h"
9 #include "webkit/fileapi/file_system_operation_context.h"
10 #include "webkit/fileapi/local_file_system_operation.h"
15 // Don't start too many inflight operations.
16 const int kMaxInflightOperations
= 5;
19 RecursiveOperationDelegate::RecursiveOperationDelegate(
20 FileSystemContext
* file_system_context
,
21 LocalFileSystemOperation
* operation
)
22 : file_system_context_(file_system_context
),
23 operation_(operation
),
24 inflight_operations_(0) {
27 RecursiveOperationDelegate::~RecursiveOperationDelegate() {
30 void RecursiveOperationDelegate::StartRecursiveOperation(
31 const FileSystemURL
& root
,
32 const StatusCallback
& callback
) {
34 pending_directories_
.push(root
);
35 ProcessNextDirectory();
38 LocalFileSystemOperation
* RecursiveOperationDelegate::NewNestedOperation() {
39 return operation_
->CreateNestedOperation();
42 void RecursiveOperationDelegate::ProcessNextDirectory() {
43 DCHECK(pending_files_
.empty());
44 if (inflight_operations_
> 0)
46 if (pending_directories_
.empty()) {
47 callback_
.Run(base::PLATFORM_FILE_OK
);
50 FileSystemURL url
= pending_directories_
.front();
51 pending_directories_
.pop();
52 inflight_operations_
++;
54 url
, base::Bind(&RecursiveOperationDelegate::DidProcessDirectory
,
58 void RecursiveOperationDelegate::ProcessPendingFiles() {
59 if (pending_files_
.empty()) {
60 ProcessNextDirectory();
63 while (!pending_files_
.empty() &&
64 inflight_operations_
< kMaxInflightOperations
) {
65 FileSystemURL url
= pending_files_
.front();
67 inflight_operations_
++;
68 base::MessageLoopProxy::current()->PostTask(
70 base::Bind(&RecursiveOperationDelegate::ProcessFile
,
72 base::Bind(&RecursiveOperationDelegate::DidProcessFile
,
77 void RecursiveOperationDelegate::DidProcessFile(base::PlatformFileError error
) {
78 inflight_operations_
--;
79 DCHECK_GE(inflight_operations_
, 0);
80 if (error
!= base::PLATFORM_FILE_OK
) {
84 ProcessPendingFiles();
87 void RecursiveOperationDelegate::DidProcessDirectory(
88 const FileSystemURL
& url
,
89 base::PlatformFileError error
) {
90 if (error
!= base::PLATFORM_FILE_OK
) {
94 NewNestedOperation()->ReadDirectory(
95 url
, base::Bind(&RecursiveOperationDelegate::DidReadDirectory
,
99 void RecursiveOperationDelegate::DidReadDirectory(
100 const FileSystemURL
& parent
,
101 base::PlatformFileError error
,
102 const FileEntryList
& entries
,
104 if (error
!= base::PLATFORM_FILE_OK
) {
105 if (error
== base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY
) {
106 // The given path may have been a file, so try RemoveFile now.
108 base::Bind(&RecursiveOperationDelegate::DidTryProcessFile
,
109 AsWeakPtr(), error
));
112 callback_
.Run(error
);
115 for (size_t i
= 0; i
< entries
.size(); i
++) {
116 FileSystemURL url
= file_system_context_
->CreateCrackedFileSystemURL(
119 parent
.virtual_path().Append(entries
[i
].name
));
120 if (entries
[i
].is_directory
)
121 pending_directories_
.push(url
);
123 pending_files_
.push(url
);
128 inflight_operations_
--;
129 DCHECK_GE(inflight_operations_
, 0);
130 ProcessPendingFiles();
133 void RecursiveOperationDelegate::DidTryProcessFile(
134 base::PlatformFileError previous_error
,
135 base::PlatformFileError error
) {
136 if (error
== base::PLATFORM_FILE_ERROR_NOT_A_FILE
) {
137 // It wasn't a file either; returns with the previous error.
138 callback_
.Run(previous_error
);
141 DidProcessFile(error
);
144 } // namespace fileapi