Files
sqlite3/vfs/file.go

248 lines
5.1 KiB
Go
Raw Normal View History

2023-06-01 18:11:37 +01:00
package vfs
2023-03-29 15:01:25 +01:00
import (
2023-05-18 16:00:34 +01:00
"errors"
"io"
"io/fs"
2023-03-29 15:01:25 +01:00
"os"
2023-05-18 16:00:34 +01:00
"path/filepath"
2025-03-26 02:13:30 +00:00
"runtime"
2023-05-23 12:38:29 +01:00
"syscall"
2023-03-29 15:01:25 +01:00
)
2023-05-19 02:00:16 +01:00
type vfsOS struct{}
2023-05-18 16:00:34 +01:00
2023-05-19 02:00:16 +01:00
func (vfsOS) FullPathname(path string) (string, error) {
2023-05-18 16:00:34 +01:00
path, err := filepath.Abs(path)
if err != nil {
return "", err
}
2024-09-27 12:32:11 +01:00
return path, testSymlinks(filepath.Dir(path))
}
func testSymlinks(path string) error {
p, err := filepath.EvalSymlinks(path)
2023-05-18 16:00:34 +01:00
if err != nil {
2024-09-27 12:32:11 +01:00
return err
2023-05-18 16:00:34 +01:00
}
2024-09-27 12:32:11 +01:00
if p != path {
return _OK_SYMLINK
2023-05-18 16:00:34 +01:00
}
2024-09-27 12:32:11 +01:00
return nil
2023-05-18 16:00:34 +01:00
}
2023-05-19 02:00:16 +01:00
func (vfsOS) Delete(path string, syncDir bool) error {
2023-05-18 16:00:34 +01:00
err := os.Remove(path)
2024-10-30 12:20:21 +00:00
if errors.Is(err, fs.ErrNotExist) {
return _IOERR_DELETE_NOENT
}
2023-05-18 16:00:34 +01:00
if err != nil {
return err
}
2025-03-26 02:13:30 +00:00
if isUnix && syncDir {
2023-05-18 16:00:34 +01:00
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
}
2023-05-19 03:04:07 +01:00
func (vfsOS) Access(name string, flags AccessFlag) (bool, error) {
2023-05-18 16:00:34 +01:00
err := osAccess(name, flags)
2023-05-19 03:04:07 +01:00
if flags == ACCESS_EXISTS {
2023-05-18 16:00:34 +01:00
if errors.Is(err, fs.ErrNotExist) {
return false, nil
}
} else {
if errors.Is(err, fs.ErrPermission) {
return false, nil
}
}
return err == nil, err
}
2023-05-19 03:04:07 +01:00
func (vfsOS) Open(name string, flags OpenFlag) (File, OpenFlag, error) {
2024-07-26 01:23:35 +01:00
// notest // OpenFilename is called instead
return nil, 0, _CANTOPEN
2023-06-02 02:31:15 +01:00
}
func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error) {
2024-09-27 12:32:11 +01:00
oflags := _O_NOFOLLOW
2023-05-19 03:04:07 +01:00
if flags&OPEN_EXCLUSIVE != 0 {
2023-05-18 16:00:34 +01:00
oflags |= os.O_EXCL
}
2023-05-19 03:04:07 +01:00
if flags&OPEN_CREATE != 0 {
2023-05-18 16:00:34 +01:00
oflags |= os.O_CREATE
}
2023-05-19 03:04:07 +01:00
if flags&OPEN_READONLY != 0 {
2023-05-18 16:00:34 +01:00
oflags |= os.O_RDONLY
}
2023-05-19 03:04:07 +01:00
if flags&OPEN_READWRITE != 0 {
2023-05-18 16:00:34 +01:00
oflags |= os.O_RDWR
}
2025-02-24 12:25:19 +00:00
isCreate := flags&(OPEN_CREATE) != 0
isJournl := flags&(OPEN_MAIN_JOURNAL|OPEN_SUPER_JOURNAL|OPEN_WAL) != 0
2023-05-18 16:00:34 +01:00
var err error
var f *os.File
if name == nil {
2025-02-24 13:12:30 +00:00
f, err = os.CreateTemp(os.Getenv("SQLITE_TMPDIR"), "*.db")
2023-05-18 16:00:34 +01:00
} else {
2025-03-26 02:13:30 +00:00
f, err = os.OpenFile(name.String(), oflags, 0666)
2023-05-18 16:00:34 +01:00
}
if err != nil {
2024-06-06 00:09:14 +01:00
if name == nil {
return nil, flags, _IOERR_GETTEMPPATH
}
2023-05-23 12:38:29 +01:00
if errors.Is(err, syscall.EISDIR) {
return nil, flags, _CANTOPEN_ISDIR
}
2025-02-24 12:25:19 +00:00
if isCreate && isJournl && errors.Is(err, fs.ErrPermission) &&
osAccess(name.String(), ACCESS_EXISTS) != nil {
return nil, flags, _READONLY_DIRECTORY
}
2023-05-18 16:00:34 +01:00
return nil, flags, err
}
if modeof := name.URIParameter("modeof"); modeof != "" {
2023-06-02 02:31:15 +01:00
if err = osSetMode(f, modeof); err != nil {
f.Close()
return nil, flags, _IOERR_FSTAT
}
}
2025-03-26 02:13:30 +00:00
if isUnix && flags&OPEN_DELETEONCLOSE != 0 {
2023-05-18 16:00:34 +01:00
os.Remove(f.Name())
}
file := vfsFile{
File: f,
psow: true,
2025-03-12 17:29:12 +00:00
atomic: osBatchAtomic(f),
2023-05-19 03:04:07 +01:00
readOnly: flags&OPEN_READONLY != 0,
2025-03-26 02:13:30 +00:00
syncDir: isUnix && isCreate && isJournl,
delete: !isUnix && flags&OPEN_DELETEONCLOSE != 0,
2025-02-24 12:25:19 +00:00
shm: NewSharedMemory(name.String()+"-shm", flags),
2023-05-18 16:00:34 +01:00
}
return &file, flags, nil
}
2023-04-10 19:55:44 +01:00
type vfsFile struct {
*os.File
2024-04-27 20:53:54 +01:00
shm SharedMemory
2023-09-21 02:48:59 +01:00
lock LockLevel
readOnly bool
2024-03-14 14:18:37 +00:00
keepWAL bool
syncDir bool
2025-03-12 17:29:12 +00:00
atomic bool
2025-03-26 02:13:30 +00:00
delete bool
2024-03-14 14:18:37 +00:00
psow bool
2023-04-10 19:55:44 +01:00
}
2023-03-29 15:01:25 +01:00
2023-05-19 02:00:16 +01:00
var (
// Ensure these interfaces are implemented:
2023-05-19 03:04:07 +01:00
_ FileLockState = &vfsFile{}
_ FileHasMoved = &vfsFile{}
_ FileSizeHint = &vfsFile{}
2025-01-13 09:28:47 +00:00
_ FilePersistWAL = &vfsFile{}
2023-05-19 03:04:07 +01:00
_ FilePowersafeOverwrite = &vfsFile{}
2023-05-19 02:00:16 +01:00
)
func (f *vfsFile) Close() error {
2025-03-26 02:13:30 +00:00
if f.delete {
defer os.Remove(f.Name())
}
2024-04-27 20:53:54 +01:00
if f.shm != nil {
f.shm.Close()
}
2024-10-30 12:20:21 +00:00
f.Unlock(LOCK_NONE)
return f.File.Close()
}
2025-02-24 12:25:19 +00:00
func (f *vfsFile) ReadAt(p []byte, off int64) (n int, err error) {
return osReadAt(f.File, p, off)
}
func (f *vfsFile) WriteAt(p []byte, off int64) (n int, err error) {
return osWriteAt(f.File, p, off)
}
2023-05-19 03:04:07 +01:00
func (f *vfsFile) Sync(flags SyncFlag) error {
dataonly := (flags & SYNC_DATAONLY) != 0
fullsync := (flags & 0x0f) == SYNC_FULL
2023-05-18 16:00:34 +01:00
err := osSync(f.File, fullsync, dataonly)
if err != nil {
return err
}
2025-03-26 02:13:30 +00:00
if isUnix && f.syncDir {
2023-05-18 16:00:34 +01:00
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
}
2023-05-23 16:34:09 +01:00
func (f *vfsFile) Size() (int64, error) {
2023-05-18 16:00:34 +01:00
return f.Seek(0, io.SeekEnd)
}
2024-04-28 10:33:39 +01:00
func (f *vfsFile) SectorSize() int {
2023-05-18 16:00:34 +01:00
return _DEFAULT_SECTOR_SIZE
}
2023-05-19 02:00:16 +01:00
2023-05-19 03:04:07 +01:00
func (f *vfsFile) DeviceCharacteristics() DeviceCharacteristic {
2025-01-21 01:42:57 +00:00
ret := IOCAP_SUBPAGE_READ
2025-03-12 17:29:12 +00:00
if f.atomic {
2025-01-21 01:42:57 +00:00
ret |= IOCAP_BATCH_ATOMIC
}
2023-05-19 02:00:16 +01:00
if f.psow {
2025-01-21 01:42:57 +00:00
ret |= IOCAP_POWERSAFE_OVERWRITE
2023-05-19 02:00:16 +01:00
}
2025-03-26 02:13:30 +00:00
if runtime.GOOS == "windows" {
ret |= IOCAP_UNDELETABLE_WHEN_OPEN
}
2025-01-21 01:42:57 +00:00
return ret
2023-05-19 02:00:16 +01:00
}
func (f *vfsFile) SizeHint(size int64) error {
return osAllocate(f.File, size)
}
func (f *vfsFile) HasMoved() (bool, error) {
2025-03-26 02:13:30 +00:00
if runtime.GOOS == "windows" {
return false, nil
}
2023-05-19 02:00:16 +01:00
fi, err := f.Stat()
if err != nil {
return false, err
}
pi, err := os.Stat(f.Name())
2024-10-30 12:20:21 +00:00
if errors.Is(err, fs.ErrNotExist) {
return true, nil
}
2023-05-23 12:38:29 +01:00
if err != nil {
2023-05-19 02:00:16 +01:00
return false, err
}
return !os.SameFile(fi, pi), nil
}
2023-05-19 03:04:07 +01:00
func (f *vfsFile) LockState() LockLevel { return f.lock }
2023-05-19 02:00:16 +01:00
func (f *vfsFile) PowersafeOverwrite() bool { return f.psow }
2025-01-13 09:28:47 +00:00
func (f *vfsFile) PersistWAL() bool { return f.keepWAL }
2023-05-19 02:00:16 +01:00
func (f *vfsFile) SetPowersafeOverwrite(psow bool) { f.psow = psow }
2025-01-13 09:28:47 +00:00
func (f *vfsFile) SetPersistWAL(keepWAL bool) { f.keepWAL = keepWAL }