diff --git a/.github/workflows/bsd.sh b/.github/workflows/bsd.sh index b9a4d20..e751d6b 100755 --- a/.github/workflows/bsd.sh +++ b/.github/workflows/bsd.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +set -euo pipefail echo 'set -euo pipefail' > test.sh diff --git a/.github/workflows/repro.sh b/.github/workflows/repro.sh index 6d2856b..debfd76 100755 --- a/.github/workflows/repro.sh +++ b/.github/workflows/repro.sh @@ -13,7 +13,7 @@ elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then fi # Download tools -mkdir -p tools +mkdir -p tools/ [ -d "tools/wasi-sdk"* ] || curl -#L "$WASI_SDK" | tar xzC tools & [ -d "tools/binaryen-version"* ] || curl -#L "$BINARYEN" | tar xzC tools & wait diff --git a/sqlite.go b/sqlite.go index 90dc8ed..c111c44 100644 --- a/sqlite.go +++ b/sqlite.go @@ -99,8 +99,8 @@ func instantiateSQLite() (sqlt *sqlite, err error) { } sqlt.freer = util.ReadUint32(sqlt.mod, uint32(global.Get())) - if err != nil { - return nil, err + if sqlt.freer == 0 { + return nil, util.BadBinaryErr } return sqlt, nil } diff --git a/tests/testdata/f2fs.img.gz b/tests/testdata/f2fs.img.gz new file mode 100644 index 0000000..572867e Binary files /dev/null and b/tests/testdata/f2fs.img.gz differ diff --git a/tests/testdata/f2fs.sh b/tests/testdata/f2fs.sh new file mode 100755 index 0000000..8ac7bb1 --- /dev/null +++ b/tests/testdata/f2fs.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd -P -- "$(dirname -- "$0")" +ROOT=../../ + +if mountpoint -q f2fs/; then + sudo umount f2fs/ +fi + +mkdir -p f2fs/ +gunzip -c f2fs.img.gz > f2fs.img +sudo mount -nv -o loop f2fs.img f2fs/ +mkdir -p f2fs/tmp/ + +go test -c "$ROOT/tests" -coverpkg github.com/ncruces/go-sqlite3/... +TMPDIR=f2fs/tmp/ ./tests.test -test.v -test.short -test.coverprofile cover.out +go tool cover -html cover.out + +sudo umount f2fs/ +rm -r f2fs/ f2fs.img cover.out *.test \ No newline at end of file diff --git a/vfs/file.go b/vfs/file.go index 8664487..d589d37 100644 --- a/vfs/file.go +++ b/vfs/file.go @@ -173,10 +173,14 @@ func (*vfsFile) SectorSize() int { } func (f *vfsFile) DeviceCharacteristics() DeviceCharacteristic { - if f.psow { - return IOCAP_POWERSAFE_OVERWRITE + var res DeviceCharacteristic + if osBatchAtomic(f.File) { + res |= IOCAP_BATCH_ATOMIC } - return 0 + if f.psow { + res |= IOCAP_POWERSAFE_OVERWRITE + } + return res } func (f *vfsFile) SizeHint(size int64) error { diff --git a/vfs/os_f2fs_linux.go b/vfs/os_f2fs_linux.go new file mode 100644 index 0000000..6e7ee77 --- /dev/null +++ b/vfs/os_f2fs_linux.go @@ -0,0 +1,34 @@ +//go:build (amd64 || arm64) && !sqlite3_nosys + +package vfs + +import ( + "os" + + "golang.org/x/sys/unix" +) + +const ( + _F2FS_IOC_START_ATOMIC_WRITE = 62721 + _F2FS_IOC_COMMIT_ATOMIC_WRITE = 62722 + _F2FS_IOC_ABORT_ATOMIC_WRITE = 62725 + _F2FS_IOC_GET_FEATURES = 2147808524 + _F2FS_FEATURE_ATOMIC_WRITE = 4 +) + +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/vfs/os_std_atomic.go b/vfs/os_std_atomic.go new file mode 100644 index 0000000..7a62ca5 --- /dev/null +++ b/vfs/os_std_atomic.go @@ -0,0 +1,9 @@ +//go:build !linux || !(amd64 || arm64) || sqlite3_nosys + +package vfs + +import "os" + +func osBatchAtomic(*os.File) bool { + return false +}