1 // Copyright 2014 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 "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.h"
7 #include "base/callback.h"
8 #include "base/files/file.h"
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
12 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "storage/browser/blob/shareable_file_reference.h"
15 #include "storage/browser/fileapi/file_system_operation_context.h"
16 #include "storage/browser/fileapi/file_system_url.h"
18 using content::BrowserThread
;
21 namespace file_system_provider
{
25 // Executes GetFileInfo on the UI thread.
26 void GetFileInfoOnUIThread(
27 scoped_ptr
<storage::FileSystemOperationContext
> context
,
28 const storage::FileSystemURL
& url
,
29 const ProvidedFileSystemInterface::GetMetadataCallback
& callback
) {
30 util::FileSystemURLParser
parser(url
);
31 if (!parser
.Parse()) {
32 callback
.Run(make_scoped_ptr
<EntryMetadata
>(NULL
),
33 base::File::FILE_ERROR_INVALID_OPERATION
);
37 parser
.file_system()->GetMetadata(
39 ProvidedFileSystemInterface::METADATA_FIELD_DEFAULT
,
43 // Routes the response of GetFileInfo back to the IO thread with a type
45 void OnGetFileInfo(const storage::AsyncFileUtil::GetFileInfoCallback
& callback
,
46 scoped_ptr
<EntryMetadata
> metadata
,
47 base::File::Error result
) {
48 if (result
!= base::File::FILE_OK
) {
49 BrowserThread::PostTask(BrowserThread::IO
,
51 base::Bind(callback
, result
, base::File::Info()));
55 DCHECK(metadata
.get());
56 base::File::Info file_info
;
58 // TODO(mtomasz): Add support for last modified time and creation time.
59 // See: crbug.com/388540.
60 file_info
.size
= metadata
->size
;
61 file_info
.is_directory
= metadata
->is_directory
;
62 file_info
.is_symbolic_link
= false; // Not supported.
63 file_info
.last_modified
= metadata
->modification_time
;
64 file_info
.last_accessed
= metadata
->modification_time
; // Not supported.
65 file_info
.creation_time
= metadata
->modification_time
; // Not supported.
67 BrowserThread::PostTask(BrowserThread::IO
,
69 base::Bind(callback
, base::File::FILE_OK
, file_info
));
72 // Executes ReadDirectory on the UI thread.
73 void ReadDirectoryOnUIThread(
74 scoped_ptr
<storage::FileSystemOperationContext
> context
,
75 const storage::FileSystemURL
& url
,
76 const storage::AsyncFileUtil::ReadDirectoryCallback
& callback
) {
77 util::FileSystemURLParser
parser(url
);
78 if (!parser
.Parse()) {
79 callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
,
80 storage::AsyncFileUtil::EntryList(),
81 false /* has_more */);
85 parser
.file_system()->ReadDirectory(parser
.file_path(), callback
);
88 // Routes the response of ReadDirectory back to the IO thread.
90 const storage::AsyncFileUtil::ReadDirectoryCallback
& callback
,
91 base::File::Error result
,
92 const storage::AsyncFileUtil::EntryList
& entry_list
,
94 BrowserThread::PostTask(BrowserThread::IO
,
96 base::Bind(callback
, result
, entry_list
, has_more
));
99 // Executes CreateDirectory on the UI thread.
100 void CreateDirectoryOnUIThread(
101 scoped_ptr
<storage::FileSystemOperationContext
> context
,
102 const storage::FileSystemURL
& url
,
105 const storage::AsyncFileUtil::StatusCallback
& callback
) {
106 util::FileSystemURLParser
parser(url
);
107 if (!parser
.Parse()) {
108 callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
);
112 parser
.file_system()->CreateDirectory(
113 parser
.file_path(), recursive
, callback
);
116 // Routes the response of CreateDirectory back to the IO thread.
117 void OnCreateDirectory(bool exclusive
,
118 const storage::AsyncFileUtil::StatusCallback
& callback
,
119 base::File::Error result
) {
120 // If the directory already existed and the operation wasn't exclusive, then
121 // return success anyway, since it is not an error.
122 const base::File::Error error
=
123 (result
== base::File::FILE_ERROR_EXISTS
&& !exclusive
)
124 ? base::File::FILE_OK
127 BrowserThread::PostTask(
128 BrowserThread::IO
, FROM_HERE
, base::Bind(callback
, error
));
131 // Executes DeleteEntry on the UI thread.
132 void DeleteEntryOnUIThread(
133 scoped_ptr
<storage::FileSystemOperationContext
> context
,
134 const storage::FileSystemURL
& url
,
136 const storage::AsyncFileUtil::StatusCallback
& callback
) {
137 util::FileSystemURLParser
parser(url
);
138 if (!parser
.Parse()) {
139 callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
);
143 parser
.file_system()->DeleteEntry(parser
.file_path(), recursive
, callback
);
146 // Routes the response of DeleteEntry back to the IO thread.
147 void OnDeleteEntry(const storage::AsyncFileUtil::StatusCallback
& callback
,
148 base::File::Error result
) {
149 BrowserThread::PostTask(
150 BrowserThread::IO
, FROM_HERE
, base::Bind(callback
, result
));
153 // Executes CreateFile on the UI thread.
154 void CreateFileOnUIThread(
155 scoped_ptr
<storage::FileSystemOperationContext
> context
,
156 const storage::FileSystemURL
& url
,
157 const storage::AsyncFileUtil::StatusCallback
& callback
) {
158 util::FileSystemURLParser
parser(url
);
159 if (!parser
.Parse()) {
160 callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
);
164 parser
.file_system()->CreateFile(parser
.file_path(), callback
);
167 // Routes the response of CreateFile to a callback of EnsureFileExists() on the
169 void OnCreateFileForEnsureFileExists(
170 const storage::AsyncFileUtil::EnsureFileExistsCallback
& callback
,
171 base::File::Error result
) {
172 const bool created
= result
== base::File::FILE_OK
;
174 // If the file already existed, then return success anyway, since it is not
176 const base::File::Error error
=
177 result
== base::File::FILE_ERROR_EXISTS
? base::File::FILE_OK
: result
;
179 BrowserThread::PostTask(
180 BrowserThread::IO
, FROM_HERE
, base::Bind(callback
, error
, created
));
183 // Executes CopyEntry on the UI thread.
184 void CopyEntryOnUIThread(
185 scoped_ptr
<storage::FileSystemOperationContext
> context
,
186 const storage::FileSystemURL
& source_url
,
187 const storage::FileSystemURL
& target_url
,
188 const storage::AsyncFileUtil::StatusCallback
& callback
) {
189 util::FileSystemURLParser
source_parser(source_url
);
190 util::FileSystemURLParser
target_parser(target_url
);
192 if (!source_parser
.Parse() || !target_parser
.Parse() ||
193 source_parser
.file_system() != target_parser
.file_system()) {
194 callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
);
198 target_parser
.file_system()->CopyEntry(
199 source_parser
.file_path(), target_parser
.file_path(), callback
);
202 // Routes the response of CopyEntry to a callback of CopyLocalFile() on the
204 void OnCopyEntry(const storage::AsyncFileUtil::StatusCallback
& callback
,
205 base::File::Error result
) {
206 BrowserThread::PostTask(
207 BrowserThread::IO
, FROM_HERE
, base::Bind(callback
, result
));
210 // Executes MoveEntry on the UI thread.
211 void MoveEntryOnUIThread(
212 scoped_ptr
<storage::FileSystemOperationContext
> context
,
213 const storage::FileSystemURL
& source_url
,
214 const storage::FileSystemURL
& target_url
,
215 const storage::AsyncFileUtil::StatusCallback
& callback
) {
216 util::FileSystemURLParser
source_parser(source_url
);
217 util::FileSystemURLParser
target_parser(target_url
);
219 if (!source_parser
.Parse() || !target_parser
.Parse() ||
220 source_parser
.file_system() != target_parser
.file_system()) {
221 callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
);
225 target_parser
.file_system()->MoveEntry(
226 source_parser
.file_path(), target_parser
.file_path(), callback
);
229 // Routes the response of CopyEntry to a callback of MoveLocalFile() on the
231 void OnMoveEntry(const storage::AsyncFileUtil::StatusCallback
& callback
,
232 base::File::Error result
) {
233 BrowserThread::PostTask(
234 BrowserThread::IO
, FROM_HERE
, base::Bind(callback
, result
));
237 // Executes Truncate on the UI thread.
238 void TruncateOnUIThread(
239 scoped_ptr
<storage::FileSystemOperationContext
> context
,
240 const storage::FileSystemURL
& url
,
242 const storage::AsyncFileUtil::StatusCallback
& callback
) {
243 util::FileSystemURLParser
parser(url
);
244 if (!parser
.Parse()) {
245 callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
);
249 parser
.file_system()->Truncate(parser
.file_path(), length
, callback
);
252 // Routes the response of Truncate back to the IO thread.
253 void OnTruncate(const storage::AsyncFileUtil::StatusCallback
& callback
,
254 base::File::Error result
) {
255 BrowserThread::PostTask(
256 BrowserThread::IO
, FROM_HERE
, base::Bind(callback
, result
));
261 ProviderAsyncFileUtil::ProviderAsyncFileUtil() {}
263 ProviderAsyncFileUtil::~ProviderAsyncFileUtil() {}
265 void ProviderAsyncFileUtil::CreateOrOpen(
266 scoped_ptr
<storage::FileSystemOperationContext
> context
,
267 const storage::FileSystemURL
& url
,
269 const CreateOrOpenCallback
& callback
) {
270 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
271 if ((file_flags
& base::File::FLAG_CREATE
) ||
272 (file_flags
& base::File::FLAG_OPEN_ALWAYS
) ||
273 (file_flags
& base::File::FLAG_CREATE_ALWAYS
) ||
274 (file_flags
& base::File::FLAG_OPEN_TRUNCATED
)) {
275 callback
.Run(base::File(base::File::FILE_ERROR_ACCESS_DENIED
),
281 callback
.Run(base::File(base::File::FILE_ERROR_INVALID_OPERATION
),
285 void ProviderAsyncFileUtil::EnsureFileExists(
286 scoped_ptr
<storage::FileSystemOperationContext
> context
,
287 const storage::FileSystemURL
& url
,
288 const EnsureFileExistsCallback
& callback
) {
289 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
290 BrowserThread::PostTask(
293 base::Bind(&CreateFileOnUIThread
,
294 base::Passed(&context
),
296 base::Bind(&OnCreateFileForEnsureFileExists
, callback
)));
299 void ProviderAsyncFileUtil::CreateDirectory(
300 scoped_ptr
<storage::FileSystemOperationContext
> context
,
301 const storage::FileSystemURL
& url
,
304 const StatusCallback
& callback
) {
305 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
306 BrowserThread::PostTask(
309 base::Bind(&CreateDirectoryOnUIThread
,
310 base::Passed(&context
),
314 base::Bind(&OnCreateDirectory
, exclusive
, callback
)));
317 void ProviderAsyncFileUtil::GetFileInfo(
318 scoped_ptr
<storage::FileSystemOperationContext
> context
,
319 const storage::FileSystemURL
& url
,
320 const GetFileInfoCallback
& callback
) {
321 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
322 BrowserThread::PostTask(BrowserThread::UI
,
324 base::Bind(&GetFileInfoOnUIThread
,
325 base::Passed(&context
),
327 base::Bind(&OnGetFileInfo
, callback
)));
330 void ProviderAsyncFileUtil::ReadDirectory(
331 scoped_ptr
<storage::FileSystemOperationContext
> context
,
332 const storage::FileSystemURL
& url
,
333 const ReadDirectoryCallback
& callback
) {
334 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
335 BrowserThread::PostTask(BrowserThread::UI
,
337 base::Bind(&ReadDirectoryOnUIThread
,
338 base::Passed(&context
),
340 base::Bind(&OnReadDirectory
, callback
)));
343 void ProviderAsyncFileUtil::Touch(
344 scoped_ptr
<storage::FileSystemOperationContext
> context
,
345 const storage::FileSystemURL
& url
,
346 const base::Time
& last_access_time
,
347 const base::Time
& last_modified_time
,
348 const StatusCallback
& callback
) {
349 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
350 callback
.Run(base::File::FILE_ERROR_ACCESS_DENIED
);
353 void ProviderAsyncFileUtil::Truncate(
354 scoped_ptr
<storage::FileSystemOperationContext
> context
,
355 const storage::FileSystemURL
& url
,
357 const StatusCallback
& callback
) {
358 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
359 BrowserThread::PostTask(BrowserThread::UI
,
361 base::Bind(&TruncateOnUIThread
,
362 base::Passed(&context
),
365 base::Bind(&OnTruncate
, callback
)));
368 void ProviderAsyncFileUtil::CopyFileLocal(
369 scoped_ptr
<storage::FileSystemOperationContext
> context
,
370 const storage::FileSystemURL
& src_url
,
371 const storage::FileSystemURL
& dest_url
,
372 CopyOrMoveOption option
,
373 const CopyFileProgressCallback
& progress_callback
,
374 const StatusCallback
& callback
) {
375 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
376 // TODO(mtomasz): Consier adding support for options (preserving last modified
377 // time) as well as the progress callback.
378 BrowserThread::PostTask(BrowserThread::UI
,
380 base::Bind(&CopyEntryOnUIThread
,
381 base::Passed(&context
),
384 base::Bind(&OnCopyEntry
, callback
)));
387 void ProviderAsyncFileUtil::MoveFileLocal(
388 scoped_ptr
<storage::FileSystemOperationContext
> context
,
389 const storage::FileSystemURL
& src_url
,
390 const storage::FileSystemURL
& dest_url
,
391 CopyOrMoveOption option
,
392 const StatusCallback
& callback
) {
393 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
394 // TODO(mtomasz): Consier adding support for options (preserving last modified
395 // time) as well as the progress callback.
396 BrowserThread::PostTask(BrowserThread::UI
,
398 base::Bind(&MoveEntryOnUIThread
,
399 base::Passed(&context
),
402 base::Bind(&OnMoveEntry
, callback
)));
405 void ProviderAsyncFileUtil::CopyInForeignFile(
406 scoped_ptr
<storage::FileSystemOperationContext
> context
,
407 const base::FilePath
& src_file_path
,
408 const storage::FileSystemURL
& dest_url
,
409 const StatusCallback
& callback
) {
410 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
411 callback
.Run(base::File::FILE_ERROR_ACCESS_DENIED
);
414 void ProviderAsyncFileUtil::DeleteFile(
415 scoped_ptr
<storage::FileSystemOperationContext
> context
,
416 const storage::FileSystemURL
& url
,
417 const StatusCallback
& callback
) {
418 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
419 BrowserThread::PostTask(BrowserThread::UI
,
421 base::Bind(&DeleteEntryOnUIThread
,
422 base::Passed(&context
),
425 base::Bind(&OnDeleteEntry
, callback
)));
428 void ProviderAsyncFileUtil::DeleteDirectory(
429 scoped_ptr
<storage::FileSystemOperationContext
> context
,
430 const storage::FileSystemURL
& url
,
431 const StatusCallback
& callback
) {
432 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
433 BrowserThread::PostTask(BrowserThread::UI
,
435 base::Bind(&DeleteEntryOnUIThread
,
436 base::Passed(&context
),
439 base::Bind(&OnDeleteEntry
, callback
)));
442 void ProviderAsyncFileUtil::DeleteRecursively(
443 scoped_ptr
<storage::FileSystemOperationContext
> context
,
444 const storage::FileSystemURL
& url
,
445 const StatusCallback
& callback
) {
446 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
447 BrowserThread::PostTask(BrowserThread::UI
,
449 base::Bind(&DeleteEntryOnUIThread
,
450 base::Passed(&context
),
453 base::Bind(&OnDeleteEntry
, callback
)));
456 void ProviderAsyncFileUtil::CreateSnapshotFile(
457 scoped_ptr
<storage::FileSystemOperationContext
> context
,
458 const storage::FileSystemURL
& url
,
459 const CreateSnapshotFileCallback
& callback
) {
460 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
462 callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
,
465 scoped_refptr
<storage::ShareableFileReference
>());
468 } // namespace internal
469 } // namespace file_system_provider
470 } // namespace chromeos