ozone: fix HDPMLegacy - do the PF after overlays, also clear old overlays
[chromium-blink-merge.git] / storage / browser / fileapi / file_system_operation_impl.cc
blobdbca3d6af96adc853f2301a968c53b4c7012896e
1 // Copyright 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 "storage/browser/fileapi/file_system_operation_impl.h"
7 #include "base/bind.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/time/time.h"
11 #include "net/base/escape.h"
12 #include "net/url_request/url_request.h"
13 #include "storage/browser/blob/shareable_file_reference.h"
14 #include "storage/browser/fileapi/async_file_util.h"
15 #include "storage/browser/fileapi/copy_or_move_operation_delegate.h"
16 #include "storage/browser/fileapi/file_observers.h"
17 #include "storage/browser/fileapi/file_system_backend.h"
18 #include "storage/browser/fileapi/file_system_context.h"
19 #include "storage/browser/fileapi/file_system_file_util.h"
20 #include "storage/browser/fileapi/file_system_operation_context.h"
21 #include "storage/browser/fileapi/file_system_url.h"
22 #include "storage/browser/fileapi/file_writer_delegate.h"
23 #include "storage/browser/fileapi/remove_operation_delegate.h"
24 #include "storage/browser/fileapi/sandbox_file_system_backend.h"
25 #include "storage/browser/quota/quota_manager_proxy.h"
26 #include "storage/common/fileapi/file_system_types.h"
27 #include "storage/common/fileapi/file_system_util.h"
28 #include "storage/common/quota/quota_types.h"
30 using storage::ScopedFile;
32 namespace storage {
34 namespace {
36 // Takes ownership and destruct on the target thread.
37 void Destruct(base::File file) {}
39 void DidOpenFile(
40 scoped_refptr<FileSystemContext> context,
41 base::WeakPtr<FileSystemOperationImpl> operation,
42 const FileSystemOperationImpl::OpenFileCallback& callback,
43 base::File file,
44 const base::Closure& on_close_callback) {
45 if (!operation) {
46 context->default_file_task_runner()->PostTask(
47 FROM_HERE,
48 base::Bind(&Destruct, base::Passed(&file)));
49 return;
51 callback.Run(file.Pass(), on_close_callback);
54 } // namespace
56 FileSystemOperation* FileSystemOperation::Create(
57 const FileSystemURL& url,
58 FileSystemContext* file_system_context,
59 scoped_ptr<FileSystemOperationContext> operation_context) {
60 return new FileSystemOperationImpl(url, file_system_context,
61 operation_context.Pass());
64 FileSystemOperationImpl::~FileSystemOperationImpl() {
67 void FileSystemOperationImpl::CreateFile(const FileSystemURL& url,
68 bool exclusive,
69 const StatusCallback& callback) {
70 DCHECK(SetPendingOperationType(kOperationCreateFile));
71 GetUsageAndQuotaThenRunTask(
72 url,
73 base::Bind(&FileSystemOperationImpl::DoCreateFile,
74 weak_factory_.GetWeakPtr(), url, callback, exclusive),
75 base::Bind(callback, base::File::FILE_ERROR_FAILED));
78 void FileSystemOperationImpl::CreateDirectory(const FileSystemURL& url,
79 bool exclusive,
80 bool recursive,
81 const StatusCallback& callback) {
82 DCHECK(SetPendingOperationType(kOperationCreateDirectory));
83 GetUsageAndQuotaThenRunTask(
84 url,
85 base::Bind(&FileSystemOperationImpl::DoCreateDirectory,
86 weak_factory_.GetWeakPtr(), url, callback,
87 exclusive, recursive),
88 base::Bind(callback, base::File::FILE_ERROR_FAILED));
91 void FileSystemOperationImpl::Copy(
92 const FileSystemURL& src_url,
93 const FileSystemURL& dest_url,
94 CopyOrMoveOption option,
95 const CopyProgressCallback& progress_callback,
96 const StatusCallback& callback) {
97 DCHECK(SetPendingOperationType(kOperationCopy));
98 DCHECK(!recursive_operation_delegate_);
100 // TODO(hidehiko): Support |progress_callback|. (crbug.com/278038).
101 recursive_operation_delegate_.reset(
102 new CopyOrMoveOperationDelegate(
103 file_system_context(),
104 src_url, dest_url,
105 CopyOrMoveOperationDelegate::OPERATION_COPY,
106 option,
107 progress_callback,
108 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
109 weak_factory_.GetWeakPtr(), callback)));
110 recursive_operation_delegate_->RunRecursively();
113 void FileSystemOperationImpl::Move(const FileSystemURL& src_url,
114 const FileSystemURL& dest_url,
115 CopyOrMoveOption option,
116 const StatusCallback& callback) {
117 DCHECK(SetPendingOperationType(kOperationMove));
118 DCHECK(!recursive_operation_delegate_);
119 recursive_operation_delegate_.reset(
120 new CopyOrMoveOperationDelegate(
121 file_system_context(),
122 src_url, dest_url,
123 CopyOrMoveOperationDelegate::OPERATION_MOVE,
124 option,
125 FileSystemOperation::CopyProgressCallback(),
126 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
127 weak_factory_.GetWeakPtr(), callback)));
128 recursive_operation_delegate_->RunRecursively();
131 void FileSystemOperationImpl::DirectoryExists(const FileSystemURL& url,
132 const StatusCallback& callback) {
133 DCHECK(SetPendingOperationType(kOperationDirectoryExists));
134 async_file_util_->GetFileInfo(
135 operation_context_.Pass(), url,
136 base::Bind(&FileSystemOperationImpl::DidDirectoryExists,
137 weak_factory_.GetWeakPtr(), callback));
140 void FileSystemOperationImpl::FileExists(const FileSystemURL& url,
141 const StatusCallback& callback) {
142 DCHECK(SetPendingOperationType(kOperationFileExists));
143 async_file_util_->GetFileInfo(
144 operation_context_.Pass(), url,
145 base::Bind(&FileSystemOperationImpl::DidFileExists,
146 weak_factory_.GetWeakPtr(), callback));
149 void FileSystemOperationImpl::GetMetadata(
150 const FileSystemURL& url, const GetMetadataCallback& callback) {
151 DCHECK(SetPendingOperationType(kOperationGetMetadata));
152 async_file_util_->GetFileInfo(operation_context_.Pass(), url, callback);
155 void FileSystemOperationImpl::ReadDirectory(
156 const FileSystemURL& url, const ReadDirectoryCallback& callback) {
157 DCHECK(SetPendingOperationType(kOperationReadDirectory));
158 async_file_util_->ReadDirectory(
159 operation_context_.Pass(), url, callback);
162 void FileSystemOperationImpl::Remove(const FileSystemURL& url,
163 bool recursive,
164 const StatusCallback& callback) {
165 DCHECK(SetPendingOperationType(kOperationRemove));
166 DCHECK(!recursive_operation_delegate_);
168 if (recursive) {
169 // For recursive removal, try to delegate the operation to AsyncFileUtil
170 // first. If not supported, it is delegated to RemoveOperationDelegate
171 // in DidDeleteRecursively.
172 async_file_util_->DeleteRecursively(
173 operation_context_.Pass(), url,
174 base::Bind(&FileSystemOperationImpl::DidDeleteRecursively,
175 weak_factory_.GetWeakPtr(), url, callback));
176 return;
179 recursive_operation_delegate_.reset(
180 new RemoveOperationDelegate(
181 file_system_context(), url,
182 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
183 weak_factory_.GetWeakPtr(), callback)));
184 recursive_operation_delegate_->Run();
187 void FileSystemOperationImpl::Write(
188 const FileSystemURL& url,
189 scoped_ptr<FileWriterDelegate> writer_delegate,
190 scoped_ptr<net::URLRequest> blob_request,
191 const WriteCallback& callback) {
192 DCHECK(SetPendingOperationType(kOperationWrite));
193 file_writer_delegate_ = writer_delegate.Pass();
194 file_writer_delegate_->Start(
195 blob_request.Pass(),
196 base::Bind(&FileSystemOperationImpl::DidWrite,
197 weak_factory_.GetWeakPtr(), url, callback));
200 void FileSystemOperationImpl::Truncate(const FileSystemURL& url, int64 length,
201 const StatusCallback& callback) {
202 DCHECK(SetPendingOperationType(kOperationTruncate));
203 GetUsageAndQuotaThenRunTask(
204 url,
205 base::Bind(&FileSystemOperationImpl::DoTruncate,
206 weak_factory_.GetWeakPtr(), url, callback, length),
207 base::Bind(callback, base::File::FILE_ERROR_FAILED));
210 void FileSystemOperationImpl::TouchFile(const FileSystemURL& url,
211 const base::Time& last_access_time,
212 const base::Time& last_modified_time,
213 const StatusCallback& callback) {
214 DCHECK(SetPendingOperationType(kOperationTouchFile));
215 async_file_util_->Touch(
216 operation_context_.Pass(), url,
217 last_access_time, last_modified_time,
218 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
219 weak_factory_.GetWeakPtr(), callback));
222 void FileSystemOperationImpl::OpenFile(const FileSystemURL& url,
223 int file_flags,
224 const OpenFileCallback& callback) {
225 DCHECK(SetPendingOperationType(kOperationOpenFile));
227 if (file_flags &
228 (base::File::FLAG_TEMPORARY | base::File::FLAG_HIDDEN)) {
229 callback.Run(base::File(base::File::FILE_ERROR_FAILED),
230 base::Closure());
231 return;
233 GetUsageAndQuotaThenRunTask(
234 url,
235 base::Bind(&FileSystemOperationImpl::DoOpenFile,
236 weak_factory_.GetWeakPtr(),
237 url, callback, file_flags),
238 base::Bind(callback, Passed(base::File(base::File::FILE_ERROR_FAILED)),
239 base::Closure()));
242 // We can only get here on a write or truncate that's not yet completed.
243 // We don't support cancelling any other operation at this time.
244 void FileSystemOperationImpl::Cancel(const StatusCallback& cancel_callback) {
245 DCHECK(cancel_callback_.is_null());
246 cancel_callback_ = cancel_callback;
248 if (file_writer_delegate_.get()) {
249 DCHECK_EQ(kOperationWrite, pending_operation_);
250 // This will call DidWrite() with ABORT status code.
251 file_writer_delegate_->Cancel();
252 } else if (recursive_operation_delegate_) {
253 // This will call DidFinishOperation() with ABORT status code.
254 recursive_operation_delegate_->Cancel();
255 } else {
256 // For truncate we have no way to cancel the inflight operation (for now).
257 // Let it just run and dispatch cancel callback later.
258 DCHECK_EQ(kOperationTruncate, pending_operation_);
262 void FileSystemOperationImpl::CreateSnapshotFile(
263 const FileSystemURL& url,
264 const SnapshotFileCallback& callback) {
265 DCHECK(SetPendingOperationType(kOperationCreateSnapshotFile));
266 async_file_util_->CreateSnapshotFile(
267 operation_context_.Pass(), url, callback);
270 void FileSystemOperationImpl::CopyInForeignFile(
271 const base::FilePath& src_local_disk_file_path,
272 const FileSystemURL& dest_url,
273 const StatusCallback& callback) {
274 DCHECK(SetPendingOperationType(kOperationCopyInForeignFile));
275 GetUsageAndQuotaThenRunTask(
276 dest_url,
277 base::Bind(&FileSystemOperationImpl::DoCopyInForeignFile,
278 weak_factory_.GetWeakPtr(), src_local_disk_file_path, dest_url,
279 callback),
280 base::Bind(callback, base::File::FILE_ERROR_FAILED));
283 void FileSystemOperationImpl::RemoveFile(
284 const FileSystemURL& url,
285 const StatusCallback& callback) {
286 DCHECK(SetPendingOperationType(kOperationRemove));
287 async_file_util_->DeleteFile(
288 operation_context_.Pass(), url,
289 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
290 weak_factory_.GetWeakPtr(), callback));
293 void FileSystemOperationImpl::RemoveDirectory(
294 const FileSystemURL& url,
295 const StatusCallback& callback) {
296 DCHECK(SetPendingOperationType(kOperationRemove));
297 async_file_util_->DeleteDirectory(
298 operation_context_.Pass(), url,
299 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
300 weak_factory_.GetWeakPtr(), callback));
303 void FileSystemOperationImpl::CopyFileLocal(
304 const FileSystemURL& src_url,
305 const FileSystemURL& dest_url,
306 CopyOrMoveOption option,
307 const CopyFileProgressCallback& progress_callback,
308 const StatusCallback& callback) {
309 DCHECK(SetPendingOperationType(kOperationCopy));
310 DCHECK(src_url.IsInSameFileSystem(dest_url));
312 GetUsageAndQuotaThenRunTask(
313 dest_url,
314 base::Bind(&FileSystemOperationImpl::DoCopyFileLocal,
315 weak_factory_.GetWeakPtr(), src_url, dest_url, option,
316 progress_callback, callback),
317 base::Bind(callback, base::File::FILE_ERROR_FAILED));
320 void FileSystemOperationImpl::MoveFileLocal(
321 const FileSystemURL& src_url,
322 const FileSystemURL& dest_url,
323 CopyOrMoveOption option,
324 const StatusCallback& callback) {
325 DCHECK(SetPendingOperationType(kOperationMove));
326 DCHECK(src_url.IsInSameFileSystem(dest_url));
327 GetUsageAndQuotaThenRunTask(
328 dest_url,
329 base::Bind(&FileSystemOperationImpl::DoMoveFileLocal,
330 weak_factory_.GetWeakPtr(),
331 src_url, dest_url, option, callback),
332 base::Bind(callback, base::File::FILE_ERROR_FAILED));
335 base::File::Error FileSystemOperationImpl::SyncGetPlatformPath(
336 const FileSystemURL& url,
337 base::FilePath* platform_path) {
338 DCHECK(SetPendingOperationType(kOperationGetLocalPath));
339 if (!file_system_context()->IsSandboxFileSystem(url.type()))
340 return base::File::FILE_ERROR_INVALID_OPERATION;
341 FileSystemFileUtil* file_util =
342 file_system_context()->sandbox_delegate()->sync_file_util();
343 file_util->GetLocalFilePath(operation_context_.get(), url, platform_path);
344 return base::File::FILE_OK;
347 FileSystemOperationImpl::FileSystemOperationImpl(
348 const FileSystemURL& url,
349 FileSystemContext* file_system_context,
350 scoped_ptr<FileSystemOperationContext> operation_context)
351 : file_system_context_(file_system_context),
352 operation_context_(operation_context.Pass()),
353 async_file_util_(NULL),
354 pending_operation_(kOperationNone),
355 weak_factory_(this) {
356 DCHECK(operation_context_.get());
357 operation_context_->DetachUserDataThread();
358 async_file_util_ = file_system_context_->GetAsyncFileUtil(url.type());
359 DCHECK(async_file_util_);
362 void FileSystemOperationImpl::GetUsageAndQuotaThenRunTask(
363 const FileSystemURL& url,
364 const base::Closure& task,
365 const base::Closure& error_callback) {
366 storage::QuotaManagerProxy* quota_manager_proxy =
367 file_system_context()->quota_manager_proxy();
368 if (!quota_manager_proxy ||
369 !file_system_context()->GetQuotaUtil(url.type())) {
370 // If we don't have the quota manager or the requested filesystem type
371 // does not support quota, we should be able to let it go.
372 operation_context_->set_allowed_bytes_growth(kint64max);
373 task.Run();
374 return;
377 DCHECK(quota_manager_proxy);
378 DCHECK(quota_manager_proxy->quota_manager());
379 quota_manager_proxy->quota_manager()->GetUsageAndQuota(
380 url.origin(),
381 FileSystemTypeToQuotaStorageType(url.type()),
382 base::Bind(&FileSystemOperationImpl::DidGetUsageAndQuotaAndRunTask,
383 weak_factory_.GetWeakPtr(), task, error_callback));
386 void FileSystemOperationImpl::DidGetUsageAndQuotaAndRunTask(
387 const base::Closure& task,
388 const base::Closure& error_callback,
389 storage::QuotaStatusCode status,
390 int64 usage,
391 int64 quota) {
392 if (status != storage::kQuotaStatusOk) {
393 LOG(WARNING) << "Got unexpected quota error : " << status;
394 error_callback.Run();
395 return;
398 operation_context_->set_allowed_bytes_growth(quota - usage);
399 task.Run();
402 void FileSystemOperationImpl::DoCreateFile(
403 const FileSystemURL& url,
404 const StatusCallback& callback,
405 bool exclusive) {
406 async_file_util_->EnsureFileExists(
407 operation_context_.Pass(), url,
408 base::Bind(
409 exclusive ?
410 &FileSystemOperationImpl::DidEnsureFileExistsExclusive :
411 &FileSystemOperationImpl::DidEnsureFileExistsNonExclusive,
412 weak_factory_.GetWeakPtr(), callback));
415 void FileSystemOperationImpl::DoCreateDirectory(
416 const FileSystemURL& url,
417 const StatusCallback& callback,
418 bool exclusive, bool recursive) {
419 async_file_util_->CreateDirectory(
420 operation_context_.Pass(),
421 url, exclusive, recursive,
422 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
423 weak_factory_.GetWeakPtr(), callback));
426 void FileSystemOperationImpl::DoCopyFileLocal(
427 const FileSystemURL& src_url,
428 const FileSystemURL& dest_url,
429 CopyOrMoveOption option,
430 const CopyFileProgressCallback& progress_callback,
431 const StatusCallback& callback) {
432 async_file_util_->CopyFileLocal(
433 operation_context_.Pass(), src_url, dest_url, option, progress_callback,
434 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
435 weak_factory_.GetWeakPtr(), callback));
438 void FileSystemOperationImpl::DoMoveFileLocal(
439 const FileSystemURL& src_url,
440 const FileSystemURL& dest_url,
441 CopyOrMoveOption option,
442 const StatusCallback& callback) {
443 async_file_util_->MoveFileLocal(
444 operation_context_.Pass(), src_url, dest_url, option,
445 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
446 weak_factory_.GetWeakPtr(), callback));
449 void FileSystemOperationImpl::DoCopyInForeignFile(
450 const base::FilePath& src_local_disk_file_path,
451 const FileSystemURL& dest_url,
452 const StatusCallback& callback) {
453 async_file_util_->CopyInForeignFile(
454 operation_context_.Pass(),
455 src_local_disk_file_path, dest_url,
456 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
457 weak_factory_.GetWeakPtr(), callback));
460 void FileSystemOperationImpl::DoTruncate(const FileSystemURL& url,
461 const StatusCallback& callback,
462 int64 length) {
463 async_file_util_->Truncate(
464 operation_context_.Pass(), url, length,
465 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
466 weak_factory_.GetWeakPtr(), callback));
469 void FileSystemOperationImpl::DoOpenFile(const FileSystemURL& url,
470 const OpenFileCallback& callback,
471 int file_flags) {
472 async_file_util_->CreateOrOpen(
473 operation_context_.Pass(), url, file_flags,
474 base::Bind(&DidOpenFile,
475 file_system_context_, weak_factory_.GetWeakPtr(), callback));
478 void FileSystemOperationImpl::DidEnsureFileExistsExclusive(
479 const StatusCallback& callback,
480 base::File::Error rv, bool created) {
481 if (rv == base::File::FILE_OK && !created) {
482 callback.Run(base::File::FILE_ERROR_EXISTS);
483 } else {
484 DidFinishOperation(callback, rv);
488 void FileSystemOperationImpl::DidEnsureFileExistsNonExclusive(
489 const StatusCallback& callback,
490 base::File::Error rv, bool /* created */) {
491 DidFinishOperation(callback, rv);
494 void FileSystemOperationImpl::DidFinishOperation(
495 const StatusCallback& callback,
496 base::File::Error rv) {
497 if (!cancel_callback_.is_null()) {
498 StatusCallback cancel_callback = cancel_callback_;
499 callback.Run(rv);
501 // Return OK only if we succeeded to stop the operation.
502 cancel_callback.Run(rv == base::File::FILE_ERROR_ABORT ?
503 base::File::FILE_OK :
504 base::File::FILE_ERROR_INVALID_OPERATION);
505 } else {
506 callback.Run(rv);
510 void FileSystemOperationImpl::DidDirectoryExists(
511 const StatusCallback& callback,
512 base::File::Error rv,
513 const base::File::Info& file_info) {
514 if (rv == base::File::FILE_OK && !file_info.is_directory)
515 rv = base::File::FILE_ERROR_NOT_A_DIRECTORY;
516 callback.Run(rv);
519 void FileSystemOperationImpl::DidFileExists(
520 const StatusCallback& callback,
521 base::File::Error rv,
522 const base::File::Info& file_info) {
523 if (rv == base::File::FILE_OK && file_info.is_directory)
524 rv = base::File::FILE_ERROR_NOT_A_FILE;
525 callback.Run(rv);
528 void FileSystemOperationImpl::DidDeleteRecursively(
529 const FileSystemURL& url,
530 const StatusCallback& callback,
531 base::File::Error rv) {
532 if (rv == base::File::FILE_ERROR_INVALID_OPERATION) {
533 // Recursive removal is not supported on this platform.
534 DCHECK(!recursive_operation_delegate_);
535 recursive_operation_delegate_.reset(
536 new RemoveOperationDelegate(
537 file_system_context(), url,
538 base::Bind(&FileSystemOperationImpl::DidFinishOperation,
539 weak_factory_.GetWeakPtr(), callback)));
540 recursive_operation_delegate_->RunRecursively();
541 return;
544 callback.Run(rv);
547 void FileSystemOperationImpl::DidWrite(
548 const FileSystemURL& url,
549 const WriteCallback& write_callback,
550 base::File::Error rv,
551 int64 bytes,
552 FileWriterDelegate::WriteProgressStatus write_status) {
553 const bool complete = (
554 write_status != FileWriterDelegate::SUCCESS_IO_PENDING);
555 if (complete && write_status != FileWriterDelegate::ERROR_WRITE_NOT_STARTED) {
556 DCHECK(operation_context_);
557 operation_context_->change_observers()->Notify(
558 &FileChangeObserver::OnModifyFile, MakeTuple(url));
561 StatusCallback cancel_callback = cancel_callback_;
562 write_callback.Run(rv, bytes, complete);
563 if (!cancel_callback.is_null())
564 cancel_callback.Run(base::File::FILE_OK);
567 bool FileSystemOperationImpl::SetPendingOperationType(OperationType type) {
568 if (pending_operation_ != kOperationNone)
569 return false;
570 pending_operation_ = type;
571 return true;
574 } // namespace storage