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 "chrome/browser/media_galleries/fileapi/device_media_async_file_util.h"
6
7 #include <stddef.h>
8
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/callback_helpers.h"
14 #include "base/files/file_util.h"
15 #include "base/macros.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/task_runner_util.h"
19 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
20 #include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
21 #include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h"
22 #include "chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.h"
23 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
24 #include "chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.h"
25 #include "components/services/filesystem/public/mojom/types.mojom.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "storage/browser/blob/shareable_file_reference.h"
28 #include "storage/browser/file_system/file_stream_reader.h"
29 #include "storage/browser/file_system/file_system_context.h"
30 #include "storage/browser/file_system/file_system_operation_context.h"
31 #include "storage/browser/file_system/file_system_url.h"
32 #include "storage/browser/file_system/native_file_util.h"
33
34 using storage::AsyncFileUtil;
35 using storage::FileSystemOperationContext;
36 using storage::FileSystemURL;
37 using storage::ShareableFileReference;
38
39 namespace {
40
41 const char kDeviceMediaAsyncFileUtilTempDir[] = "DeviceMediaFileSystem";
42
43 // Called when GetFileInfo method call failed to get the details of file
44 // specified by the requested url. |callback| is invoked to notify the
45 // caller about the file |error|.
OnGetFileInfoError(AsyncFileUtil::GetFileInfoCallback callback,base::File::Error error)46 void OnGetFileInfoError(AsyncFileUtil::GetFileInfoCallback callback,
47 base::File::Error error) {
48 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
49 std::move(callback).Run(error, base::File::Info());
50 }
51
52 // Called after OnDidGetFileInfo finishes media check.
53 // |callback| is invoked to complete the GetFileInfo request.
OnDidCheckMediaForGetFileInfo(AsyncFileUtil::GetFileInfoCallback callback,const base::File::Info & file_info,bool is_valid_file)54 void OnDidCheckMediaForGetFileInfo(AsyncFileUtil::GetFileInfoCallback callback,
55 const base::File::Info& file_info,
56 bool is_valid_file) {
57 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
58 if (!is_valid_file) {
59 OnGetFileInfoError(std::move(callback), base::File::FILE_ERROR_NOT_FOUND);
60 return;
61 }
62 std::move(callback).Run(base::File::FILE_OK, file_info);
63 }
64
65 // Called after OnDidReadDirectory finishes media check.
66 // |callback| is invoked to complete the ReadDirectory request.
OnDidCheckMediaForReadDirectory(AsyncFileUtil::ReadDirectoryCallback callback,bool has_more,AsyncFileUtil::EntryList file_list)67 void OnDidCheckMediaForReadDirectory(
68 AsyncFileUtil::ReadDirectoryCallback callback,
69 bool has_more,
70 AsyncFileUtil::EntryList file_list) {
71 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
72 callback.Run(base::File::FILE_OK, std::move(file_list), has_more);
73 }
74
75 // Called when CreateDirectory method call failed.
OnCreateDirectoryError(AsyncFileUtil::StatusCallback callback,base::File::Error error)76 void OnCreateDirectoryError(AsyncFileUtil::StatusCallback callback,
77 base::File::Error error) {
78 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
79 std::move(callback).Run(error);
80 }
81
82 // Called when ReadDirectory method call failed to enumerate the directory
83 // objects. |callback| is invoked to notify the caller about the |error|
84 // that occured while reading the directory objects.
OnReadDirectoryError(AsyncFileUtil::ReadDirectoryCallback callback,base::File::Error error)85 void OnReadDirectoryError(AsyncFileUtil::ReadDirectoryCallback callback,
86 base::File::Error error) {
87 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
88 callback.Run(error, AsyncFileUtil::EntryList(), false /*no more*/);
89 }
90
91 // Called when CopyFileLocal method call failed.
OnCopyFileLocalError(AsyncFileUtil::StatusCallback callback,base::File::Error error)92 void OnCopyFileLocalError(AsyncFileUtil::StatusCallback callback,
93 base::File::Error error) {
94 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
95 std::move(callback).Run(error);
96 }
97
98 // Called when MoveFileLocal method call failed.
OnMoveFileLocalError(AsyncFileUtil::StatusCallback callback,base::File::Error error)99 void OnMoveFileLocalError(AsyncFileUtil::StatusCallback callback,
100 base::File::Error error) {
101 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
102 std::move(callback).Run(error);
103 }
104
105 // Called when CopyInForeignFile method call failed.
OnCopyInForeignFileError(AsyncFileUtil::StatusCallback callback,base::File::Error error)106 void OnCopyInForeignFileError(AsyncFileUtil::StatusCallback callback,
107 base::File::Error error) {
108 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
109 std::move(callback).Run(error);
110 }
111
112 // Called when DeleteFile method call failed.
OnDeleteFileError(AsyncFileUtil::StatusCallback callback,base::File::Error error)113 void OnDeleteFileError(AsyncFileUtil::StatusCallback callback,
114 base::File::Error error) {
115 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
116 std::move(callback).Run(error);
117 }
118
119 // Called when DeleteDirectory method call failed.
OnDeleteDirectoryError(AsyncFileUtil::StatusCallback callback,base::File::Error error)120 void OnDeleteDirectoryError(AsyncFileUtil::StatusCallback callback,
121 base::File::Error error) {
122 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
123 std::move(callback).Run(error);
124 }
125
126 // Called on a blocking pool thread to create a snapshot file to hold the
127 // contents of |device_file_path|. The snapshot file is created in the
128 // "profile_path/kDeviceMediaAsyncFileUtilTempDir" directory. Return the
129 // snapshot file path or an empty path on failure.
CreateSnapshotFileOnBlockingPool(const base::FilePath & profile_path)130 base::FilePath CreateSnapshotFileOnBlockingPool(
131 const base::FilePath& profile_path) {
132 base::FilePath snapshot_file_path;
133 base::FilePath media_file_system_dir_path =
134 profile_path.AppendASCII(kDeviceMediaAsyncFileUtilTempDir);
135 if (!base::CreateDirectory(media_file_system_dir_path) ||
136 !base::CreateTemporaryFileInDir(media_file_system_dir_path,
137 &snapshot_file_path)) {
138 LOG(WARNING) << "Could not create media snapshot file "
139 << media_file_system_dir_path.value();
140 snapshot_file_path = base::FilePath();
141 }
142 return snapshot_file_path;
143 }
144
145 // Called after OnDidCreateSnapshotFile finishes media check.
146 // |callback| is invoked to complete the CreateSnapshotFile request.
OnDidCheckMediaForCreateSnapshotFile(AsyncFileUtil::CreateSnapshotFileCallback callback,const base::File::Info & file_info,scoped_refptr<storage::ShareableFileReference> platform_file,base::File::Error error)147 void OnDidCheckMediaForCreateSnapshotFile(
148 AsyncFileUtil::CreateSnapshotFileCallback callback,
149 const base::File::Info& file_info,
150 scoped_refptr<storage::ShareableFileReference> platform_file,
151 base::File::Error error) {
152 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
153 base::FilePath platform_path(platform_file.get()->path());
154 if (error != base::File::FILE_OK)
155 platform_file.reset();
156 std::move(callback).Run(error, file_info, platform_path, platform_file);
157 }
158
159 // Called when the snapshot file specified by the |platform_path| is
160 // successfully created. |file_info| contains the device media file details
161 // for which the snapshot file is created.
OnDidCreateSnapshotFile(AsyncFileUtil::CreateSnapshotFileCallback callback,base::SequencedTaskRunner * media_task_runner,bool validate_media_files,const base::File::Info & file_info,const base::FilePath & platform_path)162 void OnDidCreateSnapshotFile(AsyncFileUtil::CreateSnapshotFileCallback callback,
163 base::SequencedTaskRunner* media_task_runner,
164 bool validate_media_files,
165 const base::File::Info& file_info,
166 const base::FilePath& platform_path) {
167 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
168 scoped_refptr<storage::ShareableFileReference> file =
169 ShareableFileReference::GetOrCreate(
170 platform_path,
171 ShareableFileReference::DELETE_ON_FINAL_RELEASE,
172 media_task_runner);
173
174 if (validate_media_files) {
175 base::PostTaskAndReplyWithResult(
176 media_task_runner, FROM_HERE,
177 base::BindOnce(&NativeMediaFileUtil::IsMediaFile, platform_path),
178 base::BindOnce(&OnDidCheckMediaForCreateSnapshotFile,
179 std::move(callback), file_info, file));
180 } else {
181 OnDidCheckMediaForCreateSnapshotFile(std::move(callback), file_info, file,
182 base::File::FILE_OK);
183 }
184 }
185
186 // Called when CreateSnapshotFile method call fails. |callback| is invoked to
187 // notify the caller about the |error|.
OnCreateSnapshotFileError(AsyncFileUtil::CreateSnapshotFileCallback callback,base::File::Error error)188 void OnCreateSnapshotFileError(
189 AsyncFileUtil::CreateSnapshotFileCallback callback,
190 base::File::Error error) {
191 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
192 std::move(callback).Run(error, base::File::Info(), base::FilePath(),
193 scoped_refptr<ShareableFileReference>());
194 }
195
196 // Called when the snapshot file specified by the |snapshot_file_path| is
197 // created to hold the contents of the url.path(). If the snapshot
198 // file is successfully created, |snapshot_file_path| will be an non-empty
199 // file path. In case of failure, |snapshot_file_path| will be an empty file
200 // path. Forwards the CreateSnapshot request to the delegate to copy the
201 // contents of url.path() to |snapshot_file_path|.
OnSnapshotFileCreatedRunTask(std::unique_ptr<FileSystemOperationContext> context,AsyncFileUtil::CreateSnapshotFileCallback callback,const FileSystemURL & url,bool validate_media_files,const base::FilePath & snapshot_file_path)202 void OnSnapshotFileCreatedRunTask(
203 std::unique_ptr<FileSystemOperationContext> context,
204 AsyncFileUtil::CreateSnapshotFileCallback callback,
205 const FileSystemURL& url,
206 bool validate_media_files,
207 const base::FilePath& snapshot_file_path) {
208 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
209 if (snapshot_file_path.empty()) {
210 OnCreateSnapshotFileError(std::move(callback),
211 base::File::FILE_ERROR_FAILED);
212 return;
213 }
214 MTPDeviceAsyncDelegate* delegate =
215 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(url);
216 if (!delegate) {
217 OnCreateSnapshotFileError(std::move(callback),
218 base::File::FILE_ERROR_NOT_FOUND);
219 return;
220 }
221 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
222 delegate->CreateSnapshotFile(
223 url.path(), // device file path
224 snapshot_file_path,
225 base::Bind(&OnDidCreateSnapshotFile, copyable_callback,
226 base::RetainedRef(context->task_runner()),
227 validate_media_files),
228 base::Bind(&OnCreateSnapshotFileError, copyable_callback));
229 }
230
231 } // namespace
232
233 class DeviceMediaAsyncFileUtil::MediaPathFilterWrapper
234 : public base::RefCountedThreadSafe<MediaPathFilterWrapper> {
235 public:
236 MediaPathFilterWrapper();
237
238 // Check if entries in |file_list| look like media files.
239 // Append the ones that look like media files to |results|.
240 // Should run on a media task runner.
241 AsyncFileUtil::EntryList FilterMediaEntries(
242 const AsyncFileUtil::EntryList& file_list);
243
244 // Check if |path| looks like a media file.
245 bool CheckFilePath(const base::FilePath& path);
246
247 private:
248 friend class base::RefCountedThreadSafe<MediaPathFilterWrapper>;
249
250 virtual ~MediaPathFilterWrapper();
251
252 std::unique_ptr<MediaPathFilter> media_path_filter_;
253
254 DISALLOW_COPY_AND_ASSIGN(MediaPathFilterWrapper);
255 };
256
MediaPathFilterWrapper()257 DeviceMediaAsyncFileUtil::MediaPathFilterWrapper::MediaPathFilterWrapper()
258 : media_path_filter_(new MediaPathFilter) {
259 }
260
~MediaPathFilterWrapper()261 DeviceMediaAsyncFileUtil::MediaPathFilterWrapper::~MediaPathFilterWrapper() {
262 }
263
264 AsyncFileUtil::EntryList
FilterMediaEntries(const AsyncFileUtil::EntryList & file_list)265 DeviceMediaAsyncFileUtil::MediaPathFilterWrapper::FilterMediaEntries(
266 const AsyncFileUtil::EntryList& file_list) {
267 AsyncFileUtil::EntryList results;
268 for (size_t i = 0; i < file_list.size(); ++i) {
269 const filesystem::mojom::DirectoryEntry& entry = file_list[i];
270 if (entry.type == filesystem::mojom::FsFileType::DIRECTORY ||
271 CheckFilePath(entry.name)) {
272 results.push_back(entry);
273 }
274 }
275 return results;
276 }
277
CheckFilePath(const base::FilePath & path)278 bool DeviceMediaAsyncFileUtil::MediaPathFilterWrapper::CheckFilePath(
279 const base::FilePath& path) {
280 return media_path_filter_->Match(path);
281 }
282
~DeviceMediaAsyncFileUtil()283 DeviceMediaAsyncFileUtil::~DeviceMediaAsyncFileUtil() {
284 }
285
286 // static
Create(const base::FilePath & profile_path,MediaFileValidationType validation_type)287 std::unique_ptr<DeviceMediaAsyncFileUtil> DeviceMediaAsyncFileUtil::Create(
288 const base::FilePath& profile_path,
289 MediaFileValidationType validation_type) {
290 DCHECK(!profile_path.empty());
291 return base::WrapUnique(
292 new DeviceMediaAsyncFileUtil(profile_path, validation_type));
293 }
294
SupportsStreaming(const storage::FileSystemURL & url)295 bool DeviceMediaAsyncFileUtil::SupportsStreaming(
296 const storage::FileSystemURL& url) {
297 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
298 MTPDeviceAsyncDelegate* delegate =
299 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(url);
300 if (!delegate)
301 return false;
302 return delegate->IsStreaming();
303 }
304
CreateOrOpen(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & url,int file_flags,CreateOrOpenCallback callback)305 void DeviceMediaAsyncFileUtil::CreateOrOpen(
306 std::unique_ptr<FileSystemOperationContext> context,
307 const FileSystemURL& url,
308 int file_flags,
309 CreateOrOpenCallback callback) {
310 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
311 // Returns an error if any unsupported flag is found.
312 if (file_flags & ~(base::File::FLAG_OPEN |
313 base::File::FLAG_READ |
314 base::File::FLAG_WRITE_ATTRIBUTES)) {
315 std::move(callback).Run(base::File(base::File::FILE_ERROR_SECURITY),
316 base::Closure());
317 return;
318 }
319 auto* task_runner = context->task_runner();
320 CreateSnapshotFile(
321 std::move(context), url,
322 base::BindOnce(&NativeMediaFileUtil::CreatedSnapshotFileForCreateOrOpen,
323 base::RetainedRef(task_runner), file_flags,
324 std::move(callback)));
325 }
326
EnsureFileExists(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & url,EnsureFileExistsCallback callback)327 void DeviceMediaAsyncFileUtil::EnsureFileExists(
328 std::unique_ptr<FileSystemOperationContext> context,
329 const FileSystemURL& url,
330 EnsureFileExistsCallback callback) {
331 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
332 NOTIMPLEMENTED();
333 std::move(callback).Run(base::File::FILE_ERROR_SECURITY, false);
334 }
335
CreateDirectory(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & url,bool exclusive,bool recursive,StatusCallback callback)336 void DeviceMediaAsyncFileUtil::CreateDirectory(
337 std::unique_ptr<FileSystemOperationContext> context,
338 const FileSystemURL& url,
339 bool exclusive,
340 bool recursive,
341 StatusCallback callback) {
342 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
343 MTPDeviceAsyncDelegate* delegate =
344 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(url);
345 if (!delegate) {
346 OnCreateDirectoryError(std::move(callback),
347 base::File::FILE_ERROR_NOT_FOUND);
348 return;
349 }
350 if (delegate->IsReadOnly()) {
351 OnCreateDirectoryError(std::move(callback),
352 base::File::FILE_ERROR_SECURITY);
353 return;
354 }
355 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
356 delegate->CreateDirectory(
357 url.path(), exclusive, recursive,
358 base::Bind(&DeviceMediaAsyncFileUtil::OnDidCreateDirectory,
359 weak_ptr_factory_.GetWeakPtr(), copyable_callback),
360 base::Bind(&OnCreateDirectoryError, copyable_callback));
361 }
362
GetFileInfo(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & url,int,GetFileInfoCallback callback)363 void DeviceMediaAsyncFileUtil::GetFileInfo(
364 std::unique_ptr<FileSystemOperationContext> context,
365 const FileSystemURL& url,
366 int /* flags */,
367 GetFileInfoCallback callback) {
368 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
369 MTPDeviceAsyncDelegate* delegate =
370 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(url);
371 if (!delegate) {
372 OnGetFileInfoError(std::move(callback), base::File::FILE_ERROR_NOT_FOUND);
373 return;
374 }
375 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
376 delegate->GetFileInfo(url.path(),
377 base::Bind(&DeviceMediaAsyncFileUtil::OnDidGetFileInfo,
378 weak_ptr_factory_.GetWeakPtr(),
379 base::RetainedRef(context->task_runner()),
380 url.path(), copyable_callback),
381 base::Bind(&OnGetFileInfoError, copyable_callback));
382 }
383
ReadDirectory(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & url,ReadDirectoryCallback callback)384 void DeviceMediaAsyncFileUtil::ReadDirectory(
385 std::unique_ptr<FileSystemOperationContext> context,
386 const FileSystemURL& url,
387 ReadDirectoryCallback callback) {
388 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
389 MTPDeviceAsyncDelegate* delegate =
390 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(url);
391 if (!delegate) {
392 OnReadDirectoryError(callback, base::File::FILE_ERROR_NOT_FOUND);
393 return;
394 }
395
396 delegate->ReadDirectory(
397 url.path(),
398 base::Bind(&DeviceMediaAsyncFileUtil::OnDidReadDirectory,
399 weak_ptr_factory_.GetWeakPtr(),
400 base::RetainedRef(context->task_runner()), callback),
401 base::Bind(&OnReadDirectoryError, callback));
402 }
403
Touch(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & url,const base::Time & last_access_time,const base::Time & last_modified_time,StatusCallback callback)404 void DeviceMediaAsyncFileUtil::Touch(
405 std::unique_ptr<FileSystemOperationContext> context,
406 const FileSystemURL& url,
407 const base::Time& last_access_time,
408 const base::Time& last_modified_time,
409 StatusCallback callback) {
410 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
411 NOTIMPLEMENTED();
412 std::move(callback).Run(base::File::FILE_ERROR_SECURITY);
413 }
414
Truncate(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & url,int64_t length,StatusCallback callback)415 void DeviceMediaAsyncFileUtil::Truncate(
416 std::unique_ptr<FileSystemOperationContext> context,
417 const FileSystemURL& url,
418 int64_t length,
419 StatusCallback callback) {
420 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
421 NOTIMPLEMENTED();
422 std::move(callback).Run(base::File::FILE_ERROR_SECURITY);
423 }
424
CopyFileLocal(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,CopyFileProgressCallback progress_callback,StatusCallback callback)425 void DeviceMediaAsyncFileUtil::CopyFileLocal(
426 std::unique_ptr<FileSystemOperationContext> context,
427 const FileSystemURL& src_url,
428 const FileSystemURL& dest_url,
429 CopyOrMoveOption option,
430 CopyFileProgressCallback progress_callback,
431 StatusCallback callback) {
432 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
433
434 MTPDeviceAsyncDelegate* delegate =
435 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(dest_url);
436 if (!delegate) {
437 OnCopyFileLocalError(std::move(callback), base::File::FILE_ERROR_NOT_FOUND);
438 return;
439 }
440 if (delegate->IsReadOnly()) {
441 OnCopyFileLocalError(std::move(callback), base::File::FILE_ERROR_SECURITY);
442 return;
443 }
444
445 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
446 delegate->CopyFileLocal(
447 src_url.path(), dest_url.path(),
448 base::Bind(&CreateSnapshotFileOnBlockingPool, profile_path_),
449 progress_callback,
450 base::Bind(&DeviceMediaAsyncFileUtil::OnDidCopyFileLocal,
451 weak_ptr_factory_.GetWeakPtr(), copyable_callback),
452 base::Bind(&OnCopyFileLocalError, copyable_callback));
453 }
454
MoveFileLocal(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,StatusCallback callback)455 void DeviceMediaAsyncFileUtil::MoveFileLocal(
456 std::unique_ptr<FileSystemOperationContext> context,
457 const FileSystemURL& src_url,
458 const FileSystemURL& dest_url,
459 CopyOrMoveOption option,
460 StatusCallback callback) {
461 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
462
463 MTPDeviceAsyncDelegate* delegate =
464 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(dest_url);
465 if (!delegate) {
466 OnMoveFileLocalError(std::move(callback), base::File::FILE_ERROR_NOT_FOUND);
467 return;
468 }
469 if (delegate->IsReadOnly()) {
470 OnMoveFileLocalError(std::move(callback), base::File::FILE_ERROR_SECURITY);
471 return;
472 }
473
474 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
475 delegate->MoveFileLocal(
476 src_url.path(), dest_url.path(),
477 base::Bind(&CreateSnapshotFileOnBlockingPool, profile_path_),
478 base::Bind(&DeviceMediaAsyncFileUtil::OnDidMoveFileLocal,
479 weak_ptr_factory_.GetWeakPtr(), copyable_callback),
480 base::Bind(&OnMoveFileLocalError, copyable_callback));
481 }
482
CopyInForeignFile(std::unique_ptr<FileSystemOperationContext> context,const base::FilePath & src_file_path,const FileSystemURL & dest_url,StatusCallback callback)483 void DeviceMediaAsyncFileUtil::CopyInForeignFile(
484 std::unique_ptr<FileSystemOperationContext> context,
485 const base::FilePath& src_file_path,
486 const FileSystemURL& dest_url,
487 StatusCallback callback) {
488 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
489
490 MTPDeviceAsyncDelegate* delegate =
491 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(dest_url);
492 if (!delegate) {
493 OnCopyInForeignFileError(std::move(callback),
494 base::File::FILE_ERROR_NOT_FOUND);
495 return;
496 }
497 if (delegate->IsReadOnly()) {
498 OnCopyInForeignFileError(std::move(callback),
499 base::File::FILE_ERROR_SECURITY);
500 return;
501 }
502
503 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
504 delegate->CopyFileFromLocal(
505 src_file_path, dest_url.path(),
506 base::Bind(&DeviceMediaAsyncFileUtil::OnDidCopyInForeignFile,
507 weak_ptr_factory_.GetWeakPtr(), copyable_callback),
508 base::Bind(&OnCopyInForeignFileError, copyable_callback));
509 }
510
DeleteFile(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & url,StatusCallback callback)511 void DeviceMediaAsyncFileUtil::DeleteFile(
512 std::unique_ptr<FileSystemOperationContext> context,
513 const FileSystemURL& url,
514 StatusCallback callback) {
515 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
516
517 MTPDeviceAsyncDelegate* const delegate =
518 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(url);
519 if (!delegate) {
520 OnDeleteFileError(std::move(callback), base::File::FILE_ERROR_NOT_FOUND);
521 return;
522 }
523 if (delegate->IsReadOnly()) {
524 OnDeleteFileError(std::move(callback), base::File::FILE_ERROR_SECURITY);
525 return;
526 }
527
528 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
529 delegate->DeleteFile(
530 url.path(),
531 base::Bind(&DeviceMediaAsyncFileUtil::OnDidDeleteFile,
532 weak_ptr_factory_.GetWeakPtr(), copyable_callback),
533 base::Bind(&OnDeleteFileError, copyable_callback));
534 }
535
DeleteDirectory(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & url,StatusCallback callback)536 void DeviceMediaAsyncFileUtil::DeleteDirectory(
537 std::unique_ptr<FileSystemOperationContext> context,
538 const FileSystemURL& url,
539 StatusCallback callback) {
540 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
541
542 MTPDeviceAsyncDelegate* const delegate =
543 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(url);
544 if (!delegate) {
545 OnDeleteDirectoryError(std::move(callback),
546 base::File::FILE_ERROR_NOT_FOUND);
547 return;
548 }
549 if (delegate->IsReadOnly()) {
550 OnDeleteDirectoryError(std::move(callback),
551 base::File::FILE_ERROR_SECURITY);
552 return;
553 }
554
555 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
556 delegate->DeleteDirectory(
557 url.path(),
558 base::Bind(&DeviceMediaAsyncFileUtil::OnDidDeleteDirectory,
559 weak_ptr_factory_.GetWeakPtr(), copyable_callback),
560 base::Bind(&OnDeleteDirectoryError, copyable_callback));
561 }
562
DeleteRecursively(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & url,StatusCallback callback)563 void DeviceMediaAsyncFileUtil::DeleteRecursively(
564 std::unique_ptr<FileSystemOperationContext> context,
565 const FileSystemURL& url,
566 StatusCallback callback) {
567 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
568 std::move(callback).Run(base::File::FILE_ERROR_INVALID_OPERATION);
569 }
570
CreateSnapshotFile(std::unique_ptr<FileSystemOperationContext> context,const FileSystemURL & url,CreateSnapshotFileCallback callback)571 void DeviceMediaAsyncFileUtil::CreateSnapshotFile(
572 std::unique_ptr<FileSystemOperationContext> context,
573 const FileSystemURL& url,
574 CreateSnapshotFileCallback callback) {
575 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
576 MTPDeviceAsyncDelegate* delegate =
577 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(url);
578 if (!delegate) {
579 OnCreateSnapshotFileError(std::move(callback),
580 base::File::FILE_ERROR_NOT_FOUND);
581 return;
582 }
583
584 scoped_refptr<base::SequencedTaskRunner> task_runner(context->task_runner());
585 base::PostTaskAndReplyWithResult(
586 task_runner.get(), FROM_HERE,
587 base::BindOnce(&CreateSnapshotFileOnBlockingPool, profile_path_),
588 base::BindOnce(&OnSnapshotFileCreatedRunTask, std::move(context),
589 std::move(callback), url, validate_media_files()));
590 }
591
592 std::unique_ptr<storage::FileStreamReader>
GetFileStreamReader(const FileSystemURL & url,int64_t offset,const base::Time & expected_modification_time,storage::FileSystemContext * context)593 DeviceMediaAsyncFileUtil::GetFileStreamReader(
594 const FileSystemURL& url,
595 int64_t offset,
596 const base::Time& expected_modification_time,
597 storage::FileSystemContext* context) {
598 MTPDeviceAsyncDelegate* delegate =
599 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(url);
600 if (!delegate)
601 return std::unique_ptr<storage::FileStreamReader>();
602
603 DCHECK(delegate->IsStreaming());
604 return std::unique_ptr<storage::FileStreamReader>(
605 new ReadaheadFileStreamReader(new MTPFileStreamReader(
606 context, url, offset, expected_modification_time,
607 validate_media_files())));
608 }
609
AddWatcher(const storage::FileSystemURL & url,bool recursive,storage::WatcherManager::StatusCallback callback,storage::WatcherManager::NotificationCallback notification_callback)610 void DeviceMediaAsyncFileUtil::AddWatcher(
611 const storage::FileSystemURL& url,
612 bool recursive,
613 storage::WatcherManager::StatusCallback callback,
614 storage::WatcherManager::NotificationCallback notification_callback) {
615 MTPDeviceAsyncDelegate* const delegate =
616 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(url);
617 if (!delegate) {
618 std::move(callback).Run(base::File::FILE_ERROR_FAILED);
619 return;
620 }
621
622 delegate->AddWatcher(url.origin().GetURL(), url.path(), recursive,
623 std::move(callback), std::move(notification_callback));
624 }
625
RemoveWatcher(const storage::FileSystemURL & url,const bool recursive,storage::WatcherManager::StatusCallback callback)626 void DeviceMediaAsyncFileUtil::RemoveWatcher(
627 const storage::FileSystemURL& url,
628 const bool recursive,
629 storage::WatcherManager::StatusCallback callback) {
630 MTPDeviceAsyncDelegate* const delegate =
631 MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(url);
632 if (!delegate) {
633 std::move(callback).Run(base::File::FILE_ERROR_FAILED);
634 return;
635 }
636
637 delegate->RemoveWatcher(url.origin().GetURL(), url.path(), recursive,
638 std::move(callback));
639 }
640
DeviceMediaAsyncFileUtil(const base::FilePath & profile_path,MediaFileValidationType validation_type)641 DeviceMediaAsyncFileUtil::DeviceMediaAsyncFileUtil(
642 const base::FilePath& profile_path,
643 MediaFileValidationType validation_type)
644 : profile_path_(profile_path) {
645 if (validation_type == APPLY_MEDIA_FILE_VALIDATION) {
646 media_path_filter_wrapper_ = new MediaPathFilterWrapper;
647 }
648 }
649
OnDidCreateDirectory(StatusCallback callback)650 void DeviceMediaAsyncFileUtil::OnDidCreateDirectory(StatusCallback callback) {
651 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
652
653 std::move(callback).Run(base::File::FILE_OK);
654 }
655
OnDidGetFileInfo(base::SequencedTaskRunner * task_runner,const base::FilePath & path,AsyncFileUtil::GetFileInfoCallback callback,const base::File::Info & file_info)656 void DeviceMediaAsyncFileUtil::OnDidGetFileInfo(
657 base::SequencedTaskRunner* task_runner,
658 const base::FilePath& path,
659 AsyncFileUtil::GetFileInfoCallback callback,
660 const base::File::Info& file_info) {
661 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
662 if (file_info.is_directory || !validate_media_files()) {
663 OnDidCheckMediaForGetFileInfo(std::move(callback), file_info,
664 true /* valid */);
665 return;
666 }
667
668 base::PostTaskAndReplyWithResult(
669 task_runner, FROM_HERE,
670 base::BindOnce(&MediaPathFilterWrapper::CheckFilePath,
671 media_path_filter_wrapper_, path),
672 base::BindOnce(&OnDidCheckMediaForGetFileInfo, std::move(callback),
673 file_info));
674 }
675
OnDidReadDirectory(base::SequencedTaskRunner * task_runner,AsyncFileUtil::ReadDirectoryCallback callback,AsyncFileUtil::EntryList file_list,bool has_more)676 void DeviceMediaAsyncFileUtil::OnDidReadDirectory(
677 base::SequencedTaskRunner* task_runner,
678 AsyncFileUtil::ReadDirectoryCallback callback,
679 AsyncFileUtil::EntryList file_list,
680 bool has_more) {
681 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
682 if (!validate_media_files()) {
683 OnDidCheckMediaForReadDirectory(callback, has_more, std::move(file_list));
684 return;
685 }
686
687 base::PostTaskAndReplyWithResult(
688 task_runner, FROM_HERE,
689 base::BindOnce(&MediaPathFilterWrapper::FilterMediaEntries,
690 media_path_filter_wrapper_, std::move(file_list)),
691 base::BindOnce(&OnDidCheckMediaForReadDirectory, callback, has_more));
692 }
693
OnDidCopyFileLocal(StatusCallback callback)694 void DeviceMediaAsyncFileUtil::OnDidCopyFileLocal(StatusCallback callback) {
695 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
696
697 std::move(callback).Run(base::File::FILE_OK);
698 }
699
OnDidMoveFileLocal(StatusCallback callback)700 void DeviceMediaAsyncFileUtil::OnDidMoveFileLocal(StatusCallback callback) {
701 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
702
703 std::move(callback).Run(base::File::FILE_OK);
704 }
705
OnDidCopyInForeignFile(StatusCallback callback)706 void DeviceMediaAsyncFileUtil::OnDidCopyInForeignFile(StatusCallback callback) {
707 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
708
709 std::move(callback).Run(base::File::FILE_OK);
710 }
711
OnDidDeleteFile(StatusCallback callback)712 void DeviceMediaAsyncFileUtil::OnDidDeleteFile(StatusCallback callback) {
713 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
714
715 std::move(callback).Run(base::File::FILE_OK);
716 }
717
OnDidDeleteDirectory(StatusCallback callback)718 void DeviceMediaAsyncFileUtil::OnDidDeleteDirectory(StatusCallback callback) {
719 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
720
721 std::move(callback).Run(base::File::FILE_OK);
722 }
723
validate_media_files() const724 bool DeviceMediaAsyncFileUtil::validate_media_files() const {
725 return media_path_filter_wrapper_.get() != NULL;
726 }
727