@@ -9,6 +9,7 @@ use std::fmt::{Debug, Formatter};
99use std:: fs:: File ;
1010use std:: io;
1111use std:: os:: unix:: io:: { AsRawFd , FromRawFd , RawFd } ;
12+ use std:: ptr;
1213use std:: sync:: { RwLock , RwLockReadGuard , RwLockWriteGuard } ;
1314
1415use crate :: passthrough:: PassthroughFs ;
@@ -17,29 +18,33 @@ use crate::passthrough::PassthroughFs;
1718///
1819/// According to Linux ABI, struct file_handle has a flexible array member 'f_handle', but it's
1920/// hard-coded here for simplicity.
20- pub const MAX_HANDLE_SZ : usize = 128 ;
21+ // pub const MAX_HANDLE_SZ: usize = 128;
2122
2223#[ derive( Clone , Copy ) ]
2324#[ repr( C ) ]
24- pub ( crate ) struct CFileHandle {
25+ struct CFileHandle {
2526 // Size of f_handle [in, out]
26- pub ( crate ) handle_bytes : libc:: c_uint ,
27+ handle_bytes : libc:: c_uint ,
2728 // Handle type [out]
28- pub ( crate ) handle_type : libc:: c_int ,
29+ handle_type : libc:: c_int ,
2930 // File identifier (sized by caller) [out]
30- pub ( crate ) f_handle : [ libc:: c_char ; MAX_HANDLE_SZ ] ,
31+ f_handle : * mut libc:: c_char ,
3132}
3233
3334impl CFileHandle {
3435 fn new ( ) -> Self {
3536 CFileHandle {
36- handle_bytes : MAX_HANDLE_SZ as libc :: c_uint ,
37+ handle_bytes : 0 ,
3738 handle_type : 0 ,
38- f_handle : [ 0 ; MAX_HANDLE_SZ ] ,
39+ f_handle : ptr :: null_mut ( ) ,
3940 }
4041 }
4142}
4243
44+ // Safe because f_handle is readonly once FileHandle is initialized.
45+ unsafe impl Send for CFileHandle { }
46+ unsafe impl Sync for CFileHandle { }
47+
4348impl Ord for CFileHandle {
4449 fn cmp ( & self , other : & Self ) -> Ordering {
4550 if self . handle_bytes != other. handle_bytes {
@@ -49,12 +54,8 @@ impl Ord for CFileHandle {
4954 return self . handle_type . cmp ( & other. handle_type ) ;
5055 }
5156
52- self . f_handle
53- . iter ( )
54- . zip ( other. f_handle . iter ( ) )
55- . map ( |( x, y) | x. cmp ( y) )
56- . find ( |& ord| ord != std:: cmp:: Ordering :: Equal )
57- . unwrap_or ( Ordering :: Equal )
57+ // f_handle is left to be compared by FileHandle's buf.
58+ Ordering :: Equal
5859 }
5960}
6061
@@ -83,10 +84,12 @@ impl Debug for CFileHandle {
8384}
8485
8586/// Struct to maintain information for a file handle.
86- #[ derive( Clone , Copy , PartialOrd , Ord , PartialEq , Eq , Debug ) ]
87+ #[ derive( Clone , PartialOrd , Ord , PartialEq , Eq , Debug ) ]
8788pub struct FileHandle {
8889 pub ( crate ) mnt_id : u64 ,
89- pub ( crate ) handle : CFileHandle ,
90+ handle : CFileHandle ,
91+ // internal buffer for handle.f_handle
92+ buf : Vec < libc:: c_char > ,
9093}
9194
9295extern "C" {
@@ -113,6 +116,38 @@ impl FileHandle {
113116 let mut mount_id: libc:: c_int = 0 ;
114117 let mut c_fh = CFileHandle :: new ( ) ;
115118
119+ // Per name_to_handle_at(2), the caller can discover the required size
120+ // for the file_handle structure by making a call in which
121+ // handle->handle_bytes is zero. In this case, the call fails with the
122+ // error EOVERFLOW and handle->handle_bytes is set to indicate the
123+ // required size; the caller can then use this information to allocate a
124+ // structure of the correct size.
125+ let ret = unsafe {
126+ name_to_handle_at (
127+ dir_fd,
128+ path. as_ptr ( ) ,
129+ & mut c_fh,
130+ & mut mount_id,
131+ libc:: AT_EMPTY_PATH ,
132+ )
133+ } ;
134+ if ret == -1 {
135+ let e = io:: Error :: last_os_error ( ) ;
136+ // unwrap is safe as e is obtained from last_os_error().
137+ if e. raw_os_error ( ) . unwrap ( ) != libc:: EOVERFLOW {
138+ return Err ( e) ;
139+ }
140+ } else {
141+ return Err ( io:: Error :: from ( io:: ErrorKind :: InvalidData ) ) ;
142+ }
143+
144+ let needed = c_fh. handle_bytes as usize ;
145+ let mut buf = vec ! [ 0 ; needed] ;
146+
147+ // get a unsafe pointer, FileHandle takes care of freeing the memory
148+ // that 'f_handle' points to.
149+ c_fh. f_handle = buf. as_mut_ptr ( ) ;
150+
116151 let ret = unsafe {
117152 name_to_handle_at (
118153 dir_fd,
@@ -126,6 +161,7 @@ impl FileHandle {
126161 Ok ( FileHandle {
127162 mnt_id : mount_id as u64 ,
128163 handle : c_fh,
164+ buf,
129165 } )
130166 } else {
131167 let e = io:: Error :: last_os_error ( ) ;
@@ -296,43 +332,80 @@ mod tests {
296332
297333 #[ test]
298334 fn test_file_handle_derives ( ) {
299- let mut h1 = CFileHandle {
335+ let mut buf1 = vec ! [ 0 ; 128 ] ;
336+ let h1 = CFileHandle {
300337 handle_bytes : 128 ,
301338 handle_type : 3 ,
302- f_handle : [ 0 ; MAX_HANDLE_SZ ] ,
339+ f_handle : buf1 . as_mut_ptr ( ) ,
303340 } ;
341+ let mut fh1 = FileHandle {
342+ mnt_id : 0 ,
343+ handle : h1,
344+ buf : buf1,
345+ } ;
346+
347+ let mut buf2 = vec ! [ 0 ; 129 ] ;
304348 let h2 = CFileHandle {
305349 handle_bytes : 129 ,
306350 handle_type : 3 ,
307- f_handle : [ 0 ; MAX_HANDLE_SZ ] ,
351+ f_handle : buf2 . as_mut_ptr ( ) ,
308352 } ;
353+ let fh2 = FileHandle {
354+ mnt_id : 0 ,
355+ handle : h2,
356+ buf : buf2,
357+ } ;
358+
359+ let mut buf3 = vec ! [ 0 ; 128 ] ;
309360 let h3 = CFileHandle {
310361 handle_bytes : 128 ,
311362 handle_type : 4 ,
312- f_handle : [ 0 ; MAX_HANDLE_SZ ] ,
363+ f_handle : buf3. as_mut_ptr ( ) ,
364+ } ;
365+ let fh3 = FileHandle {
366+ mnt_id : 0 ,
367+ handle : h3,
368+ buf : buf3,
313369 } ;
370+
371+ let mut buf4 = vec ! [ 1 ; 128 ] ;
314372 let h4 = CFileHandle {
315373 handle_bytes : 128 ,
316- handle_type : 4 ,
317- f_handle : [ 1 ; MAX_HANDLE_SZ ] ,
374+ handle_type : 3 ,
375+ f_handle : buf4 . as_mut_ptr ( ) ,
318376 } ;
319- let mut h5 = CFileHandle {
377+ let fh4 = FileHandle {
378+ mnt_id : 0 ,
379+ handle : h4,
380+ buf : buf4,
381+ } ;
382+
383+ let mut buf5 = vec ! [ 0 ; 128 ] ;
384+ let h5 = CFileHandle {
320385 handle_bytes : 128 ,
321386 handle_type : 3 ,
322- f_handle : [ 0 ; MAX_HANDLE_SZ ] ,
387+ f_handle : buf5. as_mut_ptr ( ) ,
388+ } ;
389+ let mut fh5 = FileHandle {
390+ mnt_id : 0 ,
391+ handle : h5,
392+ buf : buf5,
323393 } ;
324394
325- assert ! ( h1 < h2) ;
326- assert ! ( h1 != h2) ;
327- assert ! ( h1 < h3) ;
328- assert ! ( h1 != h3) ;
329- assert ! ( h1 < h4) ;
330- assert ! ( h1 != h4) ;
331-
332- assert ! ( h1 == h5) ;
333- h1. f_handle [ 0 ] = 1 ;
334- assert ! ( h1 > h5) ;
335- h5. f_handle [ 0 ] = 1 ;
336- assert ! ( h1 == h5) ;
395+ assert ! ( fh1 < fh2) ;
396+ assert ! ( fh1 != fh2) ;
397+ assert ! ( fh1 < fh3) ;
398+ assert ! ( fh1 != fh3) ;
399+ assert ! ( fh1 < fh4) ;
400+ assert ! ( fh1 != fh4) ;
401+
402+ assert ! ( fh1 == fh5) ;
403+ fh1. buf [ 0 ] = 1 ;
404+ fh1. handle . f_handle = fh1. buf . as_mut_ptr ( ) ;
405+ assert ! ( fh1 > fh5) ;
406+
407+ fh5. buf [ 0 ] = 1 ;
408+ fh5. handle . f_handle = fh5. buf . as_mut_ptr ( ) ;
409+ assert ! ( fh1 == fh5) ;
337410 }
338411}
0 commit comments