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 (!base::CreateDirectory(isolated_media_file_system_dir_path
) ||
49 !base::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(),