Repository: bytecodealliance/rustix (language: rust)

Issue:
`test_dir_seek` is failing on main
@nrath-js The test_dir_seek test is failing on main on arm on the libc backend:

https://github.com/bytecodealliance/rustix/actions/runs/12680283634/job/35341748535

It's possible this is related to a 64-bit offset being casted to a 32-bit c_long for the seekdir call. Do you know of any alternative we might use here?

If there aren't any other alternatives, we may have to revert this feature.



Discussion / hints:

Fix patch:
diff --git a/src/backend/libc/fs/dir.rs b/src/backend/libc/fs/dir.rs
index 2680b253d..411b95008 100644
--- a/src/backend/libc/fs/dir.rs
+++ b/src/backend/libc/fs/dir.rs
@@ -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(())
     }
 
@@ -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))]
@@ -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,
 }
 
@@ -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
diff --git a/src/backend/linux_raw/fs/dir.rs b/src/backend/linux_raw/fs/dir.rs
index a1b13b45f..4d8d81cc7 100644
--- a/src/backend/linux_raw/fs/dir.rs
+++ b/src/backend/linux_raw/fs/dir.rs
@@ -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();


Test patch:
diff --git a/tests/fs/dir.rs b/tests/fs/dir.rs
index df759dd0c..4a0c1a997 100644
--- a/tests/fs/dir.rs
+++ b/tests/fs/dir.rs
@@ -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;
@@ -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();
@@ -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();