summaryrefslogtreecommitdiff
path: root/vendor/github.com/ncruces/go-sqlite3/vfs/os_bsd.go
blob: 56713e3591254297e608a879d5ed99f1b2b26a99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//go:build ((freebsd || openbsd || netbsd || dragonfly || illumos) && !(sqlite3_dotlk || sqlite3_nosys)) || sqlite3_flock

package vfs

import (
	"os"

	"golang.org/x/sys/unix"
)

func osGetSharedLock(file *os.File) _ErrorCode {
	return osLock(file, unix.LOCK_SH|unix.LOCK_NB, _IOERR_RDLOCK)
}

func osGetReservedLock(file *os.File) _ErrorCode {
	rc := osLock(file, unix.LOCK_EX|unix.LOCK_NB, _IOERR_LOCK)
	if rc == _BUSY {
		// The documentation states the lock is upgraded by releasing the previous lock,
		// then acquiring the new lock.
		// This is a race, so return BUSY_SNAPSHOT to ensure the transaction is aborted.
		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 := osLock(file, unix.LOCK_SH|unix.LOCK_NB, _IOERR_RDLOCK)
	if rc == _BUSY {
		// The documentation states the lock is upgraded by releasing the previous lock,
		// then acquiring the new lock.
		// This is a race, so return IOERR_RDLOCK to ensure the transaction is aborted.
		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.
	lock, rc := osTestLock(file, _RESERVED_BYTE, 1)
	return lock == unix.F_WRLCK, rc
}

func osLock(file *os.File, how int, def _ErrorCode) _ErrorCode {
	err := unix.Flock(int(file.Fd()), how)
	return osLockErrorCode(err, def)
}