Commit 0de8fbb7 authored by Ken Rockot's avatar Ken Rockot Committed by Commit Bot

Introduce storage::FilesystemProxy

This introduces a new FilesystemProxy API into the Storage
Service client library.

FilesystemProxy provides common filesystem operations and can
operate either directly on the filesystem in an unrestricted
mode (which only actually works outside of a sandbox), or it can
operate on a remote implementation of a new
storage.mojom.Directory interface, securely scoped to a single
directory tree within the filesystem.

Bug: 1052045
Change-Id: I7fa391f2d29d9475167613c379dea6653ab22b42
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2080588
Commit-Queue: Ken Rockot <rockot@google.com>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarDaniel Murphy <dmurph@chromium.org>
Cr-Commit-Position: refs/heads/master@{#747399}
parent 18a27d25
...@@ -140,7 +140,10 @@ source_set("tests") { ...@@ -140,7 +140,10 @@ source_set("tests") {
"//base", "//base",
"//base/test:test_support", "//base/test:test_support",
"//components/services/storage/public/cpp", "//components/services/storage/public/cpp",
"//components/services/storage/public/cpp/filesystem:tests",
"//components/services/storage/public/mojom",
"//mojo/core/embedder", "//mojo/core/embedder",
"//mojo/public/cpp/bindings",
"//sql:test_support", "//sql:test_support",
"//testing/gmock", "//testing/gmock",
"//testing/gtest", "//testing/gtest",
......
...@@ -9,7 +9,10 @@ component("cpp") { ...@@ -9,7 +9,10 @@ component("cpp") {
sources = [ "constants.cc" ] sources = [ "constants.cc" ]
public_deps = [ "//base" ] public_deps = [
"//base",
"//components/services/storage/public/cpp/filesystem",
]
defines = [ "IS_STORAGE_SERVICE_PUBLIC_IMPL" ] defines = [ "IS_STORAGE_SERVICE_PUBLIC_IMPL" ]
} }
# Copyright 2020 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.
component("filesystem") {
output_name = "storage_service_filesystem_support"
public = [
"file_error_or.h",
"filesystem_impl.h",
"filesystem_proxy.h",
]
sources = [
"filesystem_impl.cc",
"filesystem_proxy.cc",
]
public_deps = [
"//base",
"//components/services/storage/public/mojom/filesystem",
"//mojo/public/cpp/bindings",
]
defines = [ "IS_STORAGE_SERVICE_FILESYSTEM_SUPPORT_IMPL" ]
}
component("typemap_traits") {
output_name = "storage_service_typemap_traits"
defines = [ "IS_STORAGE_SERVICE_FILESYSTEM_TYPEMAP_TRAITS_IMPL" ]
sources = [
"strict_relative_path_mojom_traits.cc",
"strict_relative_path_mojom_traits.h",
]
public_deps = [
"//base",
"//components/services/storage/public/mojom/filesystem:filesystem_shared",
"//mojo/public/cpp/base:shared_typemap_traits",
"//mojo/public/cpp/bindings",
]
}
source_set("tests") {
testonly = true
sources = [ "filesystem_proxy_unittest.cc" ]
deps = [
":filesystem",
"//base",
"//base/test:test_support",
"//components/services/storage/public/mojom/filesystem",
"//testing/gmock",
"//testing/gtest",
]
}
per-file *_mojom_traits*.*=set noparent
per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
// Copyright 2020 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 COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_FILESYSTEM_FILE_ERROR_OR_H_
#define COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_FILESYSTEM_FILE_ERROR_OR_H_
#include <utility>
#include "base/files/file.h"
#include "base/optional.h"
namespace storage {
// Helper for methods which perform file system operations and which may fail.
// Objects of this type can take on EITHER a base::File::Error value OR a result
// value of arbitrary type.
template <typename ValueType>
class FileErrorOr {
public:
explicit FileErrorOr() = default;
FileErrorOr(base::File::Error error) : error_(error) {}
FileErrorOr(ValueType&& value)
: maybe_value_(base::in_place, std::move(value)) {}
FileErrorOr(const FileErrorOr&) = delete;
FileErrorOr(FileErrorOr&&) = default;
FileErrorOr& operator=(const FileErrorOr&) = delete;
FileErrorOr& operator=(FileErrorOr&&) = default;
~FileErrorOr() = default;
bool is_error() const { return !maybe_value_.has_value(); }
base::File::Error error() const { return error_; }
ValueType& value() { return maybe_value_.value(); }
const ValueType& value() const { return maybe_value_.value(); }
ValueType* operator->() { return &maybe_value_.value(); }
const ValueType* operator->() const { return &maybe_value_.value(); }
private:
base::File::Error error_ = base::File::FILE_ERROR_FAILED;
base::Optional<ValueType> maybe_value_;
};
} // namespace storage
#endif // COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_FILESYSTEM_FILE_ERROR_OR_H_
// Copyright 2020 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 "components/services/storage/public/cpp/filesystem/filesystem_impl.h"
#include <set>
#include <vector>
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "base/synchronization/lock.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace storage {
namespace {
// Retains a mapping of lock file paths which have been locked by
// |FilesystemImpl::LockFile| and not yet released.
class LockTable {
public:
LockTable() = default;
LockTable(const LockTable&) = delete;
LockTable& operator=(const LockTable&) = delete;
~LockTable() = default;
bool AddLock(const base::FilePath& path) {
DCHECK(path.IsAbsolute());
base::AutoLock lock(lock_);
auto result = lock_paths_.insert(path.NormalizePathSeparators());
return result.second;
}
void RemoveLock(const base::FilePath& path) {
const base::FilePath normalized_path = path.NormalizePathSeparators();
base::AutoLock lock(lock_);
DCHECK(base::Contains(lock_paths_, normalized_path));
lock_paths_.erase(normalized_path);
}
private:
base::Lock lock_;
std::set<base::FilePath> lock_paths_ GUARDED_BY(lock_);
};
// Get the global singleton instance of LockTable. This returned object is
// thread-safe.
LockTable& GetLockTable() {
static base::NoDestructor<LockTable> table;
return *table;
}
class FileLockImpl : public mojom::FileLock {
public:
FileLockImpl(const base::FilePath& path, base::File file)
: path_(path), file_(std::move(file)) {
DCHECK(file_.IsValid());
}
~FileLockImpl() override {
if (file_.IsValid())
GetLockTable().RemoveLock(path_);
}
// mojom::FileLock implementation:
void Release(ReleaseCallback callback) override {
if (!file_.IsValid()) {
std::move(callback).Run(base::File::FILE_ERROR_INVALID_OPERATION);
return;
}
#if defined(OS_FUCHSIA)
std::move(callback).Run(base::File::FILE_OK);
#else
std::move(callback).Run(file_.Unlock());
#endif
GetLockTable().RemoveLock(path_);
file_.Close();
}
private:
const base::FilePath path_;
base::File file_;
};
} // namespace
FilesystemImpl::FilesystemImpl(const base::FilePath& root) : root_(root) {}
FilesystemImpl::~FilesystemImpl() = default;
void FilesystemImpl::PathExists(const base::FilePath& path,
PathExistsCallback callback) {
std::move(callback).Run(base::PathExists(MakeAbsolute(path)));
}
void FilesystemImpl::GetEntries(const base::FilePath& path,
mojom::GetEntriesMode mode,
GetEntriesCallback callback) {
const base::FilePath full_path = MakeAbsolute(path);
FileErrorOr<std::vector<base::FilePath>> result =
GetDirectoryEntries(full_path, mode);
if (result.is_error()) {
std::move(callback).Run(result.error(), std::vector<base::FilePath>());
return;
}
// Fix up the absolute paths to be relative to |path|.
std::vector<base::FilePath> entries;
std::vector<base::FilePath::StringType> root_components;
full_path.GetComponents(&root_components);
const size_t num_components_to_strip = root_components.size();
for (const auto& entry : result.value()) {
std::vector<base::FilePath::StringType> components;
entry.GetComponents(&components);
base::FilePath relative_path;
for (size_t i = num_components_to_strip; i < components.size(); ++i)
relative_path = relative_path.Append(components[i]);
entries.push_back(std::move(relative_path));
}
std::move(callback).Run(base::File::FILE_OK, entries);
}
void FilesystemImpl::OpenFile(const base::FilePath& path,
mojom::FileOpenMode mode,
mojom::FileReadAccess read_access,
mojom::FileWriteAccess write_access,
OpenFileCallback callback) {
uint32_t flags = 0;
switch (mode) {
case mojom::FileOpenMode::kOpenIfExists:
flags |= base::File::FLAG_OPEN;
break;
case mojom::FileOpenMode::kCreateAndOpenOnlyIfNotExists:
flags |= base::File::FLAG_CREATE;
break;
case mojom::FileOpenMode::kAlwaysOpen:
flags |= base::File::FLAG_OPEN_ALWAYS;
break;
case mojom::FileOpenMode::kAlwaysCreate:
flags |= base::File::FLAG_CREATE_ALWAYS;
break;
case mojom::FileOpenMode::kOpenIfExistsAndTruncate:
flags |= base::File::FLAG_OPEN_TRUNCATED;
break;
default:
NOTREACHED();
return;
}
switch (read_access) {
case mojom::FileReadAccess::kReadNotAllowed:
break;
case mojom::FileReadAccess::kReadAllowed:
flags |= base::File::FLAG_READ;
break;
default:
NOTREACHED();
break;
}
switch (write_access) {
case mojom::FileWriteAccess::kWriteNotAllowed:
break;
case mojom::FileWriteAccess::kWriteAllowed:
flags |= base::File::FLAG_WRITE;
break;
case mojom::FileWriteAccess::kAppendOnly:
flags |= base::File::FLAG_APPEND;
break;
default:
NOTREACHED();
break;
}
const base::FilePath full_path = MakeAbsolute(path);
base::File file(full_path, flags);
base::File::Error error = base::File::FILE_OK;
if (!file.IsValid())
error = file.error_details();
std::move(callback).Run(error, std::move(file));
}
void FilesystemImpl::RemoveFile(const base::FilePath& path,
RemoveFileCallback callback) {
std::move(callback).Run(
base::DeleteFile(MakeAbsolute(path), /*recursive=*/false));
}
void FilesystemImpl::CreateDirectory(const base::FilePath& path,
CreateDirectoryCallback callback) {
base::File::Error error = base::File::FILE_OK;
base::CreateDirectoryAndGetError(MakeAbsolute(path), &error);
std::move(callback).Run(error);
}
void FilesystemImpl::RemoveDirectory(const base::FilePath& path,
RemoveDirectoryCallback callback) {
const base::FilePath full_path = MakeAbsolute(path);
if (!base::DirectoryExists(full_path)) {
std::move(callback).Run(false);
return;
}
std::move(callback).Run(base::DeleteFile(full_path, /*recursive=*/false));
}
void FilesystemImpl::GetFileInfo(const base::FilePath& path,
GetFileInfoCallback callback) {
base::File::Info info;
if (base::GetFileInfo(MakeAbsolute(path), &info))
std::move(callback).Run(std::move(info));
else
std::move(callback).Run(base::nullopt);
}
void FilesystemImpl::RenameFile(const base::FilePath& old_path,
const base::FilePath& new_path,
RenameFileCallback callback) {
base::File::Error error = base::File::FILE_OK;
base::ReplaceFile(MakeAbsolute(old_path), MakeAbsolute(new_path), &error);
std::move(callback).Run(error);
}
void FilesystemImpl::LockFile(const base::FilePath& path,
LockFileCallback callback) {
FileErrorOr<base::File> result = LockFileLocal(MakeAbsolute(path));
if (result.is_error()) {
std::move(callback).Run(result.error(), mojo::NullRemote());
return;
}
mojo::PendingRemote<mojom::FileLock> lock;
mojo::MakeSelfOwnedReceiver(
std::make_unique<FileLockImpl>(MakeAbsolute(path),
std::move(result.value())),
lock.InitWithNewPipeAndPassReceiver());
std::move(callback).Run(base::File::FILE_OK, std::move(lock));
}
// static
FileErrorOr<base::File> FilesystemImpl::LockFileLocal(
const base::FilePath& path) {
DCHECK(path.IsAbsolute());
base::File file(path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ |
base::File::FLAG_WRITE);
if (!file.IsValid())
return file.error_details();
if (!GetLockTable().AddLock(path))
return base::File::FILE_ERROR_IN_USE;
#if !defined(OS_FUCHSIA)
base::File::Error error = file.Lock();
if (error != base::File::FILE_OK)
return error;
#endif
return file;
}
// static
void FilesystemImpl::UnlockFileLocal(const base::FilePath& path) {
GetLockTable().RemoveLock(path);
}
// static
FileErrorOr<std::vector<base::FilePath>> FilesystemImpl::GetDirectoryEntries(
const base::FilePath& path,
mojom::GetEntriesMode mode) {
DCHECK(path.IsAbsolute());
int file_types = base::FileEnumerator::FILES;
if (mode == mojom::GetEntriesMode::kFilesAndDirectories)
file_types |= base::FileEnumerator::DIRECTORIES;
base::FileEnumerator enumerator(
path, /*recursive=*/false, file_types,
/*pattern=*/base::FilePath::StringType(),
base::FileEnumerator::FolderSearchPolicy::ALL,
base::FileEnumerator::ErrorPolicy::STOP_ENUMERATION);
std::vector<base::FilePath> entries;
for (base::FilePath path = enumerator.Next(); !path.empty();
path = enumerator.Next()) {
entries.push_back(path);
}
if (enumerator.GetError() != base::File::FILE_OK)
return enumerator.GetError();
return entries;
}
base::FilePath FilesystemImpl::MakeAbsolute(const base::FilePath& path) const {
// The DCHECK is a reasonable assertion: this object is only called into via
// Mojo, and type-map traits for |storage.mojom.StrictRelativePath| ensure
// that messages can only reach this object if they carry strictly relative
// paths.
DCHECK(!path.IsAbsolute());
return root_.Append(path);
}
} // namespace storage
// Copyright 2020 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 COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_FILESYSTEM_FILESYSTEM_IMPL_H_
#define COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_FILESYSTEM_FILESYSTEM_IMPL_H_
#include <vector>
#include "base/component_export.h"
#include "base/files/file_path.h"
#include "base/util/type_safety/pass_key.h"
#include "components/services/storage/public/cpp/filesystem/file_error_or.h"
#include "components/services/storage/public/mojom/filesystem/directory.mojom.h"
namespace storage {
class FilesystemProxy;
// This is a concrete implementation of the |storage.mojom.Directory| interface
// consumed via FilesystemProxy. If running the Storage Service in a restricted
// sandbox environment, a privileged client (i.e. the browser) must provide a
// working remote Directory implementation. This implementation can generally be
// used as-is in such cases.
//
// Note that this must be constructed on a thread that allows blocking file I/O
// operations.
class COMPONENT_EXPORT(STORAGE_SERVICE_FILESYSTEM_SUPPORT) FilesystemImpl
: public mojom::Directory {
public:
// |root| must be an absolute path. Operations performed by this object
// will be contained within |root| or a transitive subdirectory thereof. All
// relative paths given to methods of this object are interpreted as relative
// to |root|.
explicit FilesystemImpl(const base::FilePath& root);
FilesystemImpl(const FilesystemImpl&) = delete;
FilesystemImpl& operator=(const FilesystemImpl) = delete;
~FilesystemImpl() override;
// mojom::Directory:
void PathExists(const base::FilePath& path,
PathExistsCallback callback) override;
void GetEntries(const base::FilePath& path,
mojom::GetEntriesMode mode,
GetEntriesCallback callback) override;
void OpenFile(const base::FilePath& path,
mojom::FileOpenMode mode,
mojom::FileReadAccess read_access,
mojom::FileWriteAccess write_access,
OpenFileCallback callback) override;
void RemoveFile(const base::FilePath& path,
RemoveFileCallback callback) override;
void CreateDirectory(const base::FilePath& path,
CreateDirectoryCallback callback) override;
void RemoveDirectory(const base::FilePath& path,
RemoveDirectoryCallback callback) override;
void GetFileInfo(const base::FilePath& path,
GetFileInfoCallback callback) override;
void RenameFile(const base::FilePath& old_path,
const base::FilePath& new_path,
RenameFileCallback callback) override;
void LockFile(const base::FilePath& path, LockFileCallback callback) override;
// Helper used by LockFile() and FilesystemProxy::LockFile() for in
// unrestricted mode.
static FileErrorOr<base::File> LockFileLocal(const base::FilePath& path);
static void UnlockFileLocal(const base::FilePath& path);
// Helper used by GetEntries() and FilesystemProxy::GetDirectoryEntries.
static FileErrorOr<std::vector<base::FilePath>> GetDirectoryEntries(
const base::FilePath& path,
mojom::GetEntriesMode mode);
private:
base::FilePath MakeAbsolute(const base::FilePath& path) const;
const base::FilePath root_;
};
} // namespace storage
#endif // COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_FILESYSTEM_FILESYSTEM_IMPL_H_
// Copyright 2020 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 COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_FILESYSTEM_FILESYSTEM_PROXY_H_
#define COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_FILESYSTEM_FILESYSTEM_PROXY_H_
#include <memory>
#include <vector>
#include "base/component_export.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequenced_task_runner.h"
#include "base/util/type_safety/pass_key.h"
#include "components/services/storage/public/cpp/filesystem/file_error_or.h"
#include "components/services/storage/public/mojom/filesystem/directory.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/shared_remote.h"
namespace storage {
// A FilesystemProxy performs common filesystem operations on the caller's
// behalf, either directly (if the calling process environment permits) or via a
// remote storage.mojom.Directory implementation if one is provided.
//
// This class is thread-safe, but must only be called from threads that allow
// blocking operations.
class COMPONENT_EXPORT(STORAGE_SERVICE_FILESYSTEM_SUPPORT) FilesystemProxy {
public:
// Tags used to clarify the meaning of each constructor so that call sites can
// be more easily evaluated.
enum { UNRESTRICTED };
enum { RESTRICTED };
// Constructs a new FilesystemProxy which performs privileged, in-process
// file system operations. Not suitable for use within a restricted sandbox
// environment, as it may ultimately attempt to work that will be blocked by
// the sandbox boundary.
//
// If relative paths are given to methods on this object, they are interpreted
// relative to |root|. Objects constructed in this way can process paths
// outside of |root| and in general suffer no restrictions on what paths are
// allowed.
//
// If |root| is empty, this object's methods will only accept absolute paths.
explicit FilesystemProxy(decltype(UNRESTRICTED), const base::FilePath& root);
// Constructs a new FilesystemProxy for |root|, using |directory| to invoke
// privileged operations. Suitable for use within a sandboxed/ environment,
// assuming |directory| is connected to a remote implementation in a more
// privileged process.
//
// Objects constructed in this way can ONLY access contents within |root|;
// relative paths are interpreted as relative to |root|, and absolute paths
// must fall within |root|.
//
// |ipc_task_runner| is a task runner suitable for internally binding the
// Directory IPC endpoint; this is the task runner used to bind the internal
// SharedRemote, and so this is where all outgoing IPCs will hop before being
// transmitted. As such it must be a thread which is never blocked. Typically
// in a Content process environment, this should be the "IO thread".
FilesystemProxy(decltype(RESTRICTED),
const base::FilePath& root,
mojo::PendingRemote<mojom::Directory> directory,
scoped_refptr<base::SequencedTaskRunner> ipc_task_runner);
FilesystemProxy(const FilesystemProxy&) = delete;
FilesystemProxy& operator=(const FilesystemProxy&) = delete;
~FilesystemProxy();
// Returns true iff |path| refers to an existing file or directory.
bool PathExists(const base::FilePath& path);
// Enumerates all files and/or directories within |path|, a directory. Not
// recursive.
enum class DirectoryEntryType {
kFilesOnly,
kFilesAndDirectories,
};
FileErrorOr<std::vector<base::FilePath>> GetDirectoryEntries(
const base::FilePath& path,
DirectoryEntryType type);
// Opens a file at |path| with the given |flags|. If successful, the newly
// opened file is returned. |flags| may be any bitwise union of
// base::File::Flags values.
FileErrorOr<base::File> OpenFile(const base::FilePath& path, int flags);
// Deletes the file at |path| if it exists and returns true iff successful.
bool RemoveFile(const base::FilePath& path);
// Creates a new directory at |path|. Any needed parent directories above
// |path| are also created if they don't already exist.
base::File::Error CreateDirectory(const base::FilePath& path);
// Deletes the directory at |path| if it exists and returns true iff
// successful.
bool RemoveDirectory(const base::FilePath& path);
// Retrieves information about a file or directory at |path|. Returns a valid
// base::File::Info value on success, or null on failure.
base::Optional<base::File::Info> GetFileInfo(const base::FilePath& path);
// Renames a file from |old_path| to |new_path|. Must be atomic.
base::File::Error RenameFile(const base::FilePath& old_path,
const base::FilePath& new_path);
// Acquires an exclusive lock on the file at |path| if possible, returning a
// FileLock object to hold the lock if successful. The lock remains held as
// long as the returned FileLock object remains alive. Destroying the FileLock
// releases the lock.
class FileLock {
public:
virtual ~FileLock() = default;
// Explicitly releases the lock. This only has side effects the first time
// it's called, and once this is called, FileLock destruction also will be a
// no-op.
virtual base::File::Error Release() = 0;
};
FileErrorOr<std::unique_ptr<FileLock>> LockFile(const base::FilePath& path);
private:
// For restricted FilesystemProxy instances, this returns a FilePath
// equivalent to |path| which is strictly relative to |root_|. It is an error
// to call with a |path| for which this is impossible.
//
// Not called by unrestricted FilesystemProxy instances.
base::FilePath MakeRelative(const base::FilePath& path) const;
// For unrestricted FilesystemProxy instances, this returns a FilePath that is
// always absolute. If |path| is absolute, it is returned unmodified. If
// relative, it is resolved against |root_|.
base::FilePath MakeAbsolute(const base::FilePath& path) const;
const base::FilePath root_;
const size_t num_root_components_ = 0;
// If |remote_directory_| is set this is a restricted proxy, otherwise
// it is unrestricted and will perform filesystem operations directly.
const mojo::SharedRemote<mojom::Directory> remote_directory_;
};
} // namespace storage
#endif // COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_FILESYSTEM_FILESYSTEM_PROXY_H_
# Copyright 2020 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.
mojom = "//components/services/storage/public/mojom/filesystem/directory.mojom"
public_headers = [ "//base/files/file_path.h" ]
traits_headers = [ "//components/services/storage/public/cpp/filesystem/strict_relative_path_mojom_traits.h" ]
public_deps =
[ "//components/services/storage/public/cpp/filesystem:typemap_traits" ]
type_mappings = [ "storage.mojom.StrictRelativePath=::base::FilePath" ]
// Copyright 2020 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 "components/services/storage/public/cpp/filesystem/strict_relative_path_mojom_traits.h"
#include <utility>
#include "base/logging.h"
#include "mojo/public/cpp/base/file_path_mojom_traits.h"
namespace mojo {
bool StructTraits<storage::mojom::StrictRelativePathDataView, base::FilePath>::
Read(storage::mojom::StrictRelativePathDataView data, base::FilePath* out) {
base::FilePath path;
if (!data.ReadPath(&path))
return false;
if (path.IsAbsolute() || path.ReferencesParent()) {
DLOG(ERROR) << "Rejecting non-relative or non-descending path: "
<< path.value();
return false;
}
*out = std::move(path);
return true;
}
} // namespace mojo
// Copyright 2020 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 COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_FILESYSTEM_STRICT_RELATIVE_PATH_MOJOM_TRAITS_H_
#define COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_FILESYSTEM_STRICT_RELATIVE_PATH_MOJOM_TRAITS_H_
#include "base/component_export.h"
#include "base/files/file_path.h"
#include "components/services/storage/public/mojom/filesystem/directory.mojom-shared.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
namespace mojo {
template <>
struct COMPONENT_EXPORT(STORAGE_SERVICE_FILESYSTEM_TYPEMAP_TRAITS)
StructTraits<storage::mojom::StrictRelativePathDataView, base::FilePath> {
public:
static const base::FilePath& path(const base::FilePath& path) { return path; }
static bool Read(storage::mojom::StrictRelativePathDataView data,
base::FilePath* out);
};
} // namespace mojo
#endif // COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_FILESYSTEM_STRICT_RELATIVE_PATH_MOJOM_TRAITS_H_
# Copyright 2020 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.
typemaps = [ "//components/services/storage/public/cpp/filesystem/strict_relative_path.typemap" ]
...@@ -18,6 +18,7 @@ mojom("mojom") { ...@@ -18,6 +18,7 @@ mojom("mojom") {
] ]
public_deps = [ public_deps = [
"//components/services/storage/public/mojom/filesystem",
"//mojo/public/mojom/base", "//mojo/public/mojom/base",
"//third_party/blink/public/mojom:mojom_platform", "//third_party/blink/public/mojom:mojom_platform",
"//url/mojom:url_mojom_origin", "//url/mojom:url_mojom_origin",
......
# Copyright 2020 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.
import("//mojo/public/tools/bindings/mojom.gni")
mojom_component("filesystem") {
output_prefix = "storage_service_filesystem_mojom"
macro_prefix = "STORAGE_SERVICE_FILESYSTEM_MOJOM"
sources = [ "directory.mojom" ]
public_deps = [ "//mojo/public/mojom/base" ]
}
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
// Copyright 2020 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.
module storage.mojom;
import "mojo/public/mojom/base/file.mojom";
import "mojo/public/mojom/base/file_error.mojom";
import "mojo/public/mojom/base/file_info.mojom";
import "mojo/public/mojom/base/file_path.mojom";
// Determines how |Directory.GetEntries()| operates.
enum GetEntriesMode {
// Only regular files will be enumerated.
kFilesOnly,
// Both files and directories will be enumerated.
kFilesAndDirectories,
};
// A special type of file path which, unlike mojo_base.mojom.FilePath, is
// restricted to descending (i.e. no references to parent directories via "..")
// relative (i.e. non-absolute) paths only. For C++ bindings, this is enforced
// by type-mapping traits.
struct StrictRelativePath {
// The actual path data.
mojo_base.mojom.FilePath path;
};
// Indicates how a file should be opened and/or created by
// |Directory.OpenFile()|.
enum FileOpenMode {
// Only opens the file if it already exists.
kOpenIfExists,
// Only creates and opens the file if it did not already exist.
kCreateAndOpenOnlyIfNotExists,
// Always opens the file, creating a new one only if it didn't already exist.
kAlwaysOpen,
// Always creates a new file, overwriting any old file that may exist.
kAlwaysCreate,
// Only opens the file if it already exists, truncating the file on open.
kOpenIfExistsAndTruncate,
};
// Indicates the type of read access a file should have when opened by
// |Directory.OpenFile()|.
enum FileReadAccess {
// No read access.
kReadNotAllowed,
// Read access allowed.
kReadAllowed,
};
// Indicates the type of write access a file should have when opened by
// |Directory.OpenFile()|.
enum FileWriteAccess {
// No write access.
kWriteNotAllowed,
// Full write access allowed.
kWriteAllowed,
// Append-only write access allowed.
kAppendOnly,
};
// An empty interface used to hold remote ownership of a lock acquired via
// |Directory.LockFile()| below. Closing the remote endpoint of this interface
// effectively releases the corresponding lock even if |Release()| is not
// called.
interface FileLock {
// Immediately releases the lock. After this is called once, the FileLock is
// permanently released. Subsequent disconnection or calls to |Release()| will
// have no interesting side-effects.
[Sync] Release() => (mojo_base.mojom.FileError error);
};
// A client interface consumed by the Storage Service in order to access
// directory contents from within a sandboxed process. Must be implemented by
// a more privileged process like the browser.
//
// Each bound Directory interface corresponds to a fixed directory in the
// filesystem, and all StrictRelatvePath references must be interpreted as
// relative to that directory.
interface Directory {
// Indicates whether |path| exists.
[Sync]
PathExists(StrictRelativePath path) => (bool exists);
// Enumerates all files and/or subdirectories within |path|. Not recursive.
// All returned paths are relative to |path|.
[Sync]
GetEntries(StrictRelativePath path, GetEntriesMode mode)
=> (mojo_base.mojom.FileError error,
array<mojo_base.mojom.FilePath> entries);
// Opens a file at |path|.
[Sync]
OpenFile(StrictRelativePath path,
FileOpenMode mode,
FileReadAccess read_access,
FileWriteAccess write_access)
=> (mojo_base.mojom.FileError error, mojo_base.mojom.File? file);
// Deletes a regular file at |path|.
[Sync]
RemoveFile(StrictRelativePath path) => (bool success);
// Creates a new directory at |path|.
[Sync]
CreateDirectory(StrictRelativePath path) => (mojo_base.mojom.FileError error);
// Deletes a directory at |path|. Not recursive. If the directory at |path|
// contains only files (i.e. no subdirectories), all contents are deleted.
[Sync]
RemoveDirectory(StrictRelativePath path) => (bool success);
// Retrieves information about a specific filesystem entry at |path|. Returns
// null on failure, or a populated |info| struct on success.
[Sync]
GetFileInfo(StrictRelativePath path) => (mojo_base.mojom.FileInfo? info);
// Renames a file from |old_path| to |new_path|. Note that if |new_path|
// already exists, it will be overwritten by this call.
[Sync]
RenameFile(StrictRelativePath old_path, StrictRelativePath new_path)
=> (mojo_base.mojom.FileError error);
// Attempts to acquire an exclusive lock on the lock file identified by
// |path|, creating a new file if it didn't already exist. Upon success,
// |error| will be FILE_OK, and |lock| will be valid. As long as the caller
// retains |lock|, the acquired lock will be held. Destroying |lock| or
// explicitly calling |Release()| on it releases the lock.
[Sync]
LockFile(StrictRelativePath path) => (mojo_base.mojom.FileError error,
pending_remote<FileLock>? lock);
};
...@@ -17,6 +17,7 @@ _typemap_imports = [ ...@@ -17,6 +17,7 @@ _typemap_imports = [
"//chromeos/services/secure_channel/public/mojom/typemaps.gni", "//chromeos/services/secure_channel/public/mojom/typemaps.gni",
"//components/arc/mojom/typemaps.gni", "//components/arc/mojom/typemaps.gni",
"//components/chromeos_camera/common/typemaps.gni", "//components/chromeos_camera/common/typemaps.gni",
"//components/services/storage/public/cpp/filesystem/typemaps.gni",
"//components/sync/mojom/typemaps.gni", "//components/sync/mojom/typemaps.gni",
"//components/typemaps.gni", "//components/typemaps.gni",
"//content/browser/typemaps.gni", "//content/browser/typemaps.gni",
......
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