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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
// Copyright 2020 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/fileapi/observable_file_system_operation_impl.h"
#include "chrome/browser/ash/fileapi/file_change_service.h"
#include "chrome/browser/ash/fileapi/file_change_service_factory.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "storage/browser/file_system/copy_or_move_hook_delegate.h"
namespace ash {
namespace {
using StatusCallback = storage::FileSystemOperation::StatusCallback;
using WriteCallback = storage::FileSystemOperation::WriteCallback;
// Helpers ---------------------------------------------------------------------
// Returns the `FileChangeService` associated with the given `account_id`.
FileChangeService* GetFileChangeService(const AccountId& account_id) {
Profile* profile = ProfileHelper::Get()->GetProfileByAccountId(account_id);
return profile ? FileChangeServiceFactory::GetInstance()->GetService(profile)
: nullptr;
}
// Notifies the `FileChangeService` associated with the given `account_id` of a
// file being moved form `src` to `dst`. This method may only be called from the
// browser UI thread.
void NotifyFileMovedOnUiThread(const AccountId& account_id,
const storage::FileSystemURL& src,
const storage::FileSystemURL& dst) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
FileChangeService* service = GetFileChangeService(account_id);
if (service)
service->NotifyFileMoved(src, dst);
}
// Notifies the `FileChangeService` associated with the given `account_id` of a
// file under `url` getting modified. This method may only be called from the
// browser UI thread.
void NotifyFileModifiedOnUiThread(const AccountId& account_id,
const storage::FileSystemURL& url) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
FileChangeService* service = GetFileChangeService(account_id);
if (service)
service->NotifyFileModified(url);
}
// Returns a `WriteCallback` which runs the specified callbacks in order.
WriteCallback RunInOrderCallback(WriteCallback a, WriteCallback b) {
return base::BindRepeating(
[](WriteCallback a, WriteCallback b, base::File::Error result,
int64_t bytes, bool complete) {
std::move(a).Run(result, bytes, complete);
std::move(b).Run(result, bytes, complete);
},
std::move(a), std::move(b));
}
// Returns a `StatusCallback` which runs the specified callbacks in order.
StatusCallback RunInOrderCallback(StatusCallback a, StatusCallback b) {
return base::BindOnce(
[](StatusCallback a, StatusCallback b, base::File::Error result) {
std::move(a).Run(result);
std::move(b).Run(result);
},
std::move(a), std::move(b));
}
// Returns a `StatusCallback` which runs the specified `closure` on the browser
// UI thread if `result` indicates success.
StatusCallback RunOnUiThreadOnSuccessCallback(base::OnceClosure closure) {
return base::BindOnce(
[](base::OnceClosure closure, base::File::Error result) {
if (result == base::File::FILE_OK) {
auto task_runner = content::GetUIThreadTaskRunner({});
task_runner->PostTask(FROM_HERE, std::move(closure));
}
},
std::move(closure));
}
// Returns a `WriteCallback` which runs the specified `closure` on the browser
// UI thread if `complete` is set.
WriteCallback RunOnUiThreadOnCompleteCallback(
const base::RepeatingClosure& closure) {
return base::BindRepeating(
[](const base::RepeatingClosure& closure, base::File::Error result,
int64_t bytes, bool complete) {
if (complete && result == base::File::FILE_OK) {
auto task_runner = content::GetUIThreadTaskRunner({});
task_runner->PostTask(FROM_HERE, std::move(closure));
}
},
std::move(closure));
}
} // namespace
// ObservableFileSystemOperationImpl -------------------------------------------
ObservableFileSystemOperationImpl::ObservableFileSystemOperationImpl(
const AccountId& account_id,
storage::OperationType type,
const storage::FileSystemURL& url,
storage::FileSystemContext* file_system_context,
std::unique_ptr<storage::FileSystemOperationContext> operation_context)
: storage::FileSystemOperationImpl(
type,
url,
file_system_context,
std::move(operation_context),
storage::FileSystemOperation::CreatePassKey()),
account_id_(account_id) {}
ObservableFileSystemOperationImpl::~ObservableFileSystemOperationImpl() =
default;
void ObservableFileSystemOperationImpl::Move(
const storage::FileSystemURL& src,
const storage::FileSystemURL& dst,
CopyOrMoveOptionSet options,
ErrorBehavior error_behavior,
std::unique_ptr<storage::CopyOrMoveHookDelegate> copy_or_move_hook_delegate,
StatusCallback callback) {
storage::FileSystemOperationImpl::Move(
src, dst, options, error_behavior, std::move(copy_or_move_hook_delegate),
RunInOrderCallback(
RunOnUiThreadOnSuccessCallback(base::BindOnce(
&NotifyFileMovedOnUiThread, account_id_, src, dst)),
std::move(callback)));
}
void ObservableFileSystemOperationImpl::MoveFileLocal(
const storage::FileSystemURL& src,
const storage::FileSystemURL& dst,
CopyOrMoveOptionSet options,
StatusCallback callback) {
storage::FileSystemOperationImpl::MoveFileLocal(
src, dst, options,
RunInOrderCallback(
RunOnUiThreadOnSuccessCallback(base::BindOnce(
&NotifyFileMovedOnUiThread, account_id_, src, dst)),
std::move(callback)));
}
void ObservableFileSystemOperationImpl::WriteBlob(
const storage::FileSystemURL& url,
std::unique_ptr<storage::FileWriterDelegate> writer_delegate,
std::unique_ptr<storage::BlobReader> blob_reader,
const WriteCallback& callback) {
storage::FileSystemOperationImpl::WriteBlob(
url, std::move(writer_delegate), std::move(blob_reader),
RunInOrderCallback(RunOnUiThreadOnCompleteCallback(base::BindRepeating(
&NotifyFileModifiedOnUiThread, account_id_, url)),
std::move(callback)));
}
void ObservableFileSystemOperationImpl::Write(
const storage::FileSystemURL& url,
std::unique_ptr<storage::FileWriterDelegate> writer_delegate,
mojo::ScopedDataPipeConsumerHandle data_pipe,
const WriteCallback& callback) {
storage::FileSystemOperationImpl::Write(
url, std::move(writer_delegate), std::move(data_pipe),
RunInOrderCallback(RunOnUiThreadOnCompleteCallback(base::BindRepeating(
&NotifyFileModifiedOnUiThread, account_id_, url)),
std::move(callback)));
}
void ObservableFileSystemOperationImpl::Truncate(
const storage::FileSystemURL& url,
int64_t length,
StatusCallback callback) {
storage::FileSystemOperationImpl::Truncate(
url, length,
RunInOrderCallback(RunOnUiThreadOnSuccessCallback(base::BindOnce(
&NotifyFileModifiedOnUiThread, account_id_, url)),
std::move(callback)));
}
} // namespace ash
|