summaryrefslogtreecommitdiff
path: root/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix_lock.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/ncruces/go-sqlite3/vfs/os_unix_lock.go')
-rw-r--r--vendor/github.com/ncruces/go-sqlite3/vfs/os_unix_lock.go106
1 files changed, 106 insertions, 0 deletions
diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix_lock.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix_lock.go
new file mode 100644
index 000000000..d04c1f6a0
--- /dev/null
+++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix_lock.go
@@ -0,0 +1,106 @@
+//go:build (linux || darwin || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) && !sqlite3_nosys
+
+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, _ := osGetLock(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 osGetPendingLock(file *os.File, block bool) _ErrorCode {
+ var timeout time.Duration
+ if block {
+ timeout = -1
+ }
+ // Acquire the PENDING lock.
+ return osWriteLock(file, _PENDING_BYTE, 1, timeout)
+}
+
+func osGetExclusiveLock(file *os.File, wait bool) _ErrorCode {
+ var timeout time.Duration
+ if wait {
+ timeout = time.Millisecond
+ }
+ // Acquire the EXCLUSIVE lock.
+ return osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, timeout)
+}
+
+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 {
+ // In theory, the downgrade to a SHARED cannot fail because another
+ // process is holding an incompatible lock. If it does, this
+ // indicates that the other process is not following the locking
+ // protocol. If this happens, return _IOERR_RDLOCK. Returning
+ // BUSY would confuse the upper layer.
+ 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 := osGetLock(file, _RESERVED_BYTE, 1)
+ return lock == unix.F_WRLCK, rc
+}
+
+func osGetLock(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
+ }
+ if errno == unix.EWOULDBLOCK && unix.EWOULDBLOCK != unix.EAGAIN {
+ return _BUSY
+ }
+ }
+ return def
+}