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 "storage/browser/fileapi/async_file_util_adapter.h"
10 #include "base/sequenced_task_runner.h"
11 #include "base/task_runner_util.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "storage/browser/blob/shareable_file_reference.h"
14 #include "storage/browser/fileapi/file_system_context.h"
15 #include "storage/browser/fileapi/file_system_file_util.h"
16 #include "storage/browser/fileapi/file_system_operation_context.h"
17 #include "storage/browser/fileapi/file_system_url.h"
18 #include "storage/common/fileapi/file_system_util.h"
23 using base::Unretained
;
24 using storage::ShareableFileReference
;
30 class EnsureFileExistsHelper
{
32 EnsureFileExistsHelper() : error_(base::File::FILE_OK
), created_(false) {}
34 void RunWork(FileSystemFileUtil
* file_util
,
35 FileSystemOperationContext
* context
,
36 const FileSystemURL
& url
) {
37 error_
= file_util
->EnsureFileExists(context
, url
, &created_
);
40 void Reply(const AsyncFileUtil::EnsureFileExistsCallback
& callback
) {
41 callback
.Run(error_
, created_
);
45 base::File::Error error_
;
47 DISALLOW_COPY_AND_ASSIGN(EnsureFileExistsHelper
);
50 class GetFileInfoHelper
{
53 : error_(base::File::FILE_OK
) {}
55 void GetFileInfo(FileSystemFileUtil
* file_util
,
56 FileSystemOperationContext
* context
,
57 const FileSystemURL
& url
) {
58 error_
= file_util
->GetFileInfo(context
, url
, &file_info_
, &platform_path_
);
61 void CreateSnapshotFile(FileSystemFileUtil
* file_util
,
62 FileSystemOperationContext
* context
,
63 const FileSystemURL
& url
) {
64 scoped_file_
= file_util
->CreateSnapshotFile(
65 context
, url
, &error_
, &file_info_
, &platform_path_
);
68 void ReplyFileInfo(const AsyncFileUtil::GetFileInfoCallback
& callback
) {
69 callback
.Run(error_
, file_info_
);
72 void ReplySnapshotFile(
73 const AsyncFileUtil::CreateSnapshotFileCallback
& callback
) {
74 callback
.Run(error_
, file_info_
, platform_path_
,
75 ShareableFileReference::GetOrCreate(scoped_file_
.Pass()));
79 base::File::Error error_
;
80 base::File::Info file_info_
;
81 base::FilePath platform_path_
;
82 storage::ScopedFile scoped_file_
;
83 DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper
);
86 void ReadDirectoryHelper(FileSystemFileUtil
* file_util
,
87 FileSystemOperationContext
* context
,
88 const FileSystemURL
& url
,
89 base::SingleThreadTaskRunner
* origin_loop
,
90 const AsyncFileUtil::ReadDirectoryCallback
& callback
) {
91 base::File::Info file_info
;
92 base::FilePath platform_path
;
93 base::File::Error error
= file_util
->GetFileInfo(
94 context
, url
, &file_info
, &platform_path
);
96 if (error
== base::File::FILE_OK
&& !file_info
.is_directory
)
97 error
= base::File::FILE_ERROR_NOT_A_DIRECTORY
;
99 std::vector
<DirectoryEntry
> entries
;
100 if (error
!= base::File::FILE_OK
) {
101 origin_loop
->PostTask(
102 FROM_HERE
, base::Bind(callback
, error
, entries
, false /* has_more */));
106 // Note: Increasing this value may make some tests in LayoutTests meaningless.
107 // (Namely, read-directory-many.html and read-directory-sync-many.html are
108 // assuming that they are reading much more entries than this constant.)
109 const size_t kResultChunkSize
= 100;
111 scoped_ptr
<FileSystemFileUtil::AbstractFileEnumerator
> file_enum(
112 file_util
->CreateFileEnumerator(context
, url
));
114 base::FilePath current
;
115 while (!(current
= file_enum
->Next()).empty()) {
116 DirectoryEntry entry
;
117 entry
.is_directory
= file_enum
->IsDirectory();
118 entry
.name
= VirtualPath::BaseName(current
).value();
119 entry
.size
= file_enum
->Size();
120 entry
.last_modified_time
= file_enum
->LastModifiedTime();
121 entries
.push_back(entry
);
123 if (entries
.size() == kResultChunkSize
) {
124 origin_loop
->PostTask(
125 FROM_HERE
, base::Bind(callback
, base::File::FILE_OK
, entries
,
126 true /* has_more */));
130 origin_loop
->PostTask(
131 FROM_HERE
, base::Bind(callback
, base::File::FILE_OK
, entries
,
132 false /* has_more */));
135 void RunCreateOrOpenCallback(
136 FileSystemOperationContext
* context
,
137 const AsyncFileUtil::CreateOrOpenCallback
& callback
,
139 callback
.Run(file
.Pass(), base::Closure());
144 AsyncFileUtilAdapter::AsyncFileUtilAdapter(
145 FileSystemFileUtil
* sync_file_util
)
146 : sync_file_util_(sync_file_util
) {
147 DCHECK(sync_file_util_
.get());
150 AsyncFileUtilAdapter::~AsyncFileUtilAdapter() {
153 void AsyncFileUtilAdapter::CreateOrOpen(
154 scoped_ptr
<FileSystemOperationContext
> context
,
155 const FileSystemURL
& url
,
157 const CreateOrOpenCallback
& callback
) {
158 FileSystemOperationContext
* context_ptr
= context
.release();
159 base::PostTaskAndReplyWithResult(
160 context_ptr
->task_runner(),
162 Bind(&FileSystemFileUtil::CreateOrOpen
, Unretained(sync_file_util_
.get()),
163 context_ptr
, url
, file_flags
),
164 Bind(&RunCreateOrOpenCallback
, base::Owned(context_ptr
), callback
));
167 void AsyncFileUtilAdapter::EnsureFileExists(
168 scoped_ptr
<FileSystemOperationContext
> context
,
169 const FileSystemURL
& url
,
170 const EnsureFileExistsCallback
& callback
) {
171 EnsureFileExistsHelper
* helper
= new EnsureFileExistsHelper
;
172 FileSystemOperationContext
* context_ptr
= context
.release();
173 const bool success
= context_ptr
->task_runner()->PostTaskAndReply(
175 Bind(&EnsureFileExistsHelper::RunWork
, Unretained(helper
),
176 sync_file_util_
.get(), base::Owned(context_ptr
), url
),
177 Bind(&EnsureFileExistsHelper::Reply
, Owned(helper
), callback
));
181 void AsyncFileUtilAdapter::CreateDirectory(
182 scoped_ptr
<FileSystemOperationContext
> context
,
183 const FileSystemURL
& url
,
186 const StatusCallback
& callback
) {
187 FileSystemOperationContext
* context_ptr
= context
.release();
188 const bool success
= base::PostTaskAndReplyWithResult(
189 context_ptr
->task_runner(), FROM_HERE
,
190 Bind(&FileSystemFileUtil::CreateDirectory
,
191 Unretained(sync_file_util_
.get()),
192 base::Owned(context_ptr
), url
, exclusive
, recursive
),
197 void AsyncFileUtilAdapter::GetFileInfo(
198 scoped_ptr
<FileSystemOperationContext
> context
,
199 const FileSystemURL
& url
,
200 const GetFileInfoCallback
& callback
) {
201 FileSystemOperationContext
* context_ptr
= context
.release();
202 GetFileInfoHelper
* helper
= new GetFileInfoHelper
;
203 const bool success
= context_ptr
->task_runner()->PostTaskAndReply(
205 Bind(&GetFileInfoHelper::GetFileInfo
, Unretained(helper
),
206 sync_file_util_
.get(), base::Owned(context_ptr
), url
),
207 Bind(&GetFileInfoHelper::ReplyFileInfo
, Owned(helper
), callback
));
211 void AsyncFileUtilAdapter::ReadDirectory(
212 scoped_ptr
<FileSystemOperationContext
> context
,
213 const FileSystemURL
& url
,
214 const ReadDirectoryCallback
& callback
) {
215 FileSystemOperationContext
* context_ptr
= context
.release();
216 const bool success
= context_ptr
->task_runner()->PostTask(
218 Bind(&ReadDirectoryHelper
,
219 sync_file_util_
.get(), base::Owned(context_ptr
), url
,
220 base::ThreadTaskRunnerHandle::Get(), callback
));
224 void AsyncFileUtilAdapter::Touch(
225 scoped_ptr
<FileSystemOperationContext
> context
,
226 const FileSystemURL
& url
,
227 const base::Time
& last_access_time
,
228 const base::Time
& last_modified_time
,
229 const StatusCallback
& callback
) {
230 FileSystemOperationContext
* context_ptr
= context
.release();
231 const bool success
= base::PostTaskAndReplyWithResult(
232 context_ptr
->task_runner(), FROM_HERE
,
233 Bind(&FileSystemFileUtil::Touch
, Unretained(sync_file_util_
.get()),
234 base::Owned(context_ptr
), url
,
235 last_access_time
, last_modified_time
),
240 void AsyncFileUtilAdapter::Truncate(
241 scoped_ptr
<FileSystemOperationContext
> context
,
242 const FileSystemURL
& url
,
244 const StatusCallback
& callback
) {
245 FileSystemOperationContext
* context_ptr
= context
.release();
246 const bool success
= base::PostTaskAndReplyWithResult(
247 context_ptr
->task_runner(), FROM_HERE
,
248 Bind(&FileSystemFileUtil::Truncate
, Unretained(sync_file_util_
.get()),
249 base::Owned(context_ptr
), url
, length
),
254 void AsyncFileUtilAdapter::CopyFileLocal(
255 scoped_ptr
<FileSystemOperationContext
> context
,
256 const FileSystemURL
& src_url
,
257 const FileSystemURL
& dest_url
,
258 CopyOrMoveOption option
,
259 const CopyFileProgressCallback
& progress_callback
,
260 const StatusCallback
& callback
) {
261 // TODO(hidehiko): Support progress_callback.
262 FileSystemOperationContext
* context_ptr
= context
.release();
263 const bool success
= base::PostTaskAndReplyWithResult(
264 context_ptr
->task_runner(), FROM_HERE
,
265 Bind(&FileSystemFileUtil::CopyOrMoveFile
,
266 Unretained(sync_file_util_
.get()), base::Owned(context_ptr
),
267 src_url
, dest_url
, option
, true /* copy */),
272 void AsyncFileUtilAdapter::MoveFileLocal(
273 scoped_ptr
<FileSystemOperationContext
> context
,
274 const FileSystemURL
& src_url
,
275 const FileSystemURL
& dest_url
,
276 CopyOrMoveOption option
,
277 const StatusCallback
& callback
) {
278 FileSystemOperationContext
* context_ptr
= context
.release();
279 const bool success
= base::PostTaskAndReplyWithResult(
280 context_ptr
->task_runner(), FROM_HERE
,
281 Bind(&FileSystemFileUtil::CopyOrMoveFile
,
282 Unretained(sync_file_util_
.get()), base::Owned(context_ptr
),
283 src_url
, dest_url
, option
, false /* copy */),
288 void AsyncFileUtilAdapter::CopyInForeignFile(
289 scoped_ptr
<FileSystemOperationContext
> context
,
290 const base::FilePath
& src_file_path
,
291 const FileSystemURL
& dest_url
,
292 const StatusCallback
& callback
) {
293 FileSystemOperationContext
* context_ptr
= context
.release();
294 const bool success
= base::PostTaskAndReplyWithResult(
295 context_ptr
->task_runner(), FROM_HERE
,
296 Bind(&FileSystemFileUtil::CopyInForeignFile
,
297 Unretained(sync_file_util_
.get()),
298 base::Owned(context_ptr
), src_file_path
, dest_url
),
303 void AsyncFileUtilAdapter::DeleteFile(
304 scoped_ptr
<FileSystemOperationContext
> context
,
305 const FileSystemURL
& url
,
306 const StatusCallback
& callback
) {
307 FileSystemOperationContext
* context_ptr
= context
.release();
308 const bool success
= base::PostTaskAndReplyWithResult(
309 context_ptr
->task_runner(), FROM_HERE
,
310 Bind(&FileSystemFileUtil::DeleteFile
,
311 Unretained(sync_file_util_
.get()),
312 base::Owned(context_ptr
), url
),
317 void AsyncFileUtilAdapter::DeleteDirectory(
318 scoped_ptr
<FileSystemOperationContext
> context
,
319 const FileSystemURL
& url
,
320 const StatusCallback
& callback
) {
321 FileSystemOperationContext
* context_ptr
= context
.release();
322 const bool success
= base::PostTaskAndReplyWithResult(
323 context_ptr
->task_runner(), FROM_HERE
,
324 Bind(&FileSystemFileUtil::DeleteDirectory
,
325 Unretained(sync_file_util_
.get()),
326 base::Owned(context_ptr
), url
),
331 void AsyncFileUtilAdapter::DeleteRecursively(
332 scoped_ptr
<FileSystemOperationContext
> context
,
333 const FileSystemURL
& url
,
334 const StatusCallback
& callback
) {
335 callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
);
338 void AsyncFileUtilAdapter::CreateSnapshotFile(
339 scoped_ptr
<FileSystemOperationContext
> context
,
340 const FileSystemURL
& url
,
341 const CreateSnapshotFileCallback
& callback
) {
342 FileSystemOperationContext
* context_ptr
= context
.release();
343 GetFileInfoHelper
* helper
= new GetFileInfoHelper
;
344 const bool success
= context_ptr
->task_runner()->PostTaskAndReply(
346 Bind(&GetFileInfoHelper::CreateSnapshotFile
, Unretained(helper
),
347 sync_file_util_
.get(), base::Owned(context_ptr
), url
),
348 Bind(&GetFileInfoHelper::ReplySnapshotFile
, Owned(helper
), callback
));
352 } // namespace storage