1
1
use crate :: os:: windows:: prelude:: * ;
2
2
3
+ use crate :: borrow:: Cow ;
3
4
use crate :: ffi:: OsString ;
4
5
use crate :: fmt;
5
6
use crate :: io:: { self , BorrowedCursor , Error , IoSlice , IoSliceMut , SeekFrom } ;
@@ -719,7 +720,7 @@ impl<'a> DirBuffIter<'a> {
719
720
}
720
721
}
721
722
impl < ' a > Iterator for DirBuffIter < ' a > {
722
- type Item = ( & ' a [ u16 ] , bool ) ;
723
+ type Item = ( Cow < ' a , [ u16 ] > , bool ) ;
723
724
fn next ( & mut self ) -> Option < Self :: Item > {
724
725
use crate :: mem:: size_of;
725
726
let buffer = & self . buffer ?[ self . cursor ..] ;
@@ -734,15 +735,19 @@ impl<'a> Iterator for DirBuffIter<'a> {
734
735
// `FileNameLength` bytes)
735
736
let ( name, is_directory, next_entry) = unsafe {
736
737
let info = buffer. as_ptr ( ) . cast :: < c:: FILE_ID_BOTH_DIR_INFO > ( ) ;
737
- // Guaranteed to be aligned in documentation for
738
+ // While this is guaranteed to be aligned in documentation for
738
739
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_both_dir_info
739
- assert ! ( info. is_aligned( ) ) ;
740
- let next_entry = ( * info) . NextEntryOffset as usize ;
741
- let name = crate :: slice:: from_raw_parts (
740
+ // it does not seem that reality is so kind, and assuming this
741
+ // caused crashes in some cases (https://github.com/rust-lang/rust/issues/104530)
742
+ // presumably, this can be blamed on buggy filesystem drivers, but who knows.
743
+ let next_entry = ptr:: addr_of!( ( * info) . NextEntryOffset ) . read_unaligned ( ) as usize ;
744
+ let length = ptr:: addr_of!( ( * info) . FileNameLength ) . read_unaligned ( ) as usize ;
745
+ let attrs = ptr:: addr_of!( ( * info) . FileAttributes ) . read_unaligned ( ) ;
746
+ let name = from_maybe_unaligned (
742
747
ptr:: addr_of!( ( * info) . FileName ) . cast :: < u16 > ( ) ,
743
- ( * info ) . FileNameLength as usize / size_of :: < u16 > ( ) ,
748
+ length / size_of :: < u16 > ( ) ,
744
749
) ;
745
- let is_directory = ( ( * info ) . FileAttributes & c:: FILE_ATTRIBUTE_DIRECTORY ) != 0 ;
750
+ let is_directory = ( attrs & c:: FILE_ATTRIBUTE_DIRECTORY ) != 0 ;
746
751
747
752
( name, is_directory, next_entry)
748
753
} ;
@@ -755,13 +760,21 @@ impl<'a> Iterator for DirBuffIter<'a> {
755
760
756
761
// Skip `.` and `..` pseudo entries.
757
762
const DOT : u16 = b'.' as u16 ;
758
- match name {
763
+ match & name[ .. ] {
759
764
[ DOT ] | [ DOT , DOT ] => self . next ( ) ,
760
765
_ => Some ( ( name, is_directory) ) ,
761
766
}
762
767
}
763
768
}
764
769
770
+ unsafe fn from_maybe_unaligned < ' a > ( p : * const u16 , len : usize ) -> Cow < ' a , [ u16 ] > {
771
+ if p. is_aligned ( ) {
772
+ Cow :: Borrowed ( crate :: slice:: from_raw_parts ( p, len) )
773
+ } else {
774
+ Cow :: Owned ( ( 0 ..len) . map ( |i| p. add ( i) . read_unaligned ( ) ) . collect ( ) )
775
+ }
776
+ }
777
+
765
778
/// Open a link relative to the parent directory, ensure no symlinks are followed.
766
779
fn open_link_no_reparse ( parent : & File , name : & [ u16 ] , access : u32 ) -> io:: Result < File > {
767
780
// This is implemented using the lower level `NtCreateFile` function as
@@ -1117,13 +1130,13 @@ fn remove_dir_all_iterative(f: &File, delete: fn(&File) -> io::Result<()>) -> io
1117
1130
if is_directory {
1118
1131
let child_dir = open_link_no_reparse (
1119
1132
& dir,
1120
- name,
1133
+ & name,
1121
1134
c:: SYNCHRONIZE | c:: DELETE | c:: FILE_LIST_DIRECTORY ,
1122
1135
) ?;
1123
1136
dirlist. push ( child_dir) ;
1124
1137
} else {
1125
1138
for i in 1 ..=MAX_RETRIES {
1126
- let result = open_link_no_reparse ( & dir, name, c:: SYNCHRONIZE | c:: DELETE ) ;
1139
+ let result = open_link_no_reparse ( & dir, & name, c:: SYNCHRONIZE | c:: DELETE ) ;
1127
1140
match result {
1128
1141
Ok ( f) => delete ( & f) ?,
1129
1142
// Already deleted, so skip.
0 commit comments