[Native File System] Improve error reporting.
Don't try to force every error into a base::File::Error, instead have our own
enum and a custom error message. This should make it easier for web developers
to debug what is going on.
Also switches some DOMException constructor usage to using V8ThrowDOMException
which results in the exception messages actually being shown in dev-tools.
Bug: 971268, 991544
Change-Id: Id5128363bf5410ed08c1f4e65ebbe4b4bee93d7a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1738654
Commit-Queue: Marijn Kruisselbrink <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: Victor Costan <[email protected]>
Cr-Commit-Position: refs/heads/master@{#688278}
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 24cd1b19..53597e4 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1243,6 +1243,8 @@
"native_file_system/fixed_native_file_system_permission_grant.h",
"native_file_system/native_file_system_directory_handle_impl.cc",
"native_file_system/native_file_system_directory_handle_impl.h",
+ "native_file_system/native_file_system_error.cc",
+ "native_file_system/native_file_system_error.h",
"native_file_system/native_file_system_file_handle_impl.cc",
"native_file_system/native_file_system_file_handle_impl.h",
"native_file_system/native_file_system_file_writer_impl.cc",
diff --git a/content/browser/native_file_system/file_system_chooser.cc b/content/browser/native_file_system/file_system_chooser.cc
index 55ca206..98687a1 100644
--- a/content/browser/native_file_system/file_system_chooser.cc
+++ b/content/browser/native_file_system/file_system_chooser.cc
@@ -10,6 +10,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "build/build_config.h"
+#include "content/browser/native_file_system/native_file_system_error.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/content_browser_client.h"
@@ -175,37 +176,38 @@
callback_runner->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback),
- blink::mojom::NativeFileSystemError::New(
- base::File::FILE_ERROR_FAILED),
+ native_file_system_error::FromStatus(
+ blink::mojom::NativeFileSystemStatus::
+ kOperationFailed,
+ "Failed to create file"),
std::vector<base::FilePath>()));
return;
}
}
callback_runner->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback),
- blink::mojom::NativeFileSystemError::New(
- base::File::FILE_OK),
- std::move(files)));
+ FROM_HERE, base::BindOnce(std::move(callback),
+ native_file_system_error::Ok(),
+ std::move(files)));
},
files, callback_runner_, std::move(callback_)));
delete this;
return;
}
callback_runner_->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback_),
- blink::mojom::NativeFileSystemError::New(
- base::File::FILE_OK),
- std::move(files)));
+ FROM_HERE,
+ base::BindOnce(std::move(callback_), native_file_system_error::Ok(),
+ std::move(files)));
delete this;
}
void FileSystemChooser::FileSelectionCanceled(void* params) {
callback_runner_->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback_),
- blink::mojom::NativeFileSystemError::New(
- base::File::FILE_ERROR_ABORT),
- std::vector<base::FilePath>()));
+ FROM_HERE,
+ base::BindOnce(
+ std::move(callback_),
+ native_file_system_error::FromStatus(
+ blink::mojom::NativeFileSystemStatus::kOperationAborted),
+ std::vector<base::FilePath>()));
delete this;
}
diff --git a/content/browser/native_file_system/file_system_chooser_browsertest.cc b/content/browser/native_file_system/file_system_chooser_browsertest.cc
index 33fa3eb..1fb9a64 100644
--- a/content/browser/native_file_system/file_system_chooser_browsertest.cc
+++ b/content/browser/native_file_system/file_system_chooser_browsertest.cc
@@ -85,7 +85,7 @@
ASSERT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
auto result = EvalJs(shell(), "self.chooseFileSystemEntries()");
- EXPECT_TRUE(result.error.find("AbortError") != std::string::npos)
+ EXPECT_TRUE(result.error.find("aborted") != std::string::npos)
<< result.error;
}
@@ -241,7 +241,7 @@
NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
auto result =
EvalJs(shell(), "self.chooseFileSystemEntries({type: 'openDirectory'})");
- EXPECT_TRUE(result.error.find("AbortError") != std::string::npos)
+ EXPECT_TRUE(result.error.find("aborted") != std::string::npos)
<< result.error;
}
@@ -257,7 +257,7 @@
" {description: 'foo', extensions: ['txt', 'Js']},"
" {mimeTypes: ['image/jpeg']}"
"]})");
- EXPECT_TRUE(result.error.find("AbortError") != std::string::npos)
+ EXPECT_TRUE(result.error.find("aborted") != std::string::npos)
<< result.error;
ASSERT_TRUE(dialog_params.file_types);
diff --git a/content/browser/native_file_system/native_file_system_directory_handle_impl.cc b/content/browser/native_file_system/native_file_system_directory_handle_impl.cc
index 4967789..1e1ef73c 100644
--- a/content/browser/native_file_system/native_file_system_directory_handle_impl.cc
+++ b/content/browser/native_file_system/native_file_system_directory_handle_impl.cc
@@ -8,6 +8,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
+#include "content/browser/native_file_system/native_file_system_error.h"
#include "content/browser/native_file_system/native_file_system_transfer_token_impl.h"
#include "net/base/escape.h"
#include "storage/browser/fileapi/file_system_context.h"
@@ -19,8 +20,8 @@
using blink::mojom::NativeFileSystemEntry;
using blink::mojom::NativeFileSystemEntryPtr;
-using blink::mojom::NativeFileSystemError;
using blink::mojom::NativeFileSystemHandle;
+using blink::mojom::NativeFileSystemStatus;
using blink::mojom::NativeFileSystemTransferTokenPtr;
using blink::mojom::NativeFileSystemTransferTokenRequest;
@@ -84,16 +85,17 @@
DCHECK_CURRENTLY_ON(BrowserThread::IO);
storage::FileSystemURL child_url;
- const base::File::Error file_error = GetChildURL(basename, &child_url);
- if (file_error != base::File::FILE_OK) {
- std::move(callback).Run(NativeFileSystemError::New(file_error), nullptr);
+ blink::mojom::NativeFileSystemErrorPtr get_child_url_result =
+ GetChildURL(basename, &child_url);
+ if (get_child_url_result->status != NativeFileSystemStatus::kOk) {
+ std::move(callback).Run(std::move(get_child_url_result), nullptr);
return;
}
if (GetReadPermissionStatus() != PermissionStatus::GRANTED) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
- nullptr);
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied),
+ nullptr);
return;
}
@@ -107,7 +109,8 @@
weak_factory_.GetWeakPtr(), child_url),
base::BindOnce([](GetFileCallback callback) {
std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
+ native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied),
nullptr);
}),
std::move(callback));
@@ -127,16 +130,17 @@
DCHECK_CURRENTLY_ON(BrowserThread::IO);
storage::FileSystemURL child_url;
- const base::File::Error file_error = GetChildURL(basename, &child_url);
- if (file_error != base::File::FILE_OK) {
- std::move(callback).Run(NativeFileSystemError::New(file_error), nullptr);
+ blink::mojom::NativeFileSystemErrorPtr get_child_url_result =
+ GetChildURL(basename, &child_url);
+ if (get_child_url_result->status != NativeFileSystemStatus::kOk) {
+ std::move(callback).Run(std::move(get_child_url_result), nullptr);
return;
}
if (GetReadPermissionStatus() != PermissionStatus::GRANTED) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
- nullptr);
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied),
+ nullptr);
return;
}
@@ -150,7 +154,8 @@
weak_factory_.GetWeakPtr(), child_url),
base::BindOnce([](GetDirectoryCallback callback) {
std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
+ native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied),
nullptr);
}),
std::move(callback));
@@ -181,9 +186,10 @@
DCHECK_CURRENTLY_ON(BrowserThread::IO);
storage::FileSystemURL child_url;
- const base::File::Error file_error = GetChildURL(basename, &child_url);
- if (file_error != base::File::FILE_OK) {
- std::move(callback).Run(NativeFileSystemError::New(file_error));
+ blink::mojom::NativeFileSystemErrorPtr get_child_url_result =
+ GetChildURL(basename, &child_url);
+ if (get_child_url_result->status != NativeFileSystemStatus::kOk) {
+ std::move(callback).Run(std::move(get_child_url_result));
return;
}
@@ -191,8 +197,8 @@
base::BindOnce(&NativeFileSystemDirectoryHandleImpl::RemoveEntryImpl,
weak_factory_.GetWeakPtr(), child_url, recurse),
base::BindOnce([](RemoveEntryCallback callback) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED));
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied));
}),
std::move(callback));
}
@@ -225,12 +231,13 @@
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (result != base::File::FILE_OK) {
- std::move(callback).Run(NativeFileSystemError::New(result), nullptr);
+ std::move(callback).Run(native_file_system_error::FromFileError(result),
+ nullptr);
return;
}
std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_OK),
+ native_file_system_error::Ok(),
manager()->CreateFileHandle(context(), url, handle_state()));
}
@@ -255,12 +262,13 @@
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (result != base::File::FILE_OK) {
- std::move(callback).Run(NativeFileSystemError::New(result), nullptr);
+ std::move(callback).Run(native_file_system_error::FromFileError(result),
+ nullptr);
return;
}
std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_OK),
+ native_file_system_error::Ok(),
manager()->CreateDirectoryHandle(context(), url, handle_state()));
}
@@ -273,7 +281,8 @@
if (result != base::File::FILE_OK) {
DCHECK(!has_more);
- std::move(state->callback).Run(NativeFileSystemError::New(result), {});
+ std::move(state->callback)
+ .Run(native_file_system_error::FromFileError(result), {});
return;
}
@@ -281,11 +290,12 @@
std::string basename = storage::FilePathToString(entry.name);
storage::FileSystemURL child_url;
- const base::File::Error file_error = GetChildURL(basename, &child_url);
+ blink::mojom::NativeFileSystemErrorPtr get_child_url_result =
+ GetChildURL(basename, &child_url);
// All entries must exist in this directory as a direct child with a valid
// |basename|.
- CHECK_EQ(file_error, base::File::FILE_OK);
+ CHECK_EQ(get_child_url_result->status, NativeFileSystemStatus::kOk);
state->entries.push_back(
CreateEntry(basename, child_url,
@@ -296,8 +306,7 @@
// than waiting till we have retrieved them all.
if (!has_more) {
std::move(state->callback)
- .Run(NativeFileSystemError::New(base::File::FILE_OK),
- std::move(state->entries));
+ .Run(native_file_system_error::Ok(), std::move(state->entries));
}
}
@@ -313,25 +322,31 @@
url, recurse,
base::BindOnce(
[](RemoveEntryCallback callback, base::File::Error result) {
- std::move(callback).Run(NativeFileSystemError::New(result));
+ std::move(callback).Run(
+ native_file_system_error::FromFileError(result));
},
std::move(callback)));
}
-base::File::Error NativeFileSystemDirectoryHandleImpl::GetChildURL(
+blink::mojom::NativeFileSystemErrorPtr
+NativeFileSystemDirectoryHandleImpl::GetChildURL(
const std::string& basename,
storage::FileSystemURL* result) {
// TODO(mek): Rather than doing URL serialization and parsing we should just
// have a way to get a child FileSystemURL directly from its parent.
if (basename.empty()) {
- return base::File::FILE_ERROR_NOT_FOUND;
+ return native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kInvalidArgument,
+ "Name can't be an empty string.");
}
if (ContainsPathSeparator(basename) || IsCurrentOrParentDirectory(basename)) {
// |basename| must refer to a entry that exists in this directory as a
// direct child.
- return base::File::FILE_ERROR_SECURITY;
+ return native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kInvalidArgument,
+ "Name contains invalid characters.");
}
std::string escaped_name =
@@ -344,7 +359,7 @@
GURL child_url = parent_url.ReplaceComponents(replacements);
*result = file_system_context()->CrackURL(child_url);
- return base::File::FILE_OK;
+ return native_file_system_error::Ok();
}
NativeFileSystemEntryPtr NativeFileSystemDirectoryHandleImpl::CreateEntry(
diff --git a/content/browser/native_file_system/native_file_system_directory_handle_impl.h b/content/browser/native_file_system/native_file_system_directory_handle_impl.h
index 20ea065d..e1e0885 100644
--- a/content/browser/native_file_system/native_file_system_directory_handle_impl.h
+++ b/content/browser/native_file_system/native_file_system_directory_handle_impl.h
@@ -80,9 +80,9 @@
// Calculates a FileSystemURL for a (direct) child of this directory with the
// given basename. Returns an error when |basename| includes invalid input
// like "/".
- base::File::Error GetChildURL(const std::string& basename,
- storage::FileSystemURL* result)
- WARN_UNUSED_RESULT;
+ blink::mojom::NativeFileSystemErrorPtr GetChildURL(
+ const std::string& basename,
+ storage::FileSystemURL* result) WARN_UNUSED_RESULT;
// Helper to create a blink::mojom::NativeFileSystemEntry struct.
blink::mojom::NativeFileSystemEntryPtr CreateEntry(
diff --git a/content/browser/native_file_system/native_file_system_error.cc b/content/browser/native_file_system/native_file_system_error.cc
new file mode 100644
index 0000000..59247c6
--- /dev/null
+++ b/content/browser/native_file_system/native_file_system_error.cc
@@ -0,0 +1,36 @@
+// Copyright 2019 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 "content/browser/native_file_system/native_file_system_error.h"
+
+namespace content {
+
+using blink::mojom::NativeFileSystemError;
+using blink::mojom::NativeFileSystemErrorPtr;
+using blink::mojom::NativeFileSystemStatus;
+
+namespace native_file_system_error {
+
+NativeFileSystemErrorPtr Ok() {
+ return NativeFileSystemError::New(NativeFileSystemStatus::kOk,
+ base::File::FILE_OK, "");
+}
+
+NativeFileSystemErrorPtr FromFileError(base::File::Error result,
+ base::StringPiece message) {
+ if (result == base::File::FILE_OK)
+ return Ok();
+ return NativeFileSystemError::New(NativeFileSystemStatus::kFileError, result,
+ std::string(message));
+}
+
+blink::mojom::NativeFileSystemErrorPtr FromStatus(
+ blink::mojom::NativeFileSystemStatus status,
+ base::StringPiece message) {
+ return NativeFileSystemError::New(status, base::File::FILE_OK,
+ std::string(message));
+}
+
+} // namespace native_file_system_error
+} // namespace content
diff --git a/content/browser/native_file_system/native_file_system_error.h b/content/browser/native_file_system/native_file_system_error.h
new file mode 100644
index 0000000..e578c130
--- /dev/null
+++ b/content/browser/native_file_system/native_file_system_error.h
@@ -0,0 +1,36 @@
+// Copyright 2019 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.
+
+#ifndef CONTENT_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_ERROR_H_
+#define CONTENT_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_ERROR_H_
+
+#include <string>
+
+#include "base/files/file.h"
+#include "base/strings/string_piece.h"
+#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom.h"
+
+namespace content {
+namespace native_file_system_error {
+
+// Returns a NativeFileSystemError representing a successful result of an
+// operation.
+blink::mojom::NativeFileSystemErrorPtr Ok();
+
+// Wraps a base::File::Error in a NativeFileSystemError, optionally with a
+// custom error message.
+blink::mojom::NativeFileSystemErrorPtr FromFileError(
+ base::File::Error result,
+ base::StringPiece message = "");
+
+// Wraps a NativeFileSystemStatus in a NativeFileSystemError, optionally with a
+// custom error message.
+blink::mojom::NativeFileSystemErrorPtr FromStatus(
+ blink::mojom::NativeFileSystemStatus status,
+ base::StringPiece message = "");
+
+} // namespace native_file_system_error
+} // namespace content
+
+#endif // CONTENT_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_ERROR_H_
diff --git a/content/browser/native_file_system/native_file_system_file_handle_impl.cc b/content/browser/native_file_system/native_file_system_file_handle_impl.cc
index 8d71b72..9d7b5dc 100644
--- a/content/browser/native_file_system/native_file_system_file_handle_impl.cc
+++ b/content/browser/native_file_system/native_file_system_file_handle_impl.cc
@@ -7,6 +7,7 @@
#include "base/guid.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
+#include "content/browser/native_file_system/native_file_system_error.h"
#include "net/base/mime_util.h"
#include "storage/browser/blob/blob_data_builder.h"
#include "storage/browser/blob/blob_impl.h"
@@ -17,7 +18,7 @@
#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom.h"
#include "third_party/blink/public/mojom/native_file_system/native_file_system_transfer_token.mojom.h"
-using blink::mojom::NativeFileSystemError;
+using blink::mojom::NativeFileSystemStatus;
using storage::BlobDataHandle;
using storage::BlobImpl;
using storage::FileSystemOperation;
@@ -52,9 +53,9 @@
void NativeFileSystemFileHandleImpl::AsBlob(AsBlobCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (GetReadPermissionStatus() != PermissionStatus::GRANTED) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
- nullptr);
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied),
+ nullptr);
return;
}
@@ -78,9 +79,9 @@
base::BindOnce(&NativeFileSystemFileHandleImpl::CreateFileWriterImpl,
weak_factory_.GetWeakPtr(), keep_existing_data),
base::BindOnce([](CreateFileWriterCallback callback) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
- nullptr);
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied),
+ nullptr);
}),
std::move(callback));
}
@@ -99,7 +100,8 @@
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (result != base::File::FILE_OK) {
- std::move(callback).Run(NativeFileSystemError::New(result), nullptr);
+ std::move(callback).Run(native_file_system_error::FromFileError(result),
+ nullptr);
return;
}
@@ -126,7 +128,9 @@
blob_context()->AddFinishedBlob(std::move(blob_builder));
if (blob_handle->IsBroken()) {
std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_FAILED), nullptr);
+ native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kOperationFailed, "Failed to create blob."),
+ nullptr);
return;
}
@@ -135,7 +139,7 @@
BlobImpl::Create(std::move(blob_handle), mojo::MakeRequest(&blob_ptr));
std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_OK),
+ native_file_system_error::Ok(),
blink::mojom::SerializedBlob::New(uuid, content_type, info.size,
blob_ptr.PassInterface()));
}
@@ -169,9 +173,9 @@
DCHECK(max_swap_files_ >= 0);
if (GetWritePermissionStatus() != blink::mojom::PermissionStatus::GRANTED) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
- nullptr);
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied),
+ nullptr);
return;
}
@@ -179,8 +183,10 @@
DLOG(ERROR) << "Error Creating Swap File, count: " << count
<< " exceeds max unique files of: " << max_swap_files_
<< " base path: " << base_swap_path;
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_MAX), nullptr);
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kOperationFailed,
+ "Failed to create swap file."),
+ nullptr);
return;
}
@@ -221,12 +227,14 @@
DLOG(ERROR) << "Error Creating Swap File, status: "
<< base::File::ErrorToString(result)
<< " path: " << swap_url.path();
- std::move(callback).Run(NativeFileSystemError::New(result), nullptr);
+ std::move(callback).Run(native_file_system_error::FromFileError(
+ result, "Error creating swap file."),
+ nullptr);
return;
}
if (!keep_existing_data) {
- std::move(callback).Run(NativeFileSystemError::New(base::File::FILE_OK),
+ std::move(callback).Run(native_file_system_error::Ok(),
manager()->CreateFileWriter(
context(), url(), swap_url, handle_state()));
return;
@@ -251,11 +259,13 @@
DLOG(ERROR) << "Error Creating Swap File, status: "
<< base::File::ErrorToString(result)
<< " path: " << swap_url.path();
- std::move(callback).Run(NativeFileSystemError::New(result), nullptr);
+ std::move(callback).Run(native_file_system_error::FromFileError(
+ result, "Error copying to swap file."),
+ nullptr);
return;
}
std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_OK),
+ native_file_system_error::Ok(),
manager()->CreateFileWriter(context(), url(), swap_url, handle_state()));
}
diff --git a/content/browser/native_file_system/native_file_system_file_handle_impl_unittest.cc b/content/browser/native_file_system/native_file_system_file_handle_impl_unittest.cc
index be51d67..50ed230 100644
--- a/content/browser/native_file_system/native_file_system_file_handle_impl_unittest.cc
+++ b/content/browser/native_file_system/native_file_system_file_handle_impl_unittest.cc
@@ -138,7 +138,8 @@
base::BindLambdaForTesting(
[&](blink::mojom::NativeFileSystemErrorPtr result,
blink::mojom::NativeFileSystemFileWriterPtr writer_ptr) {
- EXPECT_EQ(base::File::FILE_OK, result->error_code);
+ EXPECT_EQ(blink::mojom::NativeFileSystemStatus::kOk,
+ result->status);
EXPECT_EQ("", ReadFile(swap_url));
writers.push_back(std::move(writer_ptr));
loop.Quit();
@@ -152,7 +153,8 @@
base::BindLambdaForTesting(
[&](blink::mojom::NativeFileSystemErrorPtr result,
blink::mojom::NativeFileSystemFileWriterPtr writer_ptr) {
- EXPECT_EQ(base::File::FILE_ERROR_MAX, result->error_code);
+ EXPECT_EQ(blink::mojom::NativeFileSystemStatus::kOperationFailed,
+ result->status);
loop.Quit();
}));
loop.Run();
diff --git a/content/browser/native_file_system/native_file_system_file_writer_impl.cc b/content/browser/native_file_system/native_file_system_file_writer_impl.cc
index 50218af6..d77a79a 100644
--- a/content/browser/native_file_system/native_file_system_file_writer_impl.cc
+++ b/content/browser/native_file_system/native_file_system_file_writer_impl.cc
@@ -4,13 +4,14 @@
#include "content/browser/native_file_system/native_file_system_file_writer_impl.h"
#include "base/logging.h"
+#include "content/browser/native_file_system/native_file_system_error.h"
#include "content/browser/native_file_system/native_file_system_manager_impl.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/fileapi/file_system_operation_runner.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom.h"
-using blink::mojom::NativeFileSystemError;
+using blink::mojom::NativeFileSystemStatus;
using storage::BlobDataHandle;
using storage::FileSystemOperation;
@@ -59,9 +60,9 @@
base::BindOnce(&NativeFileSystemFileWriterImpl::WriteImpl,
weak_factory_.GetWeakPtr(), offset, std::move(data)),
base::BindOnce([](WriteCallback callback) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
- /*bytes_written=*/0);
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied),
+ /*bytes_written=*/0);
}),
std::move(callback));
}
@@ -76,9 +77,9 @@
base::BindOnce(&NativeFileSystemFileWriterImpl::WriteStreamImpl,
weak_factory_.GetWeakPtr(), offset, std::move(stream)),
base::BindOnce([](WriteStreamCallback callback) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
- /*bytes_written=*/0);
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied),
+ /*bytes_written=*/0);
}),
std::move(callback));
}
@@ -91,8 +92,8 @@
base::BindOnce(&NativeFileSystemFileWriterImpl::TruncateImpl,
weak_factory_.GetWeakPtr(), length),
base::BindOnce([](TruncateCallback callback) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED));
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied));
}),
std::move(callback));
}
@@ -104,8 +105,8 @@
base::BindOnce(&NativeFileSystemFileWriterImpl::CloseImpl,
weak_factory_.GetWeakPtr()),
base::BindOnce([](CloseCallback callback) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED));
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied));
}),
std::move(callback));
}
@@ -119,7 +120,9 @@
if (is_closed()) {
std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_INVALID_OPERATION),
+ native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kInvalidState,
+ "An attempt was made to write to a closed writer."),
/*bytes_written=*/0);
return;
}
@@ -138,7 +141,8 @@
if (!blob) {
std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_FAILED),
+ native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kInvalidArgument, "Blob does not exist"),
/*bytes_written=*/0);
return;
}
@@ -160,7 +164,9 @@
if (is_closed()) {
std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_INVALID_OPERATION),
+ native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kInvalidState,
+ "An attempt was made to write to a closed writer."),
/*bytes_written=*/0);
return;
}
@@ -182,7 +188,8 @@
state->bytes_written += bytes;
if (complete) {
std::move(state->callback)
- .Run(NativeFileSystemError::New(result), state->bytes_written);
+ .Run(native_file_system_error::FromFileError(result),
+ state->bytes_written);
}
}
@@ -193,8 +200,9 @@
blink::mojom::PermissionStatus::GRANTED);
if (is_closed()) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_INVALID_OPERATION));
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kInvalidState,
+ "An attempt was made to write to a closed writer."));
return;
}
@@ -202,7 +210,8 @@
swap_url(), length,
base::BindOnce(
[](TruncateCallback callback, base::File::Error result) {
- std::move(callback).Run(NativeFileSystemError::New(result));
+ std::move(callback).Run(
+ native_file_system_error::FromFileError(result));
},
std::move(callback)));
}
@@ -212,8 +221,9 @@
DCHECK_EQ(GetWritePermissionStatus(),
blink::mojom::PermissionStatus::GRANTED);
if (is_closed()) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_INVALID_OPERATION));
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kInvalidState,
+ "An attempt was made to close an already closed writer."));
return;
}
@@ -245,7 +255,7 @@
state_ = State::kClosed;
}
- std::move(callback).Run(NativeFileSystemError::New(result));
+ std::move(callback).Run(native_file_system_error::FromFileError(result));
}
base::WeakPtr<NativeFileSystemHandleBase>
diff --git a/content/browser/native_file_system/native_file_system_file_writer_impl_unittest.cc b/content/browser/native_file_system/native_file_system_file_writer_impl_unittest.cc
index 2a96d80..70033dd 100644
--- a/content/browser/native_file_system/native_file_system_file_writer_impl_unittest.cc
+++ b/content/browser/native_file_system/native_file_system_file_writer_impl_unittest.cc
@@ -28,6 +28,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
+using blink::mojom::NativeFileSystemStatus;
using storage::FileSystemURL;
namespace content {
@@ -135,16 +136,16 @@
}
}
- base::File::Error WriteBlobSync(uint64_t position,
- blink::mojom::BlobPtr blob,
- uint64_t* bytes_written_out) {
+ NativeFileSystemStatus WriteBlobSync(uint64_t position,
+ blink::mojom::BlobPtr blob,
+ uint64_t* bytes_written_out) {
base::RunLoop loop;
- base::File::Error result_out;
+ NativeFileSystemStatus result_out;
handle_->Write(position, std::move(blob),
base::BindLambdaForTesting(
[&](blink::mojom::NativeFileSystemErrorPtr result,
uint64_t bytes_written) {
- result_out = result->error_code;
+ result_out = result->status;
*bytes_written_out = bytes_written;
loop.Quit();
}));
@@ -152,17 +153,17 @@
return result_out;
}
- base::File::Error WriteStreamSync(
+ NativeFileSystemStatus WriteStreamSync(
uint64_t position,
mojo::ScopedDataPipeConsumerHandle data_pipe,
uint64_t* bytes_written_out) {
base::RunLoop loop;
- base::File::Error result_out;
+ NativeFileSystemStatus result_out;
handle_->WriteStream(position, std::move(data_pipe),
base::BindLambdaForTesting(
[&](blink::mojom::NativeFileSystemErrorPtr result,
uint64_t bytes_written) {
- result_out = result->error_code;
+ result_out = result->status;
*bytes_written_out = bytes_written;
loop.Quit();
}));
@@ -170,25 +171,25 @@
return result_out;
}
- base::File::Error TruncateSync(uint64_t length) {
+ NativeFileSystemStatus TruncateSync(uint64_t length) {
base::RunLoop loop;
- base::File::Error result_out;
+ NativeFileSystemStatus result_out;
handle_->Truncate(length,
base::BindLambdaForTesting(
[&](blink::mojom::NativeFileSystemErrorPtr result) {
- result_out = result->error_code;
+ result_out = result->status;
loop.Quit();
}));
loop.Run();
return result_out;
}
- base::File::Error CloseSync() {
+ NativeFileSystemStatus CloseSync() {
base::RunLoop loop;
- base::File::Error result_out;
+ NativeFileSystemStatus result_out;
handle_->Close(base::BindLambdaForTesting(
[&](blink::mojom::NativeFileSystemErrorPtr result) {
- result_out = result->error_code;
+ result_out = result->status;
loop.Quit();
}));
loop.Run();
@@ -197,9 +198,9 @@
virtual bool WriteUsingBlobs() { return true; }
- base::File::Error WriteSync(uint64_t position,
- const std::string& contents,
- uint64_t* bytes_written_out) {
+ NativeFileSystemStatus WriteSync(uint64_t position,
+ const std::string& contents,
+ uint64_t* bytes_written_out) {
if (WriteUsingBlobs())
return WriteBlobSync(position, CreateBlob(contents), bytes_written_out);
return WriteStreamSync(position, CreateStream(contents), bytes_written_out);
@@ -242,24 +243,25 @@
MakeRequest(&blob);
uint64_t bytes_written;
- base::File::Error result = WriteBlobSync(0, std::move(blob), &bytes_written);
- EXPECT_EQ(result, base::File::FILE_ERROR_FAILED);
+ NativeFileSystemStatus result =
+ WriteBlobSync(0, std::move(blob), &bytes_written);
+ EXPECT_EQ(result, NativeFileSystemStatus::kInvalidArgument);
EXPECT_EQ(bytes_written, 0u);
result = CloseSync();
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ("", ReadFile(test_file_url_));
}
TEST_P(NativeFileSystemFileWriterImplWriteTest, WriteValidEmptyString) {
uint64_t bytes_written;
- base::File::Error result = WriteSync(0, "", &bytes_written);
- EXPECT_EQ(result, base::File::FILE_OK);
+ NativeFileSystemStatus result = WriteSync(0, "", &bytes_written);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ(bytes_written, 0u);
result = CloseSync();
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ("", ReadFile(test_file_url_));
}
@@ -267,116 +269,116 @@
TEST_P(NativeFileSystemFileWriterImplWriteTest, WriteValidNonEmpty) {
std::string test_data("abcdefghijklmnopqrstuvwxyz");
uint64_t bytes_written;
- base::File::Error result = WriteSync(0, test_data, &bytes_written);
- EXPECT_EQ(result, base::File::FILE_OK);
+ NativeFileSystemStatus result = WriteSync(0, test_data, &bytes_written);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ(bytes_written, test_data.size());
result = CloseSync();
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ(test_data, ReadFile(test_file_url_));
}
TEST_P(NativeFileSystemFileWriterImplWriteTest, WriteWithOffsetInFile) {
uint64_t bytes_written;
- base::File::Error result;
+ NativeFileSystemStatus result;
result = WriteSync(0, "1234567890", &bytes_written);
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ(bytes_written, 10u);
result = WriteSync(4, "abc", &bytes_written);
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ(bytes_written, 3u);
result = CloseSync();
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ("1234abc890", ReadFile(test_file_url_));
}
TEST_P(NativeFileSystemFileWriterImplWriteTest, WriteWithOffsetPastFile) {
uint64_t bytes_written;
- base::File::Error result = WriteSync(4, "abc", &bytes_written);
- EXPECT_EQ(result, base::File::FILE_ERROR_FAILED);
+ NativeFileSystemStatus result = WriteSync(4, "abc", &bytes_written);
+ EXPECT_EQ(result, NativeFileSystemStatus::kFileError);
EXPECT_EQ(bytes_written, 0u);
result = CloseSync();
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ("", ReadFile(test_file_url_));
}
TEST_F(NativeFileSystemFileWriterImplTest, TruncateShrink) {
uint64_t bytes_written;
- base::File::Error result;
+ NativeFileSystemStatus result;
result = WriteSync(0, "1234567890", &bytes_written);
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ(bytes_written, 10u);
result = TruncateSync(5);
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
result = CloseSync();
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ("12345", ReadFile(test_file_url_));
}
TEST_F(NativeFileSystemFileWriterImplTest, TruncateGrow) {
uint64_t bytes_written;
- base::File::Error result;
+ NativeFileSystemStatus result;
result = WriteSync(0, "abc", &bytes_written);
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ(bytes_written, 3u);
result = TruncateSync(5);
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
result = CloseSync();
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ(std::string("abc\0\0", 5), ReadFile(test_file_url_));
}
TEST_F(NativeFileSystemFileWriterImplTest, CloseAfterCloseNotOK) {
uint64_t bytes_written;
- base::File::Error result = WriteSync(0, "abc", &bytes_written);
- EXPECT_EQ(result, base::File::FILE_OK);
+ NativeFileSystemStatus result = WriteSync(0, "abc", &bytes_written);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ(bytes_written, 3u);
result = CloseSync();
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
result = CloseSync();
- EXPECT_EQ(result, base::File::FILE_ERROR_INVALID_OPERATION);
+ EXPECT_EQ(result, NativeFileSystemStatus::kInvalidState);
}
TEST_F(NativeFileSystemFileWriterImplTest, TruncateAfterCloseNotOK) {
uint64_t bytes_written;
- base::File::Error result = WriteSync(0, "abc", &bytes_written);
- EXPECT_EQ(result, base::File::FILE_OK);
+ NativeFileSystemStatus result = WriteSync(0, "abc", &bytes_written);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ(bytes_written, 3u);
result = CloseSync();
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
result = TruncateSync(0);
- EXPECT_EQ(result, base::File::FILE_ERROR_INVALID_OPERATION);
+ EXPECT_EQ(result, NativeFileSystemStatus::kInvalidState);
}
TEST_P(NativeFileSystemFileWriterImplWriteTest, WriteAfterCloseNotOK) {
uint64_t bytes_written;
- base::File::Error result = WriteSync(0, "abc", &bytes_written);
- EXPECT_EQ(result, base::File::FILE_OK);
+ NativeFileSystemStatus result = WriteSync(0, "abc", &bytes_written);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
EXPECT_EQ(bytes_written, 3u);
result = CloseSync();
- EXPECT_EQ(result, base::File::FILE_OK);
+ EXPECT_EQ(result, NativeFileSystemStatus::kOk);
result = WriteSync(0, "bcd", &bytes_written);
- EXPECT_EQ(result, base::File::FILE_ERROR_INVALID_OPERATION);
+ EXPECT_EQ(result, NativeFileSystemStatus::kInvalidState);
}
// TODO(mek): More tests, particularly for error conditions.
diff --git a/content/browser/native_file_system/native_file_system_manager_impl.cc b/content/browser/native_file_system/native_file_system_manager_impl.cc
index b98b802..f4ad0b7 100644
--- a/content/browser/native_file_system/native_file_system_manager_impl.cc
+++ b/content/browser/native_file_system/native_file_system_manager_impl.cc
@@ -10,6 +10,7 @@
#include "content/browser/native_file_system/file_system_chooser.h"
#include "content/browser/native_file_system/fixed_native_file_system_permission_grant.h"
#include "content/browser/native_file_system/native_file_system_directory_handle_impl.h"
+#include "content/browser/native_file_system/native_file_system_error.h"
#include "content/browser/native_file_system/native_file_system_file_handle_impl.h"
#include "content/browser/native_file_system/native_file_system_file_writer_impl.h"
#include "content/browser/native_file_system/native_file_system_transfer_token_impl.h"
@@ -31,7 +32,7 @@
namespace content {
-using blink::mojom::NativeFileSystemError;
+using blink::mojom::NativeFileSystemStatus;
using PermissionStatus = NativeFileSystemPermissionGrant::PermissionStatus;
using SensitiveDirectoryResult =
NativeFileSystemPermissionContext::SensitiveDirectoryResult;
@@ -50,10 +51,11 @@
if (!web_contents) {
callback_runner->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback),
- blink::mojom::NativeFileSystemError::New(
- base::File::FILE_ERROR_ABORT),
- std::vector<base::FilePath>()));
+ FROM_HERE,
+ base::BindOnce(std::move(callback),
+ native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kOperationAborted),
+ std::vector<base::FilePath>()));
return;
}
@@ -62,10 +64,13 @@
if (embedding_origin != requesting_origin) {
// Third party iframes are not allowed to show a file picker.
callback_runner->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback),
- blink::mojom::NativeFileSystemError::New(
- base::File::FILE_ERROR_ACCESS_DENIED),
- std::vector<base::FilePath>()));
+ FROM_HERE,
+ base::BindOnce(
+ std::move(callback),
+ native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied,
+ "Third party iframes are not allowed to show a file picker."),
+ std::vector<base::FilePath>()));
return;
}
@@ -75,10 +80,13 @@
// to expire between the renderer side check and this check.
if (!rfh->HasTransientUserActivation()) {
callback_runner->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback),
- blink::mojom::NativeFileSystemError::New(
- base::File::FILE_ERROR_ACCESS_DENIED),
- std::vector<base::FilePath>()));
+ FROM_HERE,
+ base::BindOnce(
+ std::move(callback),
+ native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kPermissionDenied,
+ "User activation is required to show a file picker."),
+ std::vector<base::FilePath>()));
return;
}
@@ -347,7 +355,8 @@
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (result != base::File::FILE_OK) {
- std::move(callback).Run(NativeFileSystemError::New(result), nullptr);
+ std::move(callback).Run(native_file_system_error::FromFileError(result),
+ nullptr);
return;
}
@@ -356,7 +365,7 @@
PermissionStatus::GRANTED);
std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_OK),
+ native_file_system_error::Ok(),
CreateDirectoryHandle(
binding_context, context()->CrackURL(root),
SharedHandleState(permission_grant, permission_grant,
@@ -369,7 +378,7 @@
ChooseEntriesCallback callback,
blink::mojom::NativeFileSystemErrorPtr result,
std::vector<base::FilePath> entries) {
- if (result->error_code != base::File::FILE_OK) {
+ if (result->status != NativeFileSystemStatus::kOk) {
std::move(callback).Run(
std::move(result),
std::vector<blink::mojom::NativeFileSystemEntryPtr>());
@@ -400,7 +409,8 @@
SensitiveDirectoryResult result) {
if (result == SensitiveDirectoryResult::kAbort) {
std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ABORT),
+ native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kOperationAborted),
std::vector<blink::mojom::NativeFileSystemEntryPtr>());
return;
}
@@ -445,7 +455,7 @@
}
}
- std::move(callback).Run(NativeFileSystemError::New(base::File::FILE_OK),
+ std::move(callback).Run(native_file_system_error::Ok(),
std::move(result_entries));
}
@@ -456,14 +466,14 @@
NativeFileSystemPermissionContext::PermissionStatus permission) {
std::vector<blink::mojom::NativeFileSystemEntryPtr> result_entries;
if (permission != PermissionStatus::GRANTED) {
- std::move(callback).Run(
- NativeFileSystemError::New(base::File::FILE_ERROR_ABORT),
- std::move(result_entries));
+ std::move(callback).Run(native_file_system_error::FromStatus(
+ NativeFileSystemStatus::kOperationAborted),
+ std::move(result_entries));
return;
}
result_entries.push_back(CreateDirectoryEntryFromPath(binding_context, path));
- std::move(callback).Run(NativeFileSystemError::New(base::File::FILE_OK),
+ std::move(callback).Run(native_file_system_error::Ok(),
std::move(result_entries));
}
diff --git a/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc b/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc
index 1a4a244..d252959 100644
--- a/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc
+++ b/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc
@@ -95,7 +95,7 @@
manager_ptr_->GetSandboxedFileSystem(base::BindLambdaForTesting(
[&](blink::mojom::NativeFileSystemErrorPtr result,
blink::mojom::NativeFileSystemDirectoryHandlePtr handle) {
- EXPECT_EQ(base::File::FILE_OK, result->error_code);
+ EXPECT_EQ(blink::mojom::NativeFileSystemStatus::kOk, result->status);
root = std::move(handle);
loop.Quit();
}));