Skip to content

Commit 2519a42

Browse files
committed
Support FreeBSD-specific behavior in readdir interop test.
Filed https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=253411 for the behavior of `(struct dirent*)->d_off`, which appears to be broken in the upstream kernel driver. issue: #5
1 parent 709983d commit 2519a42

File tree

1 file changed

+107
-56
lines changed

1 file changed

+107
-56
lines changed

fuse/src/protocol/readdir/readdir_interop_test.rs

+107-56
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// SPDX-License-Identifier: Apache-2.0
1616

1717
use std::num::NonZeroU64;
18+
use std::os::unix::ffi::OsStrExt;
1819
use std::sync::mpsc;
1920
use std::{ffi, panic};
2021

@@ -70,7 +71,6 @@ impl fuse::FuseHandlers for TestFS {
7071
respond: impl for<'a> fuse::Respond<fuse::ReaddirResponse<'a>>,
7172
) {
7273
self.requests.send(format!("{:#?}", request)).unwrap();
73-
//self.requests.send(format!("{:#?}", request));
7474

7575
let mut cursor: u64 = match request.cursor() {
7676
Some(x) => x.into(),
@@ -144,152 +144,203 @@ fn readdir() {
144144
assert!(!dir_p.is_null());
145145

146146
let next_dirent = |expect| {
147-
let mut entry = libc::dirent {
148-
d_ino: 0,
149-
d_off: 0,
150-
d_reclen: 0,
151-
d_type: 0,
152-
d_name: [0; 256],
153-
};
154-
let mut result = std::ptr::null_mut();
155-
let rc = unsafe { libc::readdir_r(dir_p, &mut entry, &mut result) };
156-
assert_eq!(rc, 0);
157-
if let Some(diff) = diff_dirent(&expect, &entry) {
147+
let entry = unsafe { libc::readdir(dir_p) };
148+
assert!(!entry.is_null());
149+
if let Some(diff) = diff_dirent(expect, unsafe { &*entry }) {
158150
println!("{}", diff);
159151
assert!(false);
160152
}
161153
};
162154

163-
next_dirent(libc::dirent {
155+
next_dirent(dirent {
164156
d_ino: 10,
165157
d_off: 1,
166158
d_reclen: 32,
167159
d_type: libc::DT_REG,
160+
#[cfg(target_os = "freebsd")]
161+
d_namlen: 7,
168162
d_name: dirent_name_new(b"entry_a"),
169163
});
170164
let pos = unsafe { libc::telldir(dir_p) };
171-
next_dirent(libc::dirent {
165+
next_dirent(dirent {
172166
d_ino: 11,
173167
d_off: 2,
174168
d_reclen: 32,
175169
d_type: libc::DT_LNK,
170+
#[cfg(target_os = "freebsd")]
171+
d_namlen: 7,
176172
d_name: dirent_name_new(b"entry_b"),
177173
});
178174
unsafe {
179175
libc::seekdir(dir_p, pos)
180176
};
181-
next_dirent(libc::dirent {
177+
next_dirent(dirent {
182178
d_ino: 11,
183179
d_off: 2,
184180
d_reclen: 32,
185181
d_type: libc::DT_LNK,
182+
#[cfg(target_os = "freebsd")]
183+
d_namlen: 7,
186184
d_name: dirent_name_new(b"entry_b"),
187185
});
188-
next_dirent(libc::dirent {
186+
next_dirent(dirent {
189187
d_ino: 12,
190188
d_off: 3,
191189
d_reclen: 32,
192190
d_type: libc::DT_DIR,
191+
#[cfg(target_os = "freebsd")]
192+
d_namlen: 7,
193193
d_name: dirent_name_new(b"entry_c"),
194194
});
195195

196196
unsafe {
197197
libc::closedir(dir_p)
198198
};
199199
});
200-
assert_eq!(requests.len(), 3);
201200

202-
let expect = r#"ReaddirRequest {
201+
#[cfg(target_os = "linux")]
202+
{
203+
assert_eq!(requests.len(), 3);
204+
205+
let expect = r#"ReaddirRequest {
203206
node_id: 2,
204207
size: 4096,
205208
cursor: None,
206209
handle: 12345,
207210
opendir_flags: 0x00018000,
208211
}"#;
209-
if let Some(diff) = diff_str(expect, &requests[0]) {
210-
println!("{}", diff);
211-
assert!(false);
212-
}
212+
if let Some(diff) = diff_str(expect, &requests[0]) {
213+
println!("{}", diff);
214+
assert!(false);
215+
}
213216

214-
let expect = r#"ReaddirRequest {
217+
let expect = r#"ReaddirRequest {
215218
node_id: 2,
216219
size: 4096,
217220
cursor: Some(1),
218221
handle: 12345,
219222
opendir_flags: 0x00018000,
220223
}"#;
221-
if let Some(diff) = diff_str(expect, &requests[1]) {
222-
println!("{}", diff);
223-
assert!(false);
224-
}
224+
if let Some(diff) = diff_str(expect, &requests[1]) {
225+
println!("{}", diff);
226+
assert!(false);
227+
}
225228

226-
let expect = r#"ReaddirRequest {
229+
let expect = r#"ReaddirRequest {
227230
node_id: 2,
228231
size: 4096,
229232
cursor: Some(2),
230233
handle: 12345,
231234
opendir_flags: 0x00018000,
232235
}"#;
233-
if let Some(diff) = diff_str(expect, &requests[2]) {
234-
println!("{}", diff);
235-
assert!(false);
236+
if let Some(diff) = diff_str(expect, &requests[2]) {
237+
println!("{}", diff);
238+
assert!(false);
239+
}
240+
}
241+
242+
#[cfg(target_os = "freebsd")]
243+
{
244+
assert_eq!(requests.len(), 2);
245+
246+
let expect = r#"ReaddirRequest {
247+
node_id: 2,
248+
size: 4096,
249+
cursor: None,
250+
handle: 12345,
251+
opendir_flags: 0x00000000,
252+
}"#;
253+
if let Some(diff) = diff_str(expect, &requests[0]) {
254+
println!("{}", diff);
255+
assert!(false);
256+
}
257+
258+
let expect = r#"ReaddirRequest {
259+
node_id: 2,
260+
size: 4096,
261+
cursor: Some(2),
262+
handle: 12345,
263+
opendir_flags: 0x00000000,
264+
}"#;
265+
if let Some(diff) = diff_str(expect, &requests[1]) {
266+
println!("{}", diff);
267+
assert!(false);
268+
}
236269
}
237270
}
238271

239-
#[derive(Debug)]
240272
#[allow(non_camel_case_types)]
241273
struct dirent<'a> {
242274
d_ino: libc::ino_t,
243275
d_off: libc::off_t,
244276
d_reclen: libc::c_ushort,
245-
d_type: String,
246-
d_name: &'a ffi::CStr,
277+
d_type: u8,
278+
#[cfg(target_os = "freebsd")]
279+
d_namlen: u16,
280+
d_name: &'a ffi::OsStr,
247281
}
248282

249-
fn diff_dirent(expect: &libc::dirent, got: &libc::dirent) -> Option<String> {
250-
let expect = format!(
251-
"{:#?}",
252-
&dirent {
253-
d_ino: expect.d_ino,
254-
d_off: expect.d_off,
255-
d_reclen: expect.d_reclen,
256-
d_type: dirent_type_name(expect),
257-
d_name: dirent_name(expect),
258-
}
259-
);
283+
impl std::fmt::Debug for dirent<'_> {
284+
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
285+
let d_type = dirent_type_name(self);
286+
let mut s = fmt.debug_struct("dirent");
287+
#[cfg(target_os = "linux")]
288+
s.field("d_ino", &self.d_ino);
289+
#[cfg(target_os = "freebsd")]
290+
s.field("d_fileno", &self.d_ino);
291+
s.field("d_off", &self.d_off);
292+
s.field("d_reclen", &self.d_reclen);
293+
s.field("d_type", &format_args!("{}", &d_type));
294+
#[cfg(target_os = "freebsd")]
295+
s.field("d_namlen", &self.d_namlen);
296+
s.field("d_name", &self.d_name);
297+
s.finish()
298+
}
299+
}
300+
301+
#[allow(unused_mut)]
302+
fn diff_dirent(mut expect: dirent, got: &libc::dirent) -> Option<String> {
303+
// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=253411
304+
#[cfg(target_os = "freebsd")]
305+
{
306+
expect.d_off = 0;
307+
}
308+
309+
let expect = format!("{:#?}", &expect);
260310
let got = format!(
261311
"{:#?}",
262312
dirent {
313+
#[cfg(target_os = "linux")]
263314
d_ino: got.d_ino,
315+
#[cfg(target_os = "freebsd")]
316+
d_ino: got.d_fileno,
264317
d_off: got.d_off,
265318
d_reclen: got.d_reclen,
266-
d_type: dirent_type_name(got),
319+
d_type: got.d_type,
320+
#[cfg(target_os = "freebsd")]
321+
d_namlen: got.d_namlen,
267322
d_name: dirent_name(got),
268323
}
269324
);
270325
diff_str(&expect, &got)
271326
}
272327

273-
fn dirent_name(dirent: &libc::dirent) -> &ffi::CStr {
328+
fn dirent_name(dirent: &libc::dirent) -> &ffi::OsStr {
274329
let bytes: &[u8] = unsafe { std::mem::transmute(&dirent.d_name as &[i8]) };
275330
for (ii, byte) in bytes.iter().enumerate() {
276331
if *byte == 0 {
277-
let (cstr, _) = bytes.split_at(ii + 1);
278-
return ffi::CStr::from_bytes_with_nul(cstr).unwrap();
332+
let (name, _) = bytes.split_at(ii);
333+
return ffi::OsStr::from_bytes(name);
279334
}
280335
}
281336
panic!("no NUL in dirent d_name")
282337
}
283338

284-
fn dirent_name_new(name: &[u8]) -> [i8; 256] {
285-
let mut buf = [0i8; 256];
286-
let buf_u8: &mut [u8] =
287-
unsafe { std::mem::transmute(&mut buf as &mut [i8]) };
288-
buf_u8[..name.len()].copy_from_slice(name);
289-
buf
339+
fn dirent_name_new(name: &[u8]) -> &ffi::OsStr {
340+
ffi::OsStr::from_bytes(name)
290341
}
291342

292-
fn dirent_type_name(dirent: &libc::dirent) -> String {
343+
fn dirent_type_name(dirent: &dirent) -> String {
293344
match dirent.d_type {
294345
libc::DT_BLK => "DT_BLK".to_string(),
295346
libc::DT_CHR => "DT_CHR".to_string(),

0 commit comments

Comments
 (0)