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/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/native_media_file_util.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "webkit/browser/fileapi/file_system_operation_context.h"
17 #include "webkit/browser/fileapi/file_system_url.h"
18 #include "webkit/common/blob/shareable_file_reference.h"
20 using fileapi::FileSystemOperationContext;
21 using fileapi::FileSystemURL;
22 using webkit_blob::ShareableFileReference;
26 const char kDeviceMediaAsyncFileUtilTempDir[] = "DeviceMediaFileSystem";
28 // Called on the IO thread.
29 MTPDeviceAsyncDelegate* GetMTPDeviceDelegate(const FileSystemURL& url) {
30 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
31 return MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(
35 // Called on a blocking pool thread to create a snapshot file to hold the
36 // contents of |device_file_path|. The snapshot file is created in
37 // "profile_path/kDeviceMediaAsyncFileUtilTempDir" directory. If the snapshot
38 // file is created successfully, |snapshot_file_path| will be a non-empty file
39 // path. In case of failure, the |snapshot_file_path| will be an empty file
41 void CreateSnapshotFileOnBlockingPool(
42 const base::FilePath& device_file_path,
43 const base::FilePath& profile_path,
44 base::FilePath* snapshot_file_path) {
45 DCHECK(snapshot_file_path);
46 base::FilePath isolated_media_file_system_dir_path =
47 profile_path.AppendASCII(kDeviceMediaAsyncFileUtilTempDir);
48 if (!file_util::CreateDirectory(isolated_media_file_system_dir_path) ||
49 !file_util::CreateTemporaryFileInDir(isolated_media_file_system_dir_path,
50 snapshot_file_path)) {
51 LOG(WARNING) << "Could not create media snapshot file "
52 << isolated_media_file_system_dir_path.value();
53 *snapshot_file_path = base::FilePath();
59 DeviceMediaAsyncFileUtil::~DeviceMediaAsyncFileUtil() {
63 DeviceMediaAsyncFileUtil* DeviceMediaAsyncFileUtil::Create(
64 const base::FilePath& profile_path) {
65 DCHECK(!profile_path.empty());
66 return new DeviceMediaAsyncFileUtil(profile_path);
69 void DeviceMediaAsyncFileUtil::CreateOrOpen(
70 scoped_ptr<FileSystemOperationContext> context,
71 const FileSystemURL& url,
73 const CreateOrOpenCallback& callback) {
74 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
76 base::PlatformFile invalid_file = base::kInvalidPlatformFileValue;
77 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY,
78 base::PassPlatformFile(&invalid_file),
82 void DeviceMediaAsyncFileUtil::EnsureFileExists(
83 scoped_ptr<FileSystemOperationContext> context,
84 const FileSystemURL& url,
85 const EnsureFileExistsCallback& callback) {
86 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
88 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, false);
91 void DeviceMediaAsyncFileUtil::CreateDirectory(
92 scoped_ptr<FileSystemOperationContext> context,
93 const FileSystemURL& url,
96 const StatusCallback& callback) {
97 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
99 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
102 void DeviceMediaAsyncFileUtil::GetFileInfo(
103 scoped_ptr<FileSystemOperationContext> context,
104 const FileSystemURL& url,
105 const GetFileInfoCallback& callback) {
106 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
107 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
109 OnGetFileInfoError(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND);
112 delegate->GetFileInfo(
114 base::Bind(&DeviceMediaAsyncFileUtil::OnDidGetFileInfo,
115 weak_ptr_factory_.GetWeakPtr(),
117 base::Bind(&DeviceMediaAsyncFileUtil::OnGetFileInfoError,
118 weak_ptr_factory_.GetWeakPtr(),
122 void DeviceMediaAsyncFileUtil::ReadDirectory(
123 scoped_ptr<FileSystemOperationContext> context,
124 const FileSystemURL& url,
125 const ReadDirectoryCallback& callback) {
126 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
127 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
129 OnReadDirectoryError(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND);
132 delegate->ReadDirectory(
134 base::Bind(&DeviceMediaAsyncFileUtil::OnDidReadDirectory,
135 weak_ptr_factory_.GetWeakPtr(),
137 base::Bind(&DeviceMediaAsyncFileUtil::OnReadDirectoryError,
138 weak_ptr_factory_.GetWeakPtr(),
142 void DeviceMediaAsyncFileUtil::Touch(
143 scoped_ptr<FileSystemOperationContext> context,
144 const FileSystemURL& url,
145 const base::Time& last_access_time,
146 const base::Time& last_modified_time,
147 const StatusCallback& callback) {
148 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
150 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
153 void DeviceMediaAsyncFileUtil::Truncate(
154 scoped_ptr<FileSystemOperationContext> context,
155 const FileSystemURL& url,
157 const StatusCallback& callback) {
158 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
160 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
163 void DeviceMediaAsyncFileUtil::CopyFileLocal(
164 scoped_ptr<FileSystemOperationContext> context,
165 const FileSystemURL& src_url,
166 const FileSystemURL& dest_url,
167 CopyOrMoveOption option,
168 const CopyFileProgressCallback& progress_callback,
169 const StatusCallback& callback) {
170 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
172 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
175 void DeviceMediaAsyncFileUtil::MoveFileLocal(
176 scoped_ptr<FileSystemOperationContext> context,
177 const FileSystemURL& src_url,
178 const FileSystemURL& dest_url,
179 CopyOrMoveOption option,
180 const StatusCallback& callback) {
181 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
183 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
186 void DeviceMediaAsyncFileUtil::CopyInForeignFile(
187 scoped_ptr<FileSystemOperationContext> context,
188 const base::FilePath& src_file_path,
189 const FileSystemURL& dest_url,
190 const StatusCallback& callback) {
191 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
193 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
196 void DeviceMediaAsyncFileUtil::DeleteFile(
197 scoped_ptr<FileSystemOperationContext> context,
198 const FileSystemURL& url,
199 const StatusCallback& callback) {
200 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
202 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
205 void DeviceMediaAsyncFileUtil::DeleteDirectory(
206 scoped_ptr<FileSystemOperationContext> context,
207 const FileSystemURL& url,
208 const StatusCallback& callback) {
209 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
211 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
214 void DeviceMediaAsyncFileUtil::DeleteRecursively(
215 scoped_ptr<FileSystemOperationContext> context,
216 const FileSystemURL& url,
217 const StatusCallback& callback) {
218 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
219 callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
222 void DeviceMediaAsyncFileUtil::CreateSnapshotFile(
223 scoped_ptr<FileSystemOperationContext> context,
224 const FileSystemURL& url,
225 const CreateSnapshotFileCallback& callback) {
226 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
227 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
229 OnCreateSnapshotFileError(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND);
232 base::FilePath* snapshot_file_path = new base::FilePath;
233 base::SequencedTaskRunner* task_runner = context->task_runner();
234 const bool success = task_runner->PostTaskAndReply(
236 base::Bind(&CreateSnapshotFileOnBlockingPool,
239 base::Unretained(snapshot_file_path)),
240 base::Bind(&DeviceMediaAsyncFileUtil::OnSnapshotFileCreatedRunTask,
241 weak_ptr_factory_.GetWeakPtr(),
242 base::Passed(&context),
245 base::Owned(snapshot_file_path)));
249 DeviceMediaAsyncFileUtil::DeviceMediaAsyncFileUtil(
250 const base::FilePath& profile_path)
251 : profile_path_(profile_path),
252 weak_ptr_factory_(this) {
255 void DeviceMediaAsyncFileUtil::OnDidGetFileInfo(
256 const AsyncFileUtil::GetFileInfoCallback& callback,
257 const base::PlatformFileInfo& file_info) {
258 callback.Run(base::PLATFORM_FILE_OK, file_info);
261 void DeviceMediaAsyncFileUtil::OnGetFileInfoError(
262 const AsyncFileUtil::GetFileInfoCallback& callback,
263 base::PlatformFileError error) {
264 callback.Run(error, base::PlatformFileInfo());
267 void DeviceMediaAsyncFileUtil::OnDidReadDirectory(
268 const AsyncFileUtil::ReadDirectoryCallback& callback,
269 const AsyncFileUtil::EntryList& file_list,
271 callback.Run(base::PLATFORM_FILE_OK, file_list, has_more);
274 void DeviceMediaAsyncFileUtil::OnReadDirectoryError(
275 const AsyncFileUtil::ReadDirectoryCallback& callback,
276 base::PlatformFileError error) {
277 callback.Run(error, AsyncFileUtil::EntryList(), false /*no more*/);
280 void DeviceMediaAsyncFileUtil::OnDidCreateSnapshotFile(
281 const AsyncFileUtil::CreateSnapshotFileCallback& callback,
282 base::SequencedTaskRunner* media_task_runner,
283 const base::PlatformFileInfo& file_info,
284 const base::FilePath& platform_path) {
285 base::PostTaskAndReplyWithResult(
288 base::Bind(&NativeMediaFileUtil::IsMediaFile, platform_path),
289 base::Bind(&DeviceMediaAsyncFileUtil::OnDidCheckMedia,
290 weak_ptr_factory_.GetWeakPtr(),
293 ShareableFileReference::GetOrCreate(
295 ShareableFileReference::DELETE_ON_FINAL_RELEASE,
296 media_task_runner)));
299 void DeviceMediaAsyncFileUtil::OnDidCheckMedia(
300 const AsyncFileUtil::CreateSnapshotFileCallback& callback,
301 const base::PlatformFileInfo& file_info,
302 scoped_refptr<webkit_blob::ShareableFileReference> platform_file,
303 base::PlatformFileError error) {
304 base::FilePath platform_path(platform_file.get()->path());
305 if (error != base::PLATFORM_FILE_OK)
306 platform_file = NULL;
307 callback.Run(error, file_info, platform_path, platform_file);
310 void DeviceMediaAsyncFileUtil::OnCreateSnapshotFileError(
311 const AsyncFileUtil::CreateSnapshotFileCallback& callback,
312 base::PlatformFileError error) {
313 callback.Run(error, base::PlatformFileInfo(), base::FilePath(),
314 scoped_refptr<ShareableFileReference>());
317 void DeviceMediaAsyncFileUtil::OnSnapshotFileCreatedRunTask(
318 scoped_ptr<FileSystemOperationContext> context,
319 const AsyncFileUtil::CreateSnapshotFileCallback& callback,
320 const FileSystemURL& url,
321 base::FilePath* snapshot_file_path) {
322 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
323 if (!snapshot_file_path || snapshot_file_path->empty()) {
324 OnCreateSnapshotFileError(callback, base::PLATFORM_FILE_ERROR_FAILED);
327 MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
329 OnCreateSnapshotFileError(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND);
332 delegate->CreateSnapshotFile(
333 url.path(), // device file path
335 base::Bind(&DeviceMediaAsyncFileUtil::OnDidCreateSnapshotFile,
336 weak_ptr_factory_.GetWeakPtr(),
338 make_scoped_refptr(context->task_runner())),
339 base::Bind(&DeviceMediaAsyncFileUtil::OnCreateSnapshotFileError,
340 weak_ptr_factory_.GetWeakPtr(),