chromium/extensions/browser/api/file_system/file_system_api.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#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  // BUILDFLAG(IS_CHROMEOS_ASH)

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  // BUILDFLAG(IS_CHROMEOS)

namespace extensions {

file_system;
ChooseEntry;

namespace {

// Expand the mime-types and extensions provided in an AcceptOption, returning
// them within the passed extension vector. Returns false if no valid types
// were found.
bool GetFileTypesFromAcceptOption(
    const file_system::AcceptOption& accept_option,
    std::vector<base::FilePath::StringType>* extensions,
    std::u16string* description) {}

// Key for the path of the directory of the file last chosen by the user in
// response to a chrome.fileSystem.chooseEntry() call.
const char kLastChooseEntryDirectory[] =;

const int kGraylistedPaths[] =;

FileInfoOptCallback;

// Passes optional file info to the UI thread depending on |result| and |info|.
void PassFileInfoToUIThread(FileInfoOptCallback callback,
                            base::File::Error result,
                            const base::File::Info& info) {}

// Gets a WebContents instance handle for a platform app hosted in
// |render_frame_host|. If not found, then returns NULL.
content::WebContents* GetWebContentsForRenderFrameHost(
    content::BrowserContext* browser_context,
    content::RenderFrameHost* render_frame_host) {}

// Creates a unique filename by appending a uniquifier if needed. Returns the
// generated file path on success, or an empty path on failure.
base::FilePath GenerateUniqueSavePath(const base::FilePath& path) {}

}  // namespace

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) {}

}  // namespace file_system_api

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) {}

// static
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::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);
  // Only kiosk apps in kiosk sessions can use this API.
  // Additionally it is enabled for allowlisted component extensions and apps.
  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::FileSystemGetVolumeListFunction() = default;

FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() = default;

ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() {
  consent_provider_ =
      ExtensionsAPIClient::Get()->CreateConsentProvider(browser_context());

  FileSystemDelegate* delegate =
      ExtensionsAPIClient::Get()->GetFileSystemDelegate();
  DCHECK(delegate);
  // Only kiosk apps in kiosk sessions can use this API.
  // Additionally it is enabled for allowlisted component extensions and apps.
  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   // BUILDFLAG(IS_CHROMEOS)
/******** FileSystemRequestFileSystemFunction ********/

FileSystemRequestFileSystemFunction::~FileSystemRequestFileSystemFunction() =
    default;

ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() {}

/******** FileSystemGetVolumeListFunction ********/

FileSystemGetVolumeListFunction::~FileSystemGetVolumeListFunction() = default;

ExtensionFunction::ResponseAction FileSystemGetVolumeListFunction::Run() {}
#endif  // BUILDFLAG(IS_CHROMEOS)

}  // namespace extensions