diff options
Diffstat (limited to 'vendor/github.com/ncruces/go-sqlite3/vfs')
33 files changed, 0 insertions, 4066 deletions
diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/README.md b/vendor/github.com/ncruces/go-sqlite3/vfs/README.md deleted file mode 100644 index 4e987ce3f..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/README.md +++ /dev/null @@ -1,109 +0,0 @@ -# Go SQLite VFS API - -This package implements the SQLite [OS Interface](https://sqlite.org/vfs.html) (aka VFS). - -It replaces the default SQLite VFS with a **pure Go** implementation, -and exposes [interfaces](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs#VFS) -that should allow you to implement your own [custom VFSes](#custom-vfses). - -Since it is a from scratch reimplementation, -there are naturally some ways it deviates from the original. - -The main differences are [file locking](#file-locking) and [WAL mode](#write-ahead-logging) support. - -### File Locking - -POSIX advisory locks, which SQLite uses on Unix, are -[broken by design](https://github.com/sqlite/sqlite/blob/b74eb0/src/os_unix.c#L1073-L1161). -Instead, on Linux and macOS, this package uses -[OFD locks](https://www.gnu.org/software/libc/manual/html_node/Open-File-Description-Locks.html) -to synchronize access to database files. - -This package can also use -[BSD locks](https://man.freebsd.org/cgi/man.cgi?query=flock&sektion=2), -albeit with reduced concurrency (`BEGIN IMMEDIATE` behaves like `BEGIN EXCLUSIVE`). -BSD locks are the default on BSD and illumos, -but you can opt into them with the `sqlite3_flock` build tag. - -On Windows, this package uses `LockFileEx` and `UnlockFileEx`, -like SQLite. - -You can also opt into a cross-platform locking implementation -with the `sqlite3_dotlk` build tag. - -Otherwise, file locking is not supported, and you must use -[`nolock=1`](https://sqlite.org/uri.html#urinolock) -(or [`immutable=1`](https://sqlite.org/uri.html#uriimmutable)) -to open database files. -To use the [`database/sql`](https://pkg.go.dev/database/sql) driver -with `nolock=1` you must disable connection pooling by calling -[`db.SetMaxOpenConns(1)`](https://pkg.go.dev/database/sql#DB.SetMaxOpenConns). - -You can use [`vfs.SupportsFileLocking`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs#SupportsFileLocking) -to check if your build supports file locking. - -### Write-Ahead Logging - -On Unix, this package may use `mmap` to implement -[shared-memory for the WAL-index](https://sqlite.org/wal.html#implementation_of_shared_memory_for_the_wal_index), -like SQLite. - -On Windows, this package may use `MapViewOfFile`, like SQLite. - -You can also opt into a cross-platform, in-process, memory sharing implementation -with the `sqlite3_dotlk` build tag. - -Otherwise, [WAL support is limited](https://sqlite.org/wal.html#noshm), -and `EXCLUSIVE` locking mode must be set to create, read, and write WAL databases. -To use `EXCLUSIVE` locking mode with the -[`database/sql`](https://pkg.go.dev/database/sql) driver -you must disable connection pooling by calling -[`db.SetMaxOpenConns(1)`](https://pkg.go.dev/database/sql#DB.SetMaxOpenConns). - -You can use [`vfs.SupportsSharedMemory`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs#SupportsSharedMemory) -to check if your build supports shared memory. - -### Batch-Atomic Write - -On Linux, this package may support -[batch-atomic writes](https://sqlite.org/cgi/src/technote/714) -on the F2FS filesystem. - -### Checksums - -This package can be [configured](https://pkg.go.dev/github.com/ncruces/go-sqlite3#Conn.EnableChecksums) -to add an 8-byte checksum to the end of every page in an SQLite database. -The checksum is added as each page is written -and verified as each page is read.\ -The checksum is intended to help detect database corruption -caused by random bit-flips in the mass storage device. - -The implementation is compatible with SQLite's -[Checksum VFS Shim](https://sqlite.org/cksumvfs.html). - -### Build Tags - -The VFS can be customized with a few build tags: -- `sqlite3_flock` forces the use of BSD locks. -- `sqlite3_dotlk` forces the use of dot-file locks. - -> [!IMPORTANT] -> The default configuration of this package is compatible with the standard -> [Unix and Windows SQLite VFSes](https://sqlite.org/vfs.html#multiple_vfses); -> `sqlite3_flock` builds are compatible with the -> [`unix-flock` VFS](https://sqlite.org/compile.html#enable_locking_style); -> `sqlite3_dotlk` builds are compatible with the -> [`unix-dotfile` VFS](https://sqlite.org/compile.html#enable_locking_style). -> If incompatible file locking is used, accessing databases concurrently with -> _other_ SQLite libraries will eventually corrupt data. - -### Custom VFSes - -- [`github.com/ncruces/go-sqlite3/vfs/memdb`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/memdb) - implements an in-memory VFS. -- [`github.com/ncruces/go-sqlite3/vfs/readervfs`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/readervfs) - implements a VFS for immutable databases. -- [`github.com/ncruces/go-sqlite3/vfs/adiantum`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/adiantum) - wraps a VFS to offer encryption at rest. -- [`github.com/ncruces/go-sqlite3/vfs/xts`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/vfs/xts) - wraps a VFS to offer encryption at rest. diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/api.go b/vendor/github.com/ncruces/go-sqlite3/vfs/api.go deleted file mode 100644 index d5bb3a7ae..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/api.go +++ /dev/null @@ -1,216 +0,0 @@ -// Package vfs wraps the C SQLite VFS API. -package vfs - -import ( - "context" - "io" - - "github.com/tetratelabs/wazero/api" -) - -// A VFS defines the interface between the SQLite core and the underlying operating system. -// -// Use sqlite3.ErrorCode or sqlite3.ExtendedErrorCode to return specific error codes to SQLite. -// -// https://sqlite.org/c3ref/vfs.html -type VFS interface { - Open(name string, flags OpenFlag) (File, OpenFlag, error) - Delete(name string, syncDir bool) error - Access(name string, flags AccessFlag) (bool, error) - FullPathname(name string) (string, error) -} - -// VFSFilename extends VFS with the ability to use Filename -// objects for opening files. -// -// https://sqlite.org/c3ref/filename.html -type VFSFilename interface { - VFS - OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error) -} - -// A File represents an open file in the OS interface layer. -// -// Use sqlite3.ErrorCode or sqlite3.ExtendedErrorCode to return specific error codes to SQLite. -// In particular, sqlite3.BUSY is necessary to correctly implement lock methods. -// -// https://sqlite.org/c3ref/io_methods.html -type File interface { - Close() error - ReadAt(p []byte, off int64) (n int, err error) - WriteAt(p []byte, off int64) (n int, err error) - Truncate(size int64) error - Sync(flags SyncFlag) error - Size() (int64, error) - Lock(lock LockLevel) error - Unlock(lock LockLevel) error - CheckReservedLock() (bool, error) - SectorSize() int - DeviceCharacteristics() DeviceCharacteristic -} - -// FileUnwrap should be implemented by a File -// that wraps another File implementation. -type FileUnwrap interface { - File - Unwrap() File -} - -// FileLockState extends File to implement the -// SQLITE_FCNTL_LOCKSTATE file control opcode. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntllockstate -type FileLockState interface { - File - LockState() LockLevel -} - -// FilePersistWAL extends File to implement the -// SQLITE_FCNTL_PERSIST_WAL file control opcode. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlpersistwal -type FilePersistWAL interface { - File - PersistWAL() bool - SetPersistWAL(bool) -} - -// FilePowersafeOverwrite extends File to implement the -// SQLITE_FCNTL_POWERSAFE_OVERWRITE file control opcode. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlpowersafeoverwrite -type FilePowersafeOverwrite interface { - File - PowersafeOverwrite() bool - SetPowersafeOverwrite(bool) -} - -// FileChunkSize extends File to implement the -// SQLITE_FCNTL_CHUNK_SIZE file control opcode. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlchunksize -type FileChunkSize interface { - File - ChunkSize(size int) -} - -// FileSizeHint extends File to implement the -// SQLITE_FCNTL_SIZE_HINT file control opcode. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlsizehint -type FileSizeHint interface { - File - SizeHint(size int64) error -} - -// FileHasMoved extends File to implement the -// SQLITE_FCNTL_HAS_MOVED file control opcode. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlhasmoved -type FileHasMoved interface { - File - HasMoved() (bool, error) -} - -// FileOverwrite extends File to implement the -// SQLITE_FCNTL_OVERWRITE file control opcode. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntloverwrite -type FileOverwrite interface { - File - Overwrite() error -} - -// FileSync extends File to implement the -// SQLITE_FCNTL_SYNC file control opcode. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlsync -type FileSync interface { - File - SyncSuper(super string) error -} - -// FileCommitPhaseTwo extends File to implement the -// SQLITE_FCNTL_COMMIT_PHASETWO file control opcode. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlcommitphasetwo -type FileCommitPhaseTwo interface { - File - CommitPhaseTwo() error -} - -// FileBatchAtomicWrite extends File to implement the -// SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE -// and SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE file control opcodes. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlbeginatomicwrite -type FileBatchAtomicWrite interface { - File - BeginAtomicWrite() error - CommitAtomicWrite() error - RollbackAtomicWrite() error -} - -// FileCheckpoint extends File to implement the -// SQLITE_FCNTL_CKPT_START and SQLITE_FCNTL_CKPT_DONE -// file control opcodes. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlckptstart -type FileCheckpoint interface { - File - CheckpointStart() - CheckpointDone() -} - -// FilePragma extends File to implement the -// SQLITE_FCNTL_PRAGMA file control opcode. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlpragma -type FilePragma interface { - File - Pragma(name, value string) (string, error) -} - -// FileBusyHandler extends File to implement the -// SQLITE_FCNTL_BUSYHANDLER file control opcode. -// -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlbusyhandler -type FileBusyHandler interface { - File - BusyHandler(func() bool) -} - -// FileSharedMemory extends File to possibly implement -// shared-memory for the WAL-index. -// The same shared-memory instance must be returned -// for the entire life of the file. -// It's OK for SharedMemory to return nil. -type FileSharedMemory interface { - File - SharedMemory() SharedMemory -} - -// SharedMemory is a shared-memory WAL-index implementation. -// Use [NewSharedMemory] to create a shared-memory. -type SharedMemory interface { - shmMap(context.Context, api.Module, int32, int32, bool) (ptr_t, _ErrorCode) - shmLock(int32, int32, _ShmFlag) _ErrorCode - shmUnmap(bool) - shmBarrier() - io.Closer -} - -type blockingSharedMemory interface { - SharedMemory - shmEnableBlocking(block bool) -} - -type fileControl interface { - File - fileControl(ctx context.Context, mod api.Module, op _FcntlOpcode, pArg ptr_t) _ErrorCode -} - -type filePDB interface { - File - SetDB(any) -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/cksm.go b/vendor/github.com/ncruces/go-sqlite3/vfs/cksm.go deleted file mode 100644 index 39493df99..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/cksm.go +++ /dev/null @@ -1,157 +0,0 @@ -package vfs - -import ( - "bytes" - "context" - _ "embed" - "encoding/binary" - "strconv" - - "github.com/tetratelabs/wazero/api" - - "github.com/ncruces/go-sqlite3/internal/util" - "github.com/ncruces/go-sqlite3/util/sql3util" -) - -func cksmWrapFile(name *Filename, flags OpenFlag, file File) File { - // Checksum only main databases and WALs. - if flags&(OPEN_MAIN_DB|OPEN_WAL) == 0 { - return file - } - - cksm := cksmFile{File: file} - - if flags&OPEN_WAL != 0 { - main, _ := name.DatabaseFile().(cksmFile) - cksm.cksmFlags = main.cksmFlags - } else { - cksm.cksmFlags = new(cksmFlags) - cksm.isDB = true - } - - return cksm -} - -type cksmFile struct { - File - *cksmFlags - isDB bool -} - -type cksmFlags struct { - computeCksm bool - verifyCksm bool - inCkpt bool - pageSize int -} - -func (c cksmFile) ReadAt(p []byte, off int64) (n int, err error) { - n, err = c.File.ReadAt(p, off) - - // SQLite is reading the header of a database file. - if c.isDB && off == 0 && len(p) >= 100 && - bytes.HasPrefix(p, []byte("SQLite format 3\000")) { - c.init(p) - } - - // Verify checksums. - if c.verifyCksm && !c.inCkpt && len(p) == c.pageSize { - cksm1 := cksmCompute(p[:len(p)-8]) - cksm2 := *(*[8]byte)(p[len(p)-8:]) - if cksm1 != cksm2 { - return 0, _IOERR_DATA - } - } - return n, err -} - -func (c cksmFile) WriteAt(p []byte, off int64) (n int, err error) { - // SQLite is writing the first page of a database file. - if c.isDB && off == 0 && len(p) >= 100 && - bytes.HasPrefix(p, []byte("SQLite format 3\000")) { - c.init(p) - } - - // Compute checksums. - if c.computeCksm && !c.inCkpt && len(p) == c.pageSize { - *(*[8]byte)(p[len(p)-8:]) = cksmCompute(p[:len(p)-8]) - } - - return c.File.WriteAt(p, off) -} - -func (c cksmFile) Pragma(name string, value string) (string, error) { - switch name { - case "checksum_verification": - b, ok := sql3util.ParseBool(value) - if ok { - c.verifyCksm = b && c.computeCksm - } - if !c.verifyCksm { - return "0", nil - } - return "1", nil - - case "page_size": - if c.computeCksm { - // Do not allow page size changes on a checksum database. - return strconv.Itoa(c.pageSize), nil - } - } - return "", _NOTFOUND -} - -func (c cksmFile) DeviceCharacteristics() DeviceCharacteristic { - ret := c.File.DeviceCharacteristics() - if c.verifyCksm { - ret &^= IOCAP_SUBPAGE_READ - } - return ret -} - -func (c cksmFile) fileControl(ctx context.Context, mod api.Module, op _FcntlOpcode, pArg ptr_t) _ErrorCode { - switch op { - case _FCNTL_CKPT_START: - c.inCkpt = true - case _FCNTL_CKPT_DONE: - c.inCkpt = false - } - if rc := vfsFileControlImpl(ctx, mod, c, op, pArg); rc != _NOTFOUND { - return rc - } - return vfsFileControlImpl(ctx, mod, c.File, op, pArg) -} - -func (f *cksmFlags) init(header []byte) { - f.pageSize = 256 * int(binary.LittleEndian.Uint16(header[16:18])) - if r := header[20] == 8; r != f.computeCksm { - f.computeCksm = r - f.verifyCksm = r - } -} - -func cksmCompute(a []byte) (cksm [8]byte) { - var s1, s2 uint32 - for len(a) >= 8 { - s1 += binary.LittleEndian.Uint32(a[0:4]) + s2 - s2 += binary.LittleEndian.Uint32(a[4:8]) + s1 - a = a[8:] - } - if len(a) != 0 { - panic(util.AssertErr()) - } - binary.LittleEndian.PutUint32(cksm[0:4], s1) - binary.LittleEndian.PutUint32(cksm[4:8], s2) - return -} - -func (c cksmFile) SharedMemory() SharedMemory { - if f, ok := c.File.(FileSharedMemory); ok { - return f.SharedMemory() - } - return nil -} - -func (c cksmFile) Unwrap() File { - return c.File -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/const.go b/vendor/github.com/ncruces/go-sqlite3/vfs/const.go deleted file mode 100644 index dc3b0db83..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/const.go +++ /dev/null @@ -1,248 +0,0 @@ -package vfs - -import "github.com/ncruces/go-sqlite3/internal/util" - -const ( - _MAX_NAME = 1e6 // Self-imposed limit for most NUL terminated strings. - _MAX_SQL_LENGTH = 1e9 - _MAX_PATHNAME = 1024 - _DEFAULT_SECTOR_SIZE = 4096 - - ptrlen = util.PtrLen -) - -type ( - stk_t = util.Stk_t - ptr_t = util.Ptr_t -) - -// https://sqlite.org/rescode.html -type _ErrorCode uint32 - -func (e _ErrorCode) Error() string { - return util.ErrorCodeString(uint32(e)) -} - -const ( - _OK _ErrorCode = util.OK - _ERROR _ErrorCode = util.ERROR - _PERM _ErrorCode = util.PERM - _BUSY _ErrorCode = util.BUSY - _READONLY _ErrorCode = util.READONLY - _IOERR _ErrorCode = util.IOERR - _NOTFOUND _ErrorCode = util.NOTFOUND - _CANTOPEN _ErrorCode = util.CANTOPEN - _IOERR_READ _ErrorCode = util.IOERR_READ - _IOERR_SHORT_READ _ErrorCode = util.IOERR_SHORT_READ - _IOERR_WRITE _ErrorCode = util.IOERR_WRITE - _IOERR_FSYNC _ErrorCode = util.IOERR_FSYNC - _IOERR_DIR_FSYNC _ErrorCode = util.IOERR_DIR_FSYNC - _IOERR_TRUNCATE _ErrorCode = util.IOERR_TRUNCATE - _IOERR_FSTAT _ErrorCode = util.IOERR_FSTAT - _IOERR_UNLOCK _ErrorCode = util.IOERR_UNLOCK - _IOERR_RDLOCK _ErrorCode = util.IOERR_RDLOCK - _IOERR_DELETE _ErrorCode = util.IOERR_DELETE - _IOERR_ACCESS _ErrorCode = util.IOERR_ACCESS - _IOERR_CHECKRESERVEDLOCK _ErrorCode = util.IOERR_CHECKRESERVEDLOCK - _IOERR_LOCK _ErrorCode = util.IOERR_LOCK - _IOERR_CLOSE _ErrorCode = util.IOERR_CLOSE - _IOERR_SHMOPEN _ErrorCode = util.IOERR_SHMOPEN - _IOERR_SHMSIZE _ErrorCode = util.IOERR_SHMSIZE - _IOERR_SHMLOCK _ErrorCode = util.IOERR_SHMLOCK - _IOERR_SHMMAP _ErrorCode = util.IOERR_SHMMAP - _IOERR_SEEK _ErrorCode = util.IOERR_SEEK - _IOERR_DELETE_NOENT _ErrorCode = util.IOERR_DELETE_NOENT - _IOERR_GETTEMPPATH _ErrorCode = util.IOERR_GETTEMPPATH - _IOERR_BEGIN_ATOMIC _ErrorCode = util.IOERR_BEGIN_ATOMIC - _IOERR_COMMIT_ATOMIC _ErrorCode = util.IOERR_COMMIT_ATOMIC - _IOERR_ROLLBACK_ATOMIC _ErrorCode = util.IOERR_ROLLBACK_ATOMIC - _IOERR_DATA _ErrorCode = util.IOERR_DATA - _BUSY_SNAPSHOT _ErrorCode = util.BUSY_SNAPSHOT - _CANTOPEN_FULLPATH _ErrorCode = util.CANTOPEN_FULLPATH - _CANTOPEN_ISDIR _ErrorCode = util.CANTOPEN_ISDIR - _READONLY_CANTINIT _ErrorCode = util.READONLY_CANTINIT - _OK_SYMLINK _ErrorCode = util.OK_SYMLINK -) - -// OpenFlag is a flag for the [VFS] Open method. -// -// https://sqlite.org/c3ref/c_open_autoproxy.html -type OpenFlag uint32 - -const ( - OPEN_READONLY OpenFlag = 0x00000001 /* Ok for sqlite3_open_v2() */ - OPEN_READWRITE OpenFlag = 0x00000002 /* Ok for sqlite3_open_v2() */ - OPEN_CREATE OpenFlag = 0x00000004 /* Ok for sqlite3_open_v2() */ - OPEN_DELETEONCLOSE OpenFlag = 0x00000008 /* VFS only */ - OPEN_EXCLUSIVE OpenFlag = 0x00000010 /* VFS only */ - OPEN_AUTOPROXY OpenFlag = 0x00000020 /* VFS only */ - OPEN_URI OpenFlag = 0x00000040 /* Ok for sqlite3_open_v2() */ - OPEN_MEMORY OpenFlag = 0x00000080 /* Ok for sqlite3_open_v2() */ - OPEN_MAIN_DB OpenFlag = 0x00000100 /* VFS only */ - OPEN_TEMP_DB OpenFlag = 0x00000200 /* VFS only */ - OPEN_TRANSIENT_DB OpenFlag = 0x00000400 /* VFS only */ - OPEN_MAIN_JOURNAL OpenFlag = 0x00000800 /* VFS only */ - OPEN_TEMP_JOURNAL OpenFlag = 0x00001000 /* VFS only */ - OPEN_SUBJOURNAL OpenFlag = 0x00002000 /* VFS only */ - OPEN_SUPER_JOURNAL OpenFlag = 0x00004000 /* VFS only */ - OPEN_NOMUTEX OpenFlag = 0x00008000 /* Ok for sqlite3_open_v2() */ - OPEN_FULLMUTEX OpenFlag = 0x00010000 /* Ok for sqlite3_open_v2() */ - OPEN_SHAREDCACHE OpenFlag = 0x00020000 /* Ok for sqlite3_open_v2() */ - OPEN_PRIVATECACHE OpenFlag = 0x00040000 /* Ok for sqlite3_open_v2() */ - OPEN_WAL OpenFlag = 0x00080000 /* VFS only */ - OPEN_NOFOLLOW OpenFlag = 0x01000000 /* Ok for sqlite3_open_v2() */ -) - -// AccessFlag is a flag for the [VFS] Access method. -// -// https://sqlite.org/c3ref/c_access_exists.html -type AccessFlag uint32 - -const ( - ACCESS_EXISTS AccessFlag = 0 - ACCESS_READWRITE AccessFlag = 1 /* Used by PRAGMA temp_store_directory */ - ACCESS_READ AccessFlag = 2 /* Unused */ -) - -// SyncFlag is a flag for the [File] Sync method. -// -// https://sqlite.org/c3ref/c_sync_dataonly.html -type SyncFlag uint32 - -const ( - SYNC_NORMAL SyncFlag = 0x00002 - SYNC_FULL SyncFlag = 0x00003 - SYNC_DATAONLY SyncFlag = 0x00010 -) - -// LockLevel is a value used with [File] Lock and Unlock methods. -// -// https://sqlite.org/c3ref/c_lock_exclusive.html -type LockLevel uint32 - -const ( - // No locks are held on the database. - // The database may be neither read nor written. - // Any internally cached data is considered suspect and subject to - // verification against the database file before being used. - // Other processes can read or write the database as their own locking - // states permit. - // This is the default state. - LOCK_NONE LockLevel = 0 /* xUnlock() only */ - - // The database may be read but not written. - // Any number of processes can hold SHARED locks at the same time, - // hence there can be many simultaneous readers. - // But no other thread or process is allowed to write to the database file - // while one or more SHARED locks are active. - LOCK_SHARED LockLevel = 1 /* xLock() or xUnlock() */ - - // A RESERVED lock means that the process is planning on writing to the - // database file at some point in the future but that it is currently just - // reading from the file. - // Only a single RESERVED lock may be active at one time, - // though multiple SHARED locks can coexist with a single RESERVED lock. - // RESERVED differs from PENDING in that new SHARED locks can be acquired - // while there is a RESERVED lock. - LOCK_RESERVED LockLevel = 2 /* xLock() only */ - - // A PENDING lock means that the process holding the lock wants to write to - // the database as soon as possible and is just waiting on all current - // SHARED locks to clear so that it can get an EXCLUSIVE lock. - // No new SHARED locks are permitted against the database if a PENDING lock - // is active, though existing SHARED locks are allowed to continue. - LOCK_PENDING LockLevel = 3 /* internal use only */ - - // An EXCLUSIVE lock is needed in order to write to the database file. - // Only one EXCLUSIVE lock is allowed on the file and no other locks of any - // kind are allowed to coexist with an EXCLUSIVE lock. - // In order to maximize concurrency, SQLite works to minimize the amount of - // time that EXCLUSIVE locks are held. - LOCK_EXCLUSIVE LockLevel = 4 /* xLock() only */ -) - -// DeviceCharacteristic is a flag retuned by the [File] DeviceCharacteristics method. -// -// https://sqlite.org/c3ref/c_iocap_atomic.html -type DeviceCharacteristic uint32 - -const ( - IOCAP_ATOMIC DeviceCharacteristic = 0x00000001 - IOCAP_ATOMIC512 DeviceCharacteristic = 0x00000002 - IOCAP_ATOMIC1K DeviceCharacteristic = 0x00000004 - IOCAP_ATOMIC2K DeviceCharacteristic = 0x00000008 - IOCAP_ATOMIC4K DeviceCharacteristic = 0x00000010 - IOCAP_ATOMIC8K DeviceCharacteristic = 0x00000020 - IOCAP_ATOMIC16K DeviceCharacteristic = 0x00000040 - IOCAP_ATOMIC32K DeviceCharacteristic = 0x00000080 - IOCAP_ATOMIC64K DeviceCharacteristic = 0x00000100 - IOCAP_SAFE_APPEND DeviceCharacteristic = 0x00000200 - IOCAP_SEQUENTIAL DeviceCharacteristic = 0x00000400 - IOCAP_UNDELETABLE_WHEN_OPEN DeviceCharacteristic = 0x00000800 - IOCAP_POWERSAFE_OVERWRITE DeviceCharacteristic = 0x00001000 - IOCAP_IMMUTABLE DeviceCharacteristic = 0x00002000 - IOCAP_BATCH_ATOMIC DeviceCharacteristic = 0x00004000 - IOCAP_SUBPAGE_READ DeviceCharacteristic = 0x00008000 -) - -// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html -type _FcntlOpcode uint32 - -const ( - _FCNTL_LOCKSTATE _FcntlOpcode = 1 - _FCNTL_GET_LOCKPROXYFILE _FcntlOpcode = 2 - _FCNTL_SET_LOCKPROXYFILE _FcntlOpcode = 3 - _FCNTL_LAST_ERRNO _FcntlOpcode = 4 - _FCNTL_SIZE_HINT _FcntlOpcode = 5 - _FCNTL_CHUNK_SIZE _FcntlOpcode = 6 - _FCNTL_FILE_POINTER _FcntlOpcode = 7 - _FCNTL_SYNC_OMITTED _FcntlOpcode = 8 - _FCNTL_WIN32_AV_RETRY _FcntlOpcode = 9 - _FCNTL_PERSIST_WAL _FcntlOpcode = 10 - _FCNTL_OVERWRITE _FcntlOpcode = 11 - _FCNTL_VFSNAME _FcntlOpcode = 12 - _FCNTL_POWERSAFE_OVERWRITE _FcntlOpcode = 13 - _FCNTL_PRAGMA _FcntlOpcode = 14 - _FCNTL_BUSYHANDLER _FcntlOpcode = 15 - _FCNTL_TEMPFILENAME _FcntlOpcode = 16 - _FCNTL_MMAP_SIZE _FcntlOpcode = 18 - _FCNTL_TRACE _FcntlOpcode = 19 - _FCNTL_HAS_MOVED _FcntlOpcode = 20 - _FCNTL_SYNC _FcntlOpcode = 21 - _FCNTL_COMMIT_PHASETWO _FcntlOpcode = 22 - _FCNTL_WIN32_SET_HANDLE _FcntlOpcode = 23 - _FCNTL_WAL_BLOCK _FcntlOpcode = 24 - _FCNTL_ZIPVFS _FcntlOpcode = 25 - _FCNTL_RBU _FcntlOpcode = 26 - _FCNTL_VFS_POINTER _FcntlOpcode = 27 - _FCNTL_JOURNAL_POINTER _FcntlOpcode = 28 - _FCNTL_WIN32_GET_HANDLE _FcntlOpcode = 29 - _FCNTL_PDB _FcntlOpcode = 30 - _FCNTL_BEGIN_ATOMIC_WRITE _FcntlOpcode = 31 - _FCNTL_COMMIT_ATOMIC_WRITE _FcntlOpcode = 32 - _FCNTL_ROLLBACK_ATOMIC_WRITE _FcntlOpcode = 33 - _FCNTL_LOCK_TIMEOUT _FcntlOpcode = 34 - _FCNTL_DATA_VERSION _FcntlOpcode = 35 - _FCNTL_SIZE_LIMIT _FcntlOpcode = 36 - _FCNTL_CKPT_DONE _FcntlOpcode = 37 - _FCNTL_RESERVE_BYTES _FcntlOpcode = 38 - _FCNTL_CKPT_START _FcntlOpcode = 39 - _FCNTL_EXTERNAL_READER _FcntlOpcode = 40 - _FCNTL_CKSM_FILE _FcntlOpcode = 41 - _FCNTL_RESET_CACHE _FcntlOpcode = 42 - _FCNTL_NULL_IO _FcntlOpcode = 43 -) - -// https://sqlite.org/c3ref/c_shm_exclusive.html -type _ShmFlag uint32 - -const ( - _SHM_UNLOCK _ShmFlag = 1 - _SHM_LOCK _ShmFlag = 2 - _SHM_SHARED _ShmFlag = 4 - _SHM_EXCLUSIVE _ShmFlag = 8 - - _SHM_NLOCK = 8 - _SHM_BASE = 120 - _SHM_DMS = _SHM_BASE + _SHM_NLOCK -) diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/file.go b/vendor/github.com/ncruces/go-sqlite3/vfs/file.go deleted file mode 100644 index bc90555e7..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/file.go +++ /dev/null @@ -1,222 +0,0 @@ -package vfs - -import ( - "errors" - "io" - "io/fs" - "os" - "path/filepath" - "syscall" - - "github.com/ncruces/go-sqlite3/util/osutil" -) - -type vfsOS struct{} - -func (vfsOS) FullPathname(path string) (string, error) { - path, err := filepath.Abs(path) - if err != nil { - return "", err - } - return path, testSymlinks(filepath.Dir(path)) -} - -func testSymlinks(path string) error { - p, err := filepath.EvalSymlinks(path) - if err != nil { - return err - } - if p != path { - return _OK_SYMLINK - } - return nil -} - -func (vfsOS) Delete(path string, syncDir bool) error { - err := os.Remove(path) - if errors.Is(err, fs.ErrNotExist) { - return _IOERR_DELETE_NOENT - } - if err != nil { - return err - } - if canSyncDirs && syncDir { - f, err := os.Open(filepath.Dir(path)) - if err != nil { - return _OK - } - defer f.Close() - err = osSync(f, false, false) - if err != nil { - return _IOERR_DIR_FSYNC - } - } - return nil -} - -func (vfsOS) Access(name string, flags AccessFlag) (bool, error) { - err := osAccess(name, flags) - if flags == ACCESS_EXISTS { - if errors.Is(err, fs.ErrNotExist) { - return false, nil - } - } else { - if errors.Is(err, fs.ErrPermission) { - return false, nil - } - } - return err == nil, err -} - -func (vfsOS) Open(name string, flags OpenFlag) (File, OpenFlag, error) { - // notest // OpenFilename is called instead - return nil, 0, _CANTOPEN -} - -func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error) { - oflags := _O_NOFOLLOW - if flags&OPEN_EXCLUSIVE != 0 { - oflags |= os.O_EXCL - } - if flags&OPEN_CREATE != 0 { - oflags |= os.O_CREATE - } - if flags&OPEN_READONLY != 0 { - oflags |= os.O_RDONLY - } - if flags&OPEN_READWRITE != 0 { - oflags |= os.O_RDWR - } - - var err error - var f *os.File - if name == nil { - f, err = os.CreateTemp("", "*.db") - } else { - f, err = osutil.OpenFile(name.String(), oflags, 0666) - } - if err != nil { - if name == nil { - return nil, flags, _IOERR_GETTEMPPATH - } - if errors.Is(err, syscall.EISDIR) { - return nil, flags, _CANTOPEN_ISDIR - } - return nil, flags, err - } - - if modeof := name.URIParameter("modeof"); modeof != "" { - if err = osSetMode(f, modeof); err != nil { - f.Close() - return nil, flags, _IOERR_FSTAT - } - } - if flags&OPEN_DELETEONCLOSE != 0 { - os.Remove(f.Name()) - } - - file := vfsFile{ - File: f, - psow: true, - readOnly: flags&OPEN_READONLY != 0, - syncDir: canSyncDirs && - flags&(OPEN_MAIN_JOURNAL|OPEN_SUPER_JOURNAL|OPEN_WAL) != 0 && - flags&(OPEN_CREATE) != 0, - shm: NewSharedMemory(name.String()+"-shm", flags), - } - return &file, flags, nil -} - -type vfsFile struct { - *os.File - shm SharedMemory - lock LockLevel - readOnly bool - keepWAL bool - syncDir bool - psow bool -} - -var ( - // Ensure these interfaces are implemented: - _ FileLockState = &vfsFile{} - _ FileHasMoved = &vfsFile{} - _ FileSizeHint = &vfsFile{} - _ FilePersistWAL = &vfsFile{} - _ FilePowersafeOverwrite = &vfsFile{} -) - -func (f *vfsFile) Close() error { - if f.shm != nil { - f.shm.Close() - } - f.Unlock(LOCK_NONE) - return f.File.Close() -} - -func (f *vfsFile) Sync(flags SyncFlag) error { - dataonly := (flags & SYNC_DATAONLY) != 0 - fullsync := (flags & 0x0f) == SYNC_FULL - - err := osSync(f.File, fullsync, dataonly) - if err != nil { - return err - } - if canSyncDirs && f.syncDir { - f.syncDir = false - d, err := os.Open(filepath.Dir(f.File.Name())) - if err != nil { - return nil - } - defer d.Close() - err = osSync(d, false, false) - if err != nil { - return _IOERR_DIR_FSYNC - } - } - return nil -} - -func (f *vfsFile) Size() (int64, error) { - return f.Seek(0, io.SeekEnd) -} - -func (f *vfsFile) SectorSize() int { - return _DEFAULT_SECTOR_SIZE -} - -func (f *vfsFile) DeviceCharacteristics() DeviceCharacteristic { - ret := IOCAP_SUBPAGE_READ - if osBatchAtomic(f.File) { - ret |= IOCAP_BATCH_ATOMIC - } - if f.psow { - ret |= IOCAP_POWERSAFE_OVERWRITE - } - return ret -} - -func (f *vfsFile) SizeHint(size int64) error { - return osAllocate(f.File, size) -} - -func (f *vfsFile) HasMoved() (bool, error) { - fi, err := f.Stat() - if err != nil { - return false, err - } - pi, err := os.Stat(f.Name()) - if errors.Is(err, fs.ErrNotExist) { - return true, nil - } - if err != nil { - return false, err - } - return !os.SameFile(fi, pi), nil -} - -func (f *vfsFile) LockState() LockLevel { return f.lock } -func (f *vfsFile) PowersafeOverwrite() bool { return f.psow } -func (f *vfsFile) PersistWAL() bool { return f.keepWAL } -func (f *vfsFile) SetPowersafeOverwrite(psow bool) { f.psow = psow } -func (f *vfsFile) SetPersistWAL(keepWAL bool) { f.keepWAL = keepWAL } diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/filename.go b/vendor/github.com/ncruces/go-sqlite3/vfs/filename.go deleted file mode 100644 index 965c3b1a6..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/filename.go +++ /dev/null @@ -1,179 +0,0 @@ -package vfs - -import ( - "context" - "net/url" - - "github.com/tetratelabs/wazero/api" - - "github.com/ncruces/go-sqlite3/internal/util" -) - -// Filename is used by SQLite to pass filenames -// to the Open method of a VFS. -// -// https://sqlite.org/c3ref/filename.html -type Filename struct { - ctx context.Context - mod api.Module - zPath ptr_t - flags OpenFlag - stack [2]stk_t -} - -// GetFilename is an internal API users should not call directly. -func GetFilename(ctx context.Context, mod api.Module, id ptr_t, flags OpenFlag) *Filename { - if id == 0 { - return nil - } - return &Filename{ - ctx: ctx, - mod: mod, - zPath: id, - flags: flags, - } -} - -// String returns this filename as a string. -func (n *Filename) String() string { - if n == nil || n.zPath == 0 { - return "" - } - return util.ReadString(n.mod, n.zPath, _MAX_PATHNAME) -} - -// Database returns the name of the corresponding database file. -// -// https://sqlite.org/c3ref/filename_database.html -func (n *Filename) Database() string { - return n.path("sqlite3_filename_database") -} - -// Journal returns the name of the corresponding rollback journal file. -// -// https://sqlite.org/c3ref/filename_database.html -func (n *Filename) Journal() string { - return n.path("sqlite3_filename_journal") -} - -// Journal returns the name of the corresponding WAL file. -// -// https://sqlite.org/c3ref/filename_database.html -func (n *Filename) WAL() string { - return n.path("sqlite3_filename_wal") -} - -func (n *Filename) path(method string) string { - if n == nil || n.zPath == 0 { - return "" - } - if n.flags&(OPEN_MAIN_DB|OPEN_MAIN_JOURNAL|OPEN_WAL) == 0 { - return "" - } - - n.stack[0] = stk_t(n.zPath) - fn := n.mod.ExportedFunction(method) - if err := fn.CallWithStack(n.ctx, n.stack[:]); err != nil { - panic(err) - } - return util.ReadString(n.mod, ptr_t(n.stack[0]), _MAX_PATHNAME) -} - -// DatabaseFile returns the main database [File] corresponding to a journal. -// -// https://sqlite.org/c3ref/database_file_object.html -func (n *Filename) DatabaseFile() File { - if n == nil || n.zPath == 0 { - return nil - } - if n.flags&(OPEN_MAIN_DB|OPEN_MAIN_JOURNAL|OPEN_WAL) == 0 { - return nil - } - - n.stack[0] = stk_t(n.zPath) - fn := n.mod.ExportedFunction("sqlite3_database_file_object") - if err := fn.CallWithStack(n.ctx, n.stack[:]); err != nil { - panic(err) - } - file, _ := vfsFileGet(n.ctx, n.mod, ptr_t(n.stack[0])).(File) - return file -} - -// URIParameter returns the value of a URI parameter. -// -// https://sqlite.org/c3ref/uri_boolean.html -func (n *Filename) URIParameter(key string) string { - if n == nil || n.zPath == 0 { - return "" - } - - uriKey := n.mod.ExportedFunction("sqlite3_uri_key") - n.stack[0] = stk_t(n.zPath) - n.stack[1] = stk_t(0) - if err := uriKey.CallWithStack(n.ctx, n.stack[:]); err != nil { - panic(err) - } - - ptr := ptr_t(n.stack[0]) - if ptr == 0 { - return "" - } - - // Parse the format from: - // https://github.com/sqlite/sqlite/blob/b74eb0/src/pager.c#L4797-L4840 - // This avoids having to alloc/free the key just to find a value. - for { - k := util.ReadString(n.mod, ptr, _MAX_NAME) - if k == "" { - return "" - } - ptr += ptr_t(len(k)) + 1 - - v := util.ReadString(n.mod, ptr, _MAX_NAME) - if k == key { - return v - } - ptr += ptr_t(len(v)) + 1 - } -} - -// URIParameters obtains values for URI parameters. -// -// https://sqlite.org/c3ref/uri_boolean.html -func (n *Filename) URIParameters() url.Values { - if n == nil || n.zPath == 0 { - return nil - } - - uriKey := n.mod.ExportedFunction("sqlite3_uri_key") - n.stack[0] = stk_t(n.zPath) - n.stack[1] = stk_t(0) - if err := uriKey.CallWithStack(n.ctx, n.stack[:]); err != nil { - panic(err) - } - - ptr := ptr_t(n.stack[0]) - if ptr == 0 { - return nil - } - - var params url.Values - - // Parse the format from: - // https://github.com/sqlite/sqlite/blob/b74eb0/src/pager.c#L4797-L4840 - // This is the only way to support multiple valued keys. - for { - k := util.ReadString(n.mod, ptr, _MAX_NAME) - if k == "" { - return params - } - ptr += ptr_t(len(k)) + 1 - - v := util.ReadString(n.mod, ptr, _MAX_NAME) - if params == nil { - params = url.Values{} - } - params.Add(k, v) - ptr += ptr_t(len(v)) + 1 - } -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/lock.go b/vendor/github.com/ncruces/go-sqlite3/vfs/lock.go deleted file mode 100644 index b28d83230..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/lock.go +++ /dev/null @@ -1,128 +0,0 @@ -//go:build linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock || sqlite3_dotlk - -package vfs - -import "github.com/ncruces/go-sqlite3/internal/util" - -// SupportsFileLocking is false on platforms that do not support file locking. -// To open a database file on those platforms, -// you need to use the [nolock] or [immutable] URI parameters. -// -// [nolock]: https://sqlite.org/uri.html#urinolock -// [immutable]: https://sqlite.org/uri.html#uriimmutable -const SupportsFileLocking = true - -const ( - _PENDING_BYTE = 0x40000000 - _RESERVED_BYTE = (_PENDING_BYTE + 1) - _SHARED_FIRST = (_PENDING_BYTE + 2) - _SHARED_SIZE = 510 -) - -func (f *vfsFile) Lock(lock LockLevel) error { - switch { - case lock != LOCK_SHARED && lock != LOCK_RESERVED && lock != LOCK_EXCLUSIVE: - // Argument check. SQLite never explicitly requests a pending lock. - panic(util.AssertErr()) - case f.lock < LOCK_NONE || f.lock > LOCK_EXCLUSIVE: - // Connection state check. - panic(util.AssertErr()) - case f.lock == LOCK_NONE && lock > LOCK_SHARED: - // We never move from unlocked to anything higher than a shared lock. - panic(util.AssertErr()) - case f.lock != LOCK_SHARED && lock == LOCK_RESERVED: - // A shared lock is always held when a reserved lock is requested. - panic(util.AssertErr()) - } - - // If we already have an equal or more restrictive lock, do nothing. - if f.lock >= lock { - return nil - } - - // Do not allow any kind of write-lock on a read-only database. - if f.readOnly && lock >= LOCK_RESERVED { - return _IOERR_LOCK - } - - switch lock { - case LOCK_SHARED: - // Must be unlocked to get SHARED. - if f.lock != LOCK_NONE { - panic(util.AssertErr()) - } - if rc := osGetSharedLock(f.File); rc != _OK { - return rc - } - f.lock = LOCK_SHARED - return nil - - case LOCK_RESERVED: - // Must be SHARED to get RESERVED. - if f.lock != LOCK_SHARED { - panic(util.AssertErr()) - } - if rc := osGetReservedLock(f.File); rc != _OK { - return rc - } - f.lock = LOCK_RESERVED - return nil - - case LOCK_EXCLUSIVE: - // Must be SHARED, RESERVED or PENDING to get EXCLUSIVE. - if f.lock <= LOCK_NONE || f.lock >= LOCK_EXCLUSIVE { - panic(util.AssertErr()) - } - if rc := osGetExclusiveLock(f.File, &f.lock); rc != _OK { - return rc - } - f.lock = LOCK_EXCLUSIVE - return nil - - default: - panic(util.AssertErr()) - } -} - -func (f *vfsFile) Unlock(lock LockLevel) error { - switch { - case lock != LOCK_NONE && lock != LOCK_SHARED: - // Argument check. - panic(util.AssertErr()) - case f.lock < LOCK_NONE || f.lock > LOCK_EXCLUSIVE: - // Connection state check. - panic(util.AssertErr()) - } - - // If we don't have a more restrictive lock, do nothing. - if f.lock <= lock { - return nil - } - - switch lock { - case LOCK_SHARED: - rc := osDowngradeLock(f.File, f.lock) - f.lock = LOCK_SHARED - return rc - - case LOCK_NONE: - rc := osReleaseLock(f.File, f.lock) - f.lock = LOCK_NONE - return rc - - default: - panic(util.AssertErr()) - } -} - -func (f *vfsFile) CheckReservedLock() (bool, error) { - // Connection state check. - if f.lock < LOCK_NONE || f.lock > LOCK_EXCLUSIVE { - panic(util.AssertErr()) - } - - if f.lock >= LOCK_RESERVED { - return true, nil - } - return osCheckReservedLock(f.File) -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/lock_other.go b/vendor/github.com/ncruces/go-sqlite3/vfs/lock_other.go deleted file mode 100644 index 9bdfa3cf2..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/lock_other.go +++ /dev/null @@ -1,23 +0,0 @@ -//go:build !(linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock || sqlite3_dotlk) - -package vfs - -// SupportsFileLocking is false on platforms that do not support file locking. -// To open a database file on those platforms, -// you need to use the [nolock] or [immutable] URI parameters. -// -// [nolock]: https://sqlite.org/uri.html#urinolock -// [immutable]: https://sqlite.org/uri.html#uriimmutable -const SupportsFileLocking = false - -func (f *vfsFile) Lock(LockLevel) error { - return _IOERR_LOCK -} - -func (f *vfsFile) Unlock(LockLevel) error { - return _IOERR_UNLOCK -} - -func (f *vfsFile) CheckReservedLock() (bool, error) { - return false, _IOERR_CHECKRESERVEDLOCK -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/memdb/README.md b/vendor/github.com/ncruces/go-sqlite3/vfs/memdb/README.md deleted file mode 100644 index 2e2611bf8..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/memdb/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Go `memdb` SQLite VFS - -This package implements the [`"memdb"`](https://sqlite.org/src/doc/tip/src/memdb.c) -SQLite VFS in pure Go. - -It has some benefits over the C version: -- the memory backing the database needs not be contiguous, -- the database can grow/shrink incrementally without copying, -- reader-writer concurrency is slightly improved.
\ No newline at end of file diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/memdb/api.go b/vendor/github.com/ncruces/go-sqlite3/vfs/memdb/api.go deleted file mode 100644 index eb12eba09..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/memdb/api.go +++ /dev/null @@ -1,100 +0,0 @@ -// Package memdb implements the "memdb" SQLite VFS. -// -// The "memdb" [vfs.VFS] allows the same in-memory database to be shared -// among multiple database connections in the same process, -// as long as the database name begins with "/". -// -// Importing package memdb registers the VFS: -// -// import _ "github.com/ncruces/go-sqlite3/vfs/memdb" -package memdb - -import ( - "fmt" - "net/url" - "sync" - "testing" - - "github.com/ncruces/go-sqlite3/vfs" -) - -func init() { - vfs.Register("memdb", memVFS{}) -} - -var ( - memoryMtx sync.Mutex - // +checklocks:memoryMtx - memoryDBs = map[string]*memDB{} -) - -// Create creates a shared memory database, -// using data as its initial contents. -// The new database takes ownership of data, -// and the caller should not use data after this call. -func Create(name string, data []byte) { - memoryMtx.Lock() - defer memoryMtx.Unlock() - - db := &memDB{ - refs: 1, - name: name, - size: int64(len(data)), - } - - // Convert data from WAL/2 to rollback journal. - if len(data) >= 20 && (false || - data[18] == 2 && data[19] == 2 || - data[18] == 3 && data[19] == 3) { - data[18] = 1 - data[19] = 1 - } - - sectors := divRoundUp(db.size, sectorSize) - db.data = make([]*[sectorSize]byte, sectors) - for i := range db.data { - sector := data[i*sectorSize:] - if len(sector) >= sectorSize { - db.data[i] = (*[sectorSize]byte)(sector) - } else { - db.data[i] = new([sectorSize]byte) - copy((*db.data[i])[:], sector) - } - } - - memoryDBs[name] = db -} - -// Delete deletes a shared memory database. -func Delete(name string) { - memoryMtx.Lock() - defer memoryMtx.Unlock() - delete(memoryDBs, name) -} - -// TestDB creates an empty shared memory database for the test to use. -// The database is automatically deleted when the test and all its subtests complete. -// Each subsequent call to TestDB returns a unique database. -func TestDB(tb testing.TB, params ...url.Values) string { - tb.Helper() - - name := fmt.Sprintf("%s_%p", tb.Name(), tb) - tb.Cleanup(func() { Delete(name) }) - Create(name, nil) - - p := url.Values{"vfs": {"memdb"}} - for _, v := range params { - for k, v := range v { - for _, v := range v { - p.Add(k, v) - } - } - } - - return (&url.URL{ - Scheme: "file", - OmitHost: true, - Path: "/" + name, - RawQuery: p.Encode(), - }).String() -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/memdb/memdb.go b/vendor/github.com/ncruces/go-sqlite3/vfs/memdb/memdb.go deleted file mode 100644 index 419fd1c64..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/memdb/memdb.go +++ /dev/null @@ -1,308 +0,0 @@ -package memdb - -import ( - "io" - "runtime" - "sync" - "time" - - "github.com/ncruces/go-sqlite3" - "github.com/ncruces/go-sqlite3/vfs" -) - -const sectorSize = 65536 - -// Ensure sectorSize is a multiple of 64K (the largest page size). -var _ [0]struct{} = [sectorSize & 65535]struct{}{} - -type memVFS struct{} - -func (memVFS) Open(name string, flags vfs.OpenFlag) (vfs.File, vfs.OpenFlag, error) { - // For simplicity, we do not support reading or writing data - // across "sector" boundaries. - // - // This is not a problem for most SQLite file types: - // - databases, which only do page aligned reads/writes; - // - temp journals, as used by the sorter, which does the same: - // https://github.com/sqlite/sqlite/blob/b74eb0/src/vdbesort.c#L409-L412 - // - // We refuse to open all other file types, - // but returning OPEN_MEMORY means SQLite won't ask us to. - const types = vfs.OPEN_MAIN_DB | - vfs.OPEN_TEMP_DB | - vfs.OPEN_TEMP_JOURNAL - if flags&types == 0 { - // notest // OPEN_MEMORY - return nil, flags, sqlite3.CANTOPEN - } - - // A shared database has a name that begins with "/". - shared := len(name) > 1 && name[0] == '/' - - var db *memDB - if shared { - name = name[1:] - memoryMtx.Lock() - defer memoryMtx.Unlock() - db = memoryDBs[name] - } - if db == nil { - if flags&vfs.OPEN_CREATE == 0 { - return nil, flags, sqlite3.CANTOPEN - } - db = &memDB{name: name} - } - if shared { - db.refs++ // +checklocksforce: memoryMtx is held - memoryDBs[name] = db - } - - return &memFile{ - memDB: db, - readOnly: flags&vfs.OPEN_READONLY != 0, - }, flags | vfs.OPEN_MEMORY, nil -} - -func (memVFS) Delete(name string, dirSync bool) error { - return sqlite3.IOERR_DELETE_NOENT // used to delete journals -} - -func (memVFS) Access(name string, flag vfs.AccessFlag) (bool, error) { - return false, nil // used to check for journals -} - -func (memVFS) FullPathname(name string) (string, error) { - return name, nil -} - -type memDB struct { - name string - - // +checklocks:dataMtx - data []*[sectorSize]byte - // +checklocks:dataMtx - size int64 - - // +checklocks:memoryMtx - refs int32 - - shared int32 // +checklocks:lockMtx - pending bool // +checklocks:lockMtx - reserved bool // +checklocks:lockMtx - - lockMtx sync.Mutex - dataMtx sync.RWMutex -} - -func (m *memDB) release() { - memoryMtx.Lock() - defer memoryMtx.Unlock() - if m.refs--; m.refs == 0 && m == memoryDBs[m.name] { - delete(memoryDBs, m.name) - } -} - -type memFile struct { - *memDB - lock vfs.LockLevel - readOnly bool -} - -var ( - // Ensure these interfaces are implemented: - _ vfs.FileLockState = &memFile{} - _ vfs.FileSizeHint = &memFile{} -) - -func (m *memFile) Close() error { - m.release() - return m.Unlock(vfs.LOCK_NONE) -} - -func (m *memFile) ReadAt(b []byte, off int64) (n int, err error) { - m.dataMtx.RLock() - defer m.dataMtx.RUnlock() - - if off >= m.size { - return 0, io.EOF - } - - base := off / sectorSize - rest := off % sectorSize - have := int64(sectorSize) - if base == int64(len(m.data))-1 { - have = modRoundUp(m.size, sectorSize) - } - n = copy(b, (*m.data[base])[rest:have]) - if n < len(b) { - // notest // assume reads are page aligned - return 0, io.ErrNoProgress - } - return n, nil -} - -func (m *memFile) WriteAt(b []byte, off int64) (n int, err error) { - m.dataMtx.Lock() - defer m.dataMtx.Unlock() - - base := off / sectorSize - rest := off % sectorSize - for base >= int64(len(m.data)) { - m.data = append(m.data, new([sectorSize]byte)) - } - n = copy((*m.data[base])[rest:], b) - if n < len(b) { - // notest // assume writes are page aligned - return n, io.ErrShortWrite - } - if size := off + int64(len(b)); size > m.size { - m.size = size - } - return n, nil -} - -func (m *memFile) Truncate(size int64) error { - m.dataMtx.Lock() - defer m.dataMtx.Unlock() - return m.truncate(size) -} - -// +checklocks:m.dataMtx -func (m *memFile) truncate(size int64) error { - if size < m.size { - base := size / sectorSize - rest := size % sectorSize - if rest != 0 { - clear((*m.data[base])[rest:]) - } - } - sectors := divRoundUp(size, sectorSize) - for sectors > int64(len(m.data)) { - m.data = append(m.data, new([sectorSize]byte)) - } - clear(m.data[sectors:]) - m.data = m.data[:sectors] - m.size = size - return nil -} - -func (m *memFile) Sync(flag vfs.SyncFlag) error { - return nil -} - -func (m *memFile) Size() (int64, error) { - m.dataMtx.RLock() - defer m.dataMtx.RUnlock() - return m.size, nil -} - -const spinWait = 25 * time.Microsecond - -func (m *memFile) Lock(lock vfs.LockLevel) error { - if m.lock >= lock { - return nil - } - - if m.readOnly && lock >= vfs.LOCK_RESERVED { - return sqlite3.IOERR_LOCK - } - - m.lockMtx.Lock() - defer m.lockMtx.Unlock() - - switch lock { - case vfs.LOCK_SHARED: - if m.pending { - return sqlite3.BUSY - } - m.shared++ - - case vfs.LOCK_RESERVED: - if m.reserved { - return sqlite3.BUSY - } - m.reserved = true - - case vfs.LOCK_EXCLUSIVE: - if m.lock < vfs.LOCK_PENDING { - m.lock = vfs.LOCK_PENDING - m.pending = true - } - - for before := time.Now(); m.shared > 1; { - if time.Since(before) > spinWait { - return sqlite3.BUSY - } - m.lockMtx.Unlock() - runtime.Gosched() - m.lockMtx.Lock() - } - } - - m.lock = lock - return nil -} - -func (m *memFile) Unlock(lock vfs.LockLevel) error { - if m.lock <= lock { - return nil - } - - m.lockMtx.Lock() - defer m.lockMtx.Unlock() - - if m.lock >= vfs.LOCK_RESERVED { - m.reserved = false - } - if m.lock >= vfs.LOCK_PENDING { - m.pending = false - } - if lock < vfs.LOCK_SHARED { - m.shared-- - } - m.lock = lock - return nil -} - -func (m *memFile) CheckReservedLock() (bool, error) { - // notest // OPEN_MEMORY - if m.lock >= vfs.LOCK_RESERVED { - return true, nil - } - m.lockMtx.Lock() - defer m.lockMtx.Unlock() - return m.reserved, nil -} - -func (m *memFile) SectorSize() int { - // notest // IOCAP_POWERSAFE_OVERWRITE - return sectorSize -} - -func (m *memFile) DeviceCharacteristics() vfs.DeviceCharacteristic { - return vfs.IOCAP_ATOMIC | - vfs.IOCAP_SEQUENTIAL | - vfs.IOCAP_SAFE_APPEND | - vfs.IOCAP_POWERSAFE_OVERWRITE -} - -func (m *memFile) SizeHint(size int64) error { - m.dataMtx.Lock() - defer m.dataMtx.Unlock() - if size > m.size { - return m.truncate(size) - } - return nil -} - -func (m *memFile) LockState() vfs.LockLevel { - return m.lock -} - -func divRoundUp(a, b int64) int64 { - return (a + b - 1) / b -} - -func modRoundUp(a, b int64) int64 { - return b - (b-a%b)%b -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go deleted file mode 100644 index 4f6fadef4..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go +++ /dev/null @@ -1,101 +0,0 @@ -//go:build ((freebsd || openbsd || netbsd || dragonfly || illumos) && !sqlite3_dotlk) || sqlite3_flock - -package vfs - -import ( - "os" - - "golang.org/x/sys/unix" -) - -func osGetSharedLock(file *os.File) _ErrorCode { - return osFlock(file, unix.LOCK_SH|unix.LOCK_NB, _IOERR_RDLOCK) -} - -func osGetReservedLock(file *os.File) _ErrorCode { - rc := osFlock(file, unix.LOCK_EX|unix.LOCK_NB, _IOERR_LOCK) - if rc == _BUSY { - // The documentation states that a lock is upgraded by - // releasing the previous lock, then acquiring the new lock. - // Going over the source code of various BSDs, though, - // with LOCK_NB, the lock is not released, - // and EAGAIN is returned holding the shared lock. - // Still, if we're already in a transaction, we want to abort it, - // so return BUSY_SNAPSHOT here. If there's no transaction active, - // SQLite will change this back to SQLITE_BUSY, - // and invoke the busy handler if appropriate. - return _BUSY_SNAPSHOT - } - return rc -} - -func osGetExclusiveLock(file *os.File, state *LockLevel) _ErrorCode { - if *state >= LOCK_RESERVED { - return _OK - } - return osGetReservedLock(file) -} - -func osDowngradeLock(file *os.File, _ LockLevel) _ErrorCode { - rc := osFlock(file, unix.LOCK_SH|unix.LOCK_NB, _IOERR_RDLOCK) - if rc == _BUSY { - // The documentation states that a lock is downgraded by - // releasing the previous lock then acquiring the new lock. - // Going over the source code of various BSDs, though, - // with LOCK_SH|LOCK_NB this should never happen. - // Return IOERR_RDLOCK, as BUSY would cause an assert to fail. - return _IOERR_RDLOCK - } - return _OK -} - -func osReleaseLock(file *os.File, _ LockLevel) _ErrorCode { - err := unix.Flock(int(file.Fd()), unix.LOCK_UN) - if err != nil { - return _IOERR_UNLOCK - } - return _OK -} - -func osCheckReservedLock(file *os.File) (bool, _ErrorCode) { - // Test the RESERVED lock with fcntl(F_GETLK). - // This only works on systems where fcntl and flock are compatible. - // However, SQLite only calls this while holding a shared lock, - // so the difference is immaterial. - lock, rc := osTestLock(file, _RESERVED_BYTE, 1) - return lock == unix.F_WRLCK, rc -} - -func osFlock(file *os.File, how int, def _ErrorCode) _ErrorCode { - err := unix.Flock(int(file.Fd()), how) - return osLockErrorCode(err, def) -} - -func osReadLock(file *os.File, start, len int64) _ErrorCode { - return osLock(file, unix.F_RDLCK, start, len, _IOERR_RDLOCK) -} - -func osWriteLock(file *os.File, start, len int64) _ErrorCode { - return osLock(file, unix.F_WRLCK, start, len, _IOERR_LOCK) -} - -func osLock(file *os.File, typ int16, start, len int64, def _ErrorCode) _ErrorCode { - err := unix.FcntlFlock(file.Fd(), unix.F_SETLK, &unix.Flock_t{ - Type: typ, - Start: start, - Len: len, - }) - return osLockErrorCode(err, def) -} - -func osUnlock(file *os.File, start, len int64) _ErrorCode { - err := unix.FcntlFlock(file.Fd(), unix.F_SETLK, &unix.Flock_t{ - Type: unix.F_UNLCK, - Start: start, - Len: len, - }) - if err != nil { - return _IOERR_UNLOCK - } - return _OK -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go deleted file mode 100644 index 07de7c3d8..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_darwin.go +++ /dev/null @@ -1,97 +0,0 @@ -//go:build !sqlite3_flock - -package vfs - -import ( - "io" - "os" - "runtime" - "time" - - "golang.org/x/sys/unix" -) - -const ( - // https://github.com/apple/darwin-xnu/blob/main/bsd/sys/fcntl.h - _F_OFD_SETLK = 90 - _F_OFD_SETLKW = 91 - _F_OFD_SETLKWTIMEOUT = 93 -) - -type flocktimeout_t struct { - fl unix.Flock_t - timeout unix.Timespec -} - -func osSync(file *os.File, fullsync, _ /*dataonly*/ bool) error { - if fullsync { - return file.Sync() - } - return unix.Fsync(int(file.Fd())) -} - -func osAllocate(file *os.File, size int64) error { - off, err := file.Seek(0, io.SeekEnd) - if err != nil { - return err - } - if size <= off { - return nil - } - - store := unix.Fstore_t{ - Flags: unix.F_ALLOCATEALL | unix.F_ALLOCATECONTIG, - Posmode: unix.F_PEOFPOSMODE, - Offset: 0, - Length: size - off, - } - - // Try to get a continuous chunk of disk space. - err = unix.FcntlFstore(file.Fd(), unix.F_PREALLOCATE, &store) - if err != nil { - // OK, perhaps we are too fragmented, allocate non-continuous. - store.Flags = unix.F_ALLOCATEALL - unix.FcntlFstore(file.Fd(), unix.F_PREALLOCATE, &store) - } - return file.Truncate(size) -} - -func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode { - return osLock(file, unix.F_RDLCK, start, len, timeout, _IOERR_RDLOCK) -} - -func osWriteLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode { - return osLock(file, unix.F_WRLCK, start, len, timeout, _IOERR_LOCK) -} - -func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, def _ErrorCode) _ErrorCode { - lock := &flocktimeout_t{fl: unix.Flock_t{ - Type: typ, - Start: start, - Len: len, - }} - var err error - switch { - case timeout == 0: - err = unix.FcntlFlock(file.Fd(), _F_OFD_SETLK, &lock.fl) - case timeout < 0: - err = unix.FcntlFlock(file.Fd(), _F_OFD_SETLKW, &lock.fl) - default: - lock.timeout = unix.NsecToTimespec(int64(timeout / time.Nanosecond)) - err = unix.FcntlFlock(file.Fd(), _F_OFD_SETLKWTIMEOUT, &lock.fl) - runtime.KeepAlive(lock) - } - return osLockErrorCode(err, def) -} - -func osUnlock(file *os.File, start, len int64) _ErrorCode { - err := unix.FcntlFlock(file.Fd(), _F_OFD_SETLK, &unix.Flock_t{ - Type: unix.F_UNLCK, - Start: start, - Len: len, - }) - if err != nil { - return _IOERR_UNLOCK - } - return _OK -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go deleted file mode 100644 index 7a9c38897..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go +++ /dev/null @@ -1,143 +0,0 @@ -//go:build sqlite3_dotlk - -package vfs - -import ( - "errors" - "io/fs" - "os" - "sync" - - "github.com/ncruces/go-sqlite3/internal/dotlk" -) - -var ( - // +checklocks:vfsDotLocksMtx - vfsDotLocks = map[string]*vfsDotLocker{} - vfsDotLocksMtx sync.Mutex -) - -type vfsDotLocker struct { - shared int // +checklocks:vfsDotLocksMtx - pending *os.File // +checklocks:vfsDotLocksMtx - reserved *os.File // +checklocks:vfsDotLocksMtx -} - -func osGetSharedLock(file *os.File) _ErrorCode { - vfsDotLocksMtx.Lock() - defer vfsDotLocksMtx.Unlock() - - name := file.Name() - locker := vfsDotLocks[name] - if locker == nil { - if err := dotlk.TryLock(name + ".lock"); err != nil { - if errors.Is(err, fs.ErrExist) { - return _BUSY // Another process has the lock. - } - return _IOERR_LOCK - } - locker = &vfsDotLocker{} - vfsDotLocks[name] = locker - } - - if locker.pending != nil { - return _BUSY - } - locker.shared++ - return _OK -} - -func osGetReservedLock(file *os.File) _ErrorCode { - vfsDotLocksMtx.Lock() - defer vfsDotLocksMtx.Unlock() - - name := file.Name() - locker := vfsDotLocks[name] - if locker == nil { - return _IOERR_LOCK - } - - if locker.reserved != nil && locker.reserved != file { - return _BUSY - } - locker.reserved = file - return _OK -} - -func osGetExclusiveLock(file *os.File, _ *LockLevel) _ErrorCode { - vfsDotLocksMtx.Lock() - defer vfsDotLocksMtx.Unlock() - - name := file.Name() - locker := vfsDotLocks[name] - if locker == nil { - return _IOERR_LOCK - } - - if locker.pending != nil && locker.pending != file { - return _BUSY - } - locker.pending = file - if locker.shared > 1 { - return _BUSY - } - return _OK -} - -func osDowngradeLock(file *os.File, _ LockLevel) _ErrorCode { - vfsDotLocksMtx.Lock() - defer vfsDotLocksMtx.Unlock() - - name := file.Name() - locker := vfsDotLocks[name] - if locker == nil { - return _IOERR_UNLOCK - } - - if locker.reserved == file { - locker.reserved = nil - } - if locker.pending == file { - locker.pending = nil - } - return _OK -} - -func osReleaseLock(file *os.File, state LockLevel) _ErrorCode { - vfsDotLocksMtx.Lock() - defer vfsDotLocksMtx.Unlock() - - name := file.Name() - locker := vfsDotLocks[name] - if locker == nil { - return _IOERR_UNLOCK - } - - if locker.shared == 1 { - if err := dotlk.Unlock(name + ".lock"); err != nil { - return _IOERR_UNLOCK - } - delete(vfsDotLocks, name) - } - - if locker.reserved == file { - locker.reserved = nil - } - if locker.pending == file { - locker.pending = nil - } - locker.shared-- - return _OK -} - -func osCheckReservedLock(file *os.File) (bool, _ErrorCode) { - vfsDotLocksMtx.Lock() - defer vfsDotLocksMtx.Unlock() - - name := file.Name() - locker := vfsDotLocks[name] - if locker == nil { - return false, _OK - } - return locker.reserved != nil, _OK -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_f2fs_linux.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_f2fs_linux.go deleted file mode 100644 index 36614309d..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_f2fs_linux.go +++ /dev/null @@ -1,37 +0,0 @@ -//go:build amd64 || arm64 || riscv64 - -package vfs - -import ( - "os" - - "golang.org/x/sys/unix" -) - -const ( - // https://godbolt.org/z/1PcK5vea3 - _F2FS_IOC_START_ATOMIC_WRITE = 62721 - _F2FS_IOC_COMMIT_ATOMIC_WRITE = 62722 - _F2FS_IOC_ABORT_ATOMIC_WRITE = 62725 - _F2FS_IOC_GET_FEATURES = 2147808524 // -2147158772 - _F2FS_FEATURE_ATOMIC_WRITE = 4 -) - -// notest - -func osBatchAtomic(file *os.File) bool { - flags, err := unix.IoctlGetInt(int(file.Fd()), _F2FS_IOC_GET_FEATURES) - return err == nil && flags&_F2FS_FEATURE_ATOMIC_WRITE != 0 -} - -func (f *vfsFile) BeginAtomicWrite() error { - return unix.IoctlSetInt(int(f.Fd()), _F2FS_IOC_START_ATOMIC_WRITE, 0) -} - -func (f *vfsFile) CommitAtomicWrite() error { - return unix.IoctlSetInt(int(f.Fd()), _F2FS_IOC_COMMIT_ATOMIC_WRITE, 0) -} - -func (f *vfsFile) RollbackAtomicWrite() error { - return unix.IoctlSetInt(int(f.Fd()), _F2FS_IOC_ABORT_ATOMIC_WRITE, 0) -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go deleted file mode 100644 index 6199c7b00..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go +++ /dev/null @@ -1,58 +0,0 @@ -//go:build !sqlite3_flock - -package vfs - -import ( - "os" - "time" - - "golang.org/x/sys/unix" -) - -func osSync(file *os.File, _ /*fullsync*/, _ /*dataonly*/ bool) error { - // SQLite trusts Linux's fdatasync for all fsync's. - return unix.Fdatasync(int(file.Fd())) -} - -func osAllocate(file *os.File, size int64) error { - if size == 0 { - return nil - } - return unix.Fallocate(int(file.Fd()), 0, 0, size) -} - -func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode { - return osLock(file, unix.F_RDLCK, start, len, timeout, _IOERR_RDLOCK) -} - -func osWriteLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode { - return osLock(file, unix.F_WRLCK, start, len, timeout, _IOERR_LOCK) -} - -func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, def _ErrorCode) _ErrorCode { - lock := unix.Flock_t{ - Type: typ, - Start: start, - Len: len, - } - var err error - switch { - case timeout < 0: - err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLKW, &lock) - default: - err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock) - } - return osLockErrorCode(err, def) -} - -func osUnlock(file *os.File, start, len int64) _ErrorCode { - err := unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &unix.Flock_t{ - Type: unix.F_UNLCK, - Start: start, - Len: len, - }) - if err != nil { - return _IOERR_UNLOCK - } - return _OK -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_ofd.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_ofd.go deleted file mode 100644 index d93050e8a..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_ofd.go +++ /dev/null @@ -1,59 +0,0 @@ -//go:build (linux || darwin) && !(sqlite3_flock || sqlite3_dotlk) - -package vfs - -import ( - "os" - "time" - - "golang.org/x/sys/unix" -) - -func osGetSharedLock(file *os.File) _ErrorCode { - // Test the PENDING lock before acquiring a new SHARED lock. - if lock, _ := osTestLock(file, _PENDING_BYTE, 1); lock == unix.F_WRLCK { - return _BUSY - } - // Acquire the SHARED lock. - return osReadLock(file, _SHARED_FIRST, _SHARED_SIZE, 0) -} - -func osGetReservedLock(file *os.File) _ErrorCode { - // Acquire the RESERVED lock. - return osWriteLock(file, _RESERVED_BYTE, 1, 0) -} - -func osGetExclusiveLock(file *os.File, state *LockLevel) _ErrorCode { - if *state == LOCK_RESERVED { - // A PENDING lock is needed before acquiring an EXCLUSIVE lock. - if rc := osWriteLock(file, _PENDING_BYTE, 1, -1); rc != _OK { - return rc - } - *state = LOCK_PENDING - } - // Acquire the EXCLUSIVE lock. - return osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, time.Millisecond) -} - -func osDowngradeLock(file *os.File, state LockLevel) _ErrorCode { - if state >= LOCK_EXCLUSIVE { - // Downgrade to a SHARED lock. - if rc := osReadLock(file, _SHARED_FIRST, _SHARED_SIZE, 0); rc != _OK { - // notest // this should never happen - return _IOERR_RDLOCK - } - } - // Release the PENDING and RESERVED locks. - return osUnlock(file, _PENDING_BYTE, 2) -} - -func osReleaseLock(file *os.File, _ LockLevel) _ErrorCode { - // Release all locks. - return osUnlock(file, 0, 0) -} - -func osCheckReservedLock(file *os.File) (bool, _ErrorCode) { - // Test the RESERVED lock. - lock, rc := osTestLock(file, _RESERVED_BYTE, 1) - return lock == unix.F_WRLCK, rc -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_std.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_std.go deleted file mode 100644 index 0d0ca24c9..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_std.go +++ /dev/null @@ -1,50 +0,0 @@ -//go:build !unix - -package vfs - -import ( - "io/fs" - "os" -) - -const ( - _O_NOFOLLOW = 0 - canSyncDirs = false -) - -func osAccess(path string, flags AccessFlag) error { - fi, err := os.Stat(path) - if err != nil { - return err - } - if flags == ACCESS_EXISTS { - return nil - } - - const ( - S_IREAD = 0400 - S_IWRITE = 0200 - S_IEXEC = 0100 - ) - - var want fs.FileMode = S_IREAD - if flags == ACCESS_READWRITE { - want |= S_IWRITE - } - if fi.IsDir() { - want |= S_IEXEC - } - if fi.Mode()&want != want { - return fs.ErrPermission - } - return nil -} - -func osSetMode(file *os.File, modeof string) error { - fi, err := os.Stat(modeof) - if err != nil { - return err - } - file.Chmod(fi.Mode()) - return nil -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_std_alloc.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_std_alloc.go deleted file mode 100644 index 4dd1bb32c..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_std_alloc.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build !(linux || darwin) || sqlite3_flock - -package vfs - -import ( - "io" - "os" -) - -func osAllocate(file *os.File, size int64) error { - off, err := file.Seek(0, io.SeekEnd) - if err != nil { - return err - } - if size <= off { - return nil - } - return file.Truncate(size) -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_std_atomic.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_std_atomic.go deleted file mode 100644 index 10a0c8470..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_std_atomic.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build !linux || !(amd64 || arm64 || riscv64) - -package vfs - -import "os" - -func osBatchAtomic(*os.File) bool { - return false -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_std_sync.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_std_sync.go deleted file mode 100644 index b32e83e08..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_std_sync.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build !(linux || darwin) || sqlite3_flock - -package vfs - -import "os" - -func osSync(file *os.File, _ /*fullsync*/, _ /*dataonly*/ bool) error { - return file.Sync() -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix.go deleted file mode 100644 index c4f9ba870..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix.go +++ /dev/null @@ -1,76 +0,0 @@ -//go:build unix - -package vfs - -import ( - "os" - "syscall" - - "golang.org/x/sys/unix" -) - -const ( - _O_NOFOLLOW = unix.O_NOFOLLOW - canSyncDirs = true -) - -func osAccess(path string, flags AccessFlag) error { - var access uint32 // unix.F_OK - switch flags { - case ACCESS_READWRITE: - access = unix.R_OK | unix.W_OK - case ACCESS_READ: - access = unix.R_OK - } - return unix.Access(path, access) -} - -func osSetMode(file *os.File, modeof string) error { - fi, err := os.Stat(modeof) - if err != nil { - return err - } - file.Chmod(fi.Mode()) - if sys, ok := fi.Sys().(*syscall.Stat_t); ok { - file.Chown(int(sys.Uid), int(sys.Gid)) - } - return nil -} - -func osTestLock(file *os.File, start, len int64) (int16, _ErrorCode) { - lock := unix.Flock_t{ - Type: unix.F_WRLCK, - Start: start, - Len: len, - } - if unix.FcntlFlock(file.Fd(), unix.F_GETLK, &lock) != nil { - return 0, _IOERR_CHECKRESERVEDLOCK - } - return lock.Type, _OK -} - -func osLockErrorCode(err error, def _ErrorCode) _ErrorCode { - if err == nil { - return _OK - } - if errno, ok := err.(unix.Errno); ok { - switch errno { - case - unix.EACCES, - unix.EAGAIN, - unix.EBUSY, - unix.EINTR, - unix.ENOLCK, - unix.EDEADLK, - unix.ETIMEDOUT: - return _BUSY - case unix.EPERM: - return _PERM - } - // notest // usually EWOULDBLOCK == EAGAIN - if errno == unix.EWOULDBLOCK && unix.EWOULDBLOCK != unix.EAGAIN { - return _BUSY - } - } - return def -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go deleted file mode 100644 index 0398f4760..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go +++ /dev/null @@ -1,195 +0,0 @@ -//go:build !sqlite3_dotlk - -package vfs - -import ( - "os" - "time" - - "golang.org/x/sys/windows" -) - -func osGetSharedLock(file *os.File) _ErrorCode { - // Acquire the PENDING lock temporarily before acquiring a new SHARED lock. - rc := osReadLock(file, _PENDING_BYTE, 1, 0) - if rc == _OK { - // Acquire the SHARED lock. - rc = osReadLock(file, _SHARED_FIRST, _SHARED_SIZE, 0) - - // Release the PENDING lock. - osUnlock(file, _PENDING_BYTE, 1) - } - return rc -} - -func osGetReservedLock(file *os.File) _ErrorCode { - // Acquire the RESERVED lock. - return osWriteLock(file, _RESERVED_BYTE, 1, 0) -} - -func osGetExclusiveLock(file *os.File, state *LockLevel) _ErrorCode { - // A PENDING lock is needed before releasing the SHARED lock. - if *state < LOCK_PENDING { - // If we were RESERVED, we can block indefinitely. - var timeout time.Duration - if *state == LOCK_RESERVED { - timeout = -1 - } - if rc := osWriteLock(file, _PENDING_BYTE, 1, timeout); rc != _OK { - return rc - } - *state = LOCK_PENDING - } - - // Release the SHARED lock. - osUnlock(file, _SHARED_FIRST, _SHARED_SIZE) - - // Acquire the EXCLUSIVE lock. - // Can't wait here, because the file is not OVERLAPPED. - rc := osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, 0) - - if rc != _OK { - // Reacquire the SHARED lock. - if rc := osReadLock(file, _SHARED_FIRST, _SHARED_SIZE, 0); rc != _OK { - // notest // this should never happen - return _IOERR_RDLOCK - } - } - return rc -} - -func osDowngradeLock(file *os.File, state LockLevel) _ErrorCode { - if state >= LOCK_EXCLUSIVE { - // Release the EXCLUSIVE lock while holding the PENDING lock. - osUnlock(file, _SHARED_FIRST, _SHARED_SIZE) - - // Reacquire the SHARED lock. - if rc := osReadLock(file, _SHARED_FIRST, _SHARED_SIZE, 0); rc != _OK { - // notest // this should never happen - return _IOERR_RDLOCK - } - } - - // Release the PENDING and RESERVED locks. - if state >= LOCK_RESERVED { - osUnlock(file, _RESERVED_BYTE, 1) - } - if state >= LOCK_PENDING { - osUnlock(file, _PENDING_BYTE, 1) - } - return _OK -} - -func osReleaseLock(file *os.File, state LockLevel) _ErrorCode { - // Release all locks, PENDING must be last. - if state >= LOCK_RESERVED { - osUnlock(file, _RESERVED_BYTE, 1) - } - if state >= LOCK_SHARED { - osUnlock(file, _SHARED_FIRST, _SHARED_SIZE) - } - if state >= LOCK_PENDING { - osUnlock(file, _PENDING_BYTE, 1) - } - return _OK -} - -func osCheckReservedLock(file *os.File) (bool, _ErrorCode) { - // Test the RESERVED lock. - rc := osLock(file, 0, _RESERVED_BYTE, 1, 0, _IOERR_CHECKRESERVEDLOCK) - if rc == _BUSY { - return true, _OK - } - if rc == _OK { - // Release the RESERVED lock. - osUnlock(file, _RESERVED_BYTE, 1) - } - return false, rc -} - -func osReadLock(file *os.File, start, len uint32, timeout time.Duration) _ErrorCode { - return osLock(file, 0, start, len, timeout, _IOERR_RDLOCK) -} - -func osWriteLock(file *os.File, start, len uint32, timeout time.Duration) _ErrorCode { - return osLock(file, windows.LOCKFILE_EXCLUSIVE_LOCK, start, len, timeout, _IOERR_LOCK) -} - -func osLock(file *os.File, flags, start, len uint32, timeout time.Duration, def _ErrorCode) _ErrorCode { - var err error - switch { - case timeout == 0: - err = osLockEx(file, flags|windows.LOCKFILE_FAIL_IMMEDIATELY, start, len) - case timeout < 0: - err = osLockEx(file, flags, start, len) - default: - err = osLockExTimeout(file, flags, start, len, timeout) - } - return osLockErrorCode(err, def) -} - -func osUnlock(file *os.File, start, len uint32) _ErrorCode { - err := windows.UnlockFileEx(windows.Handle(file.Fd()), - 0, len, 0, &windows.Overlapped{Offset: start}) - if err == windows.ERROR_NOT_LOCKED { - return _OK - } - if err != nil { - return _IOERR_UNLOCK - } - return _OK -} - -func osLockEx(file *os.File, flags, start, len uint32) error { - return windows.LockFileEx(windows.Handle(file.Fd()), flags, - 0, len, 0, &windows.Overlapped{Offset: start}) -} - -func osLockExTimeout(file *os.File, flags, start, len uint32, timeout time.Duration) error { - event, err := windows.CreateEvent(nil, 1, 0, nil) - if err != nil { - return err - } - defer windows.CloseHandle(event) - - fd := windows.Handle(file.Fd()) - overlapped := &windows.Overlapped{ - Offset: start, - HEvent: event, - } - - err = windows.LockFileEx(fd, flags, 0, len, 0, overlapped) - if err != windows.ERROR_IO_PENDING { - return err - } - - ms := (timeout + time.Millisecond - 1) / time.Millisecond - rc, err := windows.WaitForSingleObject(event, uint32(ms)) - if rc == windows.WAIT_OBJECT_0 { - return nil - } - defer windows.CancelIoEx(fd, overlapped) - - if err != nil { - return err - } - return windows.Errno(rc) -} - -func osLockErrorCode(err error, def _ErrorCode) _ErrorCode { - if err == nil { - return _OK - } - if errno, ok := err.(windows.Errno); ok { - // https://devblogs.microsoft.com/oldnewthing/20140905-00/?p=63 - switch errno { - case - windows.ERROR_LOCK_VIOLATION, - windows.ERROR_OPERATION_ABORTED, - windows.ERROR_IO_PENDING, - windows.WAIT_TIMEOUT: - return _BUSY - } - } - return def -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/registry.go b/vendor/github.com/ncruces/go-sqlite3/vfs/registry.go deleted file mode 100644 index 42a2106fb..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/registry.go +++ /dev/null @@ -1,48 +0,0 @@ -package vfs - -import "sync" - -var ( - // +checklocks:vfsRegistryMtx - vfsRegistry map[string]VFS - vfsRegistryMtx sync.RWMutex -) - -// Find returns a VFS given its name. -// If there is no match, nil is returned. -// If name is empty, the default VFS is returned. -// -// https://sqlite.org/c3ref/vfs_find.html -func Find(name string) VFS { - if name == "" || name == "os" { - return vfsOS{} - } - vfsRegistryMtx.RLock() - defer vfsRegistryMtx.RUnlock() - return vfsRegistry[name] -} - -// Register registers a VFS. -// Empty and "os" are reserved names. -// -// https://sqlite.org/c3ref/vfs_find.html -func Register(name string, vfs VFS) { - if name == "" || name == "os" { - return - } - vfsRegistryMtx.Lock() - defer vfsRegistryMtx.Unlock() - if vfsRegistry == nil { - vfsRegistry = map[string]VFS{} - } - vfsRegistry[name] = vfs -} - -// Unregister unregisters a VFS. -// -// https://sqlite.org/c3ref/vfs_find.html -func Unregister(name string) { - vfsRegistryMtx.Lock() - defer vfsRegistryMtx.Unlock() - delete(vfsRegistry, name) -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/shm.go b/vendor/github.com/ncruces/go-sqlite3/vfs/shm.go deleted file mode 100644 index f28955289..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/shm.go +++ /dev/null @@ -1,26 +0,0 @@ -//go:build ((linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le)) || sqlite3_flock || sqlite3_dotlk - -package vfs - -// SupportsSharedMemory is false on platforms that do not support shared memory. -// To use [WAL without shared-memory], you need to set [EXCLUSIVE locking mode]. -// -// [WAL without shared-memory]: https://sqlite.org/wal.html#noshm -// [EXCLUSIVE locking mode]: https://sqlite.org/pragma.html#pragma_locking_mode -const SupportsSharedMemory = true - -func (f *vfsFile) SharedMemory() SharedMemory { return f.shm } - -// NewSharedMemory returns a shared-memory WAL-index -// backed by a file with the given path. -// It will return nil if shared-memory is not supported, -// or not appropriate for the given flags. -// Only [OPEN_MAIN_DB] databases may need a WAL-index. -// You must ensure all concurrent accesses to a database -// use shared-memory instances created with the same path. -func NewSharedMemory(path string, flags OpenFlag) SharedMemory { - if flags&OPEN_MAIN_DB == 0 || flags&(OPEN_DELETEONCLOSE|OPEN_MEMORY) != 0 { - return nil - } - return &vfsShm{path: path} -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go deleted file mode 100644 index 11e7bb2fd..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go +++ /dev/null @@ -1,250 +0,0 @@ -//go:build ((freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !sqlite3_dotlk) || sqlite3_flock - -package vfs - -import ( - "context" - "errors" - "io" - "io/fs" - "os" - "sync" - - "github.com/tetratelabs/wazero/api" - "golang.org/x/sys/unix" - - "github.com/ncruces/go-sqlite3/internal/util" -) - -type vfsShmParent struct { - *os.File - info os.FileInfo - - refs int // +checklocks:vfsShmListMtx - - lock [_SHM_NLOCK]int8 // +checklocks:Mutex - sync.Mutex -} - -var ( - // +checklocks:vfsShmListMtx - vfsShmList []*vfsShmParent - vfsShmListMtx sync.Mutex -) - -type vfsShm struct { - *vfsShmParent - path string - lock [_SHM_NLOCK]bool - regions []*util.MappedRegion -} - -func (s *vfsShm) Close() error { - if s.vfsShmParent == nil { - return nil - } - - vfsShmListMtx.Lock() - defer vfsShmListMtx.Unlock() - - // Unlock everything. - s.shmLock(0, _SHM_NLOCK, _SHM_UNLOCK) - - // Decrease reference count. - if s.vfsShmParent.refs > 0 { - s.vfsShmParent.refs-- - s.vfsShmParent = nil - return nil - } - - err := s.File.Close() - for i, g := range vfsShmList { - if g == s.vfsShmParent { - vfsShmList[i] = nil - s.vfsShmParent = nil - return err - } - } - panic(util.AssertErr()) -} - -func (s *vfsShm) shmOpen() _ErrorCode { - if s.vfsShmParent != nil { - return _OK - } - - var f *os.File - // Close file on error. - // Keep this here to avoid confusing checklocks. - defer func() { f.Close() }() - - vfsShmListMtx.Lock() - defer vfsShmListMtx.Unlock() - - // Stat file without opening it. - // Closing it would release all POSIX locks on it. - fi, err := os.Stat(s.path) - if err != nil && !errors.Is(err, fs.ErrNotExist) { - return _IOERR_FSTAT - } - - // Find a shared file, increase the reference count. - for _, g := range vfsShmList { - if g != nil && os.SameFile(fi, g.info) { - s.vfsShmParent = g - g.refs++ - return _OK - } - } - - // Always open file read-write, as it will be shared. - f, err = os.OpenFile(s.path, - os.O_RDWR|os.O_CREATE|_O_NOFOLLOW, 0666) - if err != nil { - return _CANTOPEN - } - - // Dead man's switch. - if lock, rc := osTestLock(f, _SHM_DMS, 1); rc != _OK { - return _IOERR_LOCK - } else if lock == unix.F_WRLCK { - return _BUSY - } else if lock == unix.F_UNLCK { - if rc := osWriteLock(f, _SHM_DMS, 1); rc != _OK { - return rc - } - if err := f.Truncate(0); err != nil { - return _IOERR_SHMOPEN - } - } - if rc := osReadLock(f, _SHM_DMS, 1); rc != _OK { - return rc - } - - fi, err = f.Stat() - if err != nil { - return _IOERR_FSTAT - } - - // Add the new shared file. - s.vfsShmParent = &vfsShmParent{ - File: f, - info: fi, - } - f = nil // Don't close the file. - for i, g := range vfsShmList { - if g == nil { - vfsShmList[i] = s.vfsShmParent - return _OK - } - } - vfsShmList = append(vfsShmList, s.vfsShmParent) - return _OK -} - -func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, _ErrorCode) { - // Ensure size is a multiple of the OS page size. - if int(size)&(unix.Getpagesize()-1) != 0 { - return 0, _IOERR_SHMMAP - } - - if rc := s.shmOpen(); rc != _OK { - return 0, rc - } - - // Check if file is big enough. - o, err := s.Seek(0, io.SeekEnd) - if err != nil { - return 0, _IOERR_SHMSIZE - } - if n := (int64(id) + 1) * int64(size); n > o { - if !extend { - return 0, _OK - } - if osAllocate(s.File, n) != nil { - return 0, _IOERR_SHMSIZE - } - } - - r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, false) - if err != nil { - return 0, _IOERR_SHMMAP - } - s.regions = append(s.regions, r) - return r.Ptr, _OK -} - -func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode { - s.Lock() - defer s.Unlock() - - // Check if we can obtain/release locks locally. - rc := s.shmMemLock(offset, n, flags) - if rc != _OK { - return rc - } - - // Obtain/release the appropriate file locks. - switch { - case flags&_SHM_UNLOCK != 0: - // Relasing a shared lock decrements the counter, - // but may leave parts of the range still locked. - begin, end := offset, offset+n - for i := begin; i < end; i++ { - if s.vfsShmParent.lock[i] != 0 { - if i > begin { - rc |= osUnlock(s.File, _SHM_BASE+int64(begin), int64(i-begin)) - } - begin = i + 1 - } - } - if end > begin { - rc |= osUnlock(s.File, _SHM_BASE+int64(begin), int64(end-begin)) - } - return rc - case flags&_SHM_SHARED != 0: - // Acquiring a new shared lock on the file is only necessary - // if there was a new shared lock in the range. - for i := offset; i < offset+n; i++ { - if s.vfsShmParent.lock[i] == 1 { - rc = osReadLock(s.File, _SHM_BASE+int64(offset), int64(n)) - break - } - } - case flags&_SHM_EXCLUSIVE != 0: - // Acquiring an exclusive lock on the file is always necessary. - rc = osWriteLock(s.File, _SHM_BASE+int64(offset), int64(n)) - default: - panic(util.AssertErr()) - } - - // Release the local locks we had acquired. - if rc != _OK { - s.shmMemLock(offset, n, flags^(_SHM_UNLOCK|_SHM_LOCK)) - } - return rc -} - -func (s *vfsShm) shmUnmap(delete bool) { - if s.vfsShmParent == nil { - return - } - - // Unmap regions. - for _, r := range s.regions { - r.Unmap() - } - s.regions = nil - - // Close the file. - if delete { - os.Remove(s.path) - } - s.Close() -} - -func (s *vfsShm) shmBarrier() { - s.Lock() - //lint:ignore SA2001 memory barrier. - s.Unlock() -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_copy.go b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_copy.go deleted file mode 100644 index db8ddb4b8..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_copy.go +++ /dev/null @@ -1,87 +0,0 @@ -//go:build (windows && (386 || arm || amd64 || arm64 || riscv64 || ppc64le)) || sqlite3_dotlk - -package vfs - -import ( - "unsafe" - - "github.com/ncruces/go-sqlite3/internal/util" -) - -const ( - _WALINDEX_HDR_SIZE = 136 - _WALINDEX_PGSZ = 32768 -) - -// This seems a safe way of keeping the WAL-index in sync. -// -// The WAL-index file starts with a header, -// and the index doesn't meaningfully change if the header doesn't change. -// -// The header starts with two 48 byte, checksummed, copies of the same information, -// which are accessed independently between memory barriers. -// The checkpoint information that follows uses 4 byte aligned words. -// -// Finally, we have the WAL-index hash tables, -// which are only modified holding the exclusive WAL_WRITE_LOCK. -// -// Since all the data is either redundant+checksummed, -// 4 byte aligned, or modified under an exclusive lock, -// the copies below should correctly keep memory in sync. -// -// https://sqlite.org/walformat.html#the_wal_index_file_format - -func (s *vfsShm) shmAcquire(ptr *_ErrorCode) { - if ptr != nil && *ptr != _OK { - return - } - if len(s.ptrs) == 0 || shmEqual(s.shadow[0][:], s.shared[0][:]) { - return - } - // Copies modified words from shared to private memory. - for id, p := range s.ptrs { - shared := shmPage(s.shared[id][:]) - shadow := shmPage(s.shadow[id][:]) - privat := shmPage(util.View(s.mod, p, _WALINDEX_PGSZ)) - for i, shared := range shared { - if shadow[i] != shared { - shadow[i] = shared - privat[i] = shared - } - } - } -} - -func (s *vfsShm) shmRelease() { - if len(s.ptrs) == 0 || shmEqual(s.shadow[0][:], util.View(s.mod, s.ptrs[0], _WALINDEX_HDR_SIZE)) { - return - } - // Copies modified words from private to shared memory. - for id, p := range s.ptrs { - shared := shmPage(s.shared[id][:]) - shadow := shmPage(s.shadow[id][:]) - privat := shmPage(util.View(s.mod, p, _WALINDEX_PGSZ)) - for i, privat := range privat { - if shadow[i] != privat { - shadow[i] = privat - shared[i] = privat - } - } - } -} - -func (s *vfsShm) shmBarrier() { - s.Lock() - s.shmAcquire(nil) - s.shmRelease() - s.Unlock() -} - -func shmPage(s []byte) *[_WALINDEX_PGSZ / 4]uint32 { - p := (*uint32)(unsafe.Pointer(unsafe.SliceData(s))) - return (*[_WALINDEX_PGSZ / 4]uint32)(unsafe.Slice(p, _WALINDEX_PGSZ/4)) -} - -func shmEqual(v1, v2 []byte) bool { - return *(*[_WALINDEX_HDR_SIZE]byte)(v1[:]) == *(*[_WALINDEX_HDR_SIZE]byte)(v2[:]) -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_dotlk.go b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_dotlk.go deleted file mode 100644 index cb697a9c8..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_dotlk.go +++ /dev/null @@ -1,178 +0,0 @@ -//go:build sqlite3_dotlk - -package vfs - -import ( - "context" - "errors" - "io/fs" - "sync" - - "github.com/tetratelabs/wazero/api" - - "github.com/ncruces/go-sqlite3/internal/dotlk" - "github.com/ncruces/go-sqlite3/internal/util" -) - -type vfsShmParent struct { - shared [][_WALINDEX_PGSZ]byte - refs int // +checklocks:vfsShmListMtx - - lock [_SHM_NLOCK]int8 // +checklocks:Mutex - sync.Mutex -} - -var ( - // +checklocks:vfsShmListMtx - vfsShmList = map[string]*vfsShmParent{} - vfsShmListMtx sync.Mutex -) - -type vfsShm struct { - *vfsShmParent - mod api.Module - alloc api.Function - free api.Function - path string - shadow [][_WALINDEX_PGSZ]byte - ptrs []ptr_t - stack [1]stk_t - lock [_SHM_NLOCK]bool -} - -func (s *vfsShm) Close() error { - if s.vfsShmParent == nil { - return nil - } - - vfsShmListMtx.Lock() - defer vfsShmListMtx.Unlock() - - // Unlock everything. - s.shmLock(0, _SHM_NLOCK, _SHM_UNLOCK) - - // Decrease reference count. - if s.vfsShmParent.refs > 0 { - s.vfsShmParent.refs-- - s.vfsShmParent = nil - return nil - } - - if err := dotlk.Unlock(s.path); err != nil { - return _IOERR_UNLOCK - } - delete(vfsShmList, s.path) - s.vfsShmParent = nil - return nil -} - -func (s *vfsShm) shmOpen() _ErrorCode { - if s.vfsShmParent != nil { - return _OK - } - - vfsShmListMtx.Lock() - defer vfsShmListMtx.Unlock() - - // Find a shared buffer, increase the reference count. - if g, ok := vfsShmList[s.path]; ok { - s.vfsShmParent = g - g.refs++ - return _OK - } - - // Dead man's switch. - err := dotlk.LockShm(s.path) - if errors.Is(err, fs.ErrExist) { - return _BUSY - } - if err != nil { - return _IOERR_LOCK - } - - // Add the new shared buffer. - s.vfsShmParent = &vfsShmParent{} - vfsShmList[s.path] = s.vfsShmParent - return _OK -} - -func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, _ErrorCode) { - if size != _WALINDEX_PGSZ { - return 0, _IOERR_SHMMAP - } - if s.mod == nil { - s.mod = mod - s.free = mod.ExportedFunction("sqlite3_free") - s.alloc = mod.ExportedFunction("sqlite3_malloc64") - } - if rc := s.shmOpen(); rc != _OK { - return 0, rc - } - - s.Lock() - defer s.Unlock() - defer s.shmAcquire(nil) - - // Extend shared memory. - if int(id) >= len(s.shared) { - if !extend { - return 0, _OK - } - s.shared = append(s.shared, make([][_WALINDEX_PGSZ]byte, int(id)-len(s.shared)+1)...) - } - - // Allocate shadow memory. - if int(id) >= len(s.shadow) { - s.shadow = append(s.shadow, make([][_WALINDEX_PGSZ]byte, int(id)-len(s.shadow)+1)...) - } - - // Allocate local memory. - for int(id) >= len(s.ptrs) { - s.stack[0] = stk_t(size) - if err := s.alloc.CallWithStack(ctx, s.stack[:]); err != nil { - panic(err) - } - if s.stack[0] == 0 { - panic(util.OOMErr) - } - clear(util.View(s.mod, ptr_t(s.stack[0]), _WALINDEX_PGSZ)) - s.ptrs = append(s.ptrs, ptr_t(s.stack[0])) - } - - s.shadow[0][4] = 1 - return s.ptrs[id], _OK -} - -func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) (rc _ErrorCode) { - s.Lock() - defer s.Unlock() - - switch { - case flags&_SHM_LOCK != 0: - defer s.shmAcquire(&rc) - case flags&_SHM_EXCLUSIVE != 0: - s.shmRelease() - } - - return s.shmMemLock(offset, n, flags) -} - -func (s *vfsShm) shmUnmap(delete bool) { - if s.vfsShmParent == nil { - return - } - defer s.Close() - - s.Lock() - s.shmRelease() - defer s.Unlock() - - for _, p := range s.ptrs { - s.stack[0] = stk_t(p) - if err := s.free.CallWithStack(context.Background(), s.stack[:]); err != nil { - panic(err) - } - } - s.ptrs = nil - s.shadow = nil -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_memlk.go b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_memlk.go deleted file mode 100644 index 5c8071ebe..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_memlk.go +++ /dev/null @@ -1,53 +0,0 @@ -//go:build ((freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le)) || sqlite3_flock || sqlite3_dotlk - -package vfs - -import "github.com/ncruces/go-sqlite3/internal/util" - -// +checklocks:s.Mutex -func (s *vfsShm) shmMemLock(offset, n int32, flags _ShmFlag) _ErrorCode { - switch { - case flags&_SHM_UNLOCK != 0: - for i := offset; i < offset+n; i++ { - if s.lock[i] { - if s.vfsShmParent.lock[i] <= 0 { - s.vfsShmParent.lock[i] = 0 - } else { - s.vfsShmParent.lock[i]-- - } - s.lock[i] = false - } - } - case flags&_SHM_SHARED != 0: - for i := offset; i < offset+n; i++ { - if !s.lock[i] && - s.vfsShmParent.lock[i]+1 <= 0 { - return _BUSY - } - } - for i := offset; i < offset+n; i++ { - if !s.lock[i] { - s.vfsShmParent.lock[i]++ - s.lock[i] = true - } - } - case flags&_SHM_EXCLUSIVE != 0: - for i := offset; i < offset+n; i++ { - if s.lock[i] { - // SQLite never requests an exclusive lock that it already holds. - panic(util.AssertErr()) - } - if s.vfsShmParent.lock[i] != 0 { - return _BUSY - } - } - for i := offset; i < offset+n; i++ { - s.vfsShmParent.lock[i] = -1 - s.lock[i] = true - } - default: - panic(util.AssertErr()) - } - - return _OK -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_ofd.go b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_ofd.go deleted file mode 100644 index b0f50fcb5..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_ofd.go +++ /dev/null @@ -1,176 +0,0 @@ -//go:build (linux || darwin) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_flock || sqlite3_dotlk) - -package vfs - -import ( - "context" - "io" - "os" - "sync" - "time" - - "github.com/tetratelabs/wazero/api" - "golang.org/x/sys/unix" - - "github.com/ncruces/go-sqlite3/internal/util" -) - -type vfsShm struct { - *os.File - path string - regions []*util.MappedRegion - readOnly bool - fileLock bool - blocking bool - sync.Mutex -} - -var _ blockingSharedMemory = &vfsShm{} - -func (s *vfsShm) shmOpen() _ErrorCode { - if s.File == nil { - f, err := os.OpenFile(s.path, - os.O_RDWR|os.O_CREATE|_O_NOFOLLOW, 0666) - if err != nil { - f, err = os.OpenFile(s.path, - os.O_RDONLY|os.O_CREATE|_O_NOFOLLOW, 0666) - s.readOnly = true - } - if err != nil { - return _CANTOPEN - } - s.File = f - } - if s.fileLock { - return _OK - } - - // Dead man's switch. - if lock, rc := osTestLock(s.File, _SHM_DMS, 1); rc != _OK { - return _IOERR_LOCK - } else if lock == unix.F_WRLCK { - return _BUSY - } else if lock == unix.F_UNLCK { - if s.readOnly { - return _READONLY_CANTINIT - } - // Do not use a blocking lock here. - // If the lock cannot be obtained immediately, - // it means some other connection is truncating the file. - // And after it has done so, it will not release its lock, - // but only downgrade it to a shared lock. - // So no point in blocking here. - // The call below to obtain the shared DMS lock may use a blocking lock. - if rc := osWriteLock(s.File, _SHM_DMS, 1, 0); rc != _OK { - return rc - } - if err := s.Truncate(0); err != nil { - return _IOERR_SHMOPEN - } - } - rc := osReadLock(s.File, _SHM_DMS, 1, time.Millisecond) - s.fileLock = rc == _OK - return rc -} - -func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (ptr_t, _ErrorCode) { - // Ensure size is a multiple of the OS page size. - if int(size)&(unix.Getpagesize()-1) != 0 { - return 0, _IOERR_SHMMAP - } - - if rc := s.shmOpen(); rc != _OK { - return 0, rc - } - - // Check if file is big enough. - o, err := s.Seek(0, io.SeekEnd) - if err != nil { - return 0, _IOERR_SHMSIZE - } - if n := (int64(id) + 1) * int64(size); n > o { - if !extend { - return 0, _OK - } - if s.readOnly || osAllocate(s.File, n) != nil { - return 0, _IOERR_SHMSIZE - } - } - - r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, s.readOnly) - if err != nil { - return 0, _IOERR_SHMMAP - } - s.regions = append(s.regions, r) - if s.readOnly { - return r.Ptr, _READONLY - } - return r.Ptr, _OK -} - -func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode { - // Argument check. - switch { - case n <= 0: - panic(util.AssertErr()) - case offset < 0 || offset+n > _SHM_NLOCK: - panic(util.AssertErr()) - case n != 1 && flags&_SHM_EXCLUSIVE == 0: - panic(util.AssertErr()) - } - switch flags { - case - _SHM_LOCK | _SHM_SHARED, - _SHM_LOCK | _SHM_EXCLUSIVE, - _SHM_UNLOCK | _SHM_SHARED, - _SHM_UNLOCK | _SHM_EXCLUSIVE: - // - default: - panic(util.AssertErr()) - } - - var timeout time.Duration - if s.blocking { - timeout = time.Millisecond - } - - switch { - case flags&_SHM_UNLOCK != 0: - return osUnlock(s.File, _SHM_BASE+int64(offset), int64(n)) - case flags&_SHM_SHARED != 0: - return osReadLock(s.File, _SHM_BASE+int64(offset), int64(n), timeout) - case flags&_SHM_EXCLUSIVE != 0: - return osWriteLock(s.File, _SHM_BASE+int64(offset), int64(n), timeout) - default: - panic(util.AssertErr()) - } -} - -func (s *vfsShm) shmUnmap(delete bool) { - if s.File == nil { - return - } - - // Unmap regions. - for _, r := range s.regions { - r.Unmap() - } - s.regions = nil - - // Close the file. - if delete { - os.Remove(s.path) - } - s.Close() - s.File = nil -} - -func (s *vfsShm) shmBarrier() { - s.Lock() - //lint:ignore SA2001 memory barrier. - s.Unlock() -} - -func (s *vfsShm) shmEnableBlocking(block bool) { - s.blocking = block -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_other.go b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_other.go deleted file mode 100644 index 69319f07d..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_other.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build !(((linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le)) || sqlite3_flock || sqlite3_dotlk) - -package vfs - -// SupportsSharedMemory is false on platforms that do not support shared memory. -// To use [WAL without shared-memory], you need to set [EXCLUSIVE locking mode]. -// -// [WAL without shared-memory]: https://sqlite.org/wal.html#noshm -// [EXCLUSIVE locking mode]: https://sqlite.org/pragma.html#pragma_locking_mode -const SupportsSharedMemory = false - -// NewSharedMemory returns a shared-memory WAL-index -// backed by a file with the given path. -// It will return nil if shared-memory is not supported, -// or not appropriate for the given flags. -// Only [OPEN_MAIN_DB] databases may need a WAL-index. -// You must ensure all concurrent accesses to a database -// use shared-memory instances created with the same path. -func NewSharedMemory(path string, flags OpenFlag) SharedMemory { - return nil -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_windows.go b/vendor/github.com/ncruces/go-sqlite3/vfs/shm_windows.go deleted file mode 100644 index ed2e93f8e..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/shm_windows.go +++ /dev/null @@ -1,190 +0,0 @@ -//go:build (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !sqlite3_dotlk - -package vfs - -import ( - "context" - "io" - "os" - "sync" - "syscall" - "time" - - "github.com/tetratelabs/wazero/api" - "golang.org/x/sys/windows" - - "github.com/ncruces/go-sqlite3/internal/util" - "github.com/ncruces/go-sqlite3/util/osutil" -) - -type vfsShm struct { - *os.File - mod api.Module - alloc api.Function - free api.Function - path string - regions []*util.MappedRegion - shared [][]byte - shadow [][_WALINDEX_PGSZ]byte - ptrs []ptr_t - stack [1]stk_t - fileLock bool - blocking bool - sync.Mutex -} - -var _ blockingSharedMemory = &vfsShm{} - -func (s *vfsShm) Close() error { - // Unmap regions. - for _, r := range s.regions { - r.Unmap() - } - s.regions = nil - - // Close the file. - return s.File.Close() -} - -func (s *vfsShm) shmOpen() _ErrorCode { - if s.File == nil { - f, err := osutil.OpenFile(s.path, - os.O_RDWR|os.O_CREATE|syscall.O_NONBLOCK, 0666) - if err != nil { - return _CANTOPEN - } - s.File = f - } - if s.fileLock { - return _OK - } - - // Dead man's switch. - if rc := osWriteLock(s.File, _SHM_DMS, 1, 0); rc == _OK { - err := s.Truncate(0) - osUnlock(s.File, _SHM_DMS, 1) - if err != nil { - return _IOERR_SHMOPEN - } - } - rc := osReadLock(s.File, _SHM_DMS, 1, time.Millisecond) - s.fileLock = rc == _OK - return rc -} - -func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (_ ptr_t, rc _ErrorCode) { - // Ensure size is a multiple of the OS page size. - if size != _WALINDEX_PGSZ || (windows.Getpagesize()-1)&_WALINDEX_PGSZ != 0 { - return 0, _IOERR_SHMMAP - } - if s.mod == nil { - s.mod = mod - s.free = mod.ExportedFunction("sqlite3_free") - s.alloc = mod.ExportedFunction("sqlite3_malloc64") - } - if rc := s.shmOpen(); rc != _OK { - return 0, rc - } - - defer s.shmAcquire(&rc) - - // Check if file is big enough. - o, err := s.Seek(0, io.SeekEnd) - if err != nil { - return 0, _IOERR_SHMSIZE - } - if n := (int64(id) + 1) * int64(size); n > o { - if !extend { - return 0, _OK - } - if osAllocate(s.File, n) != nil { - return 0, _IOERR_SHMSIZE - } - } - - // Maps regions into memory. - for int(id) >= len(s.shared) { - r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size) - if err != nil { - return 0, _IOERR_SHMMAP - } - s.regions = append(s.regions, r) - s.shared = append(s.shared, r.Data) - } - - // Allocate shadow memory. - if int(id) >= len(s.shadow) { - s.shadow = append(s.shadow, make([][_WALINDEX_PGSZ]byte, int(id)-len(s.shadow)+1)...) - } - - // Allocate local memory. - for int(id) >= len(s.ptrs) { - s.stack[0] = stk_t(size) - if err := s.alloc.CallWithStack(ctx, s.stack[:]); err != nil { - panic(err) - } - if s.stack[0] == 0 { - panic(util.OOMErr) - } - clear(util.View(s.mod, ptr_t(s.stack[0]), _WALINDEX_PGSZ)) - s.ptrs = append(s.ptrs, ptr_t(s.stack[0])) - } - - s.shadow[0][4] = 1 - return s.ptrs[id], _OK -} - -func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) (rc _ErrorCode) { - var timeout time.Duration - if s.blocking { - timeout = time.Millisecond - } - - switch { - case flags&_SHM_LOCK != 0: - defer s.shmAcquire(&rc) - case flags&_SHM_EXCLUSIVE != 0: - s.shmRelease() - } - - switch { - case flags&_SHM_UNLOCK != 0: - return osUnlock(s.File, _SHM_BASE+uint32(offset), uint32(n)) - case flags&_SHM_SHARED != 0: - return osReadLock(s.File, _SHM_BASE+uint32(offset), uint32(n), timeout) - case flags&_SHM_EXCLUSIVE != 0: - return osWriteLock(s.File, _SHM_BASE+uint32(offset), uint32(n), timeout) - default: - panic(util.AssertErr()) - } -} - -func (s *vfsShm) shmUnmap(delete bool) { - if s.File == nil { - return - } - - s.shmRelease() - - // Free local memory. - for _, p := range s.ptrs { - s.stack[0] = stk_t(p) - if err := s.free.CallWithStack(context.Background(), s.stack[:]); err != nil { - panic(err) - } - } - s.ptrs = nil - s.shadow = nil - s.shared = nil - - // Close the file. - s.Close() - s.File = nil - if delete { - os.Remove(s.path) - } -} - -func (s *vfsShm) shmEnableBlocking(block bool) { - s.blocking = block -} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go b/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go deleted file mode 100644 index ca105fff6..000000000 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go +++ /dev/null @@ -1,485 +0,0 @@ -package vfs - -import ( - "context" - "crypto/rand" - "io" - "reflect" - "strings" - "time" - - "github.com/tetratelabs/wazero" - "github.com/tetratelabs/wazero/api" - - "github.com/ncruces/go-sqlite3/internal/util" - "github.com/ncruces/go-sqlite3/util/sql3util" - "github.com/ncruces/julianday" -) - -// ExportHostFunctions is an internal API users need not call directly. -// -// ExportHostFunctions registers the required VFS host functions -// with the provided env module. -func ExportHostFunctions(env wazero.HostModuleBuilder) wazero.HostModuleBuilder { - util.ExportFuncII(env, "go_vfs_find", vfsFind) - util.ExportFuncIIJ(env, "go_localtime", vfsLocaltime) - util.ExportFuncIIII(env, "go_randomness", vfsRandomness) - util.ExportFuncIII(env, "go_sleep", vfsSleep) - util.ExportFuncIII(env, "go_current_time_64", vfsCurrentTime64) - util.ExportFuncIIIII(env, "go_full_pathname", vfsFullPathname) - util.ExportFuncIIII(env, "go_delete", vfsDelete) - util.ExportFuncIIIII(env, "go_access", vfsAccess) - util.ExportFuncIIIIIII(env, "go_open", vfsOpen) - util.ExportFuncII(env, "go_close", vfsClose) - util.ExportFuncIIIIJ(env, "go_read", vfsRead) - util.ExportFuncIIIIJ(env, "go_write", vfsWrite) - util.ExportFuncIIJ(env, "go_truncate", vfsTruncate) - util.ExportFuncIII(env, "go_sync", vfsSync) - util.ExportFuncIII(env, "go_file_size", vfsFileSize) - util.ExportFuncIIII(env, "go_file_control", vfsFileControl) - util.ExportFuncII(env, "go_sector_size", vfsSectorSize) - util.ExportFuncII(env, "go_device_characteristics", vfsDeviceCharacteristics) - util.ExportFuncIII(env, "go_lock", vfsLock) - util.ExportFuncIII(env, "go_unlock", vfsUnlock) - util.ExportFuncIII(env, "go_check_reserved_lock", vfsCheckReservedLock) - util.ExportFuncIIIIII(env, "go_shm_map", vfsShmMap) - util.ExportFuncIIIII(env, "go_shm_lock", vfsShmLock) - util.ExportFuncIII(env, "go_shm_unmap", vfsShmUnmap) - util.ExportFuncVI(env, "go_shm_barrier", vfsShmBarrier) - return env -} - -func vfsFind(ctx context.Context, mod api.Module, zVfsName ptr_t) uint32 { - name := util.ReadString(mod, zVfsName, _MAX_NAME) - if vfs := Find(name); vfs != nil && vfs != (vfsOS{}) { - return 1 - } - return 0 -} - -func vfsLocaltime(ctx context.Context, mod api.Module, pTm ptr_t, t int64) _ErrorCode { - tm := time.Unix(t, 0) - var isdst int32 - if tm.IsDST() { - isdst = 1 - } - - const size = 32 / 8 - // https://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html - util.Write32(mod, pTm+0*size, int32(tm.Second())) - util.Write32(mod, pTm+1*size, int32(tm.Minute())) - util.Write32(mod, pTm+2*size, int32(tm.Hour())) - util.Write32(mod, pTm+3*size, int32(tm.Day())) - util.Write32(mod, pTm+4*size, int32(tm.Month()-time.January)) - util.Write32(mod, pTm+5*size, int32(tm.Year()-1900)) - util.Write32(mod, pTm+6*size, int32(tm.Weekday()-time.Sunday)) - util.Write32(mod, pTm+7*size, int32(tm.YearDay()-1)) - util.Write32(mod, pTm+8*size, isdst) - return _OK -} - -func vfsRandomness(ctx context.Context, mod api.Module, pVfs ptr_t, nByte int32, zByte ptr_t) uint32 { - mem := util.View(mod, zByte, int64(nByte)) - n, _ := rand.Reader.Read(mem) - return uint32(n) -} - -func vfsSleep(ctx context.Context, mod api.Module, pVfs ptr_t, nMicro int32) _ErrorCode { - time.Sleep(time.Duration(nMicro) * time.Microsecond) - return _OK -} - -func vfsCurrentTime64(ctx context.Context, mod api.Module, pVfs, piNow ptr_t) _ErrorCode { - day, nsec := julianday.Date(time.Now()) - msec := day*86_400_000 + nsec/1_000_000 - util.Write64(mod, piNow, msec) - return _OK -} - -func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative ptr_t, nFull int32, zFull ptr_t) _ErrorCode { - vfs := vfsGet(mod, pVfs) - path := util.ReadString(mod, zRelative, _MAX_PATHNAME) - - path, err := vfs.FullPathname(path) - - if len(path) >= int(nFull) { - return _CANTOPEN_FULLPATH - } - util.WriteString(mod, zFull, path) - - return vfsErrorCode(err, _CANTOPEN_FULLPATH) -} - -func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, syncDir int32) _ErrorCode { - vfs := vfsGet(mod, pVfs) - path := util.ReadString(mod, zPath, _MAX_PATHNAME) - - err := vfs.Delete(path, syncDir != 0) - return vfsErrorCode(err, _IOERR_DELETE) -} - -func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath ptr_t, flags AccessFlag, pResOut ptr_t) _ErrorCode { - vfs := vfsGet(mod, pVfs) - path := util.ReadString(mod, zPath, _MAX_PATHNAME) - - ok, err := vfs.Access(path, flags) - var res int32 - if ok { - res = 1 - } - util.Write32(mod, pResOut, res) - return vfsErrorCode(err, _IOERR_ACCESS) -} - -func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile ptr_t, flags OpenFlag, pOutFlags, pOutVFS ptr_t) _ErrorCode { - vfs := vfsGet(mod, pVfs) - name := GetFilename(ctx, mod, zPath, flags) - - var file File - var err error - if ffs, ok := vfs.(VFSFilename); ok { - file, flags, err = ffs.OpenFilename(name, flags) - } else { - file, flags, err = vfs.Open(name.String(), flags) - } - if err != nil { - return vfsErrorCode(err, _CANTOPEN) - } - - if file, ok := file.(FilePowersafeOverwrite); ok { - if b, ok := sql3util.ParseBool(name.URIParameter("psow")); ok { - file.SetPowersafeOverwrite(b) - } - } - if file, ok := file.(FileSharedMemory); ok && - pOutVFS != 0 && file.SharedMemory() != nil { - util.Write32(mod, pOutVFS, int32(1)) - } - if pOutFlags != 0 { - util.Write32(mod, pOutFlags, flags) - } - file = cksmWrapFile(name, flags, file) - vfsFileRegister(ctx, mod, pFile, file) - return _OK -} - -func vfsClose(ctx context.Context, mod api.Module, pFile ptr_t) _ErrorCode { - err := vfsFileClose(ctx, mod, pFile) - return vfsErrorCode(err, _IOERR_CLOSE) -} - -func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf ptr_t, iAmt int32, iOfst int64) _ErrorCode { - file := vfsFileGet(ctx, mod, pFile).(File) - buf := util.View(mod, zBuf, int64(iAmt)) - - n, err := file.ReadAt(buf, iOfst) - if n == int(iAmt) { - return _OK - } - if err != io.EOF { - return vfsErrorCode(err, _IOERR_READ) - } - clear(buf[n:]) - return _IOERR_SHORT_READ -} - -func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf ptr_t, iAmt int32, iOfst int64) _ErrorCode { - file := vfsFileGet(ctx, mod, pFile).(File) - buf := util.View(mod, zBuf, int64(iAmt)) - - _, err := file.WriteAt(buf, iOfst) - return vfsErrorCode(err, _IOERR_WRITE) -} - -func vfsTruncate(ctx context.Context, mod api.Module, pFile ptr_t, nByte int64) _ErrorCode { - file := vfsFileGet(ctx, mod, pFile).(File) - err := file.Truncate(nByte) - return vfsErrorCode(err, _IOERR_TRUNCATE) -} - -func vfsSync(ctx context.Context, mod api.Module, pFile ptr_t, flags SyncFlag) _ErrorCode { - file := vfsFileGet(ctx, mod, pFile).(File) - err := file.Sync(flags) - return vfsErrorCode(err, _IOERR_FSYNC) -} - -func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize ptr_t) _ErrorCode { - file := vfsFileGet(ctx, mod, pFile).(File) - size, err := file.Size() - util.Write64(mod, pSize, size) - return vfsErrorCode(err, _IOERR_SEEK) -} - -func vfsLock(ctx context.Context, mod api.Module, pFile ptr_t, eLock LockLevel) _ErrorCode { - file := vfsFileGet(ctx, mod, pFile).(File) - err := file.Lock(eLock) - return vfsErrorCode(err, _IOERR_LOCK) -} - -func vfsUnlock(ctx context.Context, mod api.Module, pFile ptr_t, eLock LockLevel) _ErrorCode { - file := vfsFileGet(ctx, mod, pFile).(File) - err := file.Unlock(eLock) - return vfsErrorCode(err, _IOERR_UNLOCK) -} - -func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut ptr_t) _ErrorCode { - file := vfsFileGet(ctx, mod, pFile).(File) - locked, err := file.CheckReservedLock() - - var res int32 - if locked { - res = 1 - } - util.Write32(mod, pResOut, res) - return vfsErrorCode(err, _IOERR_CHECKRESERVEDLOCK) -} - -func vfsFileControl(ctx context.Context, mod api.Module, pFile ptr_t, op _FcntlOpcode, pArg ptr_t) _ErrorCode { - file := vfsFileGet(ctx, mod, pFile).(File) - if file, ok := file.(fileControl); ok { - return file.fileControl(ctx, mod, op, pArg) - } - return vfsFileControlImpl(ctx, mod, file, op, pArg) -} - -func vfsFileControlImpl(ctx context.Context, mod api.Module, file File, op _FcntlOpcode, pArg ptr_t) _ErrorCode { - switch op { - case _FCNTL_LOCKSTATE: - if file, ok := file.(FileLockState); ok { - if lk := file.LockState(); lk <= LOCK_EXCLUSIVE { - util.Write32(mod, pArg, lk) - return _OK - } - } - - case _FCNTL_PERSIST_WAL: - if file, ok := file.(FilePersistWAL); ok { - if i := util.Read32[int32](mod, pArg); i >= 0 { - file.SetPersistWAL(i != 0) - } else if file.PersistWAL() { - util.Write32(mod, pArg, int32(1)) - } else { - util.Write32(mod, pArg, int32(0)) - } - return _OK - } - - case _FCNTL_POWERSAFE_OVERWRITE: - if file, ok := file.(FilePowersafeOverwrite); ok { - if i := util.Read32[int32](mod, pArg); i >= 0 { - file.SetPowersafeOverwrite(i != 0) - } else if file.PowersafeOverwrite() { - util.Write32(mod, pArg, int32(1)) - } else { - util.Write32(mod, pArg, int32(0)) - } - return _OK - } - - case _FCNTL_CHUNK_SIZE: - if file, ok := file.(FileChunkSize); ok { - size := util.Read32[int32](mod, pArg) - file.ChunkSize(int(size)) - return _OK - } - - case _FCNTL_SIZE_HINT: - if file, ok := file.(FileSizeHint); ok { - size := util.Read64[int64](mod, pArg) - err := file.SizeHint(size) - return vfsErrorCode(err, _IOERR_TRUNCATE) - } - - case _FCNTL_HAS_MOVED: - if file, ok := file.(FileHasMoved); ok { - moved, err := file.HasMoved() - var val uint32 - if moved { - val = 1 - } - util.Write32(mod, pArg, val) - return vfsErrorCode(err, _IOERR_FSTAT) - } - - case _FCNTL_OVERWRITE: - if file, ok := file.(FileOverwrite); ok { - err := file.Overwrite() - return vfsErrorCode(err, _IOERR) - } - - case _FCNTL_SYNC: - if file, ok := file.(FileSync); ok { - var name string - if pArg != 0 { - name = util.ReadString(mod, pArg, _MAX_PATHNAME) - } - err := file.SyncSuper(name) - return vfsErrorCode(err, _IOERR) - } - - case _FCNTL_COMMIT_PHASETWO: - if file, ok := file.(FileCommitPhaseTwo); ok { - err := file.CommitPhaseTwo() - return vfsErrorCode(err, _IOERR) - } - - case _FCNTL_BEGIN_ATOMIC_WRITE: - if file, ok := file.(FileBatchAtomicWrite); ok { - err := file.BeginAtomicWrite() - return vfsErrorCode(err, _IOERR_BEGIN_ATOMIC) - } - case _FCNTL_COMMIT_ATOMIC_WRITE: - if file, ok := file.(FileBatchAtomicWrite); ok { - err := file.CommitAtomicWrite() - return vfsErrorCode(err, _IOERR_COMMIT_ATOMIC) - } - case _FCNTL_ROLLBACK_ATOMIC_WRITE: - if file, ok := file.(FileBatchAtomicWrite); ok { - err := file.RollbackAtomicWrite() - return vfsErrorCode(err, _IOERR_ROLLBACK_ATOMIC) - } - - case _FCNTL_CKPT_START: - if file, ok := file.(FileCheckpoint); ok { - file.CheckpointStart() - return _OK - } - case _FCNTL_CKPT_DONE: - if file, ok := file.(FileCheckpoint); ok { - file.CheckpointDone() - return _OK - } - - case _FCNTL_PRAGMA: - if file, ok := file.(FilePragma); ok { - ptr := util.Read32[ptr_t](mod, pArg+1*ptrlen) - name := util.ReadString(mod, ptr, _MAX_SQL_LENGTH) - var value string - if ptr := util.Read32[ptr_t](mod, pArg+2*ptrlen); ptr != 0 { - value = util.ReadString(mod, ptr, _MAX_SQL_LENGTH) - } - - out, err := file.Pragma(strings.ToLower(name), value) - - ret := vfsErrorCode(err, _ERROR) - if ret == _ERROR { - out = err.Error() - } - if out != "" { - fn := mod.ExportedFunction("sqlite3_malloc64") - stack := [...]stk_t{stk_t(len(out) + 1)} - if err := fn.CallWithStack(ctx, stack[:]); err != nil { - panic(err) - } - util.Write32(mod, pArg, ptr_t(stack[0])) - util.WriteString(mod, ptr_t(stack[0]), out) - } - return ret - } - - case _FCNTL_BUSYHANDLER: - if file, ok := file.(FileBusyHandler); ok { - arg := util.Read64[stk_t](mod, pArg) - fn := mod.ExportedFunction("sqlite3_invoke_busy_handler_go") - file.BusyHandler(func() bool { - stack := [...]stk_t{arg} - if err := fn.CallWithStack(ctx, stack[:]); err != nil { - panic(err) - } - return uint32(stack[0]) != 0 - }) - return _OK - } - - case _FCNTL_LOCK_TIMEOUT: - if file, ok := file.(FileSharedMemory); ok { - if shm, ok := file.SharedMemory().(blockingSharedMemory); ok { - shm.shmEnableBlocking(util.Read32[uint32](mod, pArg) != 0) - return _OK - } - } - - case _FCNTL_PDB: - if file, ok := file.(filePDB); ok { - file.SetDB(ctx.Value(util.ConnKey{})) - return _OK - } - } - - return _NOTFOUND -} - -func vfsSectorSize(ctx context.Context, mod api.Module, pFile ptr_t) uint32 { - file := vfsFileGet(ctx, mod, pFile).(File) - return uint32(file.SectorSize()) -} - -func vfsDeviceCharacteristics(ctx context.Context, mod api.Module, pFile ptr_t) DeviceCharacteristic { - file := vfsFileGet(ctx, mod, pFile).(File) - return file.DeviceCharacteristics() -} - -func vfsShmBarrier(ctx context.Context, mod api.Module, pFile ptr_t) { - shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory() - shm.shmBarrier() -} - -func vfsShmMap(ctx context.Context, mod api.Module, pFile ptr_t, iRegion, szRegion, bExtend int32, pp ptr_t) _ErrorCode { - shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory() - p, rc := shm.shmMap(ctx, mod, iRegion, szRegion, bExtend != 0) - util.Write32(mod, pp, p) - return rc -} - -func vfsShmLock(ctx context.Context, mod api.Module, pFile ptr_t, offset, n int32, flags _ShmFlag) _ErrorCode { - shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory() - return shm.shmLock(offset, n, flags) -} - -func vfsShmUnmap(ctx context.Context, mod api.Module, pFile ptr_t, bDelete int32) _ErrorCode { - shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory() - shm.shmUnmap(bDelete != 0) - return _OK -} - -func vfsGet(mod api.Module, pVfs ptr_t) VFS { - var name string - if pVfs != 0 { - const zNameOffset = 16 - ptr := util.Read32[ptr_t](mod, pVfs+zNameOffset) - name = util.ReadString(mod, ptr, _MAX_NAME) - } - if vfs := Find(name); vfs != nil { - return vfs - } - panic(util.NoVFSErr + util.ErrorString(name)) -} - -func vfsFileRegister(ctx context.Context, mod api.Module, pFile ptr_t, file File) { - const fileHandleOffset = 4 - id := util.AddHandle(ctx, file) - util.Write32(mod, pFile+fileHandleOffset, id) -} - -func vfsFileGet(ctx context.Context, mod api.Module, pFile ptr_t) any { - const fileHandleOffset = 4 - id := util.Read32[ptr_t](mod, pFile+fileHandleOffset) - return util.GetHandle(ctx, id) -} - -func vfsFileClose(ctx context.Context, mod api.Module, pFile ptr_t) error { - const fileHandleOffset = 4 - id := util.Read32[ptr_t](mod, pFile+fileHandleOffset) - return util.DelHandle(ctx, id) -} - -func vfsErrorCode(err error, def _ErrorCode) _ErrorCode { - if err == nil { - return _OK - } - switch v := reflect.ValueOf(err); v.Kind() { - case reflect.Uint8, reflect.Uint16, reflect.Uint32: - return _ErrorCode(v.Uint()) - } - return def -} |