123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- // Copyright (c) 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "storage/browser/file_system/recursive_operation_delegate.h"
- #include <stddef.h>
- #include "base/bind.h"
- #include "base/check_op.h"
- #include "base/containers/queue.h"
- #include "base/files/file.h"
- #include "base/task/single_thread_task_runner.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "storage/browser/file_system/file_system_context.h"
- #include "storage/browser/file_system/file_system_operation_runner.h"
- namespace storage {
- RecursiveOperationDelegate::RecursiveOperationDelegate(
- FileSystemContext* file_system_context)
- : file_system_context_(file_system_context) {}
- RecursiveOperationDelegate::~RecursiveOperationDelegate() = default;
- void RecursiveOperationDelegate::Cancel() {
- canceled_ = true;
- OnCancel();
- }
- void RecursiveOperationDelegate::StartRecursiveOperation(
- const FileSystemURL& root,
- ErrorBehavior error_behavior,
- StatusCallback callback) {
- DCHECK(pending_directory_stack_.empty());
- DCHECK(pending_files_.empty());
- error_behavior_ = error_behavior;
- callback_ = std::move(callback);
- TryProcessFile(root);
- }
- void RecursiveOperationDelegate::TryProcessFile(const FileSystemURL& root) {
- ProcessFile(root,
- base::BindOnce(&RecursiveOperationDelegate::DidTryProcessFile,
- AsWeakPtr(), root));
- }
- FileSystemOperationRunner* RecursiveOperationDelegate::operation_runner() {
- return file_system_context_->operation_runner();
- }
- void RecursiveOperationDelegate::OnCancel() {}
- void RecursiveOperationDelegate::DidTryProcessFile(const FileSystemURL& root,
- base::File::Error error) {
- DCHECK(pending_directory_stack_.empty());
- DCHECK(pending_files_.empty());
- if (canceled_ || error != base::File::FILE_ERROR_NOT_A_FILE) {
- Done(error);
- return;
- }
- pending_directory_stack_.push(base::queue<FileSystemURL>());
- pending_directory_stack_.top().push(root);
- ProcessNextDirectory();
- }
- void RecursiveOperationDelegate::ProcessNextDirectory() {
- DCHECK(pending_files_.empty());
- DCHECK(!pending_directory_stack_.empty());
- DCHECK(!pending_directory_stack_.top().empty());
- const FileSystemURL& url = pending_directory_stack_.top().front();
- ProcessDirectory(
- url, base::BindOnce(&RecursiveOperationDelegate::DidProcessDirectory,
- AsWeakPtr()));
- }
- void RecursiveOperationDelegate::DidProcessDirectory(base::File::Error error) {
- DCHECK(pending_files_.empty());
- DCHECK(!pending_directory_stack_.empty());
- DCHECK(!pending_directory_stack_.top().empty());
- if (canceled_ || error != base::File::FILE_OK) {
- if (canceled_ ||
- error_behavior_ == FileSystemOperation::ERROR_BEHAVIOR_ABORT) {
- Done(error);
- return;
- }
- SetPreviousError(error);
- // For ERROR_BEHAVIOR_SKIP, we skip processing the current directory and
- // proceed with the next.
- pending_directory_stack_.top().pop();
- ProcessSubDirectory();
- return;
- }
- const FileSystemURL& parent = pending_directory_stack_.top().front();
- pending_directory_stack_.push(base::queue<FileSystemURL>());
- operation_runner()->ReadDirectory(
- parent, base::BindRepeating(&RecursiveOperationDelegate::DidReadDirectory,
- AsWeakPtr(), parent));
- }
- void RecursiveOperationDelegate::DidReadDirectory(const FileSystemURL& parent,
- base::File::Error error,
- FileEntryList entries,
- bool has_more) {
- DCHECK(!pending_directory_stack_.empty());
- if (canceled_ || error != base::File::FILE_OK) {
- Done(error);
- return;
- }
- for (size_t i = 0; i < entries.size(); i++) {
- FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
- parent.storage_key(), parent.mount_type(),
- parent.virtual_path().Append(entries[i].name));
- if (parent.bucket().has_value())
- url.SetBucket(parent.bucket().value());
- if (entries[i].type == filesystem::mojom::FsFileType::DIRECTORY)
- pending_directory_stack_.top().push(url);
- else
- pending_files_.push(url);
- }
- // Wait for next entries.
- if (has_more)
- return;
- ProcessPendingFiles();
- }
- void RecursiveOperationDelegate::ProcessPendingFiles() {
- DCHECK(!pending_directory_stack_.empty());
- if (pending_files_.empty() || canceled_) {
- ProcessSubDirectory();
- return;
- }
- // Do not post any new tasks.
- if (canceled_)
- return;
- // Run ProcessFile.
- scoped_refptr<base::SingleThreadTaskRunner> current_task_runner =
- base::ThreadTaskRunnerHandle::Get();
- if (!pending_files_.empty()) {
- current_task_runner->PostTask(
- FROM_HERE,
- base::BindOnce(
- &RecursiveOperationDelegate::ProcessFile, AsWeakPtr(),
- pending_files_.front(),
- base::BindOnce(&RecursiveOperationDelegate::DidProcessFile,
- AsWeakPtr(), pending_files_.front())));
- pending_files_.pop();
- }
- }
- void RecursiveOperationDelegate::DidProcessFile(const FileSystemURL& url,
- base::File::Error error) {
- if (error != base::File::FILE_OK) {
- if (error_behavior_ == FileSystemOperation::ERROR_BEHAVIOR_ABORT) {
- // If an error occurs, invoke Done immediately (even if there remain
- // running operations). It is because in the callback, this instance is
- // deleted.
- Done(error);
- return;
- }
- SetPreviousError(error);
- }
- ProcessPendingFiles();
- }
- void RecursiveOperationDelegate::ProcessSubDirectory() {
- DCHECK(pending_files_.empty());
- DCHECK(!pending_directory_stack_.empty());
- if (canceled_) {
- Done(base::File::FILE_ERROR_ABORT);
- return;
- }
- if (!pending_directory_stack_.top().empty()) {
- // There remain some sub directories. Process them first.
- ProcessNextDirectory();
- return;
- }
- // All subdirectories are processed.
- pending_directory_stack_.pop();
- if (pending_directory_stack_.empty()) {
- // All files/directories are processed.
- Done(base::File::FILE_OK);
- return;
- }
- DCHECK(!pending_directory_stack_.top().empty());
- PostProcessDirectory(
- pending_directory_stack_.top().front(),
- base::BindOnce(&RecursiveOperationDelegate::DidPostProcessDirectory,
- AsWeakPtr()));
- }
- void RecursiveOperationDelegate::DidPostProcessDirectory(
- base::File::Error error) {
- DCHECK(pending_files_.empty());
- DCHECK(!pending_directory_stack_.empty());
- DCHECK(!pending_directory_stack_.top().empty());
- pending_directory_stack_.top().pop();
- if (canceled_ || error != base::File::FILE_OK) {
- if (canceled_ || error_behavior_ == ErrorBehavior::ERROR_BEHAVIOR_ABORT) {
- Done(error);
- return;
- }
- SetPreviousError(error);
- }
- ProcessSubDirectory();
- }
- void RecursiveOperationDelegate::SetPreviousError(base::File::Error error) {
- DCHECK_NE(error, base::File::FILE_OK);
- previous_error_ = error;
- }
- void RecursiveOperationDelegate::Done(base::File::Error error) {
- if (canceled_ && error == base::File::FILE_OK) {
- std::move(callback_).Run(base::File::FILE_ERROR_ABORT);
- } else {
- if (error != base::File::FILE_OK) {
- std::move(callback_).Run(error);
- } else {
- std::move(callback_).Run(previous_error_);
- }
- }
- }
- } // namespace storage
|