11use std:: {
2- io, mem,
2+ ffi:: CStr ,
3+ io,
34 os:: fd:: { AsRawFd , RawFd } ,
5+ ptr,
46} ;
57
68use vm_memory:: bitmap:: BitmapSlice ;
79
8- use crate :: {
9- api:: { filesystem:: DirEntry , CURRENT_DIR_CSTR , PARENT_DIR_CSTR } ,
10- bytes_to_cstr,
11- passthrough:: util:: einval,
12- } ;
10+ use crate :: api:: filesystem:: DirEntry ;
1311
1412use super :: { Handle , Inode , OffT , PassthroughFs } ;
1513
@@ -26,95 +24,50 @@ impl<S: BitmapSlice + Send + Sync> PassthroughFs<S> {
2624 return Ok ( ( ) ) ;
2725 }
2826
29- let mut buf = Vec :: < u8 > :: with_capacity ( size as usize ) ;
3027 let data = self . get_dirdata ( handle, inode, libc:: O_RDONLY ) ?;
3128
32- {
33- // Since we are going to work with the kernel offset, we have to acquire the file lock
34- // for both the `lseek64` and `getdents64` syscalls to ensure that no other thread
35- // changes the kernel offset while we are using it.
36- let ( guard, dir) = data. get_file_mut ( ) ;
37-
38- // Safe because this doesn't modify any memory and we check the return value.
39- let res = unsafe { libc:: lseek ( dir. as_raw_fd ( ) , offset as OffT , libc:: SEEK_SET ) } ;
40- if res < 0 {
41- return Err ( io:: Error :: last_os_error ( ) ) ;
42- }
43-
44- // Safe because the kernel guarantees that it will only write to `buf` and we check the
45- // return value.
46- let res = unsafe {
47- libc:: read (
48- dir. as_raw_fd ( ) ,
49- buf. as_mut_ptr ( ) as * mut libc:: c_void ,
50- size as libc:: size_t ,
51- )
52- } ;
53- if res < 0 {
54- return Err ( io:: Error :: last_os_error ( ) ) ;
55- }
56-
57- // Safe because we trust the value returned by kernel.
58- unsafe { buf. set_len ( res as usize ) } ;
59-
60- // Explicitly drop the lock so that it's not held while we fill in the fuse buffer.
61- mem:: drop ( guard) ;
29+ let ( _guard, dir) = data. get_file_mut ( ) ;
30+ if dir. metadata ( ) ?. is_dir ( ) {
31+ return Ok ( ( ) ) ;
32+ }
33+ // Safe because this doesn't modify any memory and we check the return value.
34+ let res = unsafe { libc:: lseek ( dir. as_raw_fd ( ) , offset as OffT , libc:: SEEK_SET ) } ;
35+ if res < 0 {
36+ return Err ( io:: Error :: last_os_error ( ) ) ;
6237 }
6338
64- let mut rem = & buf[ ..] ;
65- let orig_rem_len = rem. len ( ) ;
66-
67- while !rem. is_empty ( ) {
68- debug_assert ! (
69- rem. len( ) >= mem:: size_of:: <libc:: dirent>( ) ,
70- "fuse: not enough space left in `rem`"
71- ) ;
72-
73- let ( front, back) = rem. split_at ( mem:: size_of :: < libc:: dirent > ( ) ) ;
39+ let dir = unsafe { libc:: fdopendir ( dir. as_raw_fd ( ) ) } ;
40+ loop {
41+ let entry_ptr = unsafe { libc:: readdir ( dir) } ;
7442
75- let dirent = unsafe { * ( front. as_ptr ( ) as * const libc:: dirent ) } ;
43+ if entry_ptr. is_null ( ) {
44+ break ;
45+ }
7646
77- let namelen = dirent. d_namlen as usize ;
78- debug_assert ! (
79- namelen <= back. len( ) ,
80- "fuse: back is smaller than `namelen`"
81- ) ;
47+ let entry: libc:: dirent = unsafe { ptr:: read ( entry_ptr) } ;
8248
83- let name = & back[ ..namelen] ;
84- let res = if name. starts_with ( CURRENT_DIR_CSTR ) || name. starts_with ( PARENT_DIR_CSTR ) {
49+ let cstr = unsafe { CStr :: from_ptr ( entry. d_name . as_ptr ( ) ) } ;
50+ let name_str = cstr. to_str ( ) . expect ( "Failed to convert CStr to str" ) ;
51+ let res = if name_str == "." || name_str == ".." {
8552 Ok ( 1 )
8653 } else {
87- let name = bytes_to_cstr ( name)
88- . map_err ( |e| {
89- error ! ( "fuse: do_readdir: {:?}" , e) ;
90- einval ( )
91- } ) ?
92- . to_bytes ( ) ;
93-
9454 add_entry (
9555 DirEntry {
96- ino : dirent . d_ino ,
97- offset : dirent . d_seekoff ,
98- type_ : dirent . d_type as u32 ,
99- name,
56+ ino : entry . d_ino ,
57+ offset : entry . d_seekoff ,
58+ type_ : entry . d_type as u32 ,
59+ name : cstr . to_bytes ( ) ,
10060 } ,
10161 data. borrow_fd ( ) . as_raw_fd ( ) ,
10262 )
10363 } ;
104-
105- debug_assert ! (
106- rem. len( ) >= dirent. d_reclen as usize ,
107- "fuse: rem is smaller than `d_reclen`"
108- ) ;
109-
11064 match res {
11165 Ok ( 0 ) => break ,
112- Ok ( _) => rem = & rem[ dirent. d_reclen as usize ..] ,
113- Err ( e) if rem. len ( ) == orig_rem_len => return Err ( e) ,
66+ Ok ( _) => continue ,
11467 Err ( _) => return Ok ( ( ) ) ,
11568 }
11669 }
117-
70+ unsafe { libc :: closedir ( dir ) } ;
11871 Ok ( ( ) )
11972 }
12073}
0 commit comments