@@ -613,6 +613,69 @@ fn set_get_unix_permissions() {
613613 assert_eq ! ( mask & metadata1. permissions( ) . mode( ) , 0o0777 ) ;
614614}
615615
616+ #[ test]
617+ fn set_get_permissions_nofollows ( ) {
618+ let tmpdir = tmpdir ( ) ;
619+ let filename = tmpdir. join ( "set_get_unix_permissions_file" ) ;
620+ check ! ( File :: create( & filename) ) ;
621+ let file_metadata = check ! ( fs:: metadata( & filename) ) ;
622+ assert ! ( !file_metadata. permissions( ) . readonly( ) ) ;
623+ let mut permission_bits = file_metadata. permissions ( ) ;
624+ permission_bits. set_readonly ( true ) ;
625+ let result = fs:: set_permissions_nofollow ( & filename, permission_bits) ;
626+
627+ cfg_select ! {
628+ any( windows, unix, target_os = "uefi" , target_os = "solid_asp3" , target_os = "motor" ) => {
629+ assert_eq!( result. unwrap( ) , ( ) ) ;
630+ let metadata0 = check!( fs:: metadata( & filename) ) ;
631+ assert!( metadata0. permissions( ) . readonly( ) ) ;
632+ } ,
633+ target_os = "hermit" => {
634+ assert_eq!( result. unwrap_err( ) . raw_os_error( ) , Some ( 22 ) ) ;
635+ }
636+ _ => {
637+ let error_kind = result. unwrap_err( ) . kind( ) ;
638+ assert_eq!( error_kind, crate :: io:: ErrorKind :: Unsupported ) ;
639+ }
640+ }
641+ }
642+
643+ // Only Windows and Unix support `fs::set_permissions_nofollow`
644+ #[ test]
645+ #[ cfg( any( windows, unix) ) ]
646+ fn set_get_permissions_nofollows_symlink ( ) {
647+ #[ cfg( not( windows) ) ]
648+ use crate :: os:: unix:: fs:: symlink;
649+ #[ cfg( windows) ]
650+ use crate :: os:: windows:: fs:: symlink_dir;
651+
652+ let tmpdir = tmpdir ( ) ;
653+ let filename = tmpdir. join ( "set_get_unix_permissions_file" ) ;
654+ let symlink_name = tmpdir. join ( "set_get_unix_permissions" ) ;
655+ check ! ( File :: create( & filename) ) ;
656+ #[ cfg( not( windows) ) ]
657+ check ! ( symlink( & filename, & symlink_name) ) ;
658+ #[ cfg( windows) ]
659+ check ! ( symlink_dir( & filename, & symlink_name) ) ;
660+
661+ let sym_metadata = check ! ( fs:: symlink_metadata( & symlink_name) ) ;
662+ let mut permission_bits = sym_metadata. permissions ( ) ;
663+ permission_bits. set_readonly ( true ) ;
664+ let result = fs:: set_permissions_nofollow ( & symlink_name, permission_bits) ;
665+
666+ cfg_select ! {
667+ any( target_os = "macos" , target_os = "freebsd" , target_os = "openbsd" , target_os = "netbsd" , target_os = "dragonfly" , target_os = "espidf" , target_os = "horizon" ) => {
668+ assert_eq!( result. unwrap( ) , ( ) ) ;
669+ let metadata0 = check!( fs:: symlink_metadata( & symlink_name) ) ;
670+ assert!( metadata0. permissions( ) . readonly( ) ) ;
671+ } ,
672+ _ => {
673+ let error_kind = result. unwrap_err( ) . kind( ) ;
674+ assert_eq!( error_kind, crate :: io:: ErrorKind :: Unsupported ) ;
675+ }
676+ }
677+ }
678+
616679#[ test]
617680#[ cfg( windows) ]
618681fn file_test_io_seek_read_write ( ) {
@@ -1330,6 +1393,29 @@ fn fchmod_works() {
13301393 check ! ( file. set_permissions( p) ) ;
13311394}
13321395
1396+ #[ test]
1397+ fn fchmodat_works ( ) {
1398+ let tmpdir = tmpdir ( ) ;
1399+ let file = tmpdir. join ( "in.txt" ) ;
1400+
1401+ check ! ( File :: create( & file) ) ;
1402+ let attr = check ! ( fs:: metadata( & file) ) ;
1403+ assert ! ( !attr. permissions( ) . readonly( ) ) ;
1404+ let mut p = attr. permissions ( ) ;
1405+ p. set_readonly ( true ) ;
1406+ check ! ( fs:: set_permissions_nofollow( & file, p. clone( ) ) ) ;
1407+ let attr = check ! ( fs:: metadata( & file) ) ;
1408+ assert ! ( attr. permissions( ) . readonly( ) ) ;
1409+
1410+ match fs:: set_permissions_nofollow ( & tmpdir. join ( "foo" ) , p. clone ( ) ) {
1411+ Ok ( ..) => panic ! ( "wanted an error" ) ,
1412+ Err ( ..) => { }
1413+ }
1414+
1415+ p. set_readonly ( false ) ;
1416+ check ! ( fs:: set_permissions_nofollow( & file, p) ) ;
1417+ }
1418+
13331419#[ test]
13341420fn sync_doesnt_kill_anything ( ) {
13351421 let tmpdir = tmpdir ( ) ;
0 commit comments