syscall/scheme/
seek.rs

1use crate::{error::*, flag::*};
2use core::{cmp, convert::TryFrom};
3
4/// Helper for seek calls
5/// In most cases it's easier to use a usize to track the offset and buffer size internally,
6/// but the seek interface uses isize.  This wrapper ensures EOVERFLOW errors are returned
7/// as appropriate if the value in the usize can't fit in the isize.
8pub fn calc_seek_offset_usize(
9    cur_offset: usize,
10    pos: isize,
11    whence: usize,
12    buf_len: usize,
13) -> Result<isize> {
14    let cur_offset = isize::try_from(cur_offset).or_else(|_| Err(Error::new(EOVERFLOW)))?;
15    let buf_len = isize::try_from(buf_len).or_else(|_| Err(Error::new(EOVERFLOW)))?;
16    calc_seek_offset_isize(cur_offset, pos, whence, buf_len)
17}
18
19/// Helper for seek calls
20/// Result is guaranteed to be positive.
21/// EOVERFLOW returned if the arguments would cause an overflow.
22/// EINVAL returned if the new offset is out of bounds.
23pub fn calc_seek_offset_isize(
24    cur_offset: isize,
25    pos: isize,
26    whence: usize,
27    buf_len: isize,
28) -> Result<isize> {
29    let new_offset = match whence {
30        SEEK_CUR => pos.checked_add(cur_offset),
31        SEEK_END => pos.checked_add(buf_len),
32        SEEK_SET => Some(pos),
33        _ => None,
34    };
35
36    match new_offset {
37        Some(new_offset) if new_offset < 0 => Err(Error::new(EINVAL)),
38        Some(new_offset) => Ok(cmp::min(new_offset, buf_len)),
39        None => Err(Error::new(EOVERFLOW)),
40    }
41}