From 940f3f1e305c62e73a76677afcde1b9630e27453 Mon Sep 17 00:00:00 2001
From: Graham MacDonald <grahamamacdonald@gmail.com>
Date: Fri, 19 Jun 2020 23:53:05 +0100
Subject: [PATCH] move calc_seek_offset* to syscall

---
 src/scheme/mod.rs  |  2 ++
 src/scheme/seek.rs | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 src/scheme/seek.rs

diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs
index 66f8fc7..be548bd 100644
--- a/src/scheme/mod.rs
+++ b/src/scheme/mod.rs
@@ -2,8 +2,10 @@ pub use self::scheme::Scheme;
 pub use self::scheme_mut::SchemeMut;
 pub use self::scheme_block::SchemeBlock;
 pub use self::scheme_block_mut::SchemeBlockMut;
+pub use self::seek::*;
 
 mod scheme;
 mod scheme_mut;
 mod scheme_block;
 mod scheme_block_mut;
+mod seek;
diff --git a/src/scheme/seek.rs b/src/scheme/seek.rs
new file mode 100644
index 0000000..09a4518
--- /dev/null
+++ b/src/scheme/seek.rs
@@ -0,0 +1,33 @@
+use core::cmp;
+use core::convert::TryFrom;
+use crate::error::*;
+use crate::flag::*;
+
+/// Helper for seek calls
+/// In most cases it's easier to use a usize to track the offset and buffer size internally,
+/// but the seek interface uses isize.  This wrapper ensures EOVERFLOW errors are returned
+/// as appropriate if the value in the usize can't fit in the isize.
+pub fn calc_seek_offset_usize(cur_offset: usize, pos: isize, whence: usize, buf_len: usize) -> Result<isize> {
+    let cur_offset = isize::try_from(cur_offset).or_else(|_| Err(Error::new(EOVERFLOW)))?;
+    let buf_len = isize::try_from(buf_len).or_else(|_| Err(Error::new(EOVERFLOW)))?;
+    calc_seek_offset_isize(cur_offset, pos, whence, buf_len)
+}
+
+/// Helper for seek calls
+/// Result is guaranteed to be positive.
+/// EOVERFLOW returned if the arguments would cause an overflow.
+/// EINVAL returned if the new offset is out of bounds.
+pub fn calc_seek_offset_isize(cur_offset: isize, pos: isize, whence: usize, buf_len: isize) -> Result<isize> {
+    let new_offset = match whence {
+        SEEK_CUR => pos.checked_add(cur_offset),
+        SEEK_END => pos.checked_add(buf_len),
+        SEEK_SET => Some(pos),
+        _ => None,
+    };
+
+    match new_offset {
+        Some(new_offset) if new_offset < 0 => Err(Error::new(EINVAL)),
+        Some(new_offset) => Ok(cmp::min(new_offset, buf_len)),
+        None => Err(Error::new(EOVERFLOW))
+    }
+}
\ No newline at end of file
-- 
GitLab