use std::io::SeekFrom;
use super::*;
fn seek_from_offset(seek_from: SeekFrom) -> i64 {
use SeekFrom::*;
match seek_from {
Start(offset) => offset as i64,
End(offset) | Current(offset) => offset,
}
}
fn seek_from_whence(seek_from: SeekFrom) -> libc::c_short {
use libc::*;
use SeekFrom::*;
(match seek_from {
Start(_) => SEEK_SET,
Current(_) => SEEK_CUR,
End(_) => SEEK_END,
}) as c_short
}
cfg_if! {
if #[cfg(any(target_os = "macos", target_os = "freebsd"))] {
use libc::flock as flock_struct;
} else {
use libc::flock64 as flock_struct;
}
}
pub(super) fn lock_file_segment(
file: &File,
arg: FlockArg,
len: Option<i64>,
whence: SeekFrom,
) -> nix::Result<bool> {
debug!(?file, ?arg, ?len, ?whence, "locking file segment");
if let Some(len) = len {
if len == 0 {
return Ok(true);
}
}
#[allow(deprecated)]
let l_type = match arg {
LockShared | LockSharedNonblock => libc::F_RDLCK,
LockExclusive | LockExclusiveNonblock => libc::F_WRLCK,
Unlock | UnlockNonblock => libc::F_UNLCK,
_ => unimplemented!(),
};
let mut flock_arg: flock_struct = unsafe { std::mem::zeroed() };
flock_arg.l_start = seek_from_offset(whence);
flock_arg.l_len = len.unwrap_or(0);
#[allow(clippy::useless_conversion)]
let l_type = l_type.try_into().unwrap();
flock_arg.l_type = l_type;
flock_arg.l_whence = seek_from_whence(whence);
use libc::{F_OFD_SETLK as SetLock, F_OFD_SETLKW as SetLockWait};
#[allow(deprecated)]
let arg = match arg {
LockShared | LockExclusive => SetLockWait,
LockSharedNonblock | LockExclusiveNonblock | Unlock | UnlockNonblock => SetLock,
_ => unimplemented!(),
};
use nix::errno::Errno;
match Errno::result(unsafe { libc::fcntl(file.as_raw_fd(), arg, &flock_arg) }) {
Ok(_) => Ok(true),
Err(errno) if errno == Errno::EWOULDBLOCK || errno == Errno::EAGAIN => Ok(false),
Err(err) => {
error!(?err, "fcntl");
Err(err)
}
}
}
impl FileLocking for File {
fn trim_exclusive_lock_left(&self, old_left: u64, new_left: u64) -> io::Result<bool> {
if flocking() {
return Ok(true);
}
self.lock_segment(UnlockNonblock, Some(new_left - old_left), old_left)
}
fn lock_segment(&self, arg: FlockArg, len: Option<u64>, offset: u64) -> io::Result<bool> {
if flocking() {
return self.flock(arg);
}
Ok(lock_file_segment(
self,
arg,
len.map(|some| some.try_into().unwrap()),
Start(offset),
)?)
}
}