blob: 7a8c8a7040a94d1fb8332fda8404e1503b81c5c0 [file]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_SQLITE_VFS_SANDBOXED_FILE_H_
#define COMPONENTS_SQLITE_VFS_SANDBOXED_FILE_H_
#include <stdint.h>
#include <optional>
#include "base/component_export.h"
#include "base/files/file.h"
#include "components/sqlite_vfs/lock_state.h"
#include "components/sqlite_vfs/shared_locks.h"
#include "sql/sandboxed_vfs_file.h"
namespace sqlite_vfs {
enum class Client;
enum class FileType;
// Represents a file to be exposed to sql::Database via
// SqliteSandboxedVfsDelegate.
//
// This class can be bound to a sqlite3_file to which ownership is relinquished
// to SQLite. It's not copyable or movable to ensure it doesn't become invalid
// outside of SQLite's control.
class COMPONENT_EXPORT(SQLITE_VFS) SandboxedFile
: public sql::SandboxedVfsFile {
public:
enum class AccessRights { kReadWrite, kReadOnly };
// `shared_locks` must be specified only for the main database file, and only
// when the database supports multiple connections.
SandboxedFile(Client client,
FileType file_type,
base::File file,
AccessRights access_rights,
std::optional<SharedLocks> shared_locks = std::nullopt);
SandboxedFile(SandboxedFile& other) = delete;
SandboxedFile& operator=(const SandboxedFile& other) = delete;
SandboxedFile(SandboxedFile&& other) = delete;
SandboxedFile& operator=(SandboxedFile&& other) = delete;
~SandboxedFile() override;
// Called by the VFS to take the underlying base::File. `file_type` indicates
// the type of file that is being opened. Concretely, this dance occurs when a
// file is opened:
//
// SandboxedVfs::Open
// -- Acquire the base::File
// SqliteSandboxedVfsDelegate::OpenFile
// SandboxedFile::TakeUnderlyingFile
// -- Pass it back to SandboxedFile
// SqliteSandboxedVfsDelegate::RetrieveSandboxedVfsFile
// SandboxedFile::OnFileOpened base::File TakeUnderlyingFile();
base::File TakeUnderlyingFile(FileType file_type);
// Called by the VFS when the file is successfully opened.
void OnFileOpened(base::File file);
// Used for unittests.
base::File& UnderlyingFileForTesting() { return underlying_file_; }
base::File& OpenedFileForTesting() { return opened_file_; }
// Returns true if this is a valid opened file.
bool IsValid() const { return opened_file_.IsValid(); }
AccessRights access_rights() const { return access_rights_; }
Client client() const { return client_; }
FileType file_type() const { return file_type_; }
// Returns a reference to the instance's file regardless of whether it is
// open (`IsValid()` returns true) or closed (otherwise). The reference is
// invalidated upon open/close.
const base::File& GetFile() const;
base::File& GetFile();
// sqlite3_file implementation.
int Close() override;
int Read(void* buffer, int size, sqlite3_int64 offset) override;
int Write(const void* buffer, int size, sqlite3_int64 offset) override;
int Truncate(sqlite3_int64 size) override;
int Sync(int flags) override;
int FileSize(sqlite3_int64* result_size) override;
int Lock(int mode) override;
int Unlock(int mode) override;
int CheckReservedLock(int* has_reserved_lock) override;
int FileControl(int opcode, void* data) override;
int SectorSize() override;
int DeviceCharacteristics() override;
int ShmMap(int page_index,
int page_size,
int extend_file_if_needed,
void volatile** result) override;
int ShmLock(int offset, int size, int flags) override;
void ShmBarrier() override;
int ShmUnmap(int also_delete_file) override;
int Fetch(sqlite3_int64 offset, int size, void** result) override;
int Unfetch(sqlite3_int64 offset, void* fetch_result) override;
int LockModeForTesting() const { return sqlite_lock_mode_; }
// Permanently marks this database as no longer suitable for use by any
// connection. See `SqliteVfsFileSet::Abandon()` for details.
LockState Abandon();
private:
// Returns true if this instance is likely opened for exclusive access.
// Take care: this is only valid for FileType::kMainDb files.
bool is_single_connection() const { return !shared_locks_; }
// Acquire/release a lock on the underlying file. This is used when the
// creator wishes this to be the only connection allowed to the database.
bool AcquireSingleConnectionlock();
void ReleaseSingleConnectionlock();
const Client client_;
// The type of database file this represents.
const FileType file_type_;
base::File underlying_file_;
base::File opened_file_;
const AccessRights access_rights_;
// One of the SQLite locking mode constants which represent the current lock
// state of this connection (see: https://www.sqlite.org/lockingv3.html).
int sqlite_lock_mode_ = SQLITE_LOCK_NONE;
// If valid, the cross-process shared locks by which the SQLite locking
// protocols are implemented. Otherwise, this file is opened in exclusive mode
// so no shared locks are required.
std::optional<SharedLocks> shared_locks_;
};
} // namespace sqlite_vfs
#endif // COMPONENTS_SQLITE_VFS_SANDBOXED_FILE_H_