diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index d1b2c85aaa..30dfbf3317 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -4,13 +4,14 @@ use core::{ num::NonZeroU64, ptr, slice, str, }; +use object::bytes_of_slice_mut; use redox_rt::{ RtTcb, protocol::{WaitFlags, wifstopped}, sys::{Resugid, WaitpidTarget}, }; use syscall::{ - self, EILSEQ, Error, MODE_PERM, StdFsCallKind, StdFsCallMeta, + self, EILSEQ, ESRCH, Error, MODE_PERM, StdFsCallKind, StdFsCallMeta, data::{Map, TimeSpec as redox_timespec}, dirent::{DirentHeader, DirentKind}, }; @@ -31,8 +32,8 @@ use crate::{ ENOMEM, ENOSYS, EOPNOTSUPP, EPERM, ERANGE, }, fcntl::{ - self, AT_EMPTY_PATH, AT_FDCWD, AT_SYMLINK_NOFOLLOW, F_GETLK, F_OFD_SETLK, F_RDLCK, - F_SETLK, F_SETLKW, F_UNLCK, F_WRLCK, flock, + self, AT_EMPTY_PATH, AT_FDCWD, AT_SYMLINK_NOFOLLOW, F_GETLK, F_OFD_GETLK, F_OFD_SETLK, + F_RDLCK, F_SETLK, F_SETLKW, F_UNLCK, F_WRLCK, flock, }, limits, pthread::{pthread_cancel, pthread_create}, @@ -300,29 +301,17 @@ impl Pal for Sys { F_SETLK | F_OFD_SETLK => { let is_ofd = cmd == F_OFD_SETLK; let flock = unsafe { &mut *(args as *mut flock) }; - // let file_off = Self::lseek(fd, 0, SEEK_SET)?; - // TODO: overflow checks - let (start, len) = match flock.l_whence as i32 { - SEEK_SET => { - let (start, len) = if flock.l_len < 0 { - (flock.l_start + flock.l_len, -flock.l_len) - } else { - (flock.l_start, flock.l_len) - }; + let (start, len) = Self::relative_to_absolute_foffset( + fd as usize, + flock.l_whence, + flock.l_start, + flock.l_len, + )?; - if start < 0 { - return Err(Errno(EINVAL)); - } + let start = start as u64 | if is_ofd { 1 << 63 } else { 0 }; + let len = len as u64; - assert!(len >= 0); - (start as u64, len as u64) - } - // FIXME: SEEK_CUR, SEEK_END - c => unreachable!("{c}"), - }; - - let start = start | if is_ofd { 1 << 63 } else { 0 }; match flock.l_type as i32 { F_UNLCK => { let meta = StdFsCallMeta::new(StdFsCallKind::Unlock, start, len); @@ -348,7 +337,71 @@ impl Pal for Sys { }; } - F_GETLK => log::warn!("F_GETLK: not yet implemented"), + F_GETLK | F_OFD_GETLK => { + let is_ofd = cmd == F_OFD_GETLK; + let flock = unsafe { &mut *(args as *mut flock) }; + + if is_ofd && flock.l_pid != 0 { + log::warn!("POSIX requires `l_pid` to be 0 on input for `F_OFD_GETLK`"); + return Err(Errno(EINVAL)); + } + + let (start, len) = Self::relative_to_absolute_foffset( + fd as usize, + flock.l_whence, + flock.l_start, + flock.l_len, + )?; + + let mut start = start as u64; + if is_ofd { + start |= 1 << 63; + } + + let mut len = len as u64; + if flock.l_type as i32 == F_WRLCK { + len |= 1 << 63; + } + + let meta = StdFsCallMeta::new(StdFsCallKind::GetLock, 0, 0); + let payload = &mut [start, len]; + // `pid` if traditional POSIX otherwise 0 + let val = + match syscall::std_fs_call(fd as usize, bytes_of_slice_mut(payload), &meta) { + // According to POSIX Issue 8: + // > If no lock is found that would prevent this lock from being created, then + // > the structure shall be left unchanged except for the lock type in `l_type` + // > which shall be set to F_UNLCK. + Err(err) if err.errno == ESRCH => { + flock.l_type = F_UNLCK as i16; + return Ok(0); + } + + Ok(val) => val, + Err(err) => return Err(Errno(err.errno)), + }; + + debug_assert_ne!(payload[0] & (1 << 63), 1 << 63); + + if is_ofd { + flock.l_pid = -1; + } else { + flock.l_pid = val as i32; + } + + let len = payload[1] & !(1 << 63); + if payload[1] & (1 << 63) == (1 << 63) { + flock.l_type = F_WRLCK as i16; + } else { + flock.l_type = F_RDLCK as i16; + } + + flock.l_whence = SEEK_SET as _; + flock.l_start = start as i64; + flock.l_len = len as i64; + return Ok(0); + } + F_SETLKW => log::warn!("F_SETLKW: not yet implemented"), _ => {} @@ -1555,3 +1608,37 @@ impl Pal for Sys { unsafe { redox_rt::thread::exit_this_thread(stack_base, stack_size) } } } + +impl Sys { + fn relative_to_absolute_foffset( + fd: usize, + whence: c_short, + start: off_t, + len: off_t, + ) -> Result<(off_t, off_t)> { + // let file_off = Self::lseek(fd, 0, SEEK_SET)?; + match whence as i32 { + SEEK_SET => { + let (start, len) = if len < 0 { + (start + len, -len) + } else { + (start, len) + }; + + if start < 0 { + return Err(Errno(EINVAL)); + } + + assert!(len >= 0); + Ok((start, len)) + } + // FIXME: andypython: SEEK_CUR, SEEK_END + c => { + log::warn!( + "Sys::relative_to_absolute_foffset: whence={whence} not yet implemented" + ); + Ok((0, 0)) + } + } + } +}