@@ -42,6 +42,14 @@ pub trait FileSystem {
4242
4343 /// Reads the contents of the inode into the given folio.
4444 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+ }
4553}
4654
4755/// The types of directory entries reported by [`FileSystem::read_dir`].
@@ -418,6 +426,7 @@ impl<T: FileSystem + ?Sized> Tables<T> {
418426
419427 sb. 0 . s_magic = params. magic as _ ;
420428 sb. 0 . s_op = & Tables :: < T > :: SUPER_BLOCK ;
429+ sb. 0 . s_xattr = & Tables :: < T > :: XATTR_HANDLERS [ 0 ] ;
421430 sb. 0 . s_maxbytes = params. maxbytes ;
422431 sb. 0 . s_time_gran = params. time_gran ;
423432 sb. 0 . s_blocksize_bits = params. blocksize_bits ;
@@ -487,6 +496,40 @@ impl<T: FileSystem + ?Sized> Tables<T> {
487496 shutdown : None ,
488497 } ;
489498
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+
490533 const DIR_FILE_OPERATIONS : bindings:: file_operations = bindings:: file_operations {
491534 owner : ptr:: null_mut ( ) ,
492535 llseek : Some ( bindings:: generic_file_llseek) ,
0 commit comments