| 1 | module filelock |
| 2 | |
| 3 | #include <sys/file.h> |
| 4 | #insert "@VEXEROOT/vlib/os/filelock/filelock_helpers.h" |
| 5 | |
| 6 | fn C.unlink(&char) i32 |
| 7 | fn C.open(&char, i32, i32) i32 |
| 8 | fn C.close(i32) i32 |
| 9 | fn C.flock(i32, i32) i32 |
| 10 | fn C.v_filelock_lock(i32, i32, i32, u64, u64) i32 |
| 11 | fn C.v_filelock_unlock(i32, u64, u64) i32 |
| 12 | |
| 13 | fn (l &FileLock) open_lock() int { |
| 14 | if l.target == .file { |
| 15 | return open_existing_file(l.name, l.mode) |
| 16 | } |
| 17 | return open_lockfile(l.name) |
| 18 | } |
| 19 | |
| 20 | fn open_lockfile(path string) int { |
| 21 | mut fd := C.open(&char(path.str), C.O_CREAT | C.O_RDONLY, 0o644) |
| 22 | if fd == -1 { |
| 23 | fd = C.open(&char(path.str), C.O_RDONLY, 0) |
| 24 | } |
| 25 | return fd |
| 26 | } |
| 27 | |
| 28 | fn open_existing_file(path string, mode LockMode) int { |
| 29 | flags := if mode == .shared { C.O_RDONLY } else { C.O_RDWR } |
| 30 | return C.open(&char(path.str), flags, 0) |
| 31 | } |
| 32 | |
| 33 | fn (l &FileLock) lock_fd(fd int, immediate bool) bool { |
| 34 | if l.target == .file { |
| 35 | return C.v_filelock_lock(fd, int(l.mode == .exclusive), int(immediate), l.start, l.len) == 0 |
| 36 | } |
| 37 | flags := if immediate { C.LOCK_EX | C.LOCK_NB } else { C.LOCK_EX } |
| 38 | return C.flock(fd, flags) == 0 |
| 39 | } |
| 40 | |
| 41 | fn (mut l FileLock) close_lock() { |
| 42 | if l.fd == -1 { |
| 43 | return |
| 44 | } |
| 45 | fd := int(l.fd) |
| 46 | if l.target == .file { |
| 47 | C.v_filelock_unlock(fd, l.start, l.len) |
| 48 | C.close(fd) |
| 49 | } else { |
| 50 | C.close(fd) |
| 51 | C.unlink(&char(l.name.str)) |
| 52 | } |
| 53 | l.fd = -1 |
| 54 | } |
| 55 | |
| 56 | // acquire blocks until the lock is acquired. |
| 57 | pub fn (mut l FileLock) acquire() ! { |
| 58 | if l.fd != -1 { |
| 59 | return error_with_code('lock already acquired by this instance', 1) |
| 60 | } |
| 61 | fd := l.open_lock() |
| 62 | if fd == -1 { |
| 63 | msg := if l.target == .file { |
| 64 | 'cannot open file ${l.name}' |
| 65 | } else { |
| 66 | 'cannot create lock file ${l.name}' |
| 67 | } |
| 68 | return error_with_code(msg, -1) |
| 69 | } |
| 70 | if !l.lock_fd(fd, false) { |
| 71 | C.close(fd) |
| 72 | return error_with_code('cannot lock ${l.name}', -2) |
| 73 | } |
| 74 | l.fd = fd |
| 75 | } |
| 76 | |
| 77 | // try_acquire tries to acquire the lock without blocking. |
| 78 | pub fn (mut l FileLock) try_acquire() bool { |
| 79 | if l.fd != -1 { |
| 80 | return true |
| 81 | } |
| 82 | fd := l.open_lock() |
| 83 | if fd == -1 { |
| 84 | return false |
| 85 | } |
| 86 | if !l.lock_fd(fd, true) { |
| 87 | C.close(fd) |
| 88 | return false |
| 89 | } |
| 90 | l.fd = fd |
| 91 | return true |
| 92 | } |
| 93 | |