@@ -42,6 +42,14 @@ pub trait FileSystem {
42
42
43
43
/// Reads the contents of the inode into the given folio.
44
44
fn read_folio ( inode : & INode < Self > , folio : LockedFolio < ' _ > ) -> Result ;
45
+
46
+ /// Reads an xattr.
47
+ ///
48
+ /// Returns the number of bytes written to `outbuf`. If it is too small, returns the number of
49
+ /// bytes needs to hold the attribute.
50
+ fn read_xattr ( _inode : & INode < Self > , _name : & CStr , _outbuf : & mut [ u8 ] ) -> Result < usize > {
51
+ Err ( EOPNOTSUPP )
52
+ }
45
53
}
46
54
47
55
/// The types of directory entries reported by [`FileSystem::read_dir`].
@@ -418,6 +426,7 @@ impl<T: FileSystem + ?Sized> Tables<T> {
418
426
419
427
sb. 0 . s_magic = params. magic as _ ;
420
428
sb. 0 . s_op = & Tables :: < T > :: SUPER_BLOCK ;
429
+ sb. 0 . s_xattr = & Tables :: < T > :: XATTR_HANDLERS [ 0 ] ;
421
430
sb. 0 . s_maxbytes = params. maxbytes ;
422
431
sb. 0 . s_time_gran = params. time_gran ;
423
432
sb. 0 . s_blocksize_bits = params. blocksize_bits ;
@@ -487,6 +496,40 @@ impl<T: FileSystem + ?Sized> Tables<T> {
487
496
shutdown : None ,
488
497
} ;
489
498
499
+ const XATTR_HANDLERS : [ * const bindings:: xattr_handler ; 2 ] = [ & Self :: XATTR_HANDLER , ptr:: null ( ) ] ;
500
+
501
+ const XATTR_HANDLER : bindings:: xattr_handler = bindings:: xattr_handler {
502
+ name : ptr:: null ( ) ,
503
+ prefix : crate :: c_str!( "" ) . as_char_ptr ( ) ,
504
+ flags : 0 ,
505
+ list : None ,
506
+ get : Some ( Self :: xattr_get_callback) ,
507
+ set : None ,
508
+ } ;
509
+
510
+ unsafe extern "C" fn xattr_get_callback (
511
+ _handler : * const bindings:: xattr_handler ,
512
+ _dentry : * mut bindings:: dentry ,
513
+ inode_ptr : * mut bindings:: inode ,
514
+ name : * const core:: ffi:: c_char ,
515
+ buffer : * mut core:: ffi:: c_void ,
516
+ size : usize ,
517
+ ) -> core:: ffi:: c_int {
518
+ from_result ( || {
519
+ // SAFETY: The C API guarantees that `inode_ptr` is a valid inode.
520
+ let inode = unsafe { & * inode_ptr. cast :: < INode < T > > ( ) } ;
521
+
522
+ // SAFETY: The c API guarantees that `name` is a valid null-terminated string. It
523
+ // also guarantees that it's valid for the duration of the callback.
524
+ let name = unsafe { CStr :: from_char_ptr ( name) } ;
525
+
526
+ // SAFETY: The C API guarantees that `buffer` is at least `size` bytes in length.
527
+ let buf = unsafe { core:: slice:: from_raw_parts_mut ( buffer. cast ( ) , size) } ;
528
+ let len = T :: read_xattr ( inode, name, buf) ?;
529
+ Ok ( len. try_into ( ) ?)
530
+ } )
531
+ }
532
+
490
533
const DIR_FILE_OPERATIONS : bindings:: file_operations = bindings:: file_operations {
491
534
owner : ptr:: null_mut ( ) ,
492
535
llseek : Some ( bindings:: generic_file_llseek) ,
0 commit comments