blob: a7eed6288defdd52f1c988ab063bce6dca6ec57f [file] [log] [blame]
// 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 <stdint.h>
#include <memory>
#include "base/component_export.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/optional.h"
#include "third_party/sqlite/sqlite3.h"
namespace sql {
// SQLite VFS file implementation that works in a sandboxed process.
// Instances are thread-friendly.
class COMPONENT_EXPORT(SQL) SandboxedVfs {
// Describes access rights for a path, used by Delegate::GetPathAccess below.
struct PathAccessInfo {
bool can_read = false;
bool can_write = false;
// Environment-specific SandboxedVfs implementation details.
// This abstracts a handful of operations that don't typically work in a
// sandbox environment given a typical naive implementation. Instances must be
// thread-safe.
class Delegate {
virtual ~Delegate() = default;
// Opens a file.
// `file_path` is the parsed version of a path passed by SQLite to Open().
// `sqlite_requested_flags` is a bitwise combination SQLite flags used when
// opening files. Returns the opened File on success, or an invalid File on
// failure.
virtual base::File OpenFile(const base::FilePath& file_path,
int sqlite_requested_flags) = 0;
// Deletes a file.
// `file_path` is the parsed version of a path passed by SQLite to Delete().
// If `sync_dir` is true, the implementation should attempt to flush to disk
// the changes to the file's directory, to ensure that the deletion is
// reflected after a power failure. Returns an SQLite error code indicating
// the status of the operation.
virtual int DeleteFile(const base::FilePath& file_path, bool sync_dir) = 0;
// Queries path access information for `file_path`. Returns null if the
// given path does not exist.
virtual base::Optional<PathAccessInfo> GetPathAccess(
const base::FilePath& file_path) = 0;
// Resizes a file.
// `file` is the result of a previous call to Delegate::OpenFile() with
// `file_path`. `size` is the new desired size in bytes, and may be smaller
// or larger than the current file size. Returns true if successful and
// false otherwise.
// Implementations can modify `file` directly, or operate on the filesystem
// via `file_path`.
// This is only called after the direct approach of base::File::SetLength()
// fails. So, the implementation should not bother trying to call
// SetLength() on `file`. This currently only happens on macOS < 10.15.
virtual bool SetFileLength(const base::FilePath& file_path,
base::File& file,
size_t size) = 0;
// We don't allow SandboxedVfs instances to be destroyed. Once created, they
// are permanently registered in the calling process.
~SandboxedVfs() = delete;
// Constructs a new instance of ths object using `delegate` to support various
// operations from within the sandbox. The VFS is registered with SQLite under
// `name` and if `make_default` is true then the VFS is also set as the global
// default for new database instances within the calling process.
// Note that `name` must be globally unique to the calling process.
static void Register(const char* name,
std::unique_ptr<Delegate> delegate,
bool make_default);
Delegate* delegate() const { return delegate_.get(); }
// sqlite3_vfs implementation.
int Open(const char* full_path,
sqlite3_file& result_file,
int requested_flags,
int* granted_flags);
int Delete(const char* full_path, int sync_dir);
int Access(const char* full_path, int flags, int& result);
int FullPathname(const char* file_path, int result_size, char* result);
int Randomness(int result_size, char* result);
int Sleep(int microseconds);
int GetLastError(int message_size, char* message) const;
int CurrentTimeInt64(sqlite3_int64* result_ms);
// Used by SandboxedVfsFile.
void SetLastError(base::File::Error error) { this->last_error_ = error; }
SandboxedVfs(const char* name,
std::unique_ptr<Delegate> delegate,
bool make_default);
sqlite3_vfs sandboxed_vfs_;
const base::Time sqlite_epoch_;
const std::unique_ptr<Delegate> delegate_;
base::File::Error last_error_;
} // namespace sql