Commit 0b6377ae authored by Marijn Kruisselbrink's avatar Marijn Kruisselbrink Committed by Commit Bot

[NativeFS] Fix writing to files on ChromeOS.

Create FileSystemURL for swap file based on virtual_path and mount_type
of original entry, rather than based on path and type.

To make things more complicated, it isn't always possible to create the
swap file in the same file system as the original file, as the file
might be part of a single-file isolated file system. In that case we
create a new single-file isolated file system for the swap file.

Bug: 993597
Change-Id: Iaf13787ab7d274be91e4d45b6fc7ef5ed666dbff
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1766454
Commit-Queue: Marijn Kruisselbrink <mek@chromium.org>
Reviewed-by: default avatarVictor Costan <pwnall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#690165}
parent 7a4e8cf2
...@@ -117,13 +117,7 @@ class NativeFileSystemBrowserTest : public InProcessBrowserTest { ...@@ -117,13 +117,7 @@ class NativeFileSystemBrowserTest : public InProcessBrowserTest {
base::ScopedTempDir temp_dir_; base::ScopedTempDir temp_dir_;
}; };
#if defined(OS_CHROMEOS) IN_PROC_BROWSER_TEST_F(NativeFileSystemBrowserTest, SaveFile) {
// TODO(https://crbug.com/993597): Writing is currently broken on ChromeOS.
#define MAYBE_SaveFile DISABLED_SaveFile
#else
#define MAYBE_SaveFile SaveFile
#endif
IN_PROC_BROWSER_TEST_F(NativeFileSystemBrowserTest, MAYBE_SaveFile) {
const base::FilePath test_file = CreateTestFile(""); const base::FilePath test_file = CreateTestFile("");
const std::string file_contents = "file contents to write"; const std::string file_contents = "file contents to write";
...@@ -167,13 +161,7 @@ IN_PROC_BROWSER_TEST_F(NativeFileSystemBrowserTest, MAYBE_SaveFile) { ...@@ -167,13 +161,7 @@ IN_PROC_BROWSER_TEST_F(NativeFileSystemBrowserTest, MAYBE_SaveFile) {
} }
} }
#if defined(OS_CHROMEOS) IN_PROC_BROWSER_TEST_F(NativeFileSystemBrowserTest, OpenFile) {
// TODO(https://crbug.com/993597): Writing is currently broken on ChromeOS.
#define MAYBE_OpenFile DISABLED_OpenFile
#else
#define MAYBE_OpenFile OpenFile
#endif
IN_PROC_BROWSER_TEST_F(NativeFileSystemBrowserTest, MAYBE_OpenFile) {
const base::FilePath test_file = CreateTestFile(""); const base::FilePath test_file = CreateTestFile("");
const std::string file_contents = "file contents to write"; const std::string file_contents = "file contents to write";
......
...@@ -22,6 +22,7 @@ using blink::mojom::NativeFileSystemStatus; ...@@ -22,6 +22,7 @@ using blink::mojom::NativeFileSystemStatus;
using storage::BlobDataHandle; using storage::BlobDataHandle;
using storage::BlobImpl; using storage::BlobImpl;
using storage::FileSystemOperation; using storage::FileSystemOperation;
using storage::IsolatedContext;
namespace content { namespace content {
...@@ -157,15 +158,12 @@ void NativeFileSystemFileHandleImpl::CreateFileWriterImpl( ...@@ -157,15 +158,12 @@ void NativeFileSystemFileHandleImpl::CreateFileWriterImpl(
// already exists. Using the filesystem for synchronization, a successful // already exists. Using the filesystem for synchronization, a successful
// creation of the file ensures that this File Writer creation request owns // creation of the file ensures that this File Writer creation request owns
// the file and eliminates possible race conditions. // the file and eliminates possible race conditions.
auto base_swap_path =
base::FilePath(url().path()).AddExtensionASCII(".crswap");
CreateSwapFile( CreateSwapFile(
/*count=*/0, base_swap_path, keep_existing_data, std::move(callback)); /*count=*/0, keep_existing_data, std::move(callback));
} }
void NativeFileSystemFileHandleImpl::CreateSwapFile( void NativeFileSystemFileHandleImpl::CreateSwapFile(
int count, int count,
const base::FilePath& base_swap_path,
bool keep_existing_data, bool keep_existing_data,
CreateFileWriterCallback callback) { CreateFileWriterCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
...@@ -179,10 +177,14 @@ void NativeFileSystemFileHandleImpl::CreateSwapFile( ...@@ -179,10 +177,14 @@ void NativeFileSystemFileHandleImpl::CreateSwapFile(
return; return;
} }
auto swap_path =
base::FilePath(url().virtual_path()).AddExtensionASCII(".crswap");
auto swap_file_system = file_system();
if (count >= max_swap_files_) { if (count >= max_swap_files_) {
DLOG(ERROR) << "Error Creating Swap File, count: " << count DLOG(ERROR) << "Error Creating Swap File, count: " << count
<< " exceeds max unique files of: " << max_swap_files_ << " exceeds max unique files of: " << max_swap_files_
<< " base path: " << base_swap_path; << " base path: " << swap_path;
std::move(callback).Run(native_file_system_error::FromStatus( std::move(callback).Run(native_file_system_error::FromStatus(
NativeFileSystemStatus::kOperationFailed, NativeFileSystemStatus::kOperationFailed,
"Failed to create swap file."), "Failed to create swap file."),
...@@ -190,36 +192,56 @@ void NativeFileSystemFileHandleImpl::CreateSwapFile( ...@@ -190,36 +192,56 @@ void NativeFileSystemFileHandleImpl::CreateSwapFile(
return; return;
} }
auto swap_path = base_swap_path;
if (count > 0) { if (count > 0) {
swap_path = base_swap_path.InsertBeforeExtensionASCII( swap_path =
base::StringPrintf(".%d", count)); swap_path.InsertBeforeExtensionASCII(base::StringPrintf(".%d", count));
} }
// First attempt to just create the swap file in the same file system as this
// file.
storage::FileSystemURL swap_url = storage::FileSystemURL swap_url =
manager()->context()->CreateCrackedFileSystemURL(url().origin().GetURL(), manager()->context()->CreateCrackedFileSystemURL(
url().type(), swap_path); url().origin().GetURL(), url().mount_type(), swap_path);
// If that failed, it means this file was part of an isolated file system,
// and specifically, a single file isolated file system. In that case we'll
// need to register a new isolated file system for the swap file, and use that
// for the writer.
if (!swap_url.is_valid()) {
DCHECK_EQ(url().mount_type(), storage::kFileSystemTypeIsolated);
swap_path = base::FilePath(url().path()).AddExtensionASCII(".crswap");
if (count > 0) {
swap_path = swap_path.InsertBeforeExtensionASCII(
base::StringPrintf(".%d", count));
}
auto handle =
manager()->CreateFileSystemURLFromPath(context().origin, swap_path);
swap_url = std::move(handle.url);
swap_file_system = std::move(handle.file_system);
}
operation_runner()->CreateFile( operation_runner()->CreateFile(
swap_url, swap_url,
/*exclusive=*/true, /*exclusive=*/true,
base::BindOnce(&NativeFileSystemFileHandleImpl::DidCreateSwapFile, base::BindOnce(&NativeFileSystemFileHandleImpl::DidCreateSwapFile,
weak_factory_.GetWeakPtr(), count, base_swap_path, weak_factory_.GetWeakPtr(), count, swap_url,
swap_url, keep_existing_data, std::move(callback))); swap_file_system, keep_existing_data,
std::move(callback)));
} }
void NativeFileSystemFileHandleImpl::DidCreateSwapFile( void NativeFileSystemFileHandleImpl::DidCreateSwapFile(
int count, int count,
const base::FilePath& base_swap_path,
const storage::FileSystemURL& swap_url, const storage::FileSystemURL& swap_url,
storage::IsolatedContext::ScopedFSHandle swap_file_system,
bool keep_existing_data, bool keep_existing_data,
CreateFileWriterCallback callback, CreateFileWriterCallback callback,
base::File::Error result) { base::File::Error result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (result == base::File::FILE_ERROR_EXISTS) { if (result == base::File::FILE_ERROR_EXISTS) {
// Creation attempt failed. We need to find an unused filename. // Creation attempt failed. We need to find an unused filename.
CreateSwapFile(count + 1, base_swap_path, keep_existing_data, CreateSwapFile(count + 1, keep_existing_data, std::move(callback));
std::move(callback));
return; return;
} }
...@@ -234,9 +256,13 @@ void NativeFileSystemFileHandleImpl::DidCreateSwapFile( ...@@ -234,9 +256,13 @@ void NativeFileSystemFileHandleImpl::DidCreateSwapFile(
} }
if (!keep_existing_data) { if (!keep_existing_data) {
std::move(callback).Run(native_file_system_error::Ok(), std::move(callback).Run(
manager()->CreateFileWriter( native_file_system_error::Ok(),
context(), url(), swap_url, handle_state())); manager()->CreateFileWriter(
context(), url(), swap_url,
NativeFileSystemManagerImpl::SharedHandleState(
handle_state().read_grant, handle_state().write_grant,
swap_file_system)));
return; return;
} }
...@@ -246,12 +272,13 @@ void NativeFileSystemFileHandleImpl::DidCreateSwapFile( ...@@ -246,12 +272,13 @@ void NativeFileSystemFileHandleImpl::DidCreateSwapFile(
storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT, storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT,
storage::FileSystemOperation::CopyProgressCallback(), storage::FileSystemOperation::CopyProgressCallback(),
base::BindOnce(&NativeFileSystemFileHandleImpl::DidCopySwapFile, base::BindOnce(&NativeFileSystemFileHandleImpl::DidCopySwapFile,
weak_factory_.GetWeakPtr(), swap_url, weak_factory_.GetWeakPtr(), swap_url, swap_file_system,
std::move(callback))); std::move(callback)));
} }
void NativeFileSystemFileHandleImpl::DidCopySwapFile( void NativeFileSystemFileHandleImpl::DidCopySwapFile(
const storage::FileSystemURL& swap_url, const storage::FileSystemURL& swap_url,
storage::IsolatedContext::ScopedFSHandle swap_file_system,
CreateFileWriterCallback callback, CreateFileWriterCallback callback,
base::File::Error result) { base::File::Error result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
...@@ -266,7 +293,11 @@ void NativeFileSystemFileHandleImpl::DidCopySwapFile( ...@@ -266,7 +293,11 @@ void NativeFileSystemFileHandleImpl::DidCopySwapFile(
} }
std::move(callback).Run( std::move(callback).Run(
native_file_system_error::Ok(), native_file_system_error::Ok(),
manager()->CreateFileWriter(context(), url(), swap_url, handle_state())); manager()->CreateFileWriter(
context(), url(), swap_url,
NativeFileSystemManagerImpl::SharedHandleState(
handle_state().read_grant, handle_state().write_grant,
swap_file_system)));
} }
base::WeakPtr<NativeFileSystemHandleBase> base::WeakPtr<NativeFileSystemHandleBase>
......
...@@ -58,18 +58,23 @@ class CONTENT_EXPORT NativeFileSystemFileHandleImpl ...@@ -58,18 +58,23 @@ class CONTENT_EXPORT NativeFileSystemFileHandleImpl
void CreateFileWriterImpl(bool keep_existing_data, void CreateFileWriterImpl(bool keep_existing_data,
CreateFileWriterCallback callback); CreateFileWriterCallback callback);
void CreateSwapFile(int count, void CreateSwapFile(int count,
const base::FilePath& base_swap_path,
bool keep_existing_data, bool keep_existing_data,
CreateFileWriterCallback callback); CreateFileWriterCallback callback);
void DidCreateSwapFile(int count, // |swap_file_system| is set to the isolated file system the swap url was
const base::FilePath& base_swap_path, // created in (if any) as that file system might be different than the file
const storage::FileSystemURL& swap_url, // system |this| was created from.
bool keep_existing_data, void DidCreateSwapFile(
CreateFileWriterCallback callback, int count,
base::File::Error result); const storage::FileSystemURL& swap_url,
void DidCopySwapFile(const storage::FileSystemURL& swap_url, storage::IsolatedContext::ScopedFSHandle swap_file_system,
CreateFileWriterCallback callback, bool keep_existing_data,
base::File::Error result); CreateFileWriterCallback callback,
base::File::Error result);
void DidCopySwapFile(
const storage::FileSystemURL& swap_url,
storage::IsolatedContext::ScopedFSHandle swap_file_system,
CreateFileWriterCallback callback,
base::File::Error result);
// A FileWriter will write to a "swap" file until the `Close()` operation is // A FileWriter will write to a "swap" file until the `Close()` operation is
// called to swap the file into the target path. For each writer, a new swap // called to swap the file into the target path. For each writer, a new swap
......
...@@ -164,6 +164,8 @@ class CONTENT_EXPORT NativeFileSystemManagerImpl ...@@ -164,6 +164,8 @@ class CONTENT_EXPORT NativeFileSystemManagerImpl
} }
private: private:
friend class NativeFileSystemFileHandleImpl;
~NativeFileSystemManagerImpl() override; ~NativeFileSystemManagerImpl() override;
void DidOpenSandboxedFileSystem(const BindingContext& binding_context, void DidOpenSandboxedFileSystem(const BindingContext& binding_context,
GetSandboxedFileSystemCallback callback, GetSandboxedFileSystemCallback callback,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment