@@ -9,6 +9,7 @@ use std::fmt::{Debug, Formatter};
9
9
use std:: fs:: File ;
10
10
use std:: io;
11
11
use std:: os:: unix:: io:: { AsRawFd , FromRawFd , RawFd } ;
12
+ use std:: ptr;
12
13
use std:: sync:: { RwLock , RwLockReadGuard , RwLockWriteGuard } ;
13
14
14
15
use crate :: passthrough:: PassthroughFs ;
@@ -17,29 +18,33 @@ use crate::passthrough::PassthroughFs;
17
18
///
18
19
/// According to Linux ABI, struct file_handle has a flexible array member 'f_handle', but it's
19
20
/// hard-coded here for simplicity.
20
- pub const MAX_HANDLE_SZ : usize = 128 ;
21
+ // pub const MAX_HANDLE_SZ: usize = 128;
21
22
22
23
#[ derive( Clone , Copy ) ]
23
24
#[ repr( C ) ]
24
- pub ( crate ) struct CFileHandle {
25
+ struct CFileHandle {
25
26
// Size of f_handle [in, out]
26
- pub ( crate ) handle_bytes : libc:: c_uint ,
27
+ handle_bytes : libc:: c_uint ,
27
28
// Handle type [out]
28
- pub ( crate ) handle_type : libc:: c_int ,
29
+ handle_type : libc:: c_int ,
29
30
// File identifier (sized by caller) [out]
30
- pub ( crate ) f_handle : [ libc:: c_char ; MAX_HANDLE_SZ ] ,
31
+ f_handle : * mut libc:: c_char ,
31
32
}
32
33
33
34
impl CFileHandle {
34
35
fn new ( ) -> Self {
35
36
CFileHandle {
36
- handle_bytes : MAX_HANDLE_SZ as libc :: c_uint ,
37
+ handle_bytes : 0 ,
37
38
handle_type : 0 ,
38
- f_handle : [ 0 ; MAX_HANDLE_SZ ] ,
39
+ f_handle : ptr :: null_mut ( ) ,
39
40
}
40
41
}
41
42
}
42
43
44
+ // Safe because f_handle is readonly once FileHandle is initialized.
45
+ unsafe impl Send for CFileHandle { }
46
+ unsafe impl Sync for CFileHandle { }
47
+
43
48
impl Ord for CFileHandle {
44
49
fn cmp ( & self , other : & Self ) -> Ordering {
45
50
if self . handle_bytes != other. handle_bytes {
@@ -49,12 +54,8 @@ impl Ord for CFileHandle {
49
54
return self . handle_type . cmp ( & other. handle_type ) ;
50
55
}
51
56
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
58
59
}
59
60
}
60
61
@@ -83,10 +84,12 @@ impl Debug for CFileHandle {
83
84
}
84
85
85
86
/// 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 ) ]
87
88
pub struct FileHandle {
88
89
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 > ,
90
93
}
91
94
92
95
extern "C" {
@@ -113,6 +116,38 @@ impl FileHandle {
113
116
let mut mount_id: libc:: c_int = 0 ;
114
117
let mut c_fh = CFileHandle :: new ( ) ;
115
118
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
+
116
151
let ret = unsafe {
117
152
name_to_handle_at (
118
153
dir_fd,
@@ -126,6 +161,7 @@ impl FileHandle {
126
161
Ok ( FileHandle {
127
162
mnt_id : mount_id as u64 ,
128
163
handle : c_fh,
164
+ buf,
129
165
} )
130
166
} else {
131
167
let e = io:: Error :: last_os_error ( ) ;
@@ -296,43 +332,80 @@ mod tests {
296
332
297
333
#[ test]
298
334
fn test_file_handle_derives ( ) {
299
- let mut h1 = CFileHandle {
335
+ let mut buf1 = vec ! [ 0 ; 128 ] ;
336
+ let h1 = CFileHandle {
300
337
handle_bytes : 128 ,
301
338
handle_type : 3 ,
302
- f_handle : [ 0 ; MAX_HANDLE_SZ ] ,
339
+ f_handle : buf1 . as_mut_ptr ( ) ,
303
340
} ;
341
+ let mut fh1 = FileHandle {
342
+ mnt_id : 0 ,
343
+ handle : h1,
344
+ buf : buf1,
345
+ } ;
346
+
347
+ let mut buf2 = vec ! [ 0 ; 129 ] ;
304
348
let h2 = CFileHandle {
305
349
handle_bytes : 129 ,
306
350
handle_type : 3 ,
307
- f_handle : [ 0 ; MAX_HANDLE_SZ ] ,
351
+ f_handle : buf2 . as_mut_ptr ( ) ,
308
352
} ;
353
+ let fh2 = FileHandle {
354
+ mnt_id : 0 ,
355
+ handle : h2,
356
+ buf : buf2,
357
+ } ;
358
+
359
+ let mut buf3 = vec ! [ 0 ; 128 ] ;
309
360
let h3 = CFileHandle {
310
361
handle_bytes : 128 ,
311
362
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,
313
369
} ;
370
+
371
+ let mut buf4 = vec ! [ 1 ; 128 ] ;
314
372
let h4 = CFileHandle {
315
373
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 ( ) ,
318
376
} ;
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 {
320
385
handle_bytes : 128 ,
321
386
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,
323
393
} ;
324
394
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) ;
337
410
}
338
411
}
0 commit comments