Update broken references to image assets
[chromium-blink-merge.git] / chrome / browser / chromeos / drive / fileapi / async_file_util.cc
blobdb361545b9d72a4c503214fff17152bce619fcc1
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/drive/fileapi/async_file_util.h"
7 #include "base/callback.h"
8 #include "base/files/file_path.h"
9 #include "base/logging.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "base/threading/sequenced_worker_pool.h"
13 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
14 #include "chrome/browser/chromeos/drive/file_system_util.h"
15 #include "chrome/browser/chromeos/drive/fileapi/fileapi_worker.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "google_apis/drive/task_util.h"
18 #include "storage/browser/blob/shareable_file_reference.h"
19 #include "storage/browser/fileapi/file_system_operation_context.h"
20 #include "storage/browser/fileapi/file_system_url.h"
22 using content::BrowserThread;
24 namespace google_apis {
25 namespace internal {
27 // Partial specialization of helper template from google_apis/drive/task_util.h
28 // to enable google_apis::CreateRelayCallback to work with CreateOrOpenCallback.
29 template<typename T2>
30 struct ComposedCallback<void(base::File, T2)> {
31 static void Run(
32 const base::Callback<void(const base::Closure&)>& runner,
33 const base::Callback<void(base::File, T2)>& callback,
34 base::File arg1, T2 arg2) {
35 runner.Run(base::Bind(callback, Passed(&arg1), arg2));
39 } // namespace internal
40 } // namespace google_apis
42 namespace drive {
43 namespace internal {
44 namespace {
46 // Posts fileapi_internal::RunFileSystemCallback to UI thread.
47 // This function must be called on IO thread.
48 // The |on_error_callback| will be called (on error case) on IO thread.
49 void PostFileSystemCallback(
50 const fileapi_internal::FileSystemGetter& file_system_getter,
51 const base::Callback<void(FileSystemInterface*)>& function,
52 const base::Closure& on_error_callback) {
53 DCHECK_CURRENTLY_ON(BrowserThread::IO);
55 BrowserThread::PostTask(
56 BrowserThread::UI,
57 FROM_HERE,
58 base::Bind(&fileapi_internal::RunFileSystemCallback,
59 file_system_getter, function,
60 on_error_callback.is_null() ?
61 base::Closure() :
62 base::Bind(&google_apis::RunTaskWithTaskRunner,
63 base::ThreadTaskRunnerHandle::Get(),
64 on_error_callback)));
67 // Runs CreateOrOpenFile callback based on the given |error| and |file|.
68 void RunCreateOrOpenFileCallback(
69 const AsyncFileUtil::CreateOrOpenCallback& callback,
70 base::File file,
71 const base::Closure& close_callback_on_ui_thread) {
72 DCHECK_CURRENTLY_ON(BrowserThread::IO);
74 // It is necessary to make a closure, which runs on file closing here.
75 // It will be provided as a FileSystem::OpenFileCallback's argument later.
76 // (crbug.com/259184).
77 callback.Run(
78 file.Pass(),
79 base::Bind(&google_apis::RunTaskWithTaskRunner,
80 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
81 close_callback_on_ui_thread));
84 // Runs CreateOrOpenFile when the error happens.
85 void RunCreateOrOpenFileCallbackOnError(
86 const AsyncFileUtil::CreateOrOpenCallback& callback,
87 base::File::Error error) {
88 callback.Run(base::File(error), base::Closure());
91 // Runs EnsureFileExistsCallback based on the given |error|.
92 void RunEnsureFileExistsCallback(
93 const AsyncFileUtil::EnsureFileExistsCallback& callback,
94 base::File::Error error) {
95 DCHECK_CURRENTLY_ON(BrowserThread::IO);
97 // Remember if the file is actually created or not.
98 bool created = (error == base::File::FILE_OK);
100 // File::FILE_ERROR_EXISTS is not an actual error here.
101 if (error == base::File::FILE_ERROR_EXISTS)
102 error = base::File::FILE_OK;
104 callback.Run(error, created);
107 // Runs |callback| with the arguments based on the given arguments.
108 void RunCreateSnapshotFileCallback(
109 const AsyncFileUtil::CreateSnapshotFileCallback& callback,
110 base::File::Error error,
111 const base::File::Info& file_info,
112 const base::FilePath& local_path,
113 storage::ScopedFile::ScopeOutPolicy scope_out_policy) {
114 // ShareableFileReference is thread *unsafe* class. So it is necessary to
115 // create the instance (by invoking GetOrCreate) on IO thread, though
116 // most drive file system related operations run on UI thread.
117 DCHECK_CURRENTLY_ON(BrowserThread::IO);
119 scoped_refptr<storage::ShareableFileReference> file_reference =
120 storage::ShareableFileReference::GetOrCreate(storage::ScopedFile(
121 local_path, scope_out_policy, BrowserThread::GetBlockingPool()));
122 callback.Run(error, file_info, local_path, file_reference);
125 } // namespace
127 AsyncFileUtil::AsyncFileUtil() {
130 AsyncFileUtil::~AsyncFileUtil() {
133 void AsyncFileUtil::CreateOrOpen(
134 scoped_ptr<storage::FileSystemOperationContext> context,
135 const storage::FileSystemURL& url,
136 int file_flags,
137 const CreateOrOpenCallback& callback) {
138 DCHECK_CURRENTLY_ON(BrowserThread::IO);
140 base::FilePath file_path = util::ExtractDrivePathFromFileSystemUrl(url);
141 if (file_path.empty()) {
142 callback.Run(base::File(base::File::FILE_ERROR_NOT_FOUND), base::Closure());
143 return;
146 const fileapi_internal::FileSystemGetter getter =
147 base::Bind(&fileapi_internal::GetFileSystemFromUrl, url);
148 PostFileSystemCallback(
149 getter,
150 base::Bind(&fileapi_internal::OpenFile,
151 file_path, file_flags,
152 google_apis::CreateRelayCallback(
153 base::Bind(&RunCreateOrOpenFileCallback, callback))),
154 base::Bind(&RunCreateOrOpenFileCallbackOnError,
155 callback, base::File::FILE_ERROR_FAILED));
158 void AsyncFileUtil::EnsureFileExists(
159 scoped_ptr<storage::FileSystemOperationContext> context,
160 const storage::FileSystemURL& url,
161 const EnsureFileExistsCallback& callback) {
162 DCHECK_CURRENTLY_ON(BrowserThread::IO);
164 base::FilePath file_path = util::ExtractDrivePathFromFileSystemUrl(url);
165 if (file_path.empty()) {
166 callback.Run(base::File::FILE_ERROR_NOT_FOUND, false);
167 return;
170 PostFileSystemCallback(
171 base::Bind(&fileapi_internal::GetFileSystemFromUrl, url),
172 base::Bind(&fileapi_internal::CreateFile,
173 file_path, true /* is_exlusive */,
174 google_apis::CreateRelayCallback(
175 base::Bind(&RunEnsureFileExistsCallback, callback))),
176 base::Bind(callback, base::File::FILE_ERROR_FAILED, false));
179 void AsyncFileUtil::CreateDirectory(
180 scoped_ptr<storage::FileSystemOperationContext> context,
181 const storage::FileSystemURL& url,
182 bool exclusive,
183 bool recursive,
184 const StatusCallback& callback) {
185 DCHECK_CURRENTLY_ON(BrowserThread::IO);
187 base::FilePath file_path = util::ExtractDrivePathFromFileSystemUrl(url);
188 if (file_path.empty()) {
189 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
190 return;
193 PostFileSystemCallback(
194 base::Bind(&fileapi_internal::GetFileSystemFromUrl, url),
195 base::Bind(&fileapi_internal::CreateDirectory,
196 file_path, exclusive, recursive,
197 google_apis::CreateRelayCallback(callback)),
198 base::Bind(callback, base::File::FILE_ERROR_FAILED));
201 void AsyncFileUtil::GetFileInfo(
202 scoped_ptr<storage::FileSystemOperationContext> context,
203 const storage::FileSystemURL& url,
204 const GetFileInfoCallback& callback) {
205 DCHECK_CURRENTLY_ON(BrowserThread::IO);
207 base::FilePath file_path = util::ExtractDrivePathFromFileSystemUrl(url);
208 if (file_path.empty()) {
209 callback.Run(base::File::FILE_ERROR_NOT_FOUND, base::File::Info());
210 return;
213 PostFileSystemCallback(
214 base::Bind(&fileapi_internal::GetFileSystemFromUrl, url),
215 base::Bind(&fileapi_internal::GetFileInfo,
216 file_path, google_apis::CreateRelayCallback(callback)),
217 base::Bind(callback, base::File::FILE_ERROR_FAILED,
218 base::File::Info()));
221 void AsyncFileUtil::ReadDirectory(
222 scoped_ptr<storage::FileSystemOperationContext> context,
223 const storage::FileSystemURL& url,
224 const ReadDirectoryCallback& callback) {
225 DCHECK_CURRENTLY_ON(BrowserThread::IO);
227 base::FilePath file_path = util::ExtractDrivePathFromFileSystemUrl(url);
228 if (file_path.empty()) {
229 callback.Run(base::File::FILE_ERROR_NOT_FOUND, EntryList(), false);
230 return;
233 PostFileSystemCallback(
234 base::Bind(&fileapi_internal::GetFileSystemFromUrl, url),
235 base::Bind(&fileapi_internal::ReadDirectory,
236 file_path, google_apis::CreateRelayCallback(callback)),
237 base::Bind(callback, base::File::FILE_ERROR_FAILED,
238 EntryList(), false));
241 void AsyncFileUtil::Touch(
242 scoped_ptr<storage::FileSystemOperationContext> context,
243 const storage::FileSystemURL& url,
244 const base::Time& last_access_time,
245 const base::Time& last_modified_time,
246 const StatusCallback& callback) {
247 DCHECK_CURRENTLY_ON(BrowserThread::IO);
249 base::FilePath file_path = util::ExtractDrivePathFromFileSystemUrl(url);
250 if (file_path.empty()) {
251 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
252 return;
255 PostFileSystemCallback(
256 base::Bind(&fileapi_internal::GetFileSystemFromUrl, url),
257 base::Bind(&fileapi_internal::TouchFile,
258 file_path, last_access_time, last_modified_time,
259 google_apis::CreateRelayCallback(callback)),
260 base::Bind(callback, base::File::FILE_ERROR_FAILED));
263 void AsyncFileUtil::Truncate(
264 scoped_ptr<storage::FileSystemOperationContext> context,
265 const storage::FileSystemURL& url,
266 int64 length,
267 const StatusCallback& callback) {
268 DCHECK_CURRENTLY_ON(BrowserThread::IO);
270 base::FilePath file_path = util::ExtractDrivePathFromFileSystemUrl(url);
271 if (file_path.empty()) {
272 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
273 return;
276 PostFileSystemCallback(
277 base::Bind(&fileapi_internal::GetFileSystemFromUrl, url),
278 base::Bind(&fileapi_internal::Truncate,
279 file_path, length, google_apis::CreateRelayCallback(callback)),
280 base::Bind(callback, base::File::FILE_ERROR_FAILED));
283 void AsyncFileUtil::CopyFileLocal(
284 scoped_ptr<storage::FileSystemOperationContext> context,
285 const storage::FileSystemURL& src_url,
286 const storage::FileSystemURL& dest_url,
287 CopyOrMoveOption option,
288 const CopyFileProgressCallback& progress_callback,
289 const StatusCallback& callback) {
290 DCHECK_CURRENTLY_ON(BrowserThread::IO);
292 base::FilePath src_path = util::ExtractDrivePathFromFileSystemUrl(src_url);
293 base::FilePath dest_path = util::ExtractDrivePathFromFileSystemUrl(dest_url);
294 if (src_path.empty() || dest_path.empty()) {
295 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
296 return;
299 // TODO(kinaba): crbug.com/339794.
300 // Assumption here is that |src_url| and |dest_url| are always from the same
301 // profile. This indeed holds as long as we mount different profiles onto
302 // different mount point. Hence, using GetFileSystemFromUrl(dest_url) is safe.
303 // This will change after we introduce cross-profile sharing etc., and we
304 // need to deal with files from different profiles here.
305 PostFileSystemCallback(
306 base::Bind(&fileapi_internal::GetFileSystemFromUrl, dest_url),
307 base::Bind(
308 &fileapi_internal::Copy,
309 src_path,
310 dest_path,
311 option == storage::FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED,
312 google_apis::CreateRelayCallback(callback)),
313 base::Bind(callback, base::File::FILE_ERROR_FAILED));
316 void AsyncFileUtil::MoveFileLocal(
317 scoped_ptr<storage::FileSystemOperationContext> context,
318 const storage::FileSystemURL& src_url,
319 const storage::FileSystemURL& dest_url,
320 CopyOrMoveOption option,
321 const StatusCallback& callback) {
322 DCHECK_CURRENTLY_ON(BrowserThread::IO);
324 base::FilePath src_path = util::ExtractDrivePathFromFileSystemUrl(src_url);
325 base::FilePath dest_path = util::ExtractDrivePathFromFileSystemUrl(dest_url);
326 if (src_path.empty() || dest_path.empty()) {
327 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
328 return;
331 // TODO(kinaba): see the comment in CopyFileLocal(). |src_url| and |dest_url|
332 // always return the same FileSystem by GetFileSystemFromUrl, but we need to
333 // change it in order to support cross-profile file sharing etc.
334 PostFileSystemCallback(
335 base::Bind(&fileapi_internal::GetFileSystemFromUrl, dest_url),
336 base::Bind(&fileapi_internal::Move,
337 src_path, dest_path,
338 google_apis::CreateRelayCallback(callback)),
339 base::Bind(callback, base::File::FILE_ERROR_FAILED));
342 void AsyncFileUtil::CopyInForeignFile(
343 scoped_ptr<storage::FileSystemOperationContext> context,
344 const base::FilePath& src_file_path,
345 const storage::FileSystemURL& dest_url,
346 const StatusCallback& callback) {
347 DCHECK_CURRENTLY_ON(BrowserThread::IO);
349 base::FilePath dest_path = util::ExtractDrivePathFromFileSystemUrl(dest_url);
350 if (dest_path.empty()) {
351 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
352 return;
355 PostFileSystemCallback(
356 base::Bind(&fileapi_internal::GetFileSystemFromUrl, dest_url),
357 base::Bind(&fileapi_internal::CopyInForeignFile,
358 src_file_path, dest_path,
359 google_apis::CreateRelayCallback(callback)),
360 base::Bind(callback, base::File::FILE_ERROR_FAILED));
363 void AsyncFileUtil::DeleteFile(
364 scoped_ptr<storage::FileSystemOperationContext> context,
365 const storage::FileSystemURL& url,
366 const StatusCallback& callback) {
367 DCHECK_CURRENTLY_ON(BrowserThread::IO);
369 base::FilePath file_path = util::ExtractDrivePathFromFileSystemUrl(url);
370 if (file_path.empty()) {
371 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
372 return;
375 PostFileSystemCallback(
376 base::Bind(&fileapi_internal::GetFileSystemFromUrl, url),
377 base::Bind(&fileapi_internal::Remove,
378 file_path, false /* not recursive */,
379 google_apis::CreateRelayCallback(callback)),
380 base::Bind(callback, base::File::FILE_ERROR_FAILED));
383 void AsyncFileUtil::DeleteDirectory(
384 scoped_ptr<storage::FileSystemOperationContext> context,
385 const storage::FileSystemURL& url,
386 const StatusCallback& callback) {
387 DCHECK_CURRENTLY_ON(BrowserThread::IO);
389 base::FilePath file_path = util::ExtractDrivePathFromFileSystemUrl(url);
390 if (file_path.empty()) {
391 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
392 return;
395 PostFileSystemCallback(
396 base::Bind(&fileapi_internal::GetFileSystemFromUrl, url),
397 base::Bind(&fileapi_internal::Remove,
398 file_path, false /* not recursive */,
399 google_apis::CreateRelayCallback(callback)),
400 base::Bind(callback, base::File::FILE_ERROR_FAILED));
403 void AsyncFileUtil::DeleteRecursively(
404 scoped_ptr<storage::FileSystemOperationContext> context,
405 const storage::FileSystemURL& url,
406 const StatusCallback& callback) {
407 DCHECK_CURRENTLY_ON(BrowserThread::IO);
409 base::FilePath file_path = util::ExtractDrivePathFromFileSystemUrl(url);
410 if (file_path.empty()) {
411 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
412 return;
415 PostFileSystemCallback(
416 base::Bind(&fileapi_internal::GetFileSystemFromUrl, url),
417 base::Bind(&fileapi_internal::Remove,
418 file_path, true /* recursive */,
419 google_apis::CreateRelayCallback(callback)),
420 base::Bind(callback, base::File::FILE_ERROR_FAILED));
423 void AsyncFileUtil::CreateSnapshotFile(
424 scoped_ptr<storage::FileSystemOperationContext> context,
425 const storage::FileSystemURL& url,
426 const CreateSnapshotFileCallback& callback) {
427 DCHECK_CURRENTLY_ON(BrowserThread::IO);
429 base::FilePath file_path = util::ExtractDrivePathFromFileSystemUrl(url);
430 if (file_path.empty()) {
431 callback.Run(base::File::FILE_ERROR_NOT_FOUND,
432 base::File::Info(),
433 base::FilePath(),
434 scoped_refptr<storage::ShareableFileReference>());
435 return;
438 PostFileSystemCallback(
439 base::Bind(&fileapi_internal::GetFileSystemFromUrl, url),
440 base::Bind(&fileapi_internal::CreateSnapshotFile,
441 file_path,
442 google_apis::CreateRelayCallback(
443 base::Bind(&RunCreateSnapshotFileCallback, callback))),
444 base::Bind(callback,
445 base::File::FILE_ERROR_FAILED,
446 base::File::Info(),
447 base::FilePath(),
448 scoped_refptr<storage::ShareableFileReference>()));
451 } // namespace internal
452 } // namespace drive