1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/file_system_provider/scoped_file_opener.h"
#include "base/functional/bind.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ash/file_system_provider/abort_callback.h"
namespace ash::file_system_provider {
using OpenFileCallback = ProvidedFileSystemInterface::OpenFileCallback;
// Opens and closes files automatically. Extracted from ScopedFileOpener to
// be able to make ScopedFileOpener *not* ref counted.
class ScopedFileOpener::Runner
: public base::RefCounted<ScopedFileOpener::Runner> {
public:
static scoped_refptr<Runner> Create(ProvidedFileSystemInterface* file_system,
const base::FilePath& file_path,
OpenFileMode mode,
OpenFileCallback callback) {
auto runner =
base::WrapRefCounted(new Runner(file_system, std::move(callback)));
runner->abort_callback_ = file_system->OpenFile(
file_path, mode,
base::BindOnce(&ScopedFileOpener::Runner::OnOpenFileCompleted, runner));
return runner;
}
// Aborts pending open operation, or closes a file if it's already opened.
// Called from ScopedFileOpener::~ScopedFileOpener.
void AbortOrClose() {
if (!open_completed_) {
aborting_requested_ = true;
std::move(abort_callback_).Run();
return;
}
if (open_completed_ && file_handle_ != 0) {
if (file_system_.get()) {
file_system_->CloseFile(
file_handle_,
base::BindOnce(
&ScopedFileOpener::Runner::OnCloseFileAfterAbortCompleted, this,
file_handle_));
}
return;
}
// Otherwise nothing to abort nor to close - the opening process has
// completed, but the file failed to open, so there is no need to close it.
DCHECK(open_completed_ && file_handle_ == 0);
}
private:
friend class base::RefCounted<ScopedFileOpener::Runner>;
Runner(ProvidedFileSystemInterface* file_system, OpenFileCallback callback)
: file_system_(file_system->GetWeakPtr()),
open_callback_(std::move(callback)),
aborting_requested_(false),
open_completed_(false),
file_handle_(0) {}
~Runner() = default;
// Called when opening is completed with either a success or an error.
void OnOpenFileCompleted(int file_handle,
base::File::Error result,
std::unique_ptr<EntryMetadata> metadata) {
open_completed_ = true;
if (result != base::File::FILE_OK) {
CallOpenCallbackOnce(file_handle, result);
return;
}
file_handle_ = file_handle;
if (aborting_requested_ && file_system_.get()) {
// The opening request has been aborted earlier, but the abort request
// either hasn't arrived yet the extension, or it abort request events are
// not handled by the extension. In either case, close the file now.
file_system_->CloseFile(
file_handle,
base::BindOnce(
&ScopedFileOpener::Runner::OnCloseFileAfterAbortCompleted, this,
file_handle_));
return;
}
DCHECK_EQ(base::File::FILE_OK, result);
CallOpenCallbackOnce(file_handle, base::File::FILE_OK);
}
// Called when automatic closing a file is completed. It's performed when
// a file is opened successfully after the abort callback is called.
void OnCloseFileAfterAbortCompleted(int file_handle,
base::File::Error result) {
if (result == base::File::FILE_ERROR_ABORT) {
// Closing is aborted, so the file is still open. Call the OpenFile
// callback with a success error code and mark the file as opened.
//
// This is not good, as callers, such as file stream readers may expect
// aborting to *always* work, and leave the file opened permanently.
// The problem will go away once we remove the dialog to abort slow
// operations. See: crbug.com/475355.
CallOpenCallbackOnce(file_handle, base::File::FILE_OK);
return;
}
// Call the OpenFile callback with the ABORT error code, as the file is not
// opened anymore.
CallOpenCallbackOnce(file_handle, base::File::FILE_ERROR_ABORT);
}
// Calls the |open_callback_| only once with a result for opening a file.
void CallOpenCallbackOnce(int file_handle, base::File::Error result) {
if (open_callback_.is_null())
return;
std::move(open_callback_)
.Run(file_handle, result, /*cloud_file_info=*/nullptr);
}
base::WeakPtr<ProvidedFileSystemInterface> file_system_;
OpenFileCallback open_callback_;
AbortCallback abort_callback_;
bool aborting_requested_;
bool open_completed_;
int file_handle_;
};
ScopedFileOpener::ScopedFileOpener(ProvidedFileSystemInterface* file_system,
const base::FilePath& file_path,
OpenFileMode mode,
OpenFileCallback callback)
: runner_(
Runner::Create(file_system, file_path, mode, std::move(callback))) {}
ScopedFileOpener::~ScopedFileOpener() {
runner_->AbortOrClose();
}
} // namespace ash::file_system_provider
|