// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/extensions/file_manager/fmpi_get_volume_root_function.h"
#include "ash/webui/file_manager/url_constants.h"
#include "base/files/file.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/ash/file_manager/fileapi_util.h"
#include "chrome/browser/ash/file_manager/volume_manager.h"
#include "chrome/browser/ash/fileapi/file_system_backend.h"
#include "chrome/browser/extensions/chrome_extension_function_details.h"
#include "chrome/common/extensions/api/file_manager_private_internal.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/storage_partition.h"
namespace extensions {
ExtensionFunction::ResponseAction
FileManagerPrivateInternalGetVolumeRootFunction::Run() {
using extensions::api::file_manager_private_internal::GetVolumeRoot::Params;
const std::optional<Params> params = Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(params);
const std::string& volume_id = params->options.volume_id;
if (volume_id.empty()) {
return RespondNow(Error("Volume ID must be provided."));
}
file_manager::VolumeManager* const volume_manager =
file_manager::VolumeManager::Get(
Profile::FromBrowserContext(browser_context()));
DCHECK(volume_manager);
base::WeakPtr<file_manager::Volume> volume =
volume_manager->FindVolumeById(volume_id);
if (!volume.get()) {
return RespondNow(Error("Volume with ID '*' not found", volume_id));
}
content::ChildProcessSecurityPolicy* policy =
content::ChildProcessSecurityPolicy::GetInstance();
DCHECK(policy);
const auto process_id = source_process_id();
// Read-only permisisons.
policy->GrantReadFile(process_id, volume->mount_path());
if (params->options.writable.value_or(false)) {
// Additional write permissions.
policy->GrantCreateReadWriteFile(process_id, volume->mount_path());
policy->GrantCopyInto(process_id, volume->mount_path());
}
// Convert volume's mount path to a virtual path.
scoped_refptr<storage::FileSystemContext> file_system_context =
render_frame_host()->GetStoragePartition()->GetFileSystemContext();
DCHECK(file_system_context.get());
auto* const backend = ash::FileSystemBackend::Get(*file_system_context);
DCHECK(backend);
file_manager::util::FileDefinition fd;
if (!backend->GetVirtualPath(volume->mount_path(), &fd.virtual_path)) {
return RespondNow(
Error("Cannot get virtual path for volume with ID '*'", volume_id));
}
// Grant the caller right rights to crack URLs based on the virtual path.
const url::Origin origin = url::Origin::Create(source_url());
backend->GrantFileAccessToOrigin(origin, fd.virtual_path);
// Convert volume's mount path to an EntryDefinition.
file_manager::util::ConvertFileDefinitionToEntryDefinition(
file_system_context, origin, fd,
base::BindOnce(
&FileManagerPrivateInternalGetVolumeRootFunction::OnRequestDone,
this));
return RespondLater();
}
void FileManagerPrivateInternalGetVolumeRootFunction::OnRequestDone(
const file_manager::util::EntryDefinition& entry_definition) {
if (entry_definition.error != base::File::FILE_OK) {
Respond(Error("Failed to resolve volume's root directory: *",
base::NumberToString(entry_definition.error)));
} else {
Respond(WithArguments(ConvertEntryDefinitionToValue(entry_definition)));
}
}
} // namespace extensions