summaryrefslogtreecommitdiff
path: root/chromium/content/browser/native_io
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/native_io')
-rw-r--r--chromium/content/browser/native_io/native_io_context_unittest.cc87
-rw-r--r--chromium/content/browser/native_io/native_io_host.cc75
-rw-r--r--chromium/content/browser/native_io/native_io_host.h9
3 files changed, 157 insertions, 14 deletions
diff --git a/chromium/content/browser/native_io/native_io_context_unittest.cc b/chromium/content/browser/native_io/native_io_context_unittest.cc
index f362d35e465..cd6d262df9d 100644
--- a/chromium/content/browser/native_io/native_io_context_unittest.cc
+++ b/chromium/content/browser/native_io/native_io_context_unittest.cc
@@ -77,6 +77,18 @@ class NativeIOHostSync {
return names;
}
+ bool RenameFile(const std::string& old_name, const std::string& new_name) {
+ bool success = false;
+ base::RunLoop run_loop;
+ io_host_->RenameFile(old_name, new_name,
+ base::BindLambdaForTesting([&](bool backend_success) {
+ success = backend_success;
+ run_loop.Quit();
+ }));
+ run_loop.Run();
+ return success;
+ }
+
private:
blink::mojom::NativeIOHost* const io_host_;
};
@@ -142,17 +154,18 @@ class NativeIOContextTest : public testing::Test {
mojo::Remote<blink::mojom::NativeIOHost> google_host_remote_;
std::unique_ptr<NativeIOHostSync> example_host_;
std::unique_ptr<NativeIOHostSync> google_host_;
-};
-TEST_F(NativeIOContextTest, OpenFile_BadNames) {
- std::vector<std::string> bad_names = {
+ // Names disallowed by NativeIO
+ const std::vector<std::string> bad_names_ = {
"Uppercase",
"has-dash",
"has.dot",
"has/slash",
};
+};
- for (const std::string& bad_name : bad_names) {
+TEST_F(NativeIOContextTest, OpenFile_BadNames) {
+ for (const std::string& bad_name : bad_names_) {
mojo::test::BadMessageObserver bad_message_observer;
mojo::Remote<blink::mojom::NativeIOFileHost> file_host;
@@ -199,14 +212,7 @@ TEST_F(NativeIOContextTest, OpenFile_SameName) {
}
TEST_F(NativeIOContextTest, DeleteFile_BadNames) {
- std::vector<std::string> bad_names = {
- "Uppercase",
- "has-dash",
- "has.dot",
- "has/slash",
- };
-
- for (const std::string& bad_name : bad_names) {
+ for (const std::string& bad_name : bad_names_) {
mojo::test::BadMessageObserver bad_message_observer;
EXPECT_FALSE(example_host_->DeleteFile(bad_name));
@@ -223,6 +229,30 @@ TEST_F(NativeIOContextTest, OpenFile_Locks_DeleteFile) {
EXPECT_FALSE(example_host_->DeleteFile("test_file"));
}
+TEST_F(NativeIOContextTest, OpenFile_Locks_RenameFile) {
+ mojo::Remote<blink::mojom::NativeIOFileHost> file_host;
+ base::File file = example_host_->OpenFile(
+ "test_file_in_use", file_host.BindNewPipeAndPassReceiver());
+ EXPECT_TRUE(file.IsValid());
+
+ mojo::Remote<blink::mojom::NativeIOFileHost> file_host2;
+ base::File file2 = example_host_->OpenFile(
+ "test_file_closed", file_host2.BindNewPipeAndPassReceiver());
+ EXPECT_TRUE(file2.IsValid());
+ file2.Close();
+ NativeIOFileHostSync file_host2_sync(file_host2.get());
+ file_host2_sync.Close();
+
+ EXPECT_FALSE(
+ example_host_->RenameFile("test_file_in_use", "renamed_test_file"))
+ << "An open file cannot be renamed";
+
+ EXPECT_FALSE(
+ example_host_->RenameFile("test_file_closed", "test_file_in_use"))
+ << "An open file cannot be overwritten";
+ ;
+}
+
TEST_F(NativeIOContextTest, DeleteFile_WipesData) {
const std::string kTestData("Test Data");
@@ -264,6 +294,39 @@ TEST_F(NativeIOContextTest, GetAllFiles_AfterOpen) {
EXPECT_EQ("test_file", file_names[0]);
}
+TEST_F(NativeIOContextTest, RenameFile_AfterOpenAndRename) {
+ mojo::Remote<blink::mojom::NativeIOFileHost> file_host_remote;
+ base::File file = example_host_->OpenFile(
+ "test_file", file_host_remote.BindNewPipeAndPassReceiver());
+ file.Close();
+ NativeIOFileHostSync file_host(file_host_remote.get());
+ file_host.Close();
+
+ example_host_->RenameFile("test_file", "renamed_test_file");
+ std::vector<std::string> file_names = example_host_->GetAllFileNames();
+ EXPECT_EQ(1u, file_names.size());
+ EXPECT_EQ("renamed_test_file", file_names[0]);
+}
+
+TEST_F(NativeIOContextTest, RenameFile_BadNames) {
+ mojo::Remote<blink::mojom::NativeIOFileHost> file_host_remote;
+ base::File file = example_host_->OpenFile(
+ "test_file", file_host_remote.BindNewPipeAndPassReceiver());
+ file.Close();
+ NativeIOFileHostSync file_host(file_host_remote.get());
+ file_host.Close();
+
+ for (const std::string& bad_name : bad_names_) {
+ mojo::test::BadMessageObserver bad_message_observer;
+
+ EXPECT_FALSE(example_host_->RenameFile("test_file", bad_name));
+ EXPECT_EQ("Invalid file name", bad_message_observer.WaitForBadMessage());
+
+ EXPECT_FALSE(example_host_->RenameFile(bad_name, "inexistant_test_file"));
+ EXPECT_EQ("Invalid file name", bad_message_observer.WaitForBadMessage());
+ }
+}
+
TEST_F(NativeIOContextTest, OriginIsolation) {
const std::string kTestData("Test Data");
diff --git a/chromium/content/browser/native_io/native_io_host.cc b/chromium/content/browser/native_io/native_io_host.cc
index 2df37b9d470..d152638ee90 100644
--- a/chromium/content/browser/native_io/native_io_host.cc
+++ b/chromium/content/browser/native_io/native_io_host.cc
@@ -56,10 +56,9 @@ base::FilePath GetNativeIOFilePath(const base::FilePath& root_path,
scoped_refptr<base::TaskRunner> CreateFileTaskRunner() {
// We use a SequencedTaskRunner so that there is a global ordering to an
// origin's directory operations.
- return base::CreateSequencedTaskRunner({
+ return base::ThreadPool::CreateSequencedTaskRunner({
// Needed for file I/O.
base::MayBlock(),
- base::ThreadPool(),
// Reasonable compromise, given that a few database operations are
// blocking, while most operations are not. We should be able to do better
@@ -156,6 +155,27 @@ void DidGetAllFileNames(
std::move(result.second));
}
+// Performs the file I/O work in RenameFile().
+bool DoRenameFile(const base::FilePath& root_path,
+ const std::string& old_name,
+ const std::string& new_name) {
+ DCHECK(IsValidNativeIOName(old_name));
+ DCHECK(IsValidNativeIOName(new_name));
+
+ // If the origin's directory wasn't created yet, there's nothing to rename.
+ if (!base::PathExists(root_path))
+ return false;
+
+ // Do not overwrite an existing file.
+ if (base::PathExists(GetNativeIOFilePath(root_path, new_name)))
+ return false;
+
+ // TODO(rstz): Report error.
+ base::File::Error error;
+ return base::ReplaceFile(GetNativeIOFilePath(root_path, old_name),
+ GetNativeIOFilePath(root_path, new_name), &error);
+}
+
} // namespace
NativeIOHost::NativeIOHost(NativeIOContext* context,
@@ -256,6 +276,42 @@ void NativeIOHost::GetAllFileNames(GetAllFileNamesCallback callback) {
base::BindOnce(&DidGetAllFileNames, std::move(callback)));
}
+void NativeIOHost::RenameFile(const std::string& old_name,
+ const std::string& new_name,
+ RenameFileCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (!IsValidNativeIOName(old_name) || !IsValidNativeIOName(new_name)) {
+ mojo::ReportBadMessage("Invalid file name");
+ std::move(callback).Run(false);
+ return;
+ }
+
+ if (open_file_hosts_.find(old_name) != open_file_hosts_.end() ||
+ open_file_hosts_.find(new_name) != open_file_hosts_.end()) {
+ // TODO(rstz): Report that the file is locked.
+ std::move(callback).Run(false);
+ return;
+ }
+
+ auto old_iterator_and_success = io_pending_files_.insert(old_name);
+ if (!old_iterator_and_success.second) {
+ std::move(callback).Run(false);
+ return;
+ }
+ auto new_iterator_and_success = io_pending_files_.insert(new_name);
+ if (!new_iterator_and_success.second) {
+ io_pending_files_.erase(old_iterator_and_success.first);
+ std::move(callback).Run(false);
+ return;
+ }
+
+ file_task_runner_->PostTaskAndReplyWithResult(
+ FROM_HERE, base::BindOnce(&DoRenameFile, root_path_, old_name, new_name),
+ base::BindOnce(&NativeIOHost::DidRenameFile, weak_factory_.GetWeakPtr(),
+ old_name, new_name, std::move(callback)));
+}
+
void NativeIOHost::OnFileClose(NativeIOFileHost* file_host) {
DCHECK(open_file_hosts_.count(file_host->file_name()) > 0);
DCHECK_EQ(open_file_hosts_[file_host->file_name()].get(), file_host);
@@ -302,4 +358,19 @@ void NativeIOHost::DidDeleteFile(const std::string& name,
return;
}
+void NativeIOHost::DidRenameFile(const std::string& old_name,
+ const std::string& new_name,
+ RenameFileCallback callback,
+ bool success) {
+ DCHECK(io_pending_files_.count(old_name));
+ DCHECK(!open_file_hosts_.count(old_name));
+ DCHECK(io_pending_files_.count(new_name));
+ DCHECK(!open_file_hosts_.count(new_name));
+ io_pending_files_.erase(old_name);
+ io_pending_files_.erase(new_name);
+
+ std::move(callback).Run(success);
+ return;
+}
+
} // namespace content
diff --git a/chromium/content/browser/native_io/native_io_host.h b/chromium/content/browser/native_io/native_io_host.h
index bf2a50308f3..56bcd6d2f43 100644
--- a/chromium/content/browser/native_io/native_io_host.h
+++ b/chromium/content/browser/native_io/native_io_host.h
@@ -67,6 +67,9 @@ class NativeIOHost : public blink::mojom::NativeIOHost {
void DeleteFile(const std::string& name,
DeleteFileCallback callback) override;
void GetAllFileNames(GetAllFileNamesCallback callback) override;
+ void RenameFile(const std::string& old_name,
+ const std::string& new_name,
+ RenameFileCallback callback) override;
// Called when one of the open files for this origin closes.
//
@@ -90,6 +93,12 @@ class NativeIOHost : public blink::mojom::NativeIOHost {
DeleteFileCallback callback,
bool success);
+ // Called after the file I/O part of RenameFile() completed.
+ void DidRenameFile(const std::string& old_name,
+ const std::string& new_name,
+ RenameFileCallback callback,
+ bool success);
+
// The directory holding all the files for this origin.
const base::FilePath root_path_;