Skip to content

Commit

Permalink
Restrict Dir::seek to 64-bit platforms. (#1289)
Browse files Browse the repository at this point in the history
Restrict `Dir::seek` to 64-bit platforms, since it's implemented in
terms of `libc::seekdir` which uses a `c_long` for the offset.

Also, rename `Dir::seekdir` to `Dir::seek` since it's a member of `Dir`
it doesn't need the extra `dir` qualification.

Fixes #1263.
  • Loading branch information
sunfishcode authored Jan 25, 2025
1 parent f377e85 commit 2cc2fd4
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 10 deletions.
40 changes: 35 additions & 5 deletions src/backend/libc/fs/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,19 @@ impl Dir {
}

/// `seekdir(self, offset)`
///
/// This function iso only available on 64-bit platforms because it's
/// implemented using [`libc::seekdir`] which only supports offsets that
/// fit in a `c_long`.
///
/// [`libc::seekdir`]: https://docs.rs/libc/latest/arm-unknown-linux-gnueabihf/libc/fn.seekdir.html
#[cfg(target_pointer_width = "64")]
#[cfg_attr(docsrs, doc(cfg(target_pointer_width = "64")))]
#[doc(alias = "seekdir")]
#[inline]
pub fn seekdir(&mut self, offset: i64) -> io::Result<()> {
pub fn seek(&mut self, offset: i64) -> io::Result<()> {
self.any_errors = false;
unsafe { c::seekdir(self.libc_dir.as_ptr(), offset as c::c_long) }
unsafe { c::seekdir(self.libc_dir.as_ptr(), offset) }
Ok(())
}

Expand Down Expand Up @@ -179,7 +188,14 @@ impl Dir {
#[cfg(not(any(freebsdlike, netbsdlike, target_os = "vita")))]
d_ino: dirent.d_ino,

#[cfg(any(linux_like))]
#[cfg(any(
linux_like,
solarish,
target_os = "fuchsia",
target_os = "hermit",
target_os = "openbsd",
target_os = "redox"
))]
d_off: dirent.d_off,

#[cfg(any(freebsdlike, netbsdlike))]
Expand Down Expand Up @@ -290,7 +306,14 @@ pub struct DirEntry {

name: CString,

#[cfg(any(linux_like))]
#[cfg(any(
linux_like,
solarish,
target_os = "fuchsia",
target_os = "hermit",
target_os = "openbsd",
target_os = "redox"
))]
d_off: c::off_t,
}

Expand All @@ -304,7 +327,14 @@ impl DirEntry {
/// Returns the "offset" of this directory entry. Note that this is not
/// a true numerical offset but an opaque cookie that identifies a
/// position in the given stream.
#[cfg(any(linux_like))]
#[cfg(any(
linux_like,
solarish,
target_os = "fuchsia",
target_os = "hermit",
target_os = "openbsd",
target_os = "redox"
))]
#[inline]
pub fn offset(&self) -> i64 {
self.d_off as i64
Expand Down
14 changes: 13 additions & 1 deletion src/backend/linux_raw/fs/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,20 @@ impl Dir {
}

/// `seekdir(self, offset)`
///
/// This function iso only available on 64-bit platforms because it's
/// implemented using [`libc::seekdir`] which only supports offsets that
/// fit in a `c_long`.
///
/// [`libc::seekdir`]: https://docs.rs/libc/latest/arm-unknown-linux-gnueabihf/libc/fn.seekdir.html
// In the linux_raw backend here, we don't use `libc::seekdir` and don't
// have this limitattion, but it's a goal of rustix to support the same API
// on both the linux_raw and libc backends.
#[cfg(target_pointer_width = "64")]
#[cfg_attr(docsrs, doc(cfg(target_pointer_width = "64")))]
#[doc(alias = "seekdir")]
#[inline]
pub fn seekdir(&mut self, offset: i64) -> io::Result<()> {
pub fn seek(&mut self, offset: i64) -> io::Result<()> {
self.any_errors = false;
self.rewind = false;
self.pos = self.buf.len();
Expand Down
29 changes: 25 additions & 4 deletions tests/fs/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,14 @@ fn test_dir_read_from() {
assert!(saw_cargo_toml);
}

#[cfg(any(linux_like))]
#[cfg(any(
linux_like,
solarish,
target_os = "fuchsia",
target_os = "hermit",
target_os = "openbsd",
target_os = "redox"
))]
#[test]
fn test_dir_seek() {
use std::io::Write;
Expand Down Expand Up @@ -94,7 +101,7 @@ fn test_dir_seek() {
for _ in 0..count / 2 {
dir.read().unwrap().unwrap();
}
let offset = dir.read().unwrap().unwrap().offset();
let offset: i64 = dir.read().unwrap().unwrap().offset();

// Read the rest of the directory entries and record the names
let mut entries = Vec::new();
Expand All @@ -104,8 +111,22 @@ fn test_dir_seek() {
}
assert!(entries.len() >= count / 2);

// Seek to the stored position
dir.seekdir(offset).unwrap();
// Seek to the stored position. On 64-bit platforms we can `seek`.
// On 32-bit platforms, `seek` isn't supported so rewind and scan.
#[cfg(target_pointer_width = "64")]
{
dir.seek(offset).unwrap();
}
#[cfg(target_pointer_width = "32")]
{
dir.rewind();
while let Some(entry) = dir.read() {
let entry = entry.unwrap();
if entry.offset() == offset {
break;
}
}
}

// Confirm that we're getting the same results as before
let mut entries2 = Vec::new();
Expand Down

0 comments on commit 2cc2fd4

Please sign in to comment.