11use crate :: os:: windows:: prelude:: * ;
22
3+ use crate :: borrow:: Cow ;
34use crate :: ffi:: OsString ;
45use crate :: fmt;
56use crate :: io:: { self , BorrowedCursor , Error , IoSlice , IoSliceMut , SeekFrom } ;
@@ -719,7 +720,7 @@ impl<'a> DirBuffIter<'a> {
719720 }
720721}
721722impl < ' a > Iterator for DirBuffIter < ' a > {
722- type Item = ( & ' a [ u16 ] , bool ) ;
723+ type Item = ( Cow < ' a , [ u16 ] > , bool ) ;
723724 fn next ( & mut self ) -> Option < Self :: Item > {
724725 use crate :: mem:: size_of;
725726 let buffer = & self . buffer ?[ self . cursor ..] ;
@@ -734,15 +735,19 @@ impl<'a> Iterator for DirBuffIter<'a> {
734735 // `FileNameLength` bytes)
735736 let ( name, is_directory, next_entry) = unsafe {
736737 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
738739 // 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 (
742747 ptr:: addr_of!( ( * info) . FileName ) . cast :: < u16 > ( ) ,
743- ( * info ) . FileNameLength as usize / size_of :: < u16 > ( ) ,
748+ length / size_of :: < u16 > ( ) ,
744749 ) ;
745- let is_directory = ( ( * info ) . FileAttributes & c:: FILE_ATTRIBUTE_DIRECTORY ) != 0 ;
750+ let is_directory = ( attrs & c:: FILE_ATTRIBUTE_DIRECTORY ) != 0 ;
746751
747752 ( name, is_directory, next_entry)
748753 } ;
@@ -755,13 +760,21 @@ impl<'a> Iterator for DirBuffIter<'a> {
755760
756761 // Skip `.` and `..` pseudo entries.
757762 const DOT : u16 = b'.' as u16 ;
758- match name {
763+ match & name[ .. ] {
759764 [ DOT ] | [ DOT , DOT ] => self . next ( ) ,
760765 _ => Some ( ( name, is_directory) ) ,
761766 }
762767 }
763768}
764769
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+
765778/// Open a link relative to the parent directory, ensure no symlinks are followed.
766779fn open_link_no_reparse ( parent : & File , name : & [ u16 ] , access : u32 ) -> io:: Result < File > {
767780 // 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
11171130 if is_directory {
11181131 let child_dir = open_link_no_reparse (
11191132 & dir,
1120- name,
1133+ & name,
11211134 c:: SYNCHRONIZE | c:: DELETE | c:: FILE_LIST_DIRECTORY ,
11221135 ) ?;
11231136 dirlist. push ( child_dir) ;
11241137 } else {
11251138 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 ) ;
11271140 match result {
11281141 Ok ( f) => delete ( & f) ?,
11291142 // Already deleted, so skip.
0 commit comments