@@ -1918,6 +1918,33 @@ impl PathFilesystem for EncFs {
19181918 Ok ( self . write_impl ( handle, offset, data) ? as usize )
19191919 }
19201920
1921+ fn flush (
1922+ & self ,
1923+ _path : Option < & Path > ,
1924+ handle : & FileHandle ,
1925+ _caller : & Request ,
1926+ ) -> Result < ( ) , Errno > {
1927+ handle
1928+ . file
1929+ . sync_all ( )
1930+ . map_err ( |e| e. raw_os_error ( ) . unwrap_or ( libc:: EIO ) . into ( ) )
1931+ }
1932+
1933+ fn fsync (
1934+ & self ,
1935+ _path : Option < & Path > ,
1936+ handle : & FileHandle ,
1937+ datasync : bool ,
1938+ _caller : & Request ,
1939+ ) -> Result < ( ) , Errno > {
1940+ let sync_result = if datasync {
1941+ handle. file . sync_data ( )
1942+ } else {
1943+ handle. file . sync_all ( )
1944+ } ;
1945+ sync_result. map_err ( |e| e. raw_os_error ( ) . unwrap_or ( libc:: EIO ) . into ( ) )
1946+ }
1947+
19211948 fn flock (
19221949 & self ,
19231950 _path : Option < & Path > ,
@@ -1979,9 +2006,16 @@ impl PathFilesystem for EncFs {
19792006#[ cfg( test) ]
19802007mod tests {
19812008 use super :: {
1982- FILE_STATE_SWEEP_FLOOR , FileStates , headerless_file_iv , is_apple_xattr ,
1983- lock_source_and_dest,
2009+ EncFs , FILE_STATE_SWEEP_FLOOR , FileHandle , FileState , FileStates , headerless_file_iv ,
2010+ is_apple_xattr , lock_source_and_dest,
19842011 } ;
2012+ use crate :: config:: { EncfsConfig , Interface } ;
2013+ use crate :: crypto:: ssl:: SslCipher ;
2014+ use std:: fs:: File ;
2015+ use std:: os:: fd:: FromRawFd ;
2016+ use std:: path:: PathBuf ;
2017+ use std:: sync:: Arc ;
2018+ use typed_fuse:: { Caller , PathFilesystem } ;
19852019
19862020 fn table_len ( states : & FileStates ) -> usize {
19872021 states. table . lock ( ) . unwrap ( ) . entries . len ( )
@@ -2089,4 +2123,53 @@ mod tests {
20892123 assert ! ( !is_apple_xattr( "user.encfs.attribute" ) ) ;
20902124 assert ! ( !is_apple_xattr( "com.example.attribute" ) ) ;
20912125 }
2126+
2127+ fn test_fs ( ) -> EncFs {
2128+ let interface = Interface {
2129+ name : "ssl/aes" . to_string ( ) ,
2130+ major : 3 ,
2131+ minor : 0 ,
2132+ age : 0 ,
2133+ } ;
2134+ let mut cipher = SslCipher :: new ( & interface, 192 ) . unwrap ( ) ;
2135+ cipher. set_key ( & [ 1u8 ; 24 ] , & [ 2u8 ; 16 ] ) ;
2136+ EncFs :: new (
2137+ PathBuf :: new ( ) ,
2138+ Box :: new ( cipher) ,
2139+ EncfsConfig :: test_default ( ) ,
2140+ )
2141+ }
2142+
2143+ fn test_caller ( ) -> Caller {
2144+ Caller {
2145+ pid : 1 ,
2146+ gid : 0 ,
2147+ uid : 0 ,
2148+ umask : 0 ,
2149+ }
2150+ }
2151+
2152+ #[ test]
2153+ fn sync_callbacks_forward_backing_file_errors ( ) {
2154+ let mut fds = [ 0 ; 2 ] ;
2155+ assert_eq ! ( unsafe { libc:: pipe( fds. as_mut_ptr( ) ) } , 0 ) ;
2156+ assert_eq ! ( unsafe { libc:: close( fds[ 0 ] ) } , 0 ) ;
2157+
2158+ // A pipe does not support synchronization. Using it as the backing
2159+ // file proves these callbacks issue real sync syscalls rather than
2160+ // inheriting PathFilesystem's successful no-op defaults. The errno
2161+ // differs across platforms, so the regression condition is simply that
2162+ // it propagates.
2163+ let handle = FileHandle {
2164+ file : unsafe { File :: from_raw_fd ( fds[ 1 ] ) } ,
2165+ headerless_iv : 0 ,
2166+ state : Arc :: new ( FileState :: new ( ( 0 , 0 ) ) ) ,
2167+ } ;
2168+ let fs = test_fs ( ) ;
2169+ let caller = test_caller ( ) ;
2170+
2171+ assert ! ( fs. flush( None , & handle, & caller) . is_err( ) ) ;
2172+ assert ! ( fs. fsync( None , & handle, false , & caller) . is_err( ) ) ;
2173+ assert ! ( fs. fsync( None , & handle, true , & caller) . is_err( ) ) ;
2174+ }
20922175}
0 commit comments