@@ -517,24 +517,57 @@ fn _remove_dir(p: &Path) -> Result<()> {
517
517
///
518
518
/// If the file is readonly, this will attempt to change the permissions to
519
519
/// force the file to be deleted.
520
+ /// On Windows, if the file is a symlink to a directory, this will attempt to remove
521
+ /// the symlink itself.
520
522
pub fn remove_file < P : AsRef < Path > > ( p : P ) -> Result < ( ) > {
521
523
_remove_file ( p. as_ref ( ) )
522
524
}
523
525
524
526
fn _remove_file ( p : & Path ) -> Result < ( ) > {
525
- let mut err = match fs:: remove_file ( p) {
526
- Ok ( ( ) ) => return Ok ( ( ) ) ,
527
- Err ( e) => e,
528
- } ;
529
-
530
- if err. kind ( ) == io:: ErrorKind :: PermissionDenied && set_not_readonly ( p) . unwrap_or ( false ) {
531
- match fs:: remove_file ( p) {
532
- Ok ( ( ) ) => return Ok ( ( ) ) ,
533
- Err ( e) => err = e,
527
+ // For Windows, we need to check if the file is a symlink to a directory
528
+ // and remove the symlink itself by calling `remove_dir` instead of
529
+ // `remove_file`.
530
+ #[ cfg( target_os = "windows" ) ]
531
+ {
532
+ use std:: os:: windows:: fs:: FileTypeExt ;
533
+ let metadata = symlink_metadata ( p) ?;
534
+ let file_type = metadata. file_type ( ) ;
535
+ if file_type. is_symlink_dir ( ) {
536
+ return remove_symlink_dir_with_permission_check ( p) ;
534
537
}
535
538
}
536
539
537
- Err ( err) . with_context ( || format ! ( "failed to remove file `{}`" , p. display( ) ) )
540
+ remove_file_with_permission_check ( p)
541
+ }
542
+
543
+ #[ cfg( target_os = "windows" ) ]
544
+ fn remove_symlink_dir_with_permission_check ( p : & Path ) -> Result < ( ) > {
545
+ remove_with_permission_check ( fs:: remove_dir, p)
546
+ . with_context ( || format ! ( "failed to remove symlink dir `{}`" , p. display( ) ) )
547
+ }
548
+
549
+ fn remove_file_with_permission_check ( p : & Path ) -> Result < ( ) > {
550
+ remove_with_permission_check ( fs:: remove_file, p)
551
+ . with_context ( || format ! ( "failed to remove file `{}`" , p. display( ) ) )
552
+ }
553
+
554
+ fn remove_with_permission_check < F , P > ( remove_func : F , p : P ) -> io:: Result < ( ) >
555
+ where
556
+ F : Fn ( P ) -> io:: Result < ( ) > ,
557
+ P : AsRef < Path > + Clone ,
558
+ {
559
+ match remove_func ( p. clone ( ) ) {
560
+ Ok ( ( ) ) => Ok ( ( ) ) ,
561
+ Err ( e) => {
562
+ if e. kind ( ) == io:: ErrorKind :: PermissionDenied
563
+ && set_not_readonly ( p. as_ref ( ) ) . unwrap_or ( false )
564
+ {
565
+ remove_func ( p)
566
+ } else {
567
+ Err ( e)
568
+ }
569
+ }
570
+ }
538
571
}
539
572
540
573
fn set_not_readonly ( p : & Path ) -> io:: Result < bool > {
@@ -926,9 +959,9 @@ mod tests {
926
959
927
960
assert ! ( symlink_path. exists( ) ) ;
928
961
929
- assert ! ( remove_file( symlink_path. clone( ) ) . is_err ( ) ) ;
962
+ assert ! ( remove_file( symlink_path. clone( ) ) . is_ok ( ) ) ;
930
963
931
- assert ! ( symlink_path. exists( ) ) ;
964
+ assert ! ( ! symlink_path. exists( ) ) ;
932
965
assert ! ( dir_path. exists( ) ) ;
933
966
}
934
967
0 commit comments