@@ -36,6 +36,14 @@ pub trait FileSystem {
3636
3737 /// Reads the contents of the inode into the given folio.
3838 fn read_folio ( inode : & INode < Self > , folio : LockedFolio < ' _ > ) -> Result ;
39+
40+ /// Reads an xattr.
41+ ///
42+ /// Returns the number of bytes written to `outbuf`. If it is too small, returns the number of
43+ /// bytes needs to hold the attribute.
44+ fn read_xattr ( _inode : & INode < Self > , _name : & CStr , _outbuf : & mut [ u8 ] ) -> Result < usize > {
45+ Err ( EOPNOTSUPP )
46+ }
3947}
4048
4149/// The types of directory entries reported by [`FileSystem::read_dir`].
@@ -403,6 +411,7 @@ impl<'a, T: FileSystem + ?Sized> NewSuperBlock<'a, T> {
403411
404412 sb. s_magic = params. magic as _ ;
405413 sb. s_op = & Tables :: < T > :: SUPER_BLOCK ;
414+ sb. s_xattr = & Tables :: < T > :: XATTR_HANDLERS [ 0 ] ;
406415 sb. s_maxbytes = params. maxbytes ;
407416 sb. s_time_gran = params. time_gran ;
408417 sb. s_blocksize_bits = params. blocksize_bits ;
@@ -503,6 +512,40 @@ impl<T: FileSystem + ?Sized> Tables<T> {
503512 shutdown : None ,
504513 } ;
505514
515+ const XATTR_HANDLERS : [ * const bindings:: xattr_handler ; 2 ] = [ & Self :: XATTR_HANDLER , ptr:: null ( ) ] ;
516+
517+ const XATTR_HANDLER : bindings:: xattr_handler = bindings:: xattr_handler {
518+ name : ptr:: null ( ) ,
519+ prefix : crate :: c_str!( "" ) . as_char_ptr ( ) ,
520+ flags : 0 ,
521+ list : None ,
522+ get : Some ( Self :: xattr_get_callback) ,
523+ set : None ,
524+ } ;
525+
526+ unsafe extern "C" fn xattr_get_callback (
527+ _handler : * const bindings:: xattr_handler ,
528+ _dentry : * mut bindings:: dentry ,
529+ inode_ptr : * mut bindings:: inode ,
530+ name : * const core:: ffi:: c_char ,
531+ buffer : * mut core:: ffi:: c_void ,
532+ size : usize ,
533+ ) -> core:: ffi:: c_int {
534+ from_result ( || {
535+ // SAFETY: The C API guarantees that `inode_ptr` is a valid inode.
536+ let inode = unsafe { & * inode_ptr. cast :: < INode < T > > ( ) } ;
537+
538+ // SAFETY: The c API guarantees that `name` is a valid null-terminated string. It
539+ // also guarantees that it's valid for the duration of the callback.
540+ let name = unsafe { CStr :: from_char_ptr ( name) } ;
541+
542+ // SAFETY: The C API guarantees that `buffer` is at least `size` bytes in length.
543+ let buf = unsafe { core:: slice:: from_raw_parts_mut ( buffer. cast ( ) , size) } ;
544+ let len = T :: read_xattr ( inode, name, buf) ?;
545+ Ok ( len. try_into ( ) ?)
546+ } )
547+ }
548+
506549 const DIR_FILE_OPERATIONS : bindings:: file_operations = bindings:: file_operations {
507550 owner : ptr:: null_mut ( ) ,
508551 llseek : Some ( bindings:: generic_file_llseek) ,
0 commit comments