Skip to content

Commit

Permalink
Implement fcntl_getlk
Browse files Browse the repository at this point in the history
  • Loading branch information
al8n committed Jun 17, 2024
1 parent 1716fed commit 600f50c
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 1 deletion.
35 changes: 35 additions & 0 deletions src/backend/libc/fs/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1289,6 +1289,41 @@ pub(crate) fn fcntl_lock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::R
}
}

#[cfg(not(any(
target_os = "emscripten",
target_os = "espidf",
target_os = "fuchsia",
target_os = "redox",
target_os = "vita",
target_os = "wasi"
)))]
#[inline]
pub(crate) fn fcntl_getlk(fd: BorrowedFd<'_>) -> io::Result<bool> {
use c::{flock, EINVAL, F_GETLK, F_RDLCK, F_UNLCK, F_WRLCK, SEEK_SET};

unsafe {
let mut lock: flock = core::mem::zeroed();
lock.l_type = F_WRLCK as _;

// When `l_len` is zero, this locks all the bytes from
// `l_whence`/`l_start` to the end of the file, even as the
// file grows dynamically.
lock.l_whence = SEEK_SET as _;
lock.l_start = 0;
lock.l_len = 0;
let result = c::fcntl(borrowed_fd(fd), F_GETLK, &mut lock);
if result == -1 {
return Err(io::Errno::last_os_error());
}

if lock.l_type == F_WRLCK {
Ok(true)
} else {
Ok(false)
}
}
}

pub(crate) fn seek(fd: BorrowedFd<'_>, pos: SeekFrom) -> io::Result<u64> {
let (whence, offset) = match pos {
SeekFrom::Start(pos) => {
Expand Down
56 changes: 55 additions & 1 deletion src/backend/linux_raw/fs/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::backend::conv::fs::oflags_for_open_how;
))]
use crate::backend::conv::zero;
use crate::backend::conv::{
by_ref, c_int, c_uint, dev_t, opt_mut, pass_usize, raw_fd, ret, ret_c_int, ret_c_uint,
by_mut, by_ref, c_int, c_uint, dev_t, opt_mut, pass_usize, raw_fd, ret, ret_c_int, ret_c_uint,
ret_infallible, ret_owned_fd, ret_usize, size_of, slice, slice_mut,
};
#[cfg(target_pointer_width = "64")]
Expand Down Expand Up @@ -1090,6 +1090,60 @@ pub(crate) fn fcntl_lock(fd: BorrowedFd<'_>, operation: FlockOperation) -> io::R
}
}

#[inline]
pub(crate) fn fcntl_getlk(fd: BorrowedFd<'_>) -> io::Result<bool> {
use linux_raw_sys::general::F_WRLCK;
#[cfg(target_pointer_width = "64")]
use linux_raw_sys::general::{flock, F_GETLK};
#[cfg(target_pointer_width = "32")]
use linux_raw_sys::general::{flock64 as flock, F_GETLK64 as F_GETLK};

let lock = flock {
l_type: F_WRLCK as _,

// When `l_len` is zero, this locks all the bytes from
// `l_whence`/`l_start` to the end of the file, even as the
// file grows dynamically.
l_whence: SEEK_SET as _,
l_start: 0,
l_len: 0,

// Unused.
l_pid: 0,
};

#[cfg(target_pointer_width = "32")]
let result = unsafe {
ret(syscall_readonly!(
__NR_fcntl64,
fd,
c_uint(F_GETLK),
by_mut(&mut lock)
))
};

#[cfg(target_pointer_width = "64")]
let result = unsafe {
ret(syscall_readonly!(
__NR_fcntl,
fd,
c_uint(F_GETLK),
by_mut(&mut lock)
))
};

match result {
Ok(_) => {
if lock.l_type == F_WRLCK as i16 {
Ok(true)
} else {
Ok(false)
}
}
Err(err) => return Err(err),
}
}

#[inline]
pub(crate) fn rename(old_path: &CStr, new_path: &CStr) -> io::Result<()> {
#[cfg(target_arch = "riscv64")]
Expand Down
27 changes: 27 additions & 0 deletions src/fs/fcntl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,30 @@ pub fn fcntl_add_seals<Fd: AsFd>(fd: Fd, seals: SealFlags) -> io::Result<()> {
pub fn fcntl_lock<Fd: AsFd>(fd: Fd, operation: FlockOperation) -> io::Result<()> {
backend::fs::syscalls::fcntl_lock(fd.as_fd(), operation)
}

/// `fcntl(fd, F_GETLK)`—Check if the fd is locked or not.
///
/// This function doesn't currently have an offset or len; it currently always
/// sets the `l_len` field to 0, which is a special case that means the entire
/// file should be locked.
///
/// # References
/// - [POSIX]
/// - [Linux]
///
/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html
/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html
#[cfg(not(any(
target_os = "emscripten",
target_os = "espidf",
target_os = "fuchsia",
target_os = "redox",
target_os = "vita",
target_os = "wasi"
)))]
#[inline]
#[doc(alias = "F_SETLK")]
#[doc(alias = "F_SETLKW")]
pub fn fcntl_getlk<Fd: AsFd>(fd: Fd) -> io::Result<bool> {
backend::fs::syscalls::fcntl_getlk(fd.as_fd())
}
27 changes: 27 additions & 0 deletions tests/fs/fcntl_getlk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#[test]
fn test_fcntl_getlk() {
use rustix::fs::{fcntl_getlk, flock, FlockOperation};

let f = tempfile::tempfile().unwrap();
flock(&f, FlockOperation::LockExclusive).unwrap();
assert!(fcntl_getlk(&f).unwrap());
flock(&f, FlockOperation::Unlock).unwrap();
assert!(!fcntl_getlk(&f).unwrap());
let g = tempfile::tempfile().unwrap();
flock(&g, FlockOperation::LockExclusive).unwrap();
assert!(fcntl_getlk(&g).unwrap());
flock(&g, FlockOperation::Unlock).unwrap();
assert!(!fcntl_getlk(&g).unwrap());

// when a file is locked shared, the getlk function wiil return l_type = F_UNLCK
let f = tempfile::tempfile().unwrap();
flock(&f, FlockOperation::LockShared).unwrap();
assert!(!fcntl_getlk(&f).unwrap());
flock(&f, FlockOperation::Unlock).unwrap();
assert!(!fcntl_getlk(&f).unwrap());
let g = tempfile::tempfile().unwrap();
flock(&g, FlockOperation::LockShared).unwrap();
assert!(!fcntl_getlk(&g).unwrap());
flock(&g, FlockOperation::Unlock).unwrap();
assert!(!fcntl_getlk(&g).unwrap());
}
7 changes: 7 additions & 0 deletions tests/fs/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ mod fcntl;
target_os = "redox",
target_os = "wasi"
)))]
mod fcntl_getlk;
#[cfg(not(any(
target_os = "emscripten",
target_os = "fuchsia",
target_os = "redox",
target_os = "wasi"
)))]
mod fcntl_lock;
mod file;
#[cfg(not(target_os = "wasi"))]
Expand Down

0 comments on commit 600f50c

Please sign in to comment.