@@ -613,6 +613,66 @@ 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+ _ => {
634+ let error_kind = result. unwrap_err( ) . kind( ) ;
635+ assert_eq!( error_kind, crate :: io:: ErrorKind :: Unsupported ) ;
636+ }
637+ }
638+ }
639+
640+ // Only Windows and Unix support `fs::set_permissions_nofollow`
641+ #[ test]
642+ #[ cfg( any( windows, unix) ) ]
643+ fn set_get_permissions_nofollows_symlink ( ) {
644+ #[ cfg( not( windows) ) ]
645+ use crate :: os:: unix:: fs:: symlink;
646+ #[ cfg( windows) ]
647+ use crate :: os:: windows:: fs:: symlink_dir;
648+
649+ let tmpdir = tmpdir ( ) ;
650+ let filename = tmpdir. join ( "set_get_unix_permissions_file" ) ;
651+ let symlink_name = tmpdir. join ( "set_get_unix_permissions" ) ;
652+ check ! ( File :: create( & filename) ) ;
653+ #[ cfg( not( windows) ) ]
654+ check ! ( symlink( & filename, & symlink_name) ) ;
655+ #[ cfg( windows) ]
656+ check ! ( symlink_dir( & filename, & symlink_name) ) ;
657+
658+ let sym_metadata = check ! ( fs:: symlink_metadata( & symlink_name) ) ;
659+ let mut permission_bits = sym_metadata. permissions ( ) ;
660+ permission_bits. set_readonly ( true ) ;
661+ let result = fs:: set_permissions_nofollow ( & symlink_name, permission_bits) ;
662+
663+ cfg_select ! {
664+ any( target_os = "macos" , target_os = "freebsd" , target_os = "openbsd" , target_os = "netbsd" , target_os = "dragonfly" , target_os = "espidf" , target_os = "horizon" ) => {
665+ assert_eq!( result. unwrap( ) , ( ) ) ;
666+ let metadata0 = check!( fs:: symlink_metadata( & symlink_name) ) ;
667+ assert!( metadata0. permissions( ) . readonly( ) ) ;
668+ } ,
669+ _ => {
670+ let error_kind = result. unwrap_err( ) . kind( ) ;
671+ assert_eq!( error_kind, crate :: io:: ErrorKind :: Unsupported ) ;
672+ }
673+ }
674+ }
675+
616676#[ test]
617677#[ cfg( windows) ]
618678fn file_test_io_seek_read_write ( ) {
@@ -1330,6 +1390,29 @@ fn fchmod_works() {
13301390 check ! ( file. set_permissions( p) ) ;
13311391}
13321392
1393+ #[ test]
1394+ fn fchmodat_works ( ) {
1395+ let tmpdir = tmpdir ( ) ;
1396+ let file = tmpdir. join ( "in.txt" ) ;
1397+
1398+ check ! ( File :: create( & file) ) ;
1399+ let attr = check ! ( fs:: metadata( & file) ) ;
1400+ assert ! ( !attr. permissions( ) . readonly( ) ) ;
1401+ let mut p = attr. permissions ( ) ;
1402+ p. set_readonly ( true ) ;
1403+ check ! ( fs:: set_permissions_nofollow( & file, p. clone( ) ) ) ;
1404+ let attr = check ! ( fs:: metadata( & file) ) ;
1405+ assert ! ( attr. permissions( ) . readonly( ) ) ;
1406+
1407+ match fs:: set_permissions_nofollow ( & tmpdir. join ( "foo" ) , p. clone ( ) ) {
1408+ Ok ( ..) => panic ! ( "wanted an error" ) ,
1409+ Err ( ..) => { }
1410+ }
1411+
1412+ p. set_readonly ( false ) ;
1413+ check ! ( fs:: set_permissions_nofollow( & file, p) ) ;
1414+ }
1415+
13331416#[ test]
13341417fn sync_doesnt_kill_anything ( ) {
13351418 let tmpdir = tmpdir ( ) ;
0 commit comments