@@ -49,6 +49,14 @@ pub mod ro {
4949
5050 /// Reads the contents of the inode into the given folio.
5151 fn read_folio ( inode : & INode < Self > , folio : crate :: folio:: LockedFolio < ' _ > ) -> Result ;
52+
53+ /// Reads an xattr.
54+ ///
55+ /// Returns the number of bytes written to `outbuf`. If it is too small, returns the number
56+ /// of bytes needs to hold the attribute.
57+ fn read_xattr ( _inode : & INode < Self > , _name : & CStr , _outbuf : & mut [ u8 ] ) -> Result < usize > {
58+ Err ( EOPNOTSUPP )
59+ }
5260 }
5361
5462 /// The types of directory entries reported by [`Type::read_dir`].
@@ -417,6 +425,7 @@ pub mod ro {
417425
418426 sb. s_magic = params. magic as _ ;
419427 sb. s_op = & Tables :: < T > :: SUPER_BLOCK ;
428+ sb. s_xattr = & Tables :: < T > :: XATTR_HANDLERS [ 0 ] ;
420429 sb. s_maxbytes = params. maxbytes ;
421430 sb. s_time_gran = params. time_gran ;
422431 sb. s_blocksize_bits = params. blocksize_bits ;
@@ -517,6 +526,41 @@ pub mod ro {
517526 shutdown : None ,
518527 } ;
519528
529+ const XATTR_HANDLERS : [ * const bindings:: xattr_handler ; 2 ] =
530+ [ & Self :: XATTR_HANDLER , ptr:: null ( ) ] ;
531+
532+ const XATTR_HANDLER : bindings:: xattr_handler = bindings:: xattr_handler {
533+ name : ptr:: null ( ) ,
534+ prefix : crate :: c_str!( "" ) . as_char_ptr ( ) ,
535+ flags : 0 ,
536+ list : None ,
537+ get : Some ( Self :: xattr_get_callback) ,
538+ set : None ,
539+ } ;
540+
541+ unsafe extern "C" fn xattr_get_callback (
542+ _handler : * const bindings:: xattr_handler ,
543+ _dentry : * mut bindings:: dentry ,
544+ inode_ptr : * mut bindings:: inode ,
545+ name : * const core:: ffi:: c_char ,
546+ buffer : * mut core:: ffi:: c_void ,
547+ size : usize ,
548+ ) -> core:: ffi:: c_int {
549+ from_result ( || {
550+ // SAFETY: The C api guarantees that `inode_ptr` is a valid inode.
551+ let inode = unsafe { & * inode_ptr. cast :: < INode < T > > ( ) } ;
552+
553+ // SAFETY: The c api guarantees that `name` is a valid null-terminated string. It
554+ // also guarantees that it's valid for the duration of the callback.
555+ let name = unsafe { CStr :: from_char_ptr ( name) } ;
556+
557+ // SAFETY: The C api guarantees that `buffer` is at least `size` bytes in length.
558+ let buf = unsafe { core:: slice:: from_raw_parts_mut ( buffer. cast ( ) , size) } ;
559+ let len = T :: read_xattr ( inode, name, buf) ?;
560+ Ok ( len. try_into ( ) ?)
561+ } )
562+ }
563+
520564 const DIR_FILE_OPERATIONS : bindings:: file_operations = bindings:: file_operations {
521565 owner : ptr:: null_mut ( ) ,
522566 llseek : Some ( bindings:: generic_file_llseek) ,
0 commit comments