#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "extensions/browser/api/file_system/file_system_api.h"
#include <stddef.h>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/i18n/time_formatting.h"
#include "base/json/values_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/filename_generation/filename_generation.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
#include "extensions/browser/api/file_system/consent_provider.h"
#include "extensions/browser/api/file_system/file_system_delegate.h"
#include "extensions/browser/api/file_system/saved_file_entry.h"
#include "extensions/browser/api/file_system/saved_files_service_interface.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_util.h"
#include "extensions/browser/granted_file_entry.h"
#include "extensions/browser/path_util.h"
#include "extensions/common/api/file_system.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/permissions/api_permission.h"
#include "extensions/common/permissions/permissions_data.h"
#include "net/base/mime_util.h"
#include "storage/browser/file_system/external_mount_points.h"
#include "storage/browser/file_system/file_system_context.h"
#include "storage/browser/file_system/file_system_operation_runner.h"
#include "storage/browser/file_system/isolated_context.h"
#include "storage/common/file_system/file_system_types.h"
#include "storage/common/file_system/file_system_util.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/shell_dialogs/select_file_dialog.h"
#include "url/origin.h"
#if BUILDFLAG(IS_MAC)
#include <CoreFoundation/CoreFoundation.h>
#include "base/apple/foundation_util.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "extensions/browser/api/file_handlers/non_native_file_system_delegate.h"
#endif
IsolatedContext;
const char kInvalidCallingPage[] = …;
const char kUserCancelled[] = …;
const char kWritableFileErrorFormat[] = …;
const char kRequiresFileSystemWriteError[] = …;
const char kRequiresFileSystemDirectoryError[] = …;
const char kMultipleUnsupportedError[] = …;
const char kUnknownIdError[] = …;
const char kNotSupportedOnCurrentPlatformError[] = …;
const char kRetainEntryError[] = …;
const char kRetainEntryIncognitoError[] = …;
#if BUILDFLAG(IS_CHROMEOS)
const char kNotSupportedOnNonKioskSessionError[] =
"Operation only supported for kiosk apps running in a kiosk session.";
#endif
namespace extensions {
file_system;
ChooseEntry;
namespace {
bool GetFileTypesFromAcceptOption(
const file_system::AcceptOption& accept_option,
std::vector<base::FilePath::StringType>* extensions,
std::u16string* description) { … }
const char kLastChooseEntryDirectory[] = …;
const int kGraylistedPaths[] = …;
FileInfoOptCallback;
void PassFileInfoToUIThread(FileInfoOptCallback callback,
base::File::Error result,
const base::File::Info& info) { … }
content::WebContents* GetWebContentsForRenderFrameHost(
content::BrowserContext* browser_context,
content::RenderFrameHost* render_frame_host) { … }
base::FilePath GenerateUniqueSavePath(const base::FilePath& path) { … }
}
namespace file_system_api {
base::FilePath GetLastChooseEntryDirectory(const ExtensionPrefs* prefs,
const ExtensionId& extension_id) { … }
void SetLastChooseEntryDirectory(ExtensionPrefs* prefs,
const ExtensionId& extension_id,
const base::FilePath& path) { … }
}
FileSystemGetDisplayPathFunction::~FileSystemGetDisplayPathFunction() = default;
ExtensionFunction::ResponseAction FileSystemGetDisplayPathFunction::Run() { … }
FileSystemEntryFunction::FileSystemEntryFunction() = default;
FileSystemEntryFunction::~FileSystemEntryFunction() = default;
void FileSystemEntryFunction::PrepareFilesForWritableApp(
const std::vector<base::FilePath>& paths) { … }
void FileSystemEntryFunction::RegisterFileSystemsAndSendResponse(
const std::vector<base::FilePath>& paths) { … }
base::Value::Dict FileSystemEntryFunction::CreateResult() { … }
void FileSystemEntryFunction::AddEntryToResult(const base::FilePath& path,
const std::string& id_override,
base::Value::Dict& result) { … }
void FileSystemEntryFunction::HandleWritableFileError(
const base::FilePath& error_path) { … }
FileSystemGetWritableEntryFunction::~FileSystemGetWritableEntryFunction() =
default;
ExtensionFunction::ResponseAction FileSystemGetWritableEntryFunction::Run() { … }
void FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse() { … }
void FileSystemGetWritableEntryFunction::SetIsDirectoryAsync() { … }
FileSystemIsWritableEntryFunction::~FileSystemIsWritableEntryFunction() =
default;
ExtensionFunction::ResponseAction FileSystemIsWritableEntryFunction::Run() { … }
const FileSystemChooseEntryFunction::TestOptions*
FileSystemChooseEntryFunction::g_test_options = …;
base::AutoReset<const FileSystemChooseEntryFunction::TestOptions*>
FileSystemChooseEntryFunction::SetOptionsForTesting(
const TestOptions& options) { … }
void FileSystemChooseEntryFunction::ShowPicker(
const ui::SelectFileDialog::FileTypeInfo& file_type_info,
ui::SelectFileDialog::Type picker_type,
const base::FilePath& initial_path) { … }
void FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest(
const std::string& name,
const base::FilePath& path) { … }
void FileSystemChooseEntryFunction::FilesSelected(
const std::vector<base::FilePath>& paths) { … }
void FileSystemChooseEntryFunction::FileSelectionCanceled() { … }
void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync(
bool non_native_path,
const std::vector<base::FilePath>& paths) { … }
void FileSystemChooseEntryFunction::ConfirmSensitiveDirectoryAccess(
const std::vector<base::FilePath>& paths) { … }
void FileSystemChooseEntryFunction::OnDirectoryAccessConfirmed(
const std::vector<base::FilePath>& paths) { … }
void FileSystemChooseEntryFunction::BuildFileTypeInfo(
ui::SelectFileDialog::FileTypeInfo* file_type_info,
const base::FilePath::StringType& suggested_extension,
const std::optional<AcceptOptions>& accepts,
const std::optional<bool>& accepts_all_types) { … }
void FileSystemChooseEntryFunction::BuildSuggestion(
const std::optional<std::string>& opt_name,
base::FilePath* suggested_name,
base::FilePath::StringType* suggested_extension) { … }
void FileSystemChooseEntryFunction::CalculateInitialPathAndShowPicker(
const base::FilePath& previous_path,
const base::FilePath& suggested_name,
const ui::SelectFileDialog::FileTypeInfo& file_type_info,
ui::SelectFileDialog::Type picker_type,
bool is_previous_path_directory) { … }
void FileSystemChooseEntryFunction::MaybeUseManagedSavePath(
base::OnceClosure fallback_file_picker_callback,
const base::FilePath& path) { … }
FileSystemChooseEntryFunction::~FileSystemChooseEntryFunction() = default;
ExtensionFunction::ResponseAction FileSystemChooseEntryFunction::Run() { … }
FileSystemRetainEntryFunction::~FileSystemRetainEntryFunction() = default;
ExtensionFunction::ResponseAction FileSystemRetainEntryFunction::Run() { … }
void FileSystemRetainEntryFunction::RetainFileEntry(
const std::string& entry_id,
const base::FilePath& path,
std::unique_ptr<base::File::Info> file_info) { … }
FileSystemIsRestorableFunction::~FileSystemIsRestorableFunction() = default;
ExtensionFunction::ResponseAction FileSystemIsRestorableFunction::Run() { … }
FileSystemRestoreEntryFunction::~FileSystemRestoreEntryFunction() = default;
ExtensionFunction::ResponseAction FileSystemRestoreEntryFunction::Run() { … }
#if BUILDFLAG(IS_CHROMEOS)
FileSystemRequestFileSystemFunction::FileSystemRequestFileSystemFunction() =
default;
FileSystemRequestFileSystemFunction::~FileSystemRequestFileSystemFunction() =
default;
ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() {
using file_system::RequestFileSystem::Params;
const std::optional<Params> params = Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(params);
consent_provider_ =
ExtensionsAPIClient::Get()->CreateConsentProvider(browser_context());
FileSystemDelegate* delegate =
ExtensionsAPIClient::Get()->GetFileSystemDelegate();
DCHECK(delegate);
if (!consent_provider_->IsGrantable(*extension())) {
return RespondNow(Error(kNotSupportedOnNonKioskSessionError));
}
delegate->RequestFileSystem(
browser_context(), this, consent_provider_.get(), *extension(),
params->options.volume_id, params->options.writable.value_or(false),
base::BindOnce(&FileSystemRequestFileSystemFunction::OnGotFileSystem,
this),
base::BindOnce(&FileSystemRequestFileSystemFunction::OnError, this));
return did_respond() ? AlreadyResponded() : RespondLater();
}
void FileSystemRequestFileSystemFunction::OnGotFileSystem(
const std::string& id,
const std::string& path) {
base::Value::Dict dict;
dict.Set("file_system_id", id);
dict.Set("file_system_path", path);
Respond(WithArguments(std::move(dict)));
}
void FileSystemRequestFileSystemFunction::OnError(const std::string& error) {
Respond(Error(error));
}
FileSystemGetVolumeListFunction::FileSystemGetVolumeListFunction() = default;
FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() = default;
ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() {
consent_provider_ =
ExtensionsAPIClient::Get()->CreateConsentProvider(browser_context());
FileSystemDelegate* delegate =
ExtensionsAPIClient::Get()->GetFileSystemDelegate();
DCHECK(delegate);
if (!consent_provider_->IsGrantable(*extension())) {
return RespondNow(Error(kNotSupportedOnNonKioskSessionError));
}
delegate->GetVolumeList(
browser_context(),
base::BindOnce(&FileSystemGetVolumeListFunction::OnGotVolumeList, this),
base::BindOnce(&FileSystemGetVolumeListFunction::OnError, this));
return did_respond() ? AlreadyResponded() : RespondLater();
}
void FileSystemGetVolumeListFunction::OnGotVolumeList(
const std::vector<file_system::Volume>& volumes) {
Respond(ArgumentList(file_system::GetVolumeList::Results::Create(volumes)));
}
void FileSystemGetVolumeListFunction::OnError(const std::string& error) {
Respond(Error(error));
}
#else
FileSystemRequestFileSystemFunction::~FileSystemRequestFileSystemFunction() =
default;
ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() { … }
FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() = default;
ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() { … }
#endif
}