Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / media_galleries / fileapi / device_media_async_file_util.cc
blobdb3c081250a77e7867b004285e247f9e168823b3
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 "chrome/browser/media_galleries/fileapi/device_media_async_file_util.h"
7 #include "base/callback.h"
8 #include "base/files/file_util.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/task_runner_util.h"
11 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
12 #include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
13 #include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h"
14 #include "chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.h"
15 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
16 #include "chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "storage/browser/blob/shareable_file_reference.h"
19 #include "storage/browser/fileapi/file_stream_reader.h"
20 #include "storage/browser/fileapi/file_system_context.h"
21 #include "storage/browser/fileapi/file_system_operation_context.h"
22 #include "storage/browser/fileapi/file_system_url.h"
23 #include "storage/browser/fileapi/native_file_util.h"
25 using storage::AsyncFileUtil;
26 using storage::FileSystemOperationContext;
27 using storage::FileSystemURL;
28 using storage::ShareableFileReference;
30 namespace {
32 const char kDeviceMediaAsyncFileUtilTempDir[] = "DeviceMediaFileSystem";
34 MTPDeviceAsyncDelegate* GetMTPDeviceDelegate(const FileSystemURL& url) {
35 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
36 return MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(
37 url.filesystem_id());
40 // Called when GetFileInfo method call failed to get the details of file
41 // specified by the requested url. |callback| is invoked to notify the
42 // caller about the file |error|.
43 void OnGetFileInfoError(const AsyncFileUtil::GetFileInfoCallback& callback,
44 base::File::Error error) {
45 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
46 callback.Run(error, base::File::Info());
49 // Called after OnDidGetFileInfo finishes media check.
50 // |callback| is invoked to complete the GetFileInfo request.
51 void OnDidCheckMediaForGetFileInfo(
52 const AsyncFileUtil::GetFileInfoCallback& callback,
53 const base::File::Info& file_info,
54 bool is_valid_file) {
55 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
56 if (!is_valid_file) {
57 OnGetFileInfoError(callback, base::File::FILE_ERROR_NOT_FOUND);
58 return;
60 callback.Run(base::File::FILE_OK, file_info);
63 // Called after OnDidReadDirectory finishes media check.
64 // |callback| is invoked to complete the ReadDirectory request.
65 void OnDidCheckMediaForReadDirectory(
66 const AsyncFileUtil::ReadDirectoryCallback& callback,
67 bool has_more,
68 const AsyncFileUtil::EntryList& file_list) {
69 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
70 callback.Run(base::File::FILE_OK, file_list, has_more);
73 // Called when CreateDirectory method call failed.
74 void OnCreateDirectoryError(const AsyncFileUtil::StatusCallback& callback,
75 base::File::Error error) {
76 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
77 callback.Run(error);
80 // Called when ReadDirectory method call failed to enumerate the directory
81 // objects. |callback| is invoked to notify the caller about the |error|
82 // that occured while reading the directory objects.
83 void OnReadDirectoryError(const AsyncFileUtil::ReadDirectoryCallback& callback,
84 base::File::Error error) {
85 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
86 callback.Run(error, AsyncFileUtil::EntryList(), false /*no more*/);
89 // Called when CopyFileLocal method call failed.
90 void OnCopyFileLocalError(const AsyncFileUtil::StatusCallback& callback,
91 base::File::Error error) {
92 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
93 callback.Run(error);
96 // Called when MoveFileLocal method call failed.
97 void OnMoveFileLocalError(const AsyncFileUtil::StatusCallback& callback,
98 base::File::Error error) {
99 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
100 callback.Run(error);
103 // Called when CopyInForeignFile method call failed.
104 void OnCopyInForeignFileError(const AsyncFileUtil::StatusCallback& callback,
105 base::File::Error error) {
106 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
107 callback.Run(error);
110 // Called when DeleteFile method call failed.
111 void OnDeleteFileError(const AsyncFileUtil::StatusCallback& callback,
112 base::File::Error error) {
113 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
114 callback.Run(error);
117 // Called when DeleteDirectory method call failed.
118 void OnDeleteDirectoryError(const AsyncFileUtil::StatusCallback& callback,
119 base::File::Error error) {
120 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
121 callback.Run(error);
124 // Called on a blocking pool thread to create a snapshot file to hold the
125 // contents of |device_file_path|. The snapshot file is created in the
126 // "profile_path/kDeviceMediaAsyncFileUtilTempDir" directory. Return the
127 // snapshot file path or an empty path on failure.
128 base::FilePath CreateSnapshotFileOnBlockingPool(
129 const base::FilePath& profile_path) {
130 base::FilePath snapshot_file_path;
131 base::FilePath media_file_system_dir_path =
132 profile_path.AppendASCII(kDeviceMediaAsyncFileUtilTempDir);
133 if (!base::CreateDirectory(media_file_system_dir_path) ||
134 !base::CreateTemporaryFileInDir(media_file_system_dir_path,
135 &snapshot_file_path)) {
136 LOG(WARNING) << "Could not create media snapshot file "
137 << media_file_system_dir_path.value();
138 snapshot_file_path = base::FilePath();
140 return snapshot_file_path;
143 // Called after OnDidCreateSnapshotFile finishes media check.
144 // |callback| is invoked to complete the CreateSnapshotFile request.
145 void OnDidCheckMediaForCreateSnapshotFile(
146 const AsyncFileUtil::CreateSnapshotFileCallback& callback,
147 const base::File::Info& file_info,
148 scoped_refptr<storage::ShareableFileReference> platform_file,
149 base::File::Error error) {
150 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
151 base::FilePath platform_path(platform_file.get()->path());
152 if (error != base::File::FILE_OK)
153 platform_file = NULL;
154 callback.Run(error, file_info, platform_path, platform_file);
157 // Called when the snapshot file specified by the |platform_path| is
158 // successfully created. |file_info| contains the device media file details
159 // for which the snapshot file is created.
160 void OnDidCreateSnapshotFile(
161 const AsyncFileUtil::CreateSnapshotFileCallback& callback,
162 base::SequencedTaskRunner* media_task_runner,
163 bool validate_media_files,
164 const base::File::Info& file_info,
165 const base::FilePath& platform_path) {
166 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
167 scoped_refptr<storage::ShareableFileReference> file =
168 ShareableFileReference::GetOrCreate(
169 platform_path,
170 ShareableFileReference::DELETE_ON_FINAL_RELEASE,
171 media_task_runner);
173 if (validate_media_files) {
174 base::PostTaskAndReplyWithResult(
175 media_task_runner,
176 FROM_HERE,
177 base::Bind(&NativeMediaFileUtil::IsMediaFile, platform_path),
178 base::Bind(&OnDidCheckMediaForCreateSnapshotFile,
179 callback,
180 file_info,
181 file));
182 } else {
183 OnDidCheckMediaForCreateSnapshotFile(callback, file_info, file,
184 base::File::FILE_OK);
188 // Called when CreateSnapshotFile method call fails. |callback| is invoked to
189 // notify the caller about the |error|.
190 void OnCreateSnapshotFileError(
191 const AsyncFileUtil::CreateSnapshotFileCallback& callback,
192 base::File::Error error) {
193 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
194 callback.Run(error, base::File::Info(), base::FilePath(),
195 scoped_refptr<ShareableFileReference>());
198 // Called when the snapshot file specified by the |snapshot_file_path| is
199 // created to hold the contents of the url.path(). If the snapshot
200 // file is successfully created, |snapshot_file_path| will be an non-empty
201 // file path. In case of failure, |snapshot_file_path| will be an empty file
202 // path. Forwards the CreateSnapshot request to the delegate to copy the
203 // contents of url.path() to |snapshot_file_path|.
204 void OnSnapshotFileCreatedRunTask(
205 scoped_ptr<FileSystemOperationContext> context,
206 const AsyncFileUtil::CreateSnapshotFileCallback& callback,
207 const FileSystemURL& url,
208 bool validate_media_files,
209 const base::FilePath& snapshot_file_path) {
210 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
211 if (snapshot_file_path.empty()) {
212 OnCreateSnapshotFileError(callback, base::File::FILE_ERROR_FAILED);
213 return;
215 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
216 if (!delegate) {
217 OnCreateSnapshotFileError(callback, base::File::FILE_ERROR_NOT_FOUND);
218 return;
220 delegate->CreateSnapshotFile(
221 url.path(), // device file path
222 snapshot_file_path,
223 base::Bind(&OnDidCreateSnapshotFile,
224 callback,
225 make_scoped_refptr(context->task_runner()),
226 validate_media_files),
227 base::Bind(&OnCreateSnapshotFileError, callback));
230 } // namespace
232 class DeviceMediaAsyncFileUtil::MediaPathFilterWrapper
233 : public base::RefCountedThreadSafe<MediaPathFilterWrapper> {
234 public:
235 MediaPathFilterWrapper();
237 // Check if entries in |file_list| look like media files.
238 // Append the ones that look like media files to |results|.
239 // Should run on a media task runner.
240 AsyncFileUtil::EntryList FilterMediaEntries(
241 const AsyncFileUtil::EntryList& file_list);
243 // Check if |path| looks like a media file.
244 bool CheckFilePath(const base::FilePath& path);
246 private:
247 friend class base::RefCountedThreadSafe<MediaPathFilterWrapper>;
249 virtual ~MediaPathFilterWrapper();
251 scoped_ptr<MediaPathFilter> media_path_filter_;
253 DISALLOW_COPY_AND_ASSIGN(MediaPathFilterWrapper);
256 DeviceMediaAsyncFileUtil::MediaPathFilterWrapper::MediaPathFilterWrapper()
257 : media_path_filter_(new MediaPathFilter) {
260 DeviceMediaAsyncFileUtil::MediaPathFilterWrapper::~MediaPathFilterWrapper() {
263 AsyncFileUtil::EntryList
264 DeviceMediaAsyncFileUtil::MediaPathFilterWrapper::FilterMediaEntries(
265 const AsyncFileUtil::EntryList& file_list) {
266 AsyncFileUtil::EntryList results;
267 for (size_t i = 0; i < file_list.size(); ++i) {
268 const storage::DirectoryEntry& entry = file_list[i];
269 if (entry.is_directory || CheckFilePath(base::FilePath(entry.name))) {
270 results.push_back(entry);
273 return results;
276 bool DeviceMediaAsyncFileUtil::MediaPathFilterWrapper::CheckFilePath(
277 const base::FilePath& path) {
278 return media_path_filter_->Match(path);
281 DeviceMediaAsyncFileUtil::~DeviceMediaAsyncFileUtil() {
284 // static
285 scoped_ptr<DeviceMediaAsyncFileUtil> DeviceMediaAsyncFileUtil::Create(
286 const base::FilePath& profile_path,
287 MediaFileValidationType validation_type) {
288 DCHECK(!profile_path.empty());
289 return make_scoped_ptr(
290 new DeviceMediaAsyncFileUtil(profile_path, validation_type));
293 bool DeviceMediaAsyncFileUtil::SupportsStreaming(
294 const storage::FileSystemURL& url) {
295 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
296 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
297 if (!delegate)
298 return false;
299 return delegate->IsStreaming();
302 void DeviceMediaAsyncFileUtil::CreateOrOpen(
303 scoped_ptr<FileSystemOperationContext> context,
304 const FileSystemURL& url,
305 int file_flags,
306 const CreateOrOpenCallback& callback) {
307 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
308 // Returns an error if any unsupported flag is found.
309 if (file_flags & ~(base::File::FLAG_OPEN |
310 base::File::FLAG_READ |
311 base::File::FLAG_WRITE_ATTRIBUTES)) {
312 callback.Run(base::File(base::File::FILE_ERROR_SECURITY), base::Closure());
313 return;
315 CreateSnapshotFile(
316 context.Pass(),
317 url,
318 base::Bind(&NativeMediaFileUtil::CreatedSnapshotFileForCreateOrOpen,
319 make_scoped_refptr(context->task_runner()),
320 file_flags,
321 callback));
324 void DeviceMediaAsyncFileUtil::EnsureFileExists(
325 scoped_ptr<FileSystemOperationContext> context,
326 const FileSystemURL& url,
327 const EnsureFileExistsCallback& callback) {
328 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
329 NOTIMPLEMENTED();
330 callback.Run(base::File::FILE_ERROR_SECURITY, false);
333 void DeviceMediaAsyncFileUtil::CreateDirectory(
334 scoped_ptr<FileSystemOperationContext> context,
335 const FileSystemURL& url,
336 bool exclusive,
337 bool recursive,
338 const StatusCallback& callback) {
339 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
340 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
341 if (!delegate) {
342 OnCreateDirectoryError(callback, base::File::FILE_ERROR_NOT_FOUND);
343 return;
345 if (delegate->IsReadOnly()) {
346 OnCreateDirectoryError(callback, base::File::FILE_ERROR_SECURITY);
347 return;
349 delegate->CreateDirectory(
350 url.path(), exclusive, recursive,
351 base::Bind(&DeviceMediaAsyncFileUtil::OnDidCreateDirectory,
352 weak_ptr_factory_.GetWeakPtr(), callback),
353 base::Bind(&OnCreateDirectoryError, callback));
356 void DeviceMediaAsyncFileUtil::GetFileInfo(
357 scoped_ptr<FileSystemOperationContext> context,
358 const FileSystemURL& url,
359 const GetFileInfoCallback& callback) {
360 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
361 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
362 if (!delegate) {
363 OnGetFileInfoError(callback, base::File::FILE_ERROR_NOT_FOUND);
364 return;
366 delegate->GetFileInfo(
367 url.path(),
368 base::Bind(&DeviceMediaAsyncFileUtil::OnDidGetFileInfo,
369 weak_ptr_factory_.GetWeakPtr(),
370 make_scoped_refptr(context->task_runner()),
371 url.path(),
372 callback),
373 base::Bind(&OnGetFileInfoError, callback));
376 void DeviceMediaAsyncFileUtil::ReadDirectory(
377 scoped_ptr<FileSystemOperationContext> context,
378 const FileSystemURL& url,
379 const ReadDirectoryCallback& callback) {
380 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
381 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
382 if (!delegate) {
383 OnReadDirectoryError(callback, base::File::FILE_ERROR_NOT_FOUND);
384 return;
387 delegate->ReadDirectory(
388 url.path(),
389 base::Bind(&DeviceMediaAsyncFileUtil::OnDidReadDirectory,
390 weak_ptr_factory_.GetWeakPtr(),
391 make_scoped_refptr(context->task_runner()),
392 callback),
393 base::Bind(&OnReadDirectoryError, callback));
396 void DeviceMediaAsyncFileUtil::Touch(
397 scoped_ptr<FileSystemOperationContext> context,
398 const FileSystemURL& url,
399 const base::Time& last_access_time,
400 const base::Time& last_modified_time,
401 const StatusCallback& callback) {
402 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
403 NOTIMPLEMENTED();
404 callback.Run(base::File::FILE_ERROR_SECURITY);
407 void DeviceMediaAsyncFileUtil::Truncate(
408 scoped_ptr<FileSystemOperationContext> context,
409 const FileSystemURL& url,
410 int64 length,
411 const StatusCallback& callback) {
412 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
413 NOTIMPLEMENTED();
414 callback.Run(base::File::FILE_ERROR_SECURITY);
417 void DeviceMediaAsyncFileUtil::CopyFileLocal(
418 scoped_ptr<FileSystemOperationContext> context,
419 const FileSystemURL& src_url,
420 const FileSystemURL& dest_url,
421 CopyOrMoveOption option,
422 const CopyFileProgressCallback& progress_callback,
423 const StatusCallback& callback) {
424 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
426 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(dest_url);
427 if (!delegate) {
428 OnCopyFileLocalError(callback, base::File::FILE_ERROR_NOT_FOUND);
429 return;
431 if (delegate->IsReadOnly()) {
432 OnCopyFileLocalError(callback, base::File::FILE_ERROR_SECURITY);
433 return;
436 delegate->CopyFileLocal(
437 src_url.path(), dest_url.path(),
438 base::Bind(&CreateSnapshotFileOnBlockingPool, profile_path_),
439 progress_callback,
440 base::Bind(&DeviceMediaAsyncFileUtil::OnDidCopyFileLocal,
441 weak_ptr_factory_.GetWeakPtr(), callback),
442 base::Bind(&OnCopyFileLocalError, callback));
445 void DeviceMediaAsyncFileUtil::MoveFileLocal(
446 scoped_ptr<FileSystemOperationContext> context,
447 const FileSystemURL& src_url,
448 const FileSystemURL& dest_url,
449 CopyOrMoveOption option,
450 const StatusCallback& callback) {
451 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
453 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(dest_url);
454 if (!delegate) {
455 OnMoveFileLocalError(callback, base::File::FILE_ERROR_NOT_FOUND);
456 return;
458 if (delegate->IsReadOnly()) {
459 OnMoveFileLocalError(callback, base::File::FILE_ERROR_SECURITY);
460 return;
463 delegate->MoveFileLocal(
464 src_url.path(), dest_url.path(),
465 base::Bind(&CreateSnapshotFileOnBlockingPool, profile_path_),
466 base::Bind(&DeviceMediaAsyncFileUtil::OnDidMoveFileLocal,
467 weak_ptr_factory_.GetWeakPtr(), callback),
468 base::Bind(&OnMoveFileLocalError, callback));
471 void DeviceMediaAsyncFileUtil::CopyInForeignFile(
472 scoped_ptr<FileSystemOperationContext> context,
473 const base::FilePath& src_file_path,
474 const FileSystemURL& dest_url,
475 const StatusCallback& callback) {
476 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
478 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(dest_url);
479 if (!delegate) {
480 OnCopyInForeignFileError(callback, base::File::FILE_ERROR_NOT_FOUND);
481 return;
483 if (delegate->IsReadOnly()) {
484 OnCopyInForeignFileError(callback, base::File::FILE_ERROR_SECURITY);
485 return;
488 delegate->CopyFileFromLocal(
489 src_file_path, dest_url.path(),
490 base::Bind(&DeviceMediaAsyncFileUtil::OnDidCopyInForeignFile,
491 weak_ptr_factory_.GetWeakPtr(), callback),
492 base::Bind(&OnCopyInForeignFileError, callback));
495 void DeviceMediaAsyncFileUtil::DeleteFile(
496 scoped_ptr<FileSystemOperationContext> context,
497 const FileSystemURL& url,
498 const StatusCallback& callback) {
499 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
501 MTPDeviceAsyncDelegate* const delegate = GetMTPDeviceDelegate(url);
502 if (!delegate) {
503 OnDeleteFileError(callback, base::File::FILE_ERROR_NOT_FOUND);
504 return;
506 if (delegate->IsReadOnly()) {
507 OnDeleteFileError(callback, base::File::FILE_ERROR_SECURITY);
508 return;
511 delegate->DeleteFile(url.path(),
512 base::Bind(&DeviceMediaAsyncFileUtil::OnDidDeleteFile,
513 weak_ptr_factory_.GetWeakPtr(), callback),
514 base::Bind(&OnDeleteFileError, callback));
517 void DeviceMediaAsyncFileUtil::DeleteDirectory(
518 scoped_ptr<FileSystemOperationContext> context,
519 const FileSystemURL& url,
520 const StatusCallback& callback) {
521 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
523 MTPDeviceAsyncDelegate* const delegate = GetMTPDeviceDelegate(url);
524 if (!delegate) {
525 OnDeleteDirectoryError(callback, base::File::FILE_ERROR_NOT_FOUND);
526 return;
528 if (delegate->IsReadOnly()) {
529 OnDeleteDirectoryError(callback, base::File::FILE_ERROR_SECURITY);
530 return;
533 delegate->DeleteDirectory(
534 url.path(), base::Bind(&DeviceMediaAsyncFileUtil::OnDidDeleteDirectory,
535 weak_ptr_factory_.GetWeakPtr(), callback),
536 base::Bind(&OnDeleteDirectoryError, callback));
539 void DeviceMediaAsyncFileUtil::DeleteRecursively(
540 scoped_ptr<FileSystemOperationContext> context,
541 const FileSystemURL& url,
542 const StatusCallback& callback) {
543 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
544 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
547 void DeviceMediaAsyncFileUtil::CreateSnapshotFile(
548 scoped_ptr<FileSystemOperationContext> context,
549 const FileSystemURL& url,
550 const CreateSnapshotFileCallback& callback) {
551 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
552 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
553 if (!delegate) {
554 OnCreateSnapshotFileError(callback, base::File::FILE_ERROR_NOT_FOUND);
555 return;
558 scoped_refptr<base::SequencedTaskRunner> task_runner(context->task_runner());
559 base::PostTaskAndReplyWithResult(
560 task_runner.get(), FROM_HERE,
561 base::Bind(&CreateSnapshotFileOnBlockingPool, profile_path_),
562 base::Bind(&OnSnapshotFileCreatedRunTask, base::Passed(&context),
563 callback, url, validate_media_files()));
566 scoped_ptr<storage::FileStreamReader>
567 DeviceMediaAsyncFileUtil::GetFileStreamReader(
568 const FileSystemURL& url,
569 int64 offset,
570 const base::Time& expected_modification_time,
571 storage::FileSystemContext* context) {
572 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
573 if (!delegate)
574 return scoped_ptr<storage::FileStreamReader>();
576 DCHECK(delegate->IsStreaming());
577 return scoped_ptr<storage::FileStreamReader>(new ReadaheadFileStreamReader(
578 new MTPFileStreamReader(context,
579 url,
580 offset,
581 expected_modification_time,
582 validate_media_files())));
585 void DeviceMediaAsyncFileUtil::AddWatcher(
586 const storage::FileSystemURL& url,
587 bool recursive,
588 const storage::WatcherManager::StatusCallback& callback,
589 const storage::WatcherManager::NotificationCallback&
590 notification_callback) {
591 MTPDeviceAsyncDelegate* const delegate = GetMTPDeviceDelegate(url);
592 if (!delegate) {
593 callback.Run(base::File::FILE_ERROR_FAILED);
594 return;
597 delegate->AddWatcher(url.origin(), url.path(), recursive, callback,
598 notification_callback);
601 void DeviceMediaAsyncFileUtil::RemoveWatcher(
602 const storage::FileSystemURL& url,
603 const bool recursive,
604 const storage::WatcherManager::StatusCallback& callback) {
605 MTPDeviceAsyncDelegate* const delegate = GetMTPDeviceDelegate(url);
606 if (!delegate) {
607 callback.Run(base::File::FILE_ERROR_FAILED);
608 return;
611 delegate->RemoveWatcher(url.origin(), url.path(), recursive, callback);
614 DeviceMediaAsyncFileUtil::DeviceMediaAsyncFileUtil(
615 const base::FilePath& profile_path,
616 MediaFileValidationType validation_type)
617 : profile_path_(profile_path),
618 weak_ptr_factory_(this) {
619 if (validation_type == APPLY_MEDIA_FILE_VALIDATION) {
620 media_path_filter_wrapper_ = new MediaPathFilterWrapper;
624 void DeviceMediaAsyncFileUtil::OnDidCreateDirectory(
625 const StatusCallback& callback) {
626 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
628 callback.Run(base::File::FILE_OK);
631 void DeviceMediaAsyncFileUtil::OnDidGetFileInfo(
632 base::SequencedTaskRunner* task_runner,
633 const base::FilePath& path,
634 const AsyncFileUtil::GetFileInfoCallback& callback,
635 const base::File::Info& file_info) {
636 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
637 if (file_info.is_directory || !validate_media_files()) {
638 OnDidCheckMediaForGetFileInfo(callback, file_info, true /* valid */);
639 return;
642 base::PostTaskAndReplyWithResult(
643 task_runner,
644 FROM_HERE,
645 base::Bind(&MediaPathFilterWrapper::CheckFilePath,
646 media_path_filter_wrapper_,
647 path),
648 base::Bind(&OnDidCheckMediaForGetFileInfo, callback, file_info));
651 void DeviceMediaAsyncFileUtil::OnDidReadDirectory(
652 base::SequencedTaskRunner* task_runner,
653 const AsyncFileUtil::ReadDirectoryCallback& callback,
654 const AsyncFileUtil::EntryList& file_list,
655 bool has_more) {
656 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
657 if (!validate_media_files()) {
658 OnDidCheckMediaForReadDirectory(callback, has_more, file_list);
659 return;
662 base::PostTaskAndReplyWithResult(
663 task_runner,
664 FROM_HERE,
665 base::Bind(&MediaPathFilterWrapper::FilterMediaEntries,
666 media_path_filter_wrapper_,
667 file_list),
668 base::Bind(&OnDidCheckMediaForReadDirectory, callback, has_more));
671 void DeviceMediaAsyncFileUtil::OnDidCopyFileLocal(
672 const StatusCallback& callback) {
673 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
675 callback.Run(base::File::FILE_OK);
678 void DeviceMediaAsyncFileUtil::OnDidMoveFileLocal(
679 const StatusCallback& callback) {
680 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
682 callback.Run(base::File::FILE_OK);
685 void DeviceMediaAsyncFileUtil::OnDidCopyInForeignFile(
686 const StatusCallback& callback) {
687 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
689 callback.Run(base::File::FILE_OK);
692 void DeviceMediaAsyncFileUtil::OnDidDeleteFile(const StatusCallback& callback) {
693 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
695 callback.Run(base::File::FILE_OK);
698 void DeviceMediaAsyncFileUtil::OnDidDeleteDirectory(
699 const StatusCallback& callback) {
700 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
702 callback.Run(base::File::FILE_OK);
705 bool DeviceMediaAsyncFileUtil::validate_media_files() const {
706 return media_path_filter_wrapper_.get() != NULL;