package vfs
import (
"io"
"reflect"
"strings"
_ "unsafe"
"github.com/ncruces/go-sqlite3/internal/errutil"
"github.com/ncruces/go-sqlite3/internal/sqlite3_wrap"
"github.com/ncruces/go-sqlite3/internal/util"
)
func vfsFullPathname(wrp *sqlite3_wrap .Wrapper , pVfs , zRelative ptr_t , nFull int32 , zFull ptr_t ) _ErrorCode {
vfs := vfsGet (wrp , pVfs )
path := wrp .ReadString (zRelative , _MAX_PATHNAME )
path , err := vfs .FullPathname (path )
if len (path ) >= int (nFull ) {
return _CANTOPEN_FULLPATH
}
wrp .WriteString (zFull , path )
return vfsErrorCode (wrp , err , _CANTOPEN_FULLPATH )
}
func vfsDelete(wrp *sqlite3_wrap .Wrapper , pVfs , zPath ptr_t , syncDir int32 ) _ErrorCode {
vfs := vfsGet (wrp , pVfs )
path := wrp .ReadString (zPath , _MAX_PATHNAME )
err := vfs .Delete (path , syncDir != 0 )
return vfsErrorCode (wrp , err , _IOERR_DELETE )
}
func vfsAccess(wrp *sqlite3_wrap .Wrapper , pVfs , zPath ptr_t , flags AccessFlag , pResOut ptr_t ) _ErrorCode {
vfs := vfsGet (wrp , pVfs )
path := wrp .ReadString (zPath , _MAX_PATHNAME )
ok , err := vfs .Access (path , flags )
wrp .WriteBool (pResOut , ok )
return vfsErrorCode (wrp , err , _IOERR_ACCESS )
}
func vfsOpen(wrp *sqlite3_wrap .Wrapper , pVfs , zPath , pFile ptr_t , flags OpenFlag , pOutFlags , pOutVFS ptr_t ) _ErrorCode {
vfs := vfsGet (wrp , pVfs )
name := GetFilename (wrp , 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 (wrp , err , _CANTOPEN )
}
if file , ok := file .(FilePowersafeOverwrite ); ok {
if b , ok := util .ParseBool (name .URIParameter ("psow" )); ok {
file .SetPowersafeOverwrite (b )
}
}
if file , ok := file .(FileSharedMemory ); ok && pOutVFS != 0 {
wrp .WriteBool (pOutVFS , file .SharedMemory () != nil )
}
if pOutFlags != 0 {
wrp .Write32 (pOutFlags , uint32 (flags ))
}
file = cksmWrapFile (file , flags )
vfsFileRegister (wrp , pFile , file )
return _OK
}
func vfsClose(wrp *sqlite3_wrap .Wrapper , pFile ptr_t ) _ErrorCode {
err := vfsFileClose (wrp , pFile )
return vfsErrorCode (wrp , err , _IOERR_CLOSE )
}
func vfsRead(wrp *sqlite3_wrap .Wrapper , pFile , zBuf ptr_t , iAmt int32 , iOfst int64 ) _ErrorCode {
file := vfsFileGet (wrp , pFile ).(File )
buf := wrp .Bytes (zBuf , int64 (iAmt ))
n , err := file .ReadAt (buf , iOfst )
if n == int (iAmt ) {
return _OK
}
if err != io .EOF {
return vfsErrorCode (wrp , err , _IOERR_READ )
}
clear (buf [n :])
return _IOERR_SHORT_READ
}
func vfsWrite(wrp *sqlite3_wrap .Wrapper , pFile , zBuf ptr_t , iAmt int32 , iOfst int64 ) _ErrorCode {
file := vfsFileGet (wrp , pFile ).(File )
buf := wrp .Bytes (zBuf , int64 (iAmt ))
_ , err := file .WriteAt (buf , iOfst )
return vfsErrorCode (wrp , err , _IOERR_WRITE )
}
func vfsTruncate(wrp *sqlite3_wrap .Wrapper , pFile ptr_t , nByte int64 ) _ErrorCode {
file := vfsFileGet (wrp , pFile ).(File )
err := file .Truncate (nByte )
return vfsErrorCode (wrp , err , _IOERR_TRUNCATE )
}
func vfsSync(wrp *sqlite3_wrap .Wrapper , pFile ptr_t , flags SyncFlag ) _ErrorCode {
file := vfsFileGet (wrp , pFile ).(File )
err := file .Sync (flags )
return vfsErrorCode (wrp , err , _IOERR_FSYNC )
}
func vfsFileSize(wrp *sqlite3_wrap .Wrapper , pFile , pSize ptr_t ) _ErrorCode {
file := vfsFileGet (wrp , pFile ).(File )
size , err := file .Size ()
wrp .Write64 (pSize , uint64 (size ))
return vfsErrorCode (wrp , err , _IOERR_SEEK )
}
func vfsLock(wrp *sqlite3_wrap .Wrapper , pFile ptr_t , eLock LockLevel ) _ErrorCode {
file := vfsFileGet (wrp , pFile ).(File )
err := file .Lock (eLock )
return vfsErrorCode (wrp , err , _IOERR_LOCK )
}
func vfsUnlock(wrp *sqlite3_wrap .Wrapper , pFile ptr_t , eLock LockLevel ) _ErrorCode {
file := vfsFileGet (wrp , pFile ).(File )
err := file .Unlock (LockLevel (eLock ))
return vfsErrorCode (wrp , err , _IOERR_UNLOCK )
}
func vfsCheckReservedLock(wrp *sqlite3_wrap .Wrapper , pFile , pResOut ptr_t ) _ErrorCode {
file := vfsFileGet (wrp , pFile ).(File )
locked , err := file .CheckReservedLock ()
wrp .WriteBool (pResOut , locked )
return vfsErrorCode (wrp , err , _IOERR_CHECKRESERVEDLOCK )
}
func vfsFileControl(wrp *sqlite3_wrap .Wrapper , pFile ptr_t , op _FcntlOpcode , pArg ptr_t ) _ErrorCode {
file := vfsFileGet (wrp , pFile ).(File )
if file , ok := file .(fileControl ); ok {
return file .fileControl (wrp , op , pArg )
}
return vfsFileControlImpl (wrp , file , op , pArg )
}
func vfsFileControlImpl(wrp *sqlite3_wrap .Wrapper , file File , op _FcntlOpcode , pArg ptr_t ) _ErrorCode {
mem := wrp .Memory
switch op {
case _FCNTL_LOCKSTATE :
if file , ok := file .(FileLockState ); ok {
if lk := file .LockState (); lk <= LOCK_EXCLUSIVE {
mem .Write32 (pArg , uint32 (lk ))
return _OK
}
}
case _FCNTL_PERSIST_WAL :
if file , ok := file .(FilePersistWAL ); ok {
if i := int32 (mem .Read32 (pArg )); i < 0 {
mem .WriteBool (pArg , file .PersistWAL ())
} else {
file .SetPersistWAL (i != 0 )
}
return _OK
}
case _FCNTL_POWERSAFE_OVERWRITE :
if file , ok := file .(FilePowersafeOverwrite ); ok {
if i := int32 (mem .Read32 (pArg )); i < 0 {
mem .WriteBool (pArg , file .PowersafeOverwrite ())
} else {
file .SetPowersafeOverwrite (i != 0 )
}
return _OK
}
case _FCNTL_CHUNK_SIZE :
if file , ok := file .(FileChunkSize ); ok {
size := int32 (mem .Read32 (pArg ))
file .ChunkSize (int (size ))
return _OK
}
case _FCNTL_SIZE_HINT :
if file , ok := file .(FileSizeHint ); ok {
size := int64 (mem .Read64 (pArg ))
err := file .SizeHint (size )
return vfsErrorCode (wrp , err , _IOERR_TRUNCATE )
}
case _FCNTL_HAS_MOVED :
if file , ok := file .(FileHasMoved ); ok {
moved , err := file .HasMoved ()
mem .WriteBool (pArg , moved )
return vfsErrorCode (wrp , err , _IOERR_FSTAT )
}
case _FCNTL_OVERWRITE :
if file , ok := file .(FileOverwrite ); ok {
err := file .Overwrite ()
return vfsErrorCode (wrp , err , _IOERR )
}
case _FCNTL_SYNC :
if file , ok := file .(FileSync ); ok {
var name string
if pArg != 0 {
name = mem .ReadString (pArg , _MAX_PATHNAME )
}
err := file .SyncSuper (name )
return vfsErrorCode (wrp , err , _IOERR )
}
case _FCNTL_COMMIT_PHASETWO :
if file , ok := file .(FileCommitPhaseTwo ); ok {
err := file .CommitPhaseTwo ()
return vfsErrorCode (wrp , err , _IOERR )
}
case _FCNTL_BEGIN_ATOMIC_WRITE :
if file , ok := file .(FileBatchAtomicWrite ); ok {
err := file .BeginAtomicWrite ()
return vfsErrorCode (wrp , err , _IOERR_BEGIN_ATOMIC )
}
case _FCNTL_COMMIT_ATOMIC_WRITE :
if file , ok := file .(FileBatchAtomicWrite ); ok {
err := file .CommitAtomicWrite ()
return vfsErrorCode (wrp , err , _IOERR_COMMIT_ATOMIC )
}
case _FCNTL_ROLLBACK_ATOMIC_WRITE :
if file , ok := file .(FileBatchAtomicWrite ); ok {
err := file .RollbackAtomicWrite ()
return vfsErrorCode (wrp , 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 {
var value string
ptr := ptr_t (mem .Read32 (pArg + 1 *ptrlen ))
name := mem .ReadString (ptr , _MAX_SQL_LENGTH )
if ptr := ptr_t (mem .Read32 (pArg + 2 *ptrlen )); ptr != 0 {
value = mem .ReadString (ptr , _MAX_SQL_LENGTH )
}
out , err := file .Pragma (strings .ToLower (name ), value )
ret := vfsErrorCode (wrp , err , _ERROR )
if ret == _ERROR {
out = err .Error()
}
if out != "" {
ptr := ptr_t (wrp .Xsqlite3_malloc64 (int64 (len (out )) + 1 ))
mem .Write32 (pArg , uint32 (ptr ))
mem .WriteString (ptr , out )
}
return ret
}
case _FCNTL_BUSYHANDLER :
if file , ok := file .(FileBusyHandler ); ok {
arg := int64 (mem .Read64 (pArg ))
file .BusyHandler (func () bool {
return wrp .Xsqlite3_invoke_busy_handler_go (arg ) != 0
})
return _OK
}
case _FCNTL_LOCK_TIMEOUT :
if file , ok := file .(FileSharedMemory ); ok {
if shm , ok := file .SharedMemory ().(blockingSharedMemory ); ok {
shm .shmEnableBlocking (mem .ReadBool (pArg ))
return _OK
}
}
case _FCNTL_PDB :
if file , ok := file .(filePDB ); ok {
file .SetDB (wrp .DB )
return _OK
}
case _FCNTL_NULL_IO :
file .Close ()
return _OK
}
return _NOTFOUND
}
func vfsSectorSize(wrp *sqlite3_wrap .Wrapper , pFile ptr_t ) int32 {
file := vfsFileGet (wrp , pFile ).(File )
return int32 (file .SectorSize ())
}
func vfsDeviceCharacteristics(wrp *sqlite3_wrap .Wrapper , pFile ptr_t ) DeviceCharacteristic {
file := vfsFileGet (wrp , pFile ).(File )
return file .DeviceCharacteristics ()
}
func vfsShmBarrier(wrp *sqlite3_wrap .Wrapper , pFile ptr_t ) {
shm := vfsFileGet (wrp , pFile ).(FileSharedMemory ).SharedMemory ()
shm .shmBarrier ()
}
func vfsShmMap(wrp *sqlite3_wrap .Wrapper , pFile ptr_t , iRegion , szRegion , bExtend int32 , pp ptr_t ) _ErrorCode {
shm := vfsFileGet (wrp , pFile ).(FileSharedMemory ).SharedMemory ()
p , err := shm .shmMap (wrp , iRegion , szRegion , bExtend != 0 )
wrp .Write32 (pp , uint32 (p ))
return vfsErrorCode (wrp , err , _IOERR_SHMMAP )
}
func vfsShmLock(wrp *sqlite3_wrap .Wrapper , pFile ptr_t , offset , n int32 , flags _ShmFlag ) _ErrorCode {
shm := vfsFileGet (wrp , pFile ).(FileSharedMemory ).SharedMemory ()
err := shm .shmLock (offset , n , flags )
return vfsErrorCode (wrp , err , _IOERR_SHMLOCK )
}
func vfsShmUnmap(wrp *sqlite3_wrap .Wrapper , pFile ptr_t , bDelete int32 ) _ErrorCode {
shm := vfsFileGet (wrp , pFile ).(FileSharedMemory ).SharedMemory ()
shm .shmUnmap (bDelete != 0 )
return _OK
}
func vfsGet(wrp *sqlite3_wrap .Wrapper , pVfs ptr_t ) VFS {
var name string
if pVfs != 0 {
const zNameOffset = 16
ptr := ptr_t (wrp .Read32 (pVfs + zNameOffset ))
name = wrp .ReadString (ptr , _MAX_NAME )
}
if vfs := Find (name ); vfs != nil {
return vfs
}
panic (errutil .NoVFSErr + errutil .ErrorString (name ))
}
func vfsFileRegister(wrp *sqlite3_wrap .Wrapper , pFile ptr_t , file File ) {
const fileHandleOffset = 4
id := wrp .AddHandle (file )
wrp .Write32 (pFile +fileHandleOffset , uint32 (id ))
}
func vfsFileGet(wrp *sqlite3_wrap .Wrapper , pFile ptr_t ) any {
const fileHandleOffset = 4
id := ptr_t (wrp .Read32 (pFile + fileHandleOffset ))
return wrp .GetHandle (id )
}
func vfsFileClose(wrp *sqlite3_wrap .Wrapper , pFile ptr_t ) error {
const fileHandleOffset = 4
id := ptr_t (wrp .Read32 (pFile + fileHandleOffset ))
return wrp .DelHandle (id )
}
func vfsErrorCode(wrp *sqlite3_wrap .Wrapper , err error , code _ErrorCode ) _ErrorCode {
var sys error
switch err := err .(type ) {
case nil :
code = _OK
case _ErrorCode :
code = err
case sysError :
code = err .code
sys = err .error
default :
switch v := reflect .ValueOf (err ); v .Kind () {
case reflect .Uint8 , reflect .Uint16 :
code = _ErrorCode (v .Uint ())
default :
sys = err
}
}
wrp .SysError = sys
return code
}
func SystemError [T interface { ~uint8 | ~uint16 }](err error , code T ) error {
if err == nil {
return nil
}
return sysError {error : err , code : _ErrorCode (code )}
}
type sysError struct {
error
code _ErrorCode
}
The pages are generated with Golds v0.8.4 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .