-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Closed
Description
While trying to get readdir
working on OSX (which is to be preferred over readdir_r, as readdir_r is deprecated), I ran into the error that d_name
always seemed off by 2 bytes, e.g. for /var/tmp/ it showed:
.
bash_profile
X�
�
etc.
I suspected that something is wrong with the dirent struct which is defined in libc:
pub struct dirent {
pub d_ino: u64,
pub d_seekoff: u64,
pub d_reclen: u16,
pub d_namlen: u16,
pub d_type: u8,
pub d_name: [::c_char; 1024],
}
But when running bindgen on /usr/include/dirent.h
on OSX I get this:
#[repr(C)]
#[derive(Copy)]
pub struct dirent {
pub d_ino: __uint64_t,
pub d_seekoff: __uint64_t,
pub d_reclen: __uint16_t,
pub d_namlen: __uint16_t,
pub d_type: __uint8_t,
pub d_name: [::std::os::raw::c_char; 1024usize],
}
Which is basically the same but still somehow wrong. Now, when I take the binding from freebsd it works. The freebsd binding (from libc):
pub struct dirent {
pub d_fileno: u32,
pub d_reclen: u16,
pub d_type: u8,
pub d_namlen: u8,
pub d_name: [::c_char; 256],
}
Here's an example with the right and the wrong binding:
extern crate libc;
use std::ffi::{CString, CStr};
use std::str;
use libc::{opendir, closedir, DIR, dirent, c_char};
extern "C" {
pub fn readdir(arg1: *mut DIR) -> *mut dirent;
}
pub struct my_dirent {
pub d_fileno: u32,
pub d_reclen: u16,
pub d_type: u8,
pub d_namlen: u8,
pub d_name: [c_char; 256],
}
fn main() {
let dir = CString::new("/usr").unwrap();
unsafe {
let dp = opendir(dir.as_ptr());
let mut dirp = readdir(dp);
while !dirp.is_null() {
// fails
println!("wrong: {:?}", CStr::from_ptr(&(*dirp).d_name[0]));
// succeeds
let dirp2 = &mut *(dirp as *mut my_dirent);
println!("fileno: {}, reclen: {}, type: {}, namelen: {}, name: {:?}",
(*dirp2).d_fileno,
(*dirp2).d_reclen,
(*dirp2).d_type,
(*dirp2).d_namlen,
CStr::from_ptr(&(*dirp2).d_name[0]));
dirp = readdir(dp);
}
closedir(dp);
}
}
Output:
wrong: "."
fileno: 36788336, reclen: 12, type: 4, namelen: 1, name: "."
wrong: "bash_profile"
fileno: 36384337, reclen: 12, type: 4, namelen: 2, name: ".."
wrong: ""
fileno: 67850380, reclen: 24, type: 8, namelen: 13, name: ".bash_profile"
wrong: "X\xad\x04\x14"
fileno: 80172149, reclen: 20, type: 8, namelen: 9, name: ".DS_Store"
wrong: "\x16\xad\x04\x0c"
fileno: 78469237, reclen: 20, type: 4, namelen: 8, name: "__MACOSX"
etc. And the output of ls -ali
as proof that also the other fields are mapped correctly:
36788336 drwxrwxrwt 106 root wheel 3604 Oct 3 15:41 .
36384337 drwxr-xr-x 26 root wheel 884 Sep 3 04:43 ..
67850380 -rw------- 1 philipp wheel 3768 Jun 3 01:13 .bash_profile
80172149 -rw-r--r--@ 1 philipp wheel 6148 Sep 28 11:57 .DS_Store
78469237 drwxrwxr-x@ 3 philipp wheel 102 Feb 24 2014 __MACOSX
Anyone knows what's wrong here?
Metadata
Metadata
Assignees
Labels
No labels