@@ -835,6 +835,82 @@ fn live_cross_process_posix_locks() -> Result<()> {
835835 Ok ( ( ) )
836836}
837837
838+ #[ test]
839+ #[ ignore]
840+ fn live_flock_child ( ) -> Result < ( ) > {
841+ let Some ( path) = std:: env:: var_os ( "ENCFS_FLOCK_CHILD_PATH" ) else {
842+ return Ok ( ( ) ) ;
843+ } ;
844+ let expect_blocked = std:: env:: var_os ( "ENCFS_FLOCK_EXPECT_BLOCKED" ) . is_some ( ) ;
845+ let file = OpenOptions :: new ( ) . read ( true ) . write ( true ) . open ( path) ?;
846+ let result = unsafe { libc:: flock ( file. as_raw_fd ( ) , libc:: LOCK_EX | libc:: LOCK_NB ) } ;
847+ let result = if result == 0 {
848+ Ok ( ( ) )
849+ } else {
850+ Err ( std:: io:: Error :: last_os_error ( ) )
851+ } ;
852+ match ( result, expect_blocked) {
853+ ( Err ( error) , true )
854+ if error. raw_os_error ( ) == Some ( libc:: EAGAIN )
855+ || error. raw_os_error ( ) == Some ( libc:: EWOULDBLOCK ) =>
856+ {
857+ Ok ( ( ) )
858+ }
859+ ( Ok ( ( ) ) , false ) => Ok ( ( ) ) ,
860+ ( result, expected) => {
861+ anyhow:: bail!( "unexpected child flock result {result:?}; expected blocked={expected}" )
862+ }
863+ }
864+ }
865+
866+ #[ test]
867+ #[ ignore]
868+ fn live_cross_process_flock ( ) -> Result < ( ) > {
869+ require_live ( ) ;
870+ if !live_enabled ( ) {
871+ return Ok ( ( ) ) ;
872+ }
873+ let cfg = load_live_config ( live:: LiveConfigKind :: Standard ) ?;
874+ let mount = MountGuard :: mount ( cfg, false ) ?;
875+ let path = mount. mount_point . join ( "flocked.txt" ) ;
876+ fs:: write ( & path, b"locked" ) ?;
877+ let file = OpenOptions :: new ( ) . read ( true ) . write ( true ) . open ( & path) ?;
878+ let result = unsafe { libc:: flock ( file. as_raw_fd ( ) , libc:: LOCK_EX | libc:: LOCK_NB ) } ;
879+ if result == -1 {
880+ return Err ( std:: io:: Error :: last_os_error ( ) ) . context ( "parent flock failed" ) ;
881+ }
882+
883+ let child = |expect_blocked : bool | -> Result < ( ) > {
884+ let mut command = Command :: new ( std:: env:: current_exe ( ) ?) ;
885+ command
886+ . arg ( "--exact" )
887+ . arg ( "live_flock_child" )
888+ . arg ( "--ignored" )
889+ . arg ( "--test-threads=1" )
890+ . env ( "ENCFS_FLOCK_CHILD_PATH" , & path) ;
891+ if expect_blocked {
892+ command. env ( "ENCFS_FLOCK_EXPECT_BLOCKED" , "1" ) ;
893+ }
894+ let output = command. output ( ) ?;
895+ anyhow:: ensure!(
896+ output. status. success( ) ,
897+ "flock-check child failed (expect_blocked={expect_blocked}): {}\n stdout:\n {}\n stderr:\n {}" ,
898+ output. status,
899+ String :: from_utf8_lossy( & output. stdout) ,
900+ String :: from_utf8_lossy( & output. stderr)
901+ ) ;
902+ Ok ( ( ) )
903+ } ;
904+
905+ child ( true ) ?;
906+ let result = unsafe { libc:: flock ( file. as_raw_fd ( ) , libc:: LOCK_UN ) } ;
907+ if result == -1 {
908+ return Err ( std:: io:: Error :: last_os_error ( ) ) . context ( "parent flock unlock failed" ) ;
909+ }
910+ child ( false ) ?;
911+ Ok ( ( ) )
912+ }
913+
838914#[ test]
839915#[ ignore]
840916fn live_chmod_utimens_statfs ( ) -> Result < ( ) > {
0 commit comments