| // 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_ |