@@ -293,6 +293,30 @@ impl OpenOptions {
293
293
} )
294
294
}
295
295
296
+ fn get_disposition ( & self ) -> io:: Result < u32 > {
297
+ match ( self . write , self . append ) {
298
+ ( true , false ) => { }
299
+ ( false , false ) => {
300
+ if self . truncate || self . create || self . create_new {
301
+ return Err ( Error :: from_raw_os_error ( c:: ERROR_INVALID_PARAMETER as i32 ) ) ;
302
+ }
303
+ }
304
+ ( _, true ) => {
305
+ if self . truncate && !self . create_new {
306
+ return Err ( Error :: from_raw_os_error ( c:: ERROR_INVALID_PARAMETER as i32 ) ) ;
307
+ }
308
+ }
309
+ }
310
+
311
+ Ok ( match ( self . create , self . truncate , self . create_new ) {
312
+ ( false , false , false ) => c:: FILE_OPEN ,
313
+ ( true , false , false ) => c:: FILE_OPEN_IF ,
314
+ ( false , true , false ) => c:: FILE_OVERWRITE ,
315
+ ( true , true , false ) => c:: FILE_OVERWRITE_IF ,
316
+ ( _, _, true ) => c:: FILE_CREATE ,
317
+ } )
318
+ }
319
+
296
320
fn get_flags_and_attributes ( & self ) -> u32 {
297
321
self . custom_flags
298
322
| self . attributes
@@ -855,20 +879,16 @@ impl File {
855
879
856
880
unsafe fn nt_create_file (
857
881
access : u32 ,
882
+ disposition : u32 ,
858
883
object_attributes : & c:: OBJECT_ATTRIBUTES ,
859
884
share : u32 ,
860
885
dir : bool ,
861
886
) -> Result < Handle , WinError > {
862
887
let mut handle = ptr:: null_mut ( ) ;
863
888
let mut io_status = c:: IO_STATUS_BLOCK :: PENDING ;
864
- let disposition = match ( access & c:: GENERIC_READ > 0 , access & c:: GENERIC_WRITE > 0 ) {
865
- ( true , true ) => c:: FILE_OPEN_IF ,
866
- ( true , false ) => c:: FILE_OPEN ,
867
- ( false , true ) => c:: FILE_CREATE ,
868
- ( false , false ) => {
869
- return Err ( WinError :: new ( c:: ERROR_INVALID_PARAMETER ) ) ;
870
- }
871
- } ;
889
+ let access = access | c:: SYNCHRONIZE ;
890
+ let options = if dir { c:: FILE_DIRECTORY_FILE } else { c:: FILE_NON_DIRECTORY_FILE }
891
+ | c:: FILE_SYNCHRONOUS_IO_NONALERT ;
872
892
let status = unsafe {
873
893
c:: NtCreateFile (
874
894
& mut handle,
@@ -879,7 +899,7 @@ unsafe fn nt_create_file(
879
899
c:: FILE_ATTRIBUTE_NORMAL ,
880
900
share,
881
901
disposition,
882
- if dir { c :: FILE_DIRECTORY_FILE } else { c :: FILE_NON_DIRECTORY_FILE } ,
902
+ options ,
883
903
ptr:: null ( ) ,
884
904
0 ,
885
905
)
@@ -910,38 +930,48 @@ fn run_path_with_wcstr<T, P: AsRef<Path>>(
910
930
f ( path)
911
931
}
912
932
933
+ fn run_path_with_utf16 < T , P : AsRef < Path > > (
934
+ path : P ,
935
+ f : & dyn Fn ( & [ u16 ] ) -> io:: Result < T > ,
936
+ ) -> io:: Result < T > {
937
+ let utf16: Vec < u16 > = path. as_ref ( ) . as_os_str ( ) . encode_wide ( ) . collect ( ) ;
938
+ f ( & utf16)
939
+ }
940
+
913
941
impl Dir {
914
942
pub fn new < P : AsRef < Path > > ( path : P ) -> io:: Result < Self > {
915
943
let opts = OpenOptions :: new ( ) ;
916
- run_path_with_wcstr ( path , & |path| Self :: new_native ( path, & opts) )
944
+ Self :: new_native ( path. as_ref ( ) , & opts)
917
945
}
918
946
919
947
pub fn new_with < P : AsRef < Path > > ( path : P , opts : & OpenOptions ) -> io:: Result < Self > {
920
- run_path_with_wcstr ( path , & |path| Self :: new_native ( path, & opts) )
948
+ Self :: new_native ( path. as_ref ( ) , & opts)
921
949
}
922
950
923
951
pub fn open < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < File > {
924
952
let mut opts = OpenOptions :: new ( ) ;
953
+ let path = path. as_ref ( ) . as_os_str ( ) . encode_wide ( ) . collect :: < Vec < _ > > ( ) ;
925
954
opts. read ( true ) ;
926
- Ok ( File { handle : run_path_with_wcstr ( path , & |path| self . open_native ( path, & opts) ) ? } )
955
+ Ok ( File { handle : self . open_native ( & path, & opts) ? } )
927
956
}
928
957
929
958
pub fn open_with < P : AsRef < Path > > ( & self , path : P , opts : & OpenOptions ) -> io:: Result < File > {
930
- Ok ( File { handle : run_path_with_wcstr ( path, & |path| self . open_native ( path, & opts) ) ? } )
959
+ let path = path. as_ref ( ) . as_os_str ( ) . encode_wide ( ) . collect :: < Vec < _ > > ( ) ;
960
+ Ok ( File { handle : self . open_native ( & path, & opts) ? } )
931
961
}
932
962
933
963
pub fn create_dir < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < ( ) > {
934
964
let mut opts = OpenOptions :: new ( ) ;
935
965
opts. write ( true ) ;
936
- run_path_with_wcstr ( path, & |path| self . create_dir_native ( path, & opts) . map ( |_| ( ) ) )
966
+ run_path_with_utf16 ( path, & |path| self . create_dir_native ( path, & opts) . map ( |_| ( ) ) )
937
967
}
938
968
939
969
pub fn remove_file < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < ( ) > {
940
- run_path_with_wcstr ( path, & |path| self . remove_native ( path, false ) )
970
+ run_path_with_utf16 ( path, & |path| self . remove_native ( path, false ) )
941
971
}
942
972
943
973
pub fn remove_dir < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < ( ) > {
944
- run_path_with_wcstr ( path, & |path| self . remove_native ( path, true ) )
974
+ run_path_with_utf16 ( path, & |path| self . remove_native ( path, true ) )
945
975
}
946
976
947
977
pub fn rename < P : AsRef < Path > , Q : AsRef < Path > > (
@@ -950,36 +980,18 @@ impl Dir {
950
980
to_dir : & Self ,
951
981
to : Q ,
952
982
) -> io:: Result < ( ) > {
953
- run_path_with_wcstr ( from. as_ref ( ) , & |from| {
954
- run_path_with_wcstr ( to. as_ref ( ) , & |to| self . rename_native ( from, to_dir, to) )
955
- } )
983
+ run_path_with_wcstr ( to. as_ref ( ) , & |to| self . rename_native ( from. as_ref ( ) , to_dir, to) )
956
984
}
957
985
958
- fn new_native ( path : & WCStr , opts : & OpenOptions ) -> io:: Result < Self > {
959
- let name = c:: UNICODE_STRING {
960
- Length : path. count_bytes ( ) as _ ,
961
- MaximumLength : path. count_bytes ( ) as _ ,
962
- Buffer : path. as_ptr ( ) as * mut _ ,
963
- } ;
964
- let object_attributes = c:: OBJECT_ATTRIBUTES {
965
- Length : size_of :: < c:: OBJECT_ATTRIBUTES > ( ) as _ ,
966
- RootDirectory : ptr:: null_mut ( ) ,
967
- ObjectName : & name,
968
- Attributes : 0 ,
969
- SecurityDescriptor : ptr:: null ( ) ,
970
- SecurityQualityOfService : ptr:: null ( ) ,
971
- } ;
972
- let share = c:: FILE_SHARE_READ | c:: FILE_SHARE_WRITE | c:: FILE_SHARE_DELETE ;
973
- let handle =
974
- unsafe { nt_create_file ( opts. get_access_mode ( ) ?, & object_attributes, share, true ) }
975
- . io_result ( ) ?;
986
+ fn new_native ( path : & Path , opts : & OpenOptions ) -> io:: Result < Self > {
987
+ let handle = File :: open ( path, opts) ?. into_inner ( ) ;
976
988
Ok ( Self { handle } )
977
989
}
978
990
979
- fn open_native ( & self , path : & WCStr , opts : & OpenOptions ) -> io:: Result < Handle > {
991
+ fn open_native ( & self , path : & [ u16 ] , opts : & OpenOptions ) -> io:: Result < Handle > {
980
992
let name = c:: UNICODE_STRING {
981
- Length : path. count_bytes ( ) as _ ,
982
- MaximumLength : path. count_bytes ( ) as _ ,
993
+ Length : path. len ( ) as _ ,
994
+ MaximumLength : path. len ( ) as _ ,
983
995
Buffer : path. as_ptr ( ) as * mut _ ,
984
996
} ;
985
997
let object_attributes = c:: OBJECT_ATTRIBUTES {
@@ -991,14 +1003,22 @@ impl Dir {
991
1003
SecurityQualityOfService : ptr:: null ( ) ,
992
1004
} ;
993
1005
let share = c:: FILE_SHARE_READ | c:: FILE_SHARE_WRITE | c:: FILE_SHARE_DELETE ;
994
- unsafe { nt_create_file ( opts. get_access_mode ( ) ?, & object_attributes, share, false ) }
995
- . io_result ( )
1006
+ unsafe {
1007
+ nt_create_file (
1008
+ opts. get_access_mode ( ) ?,
1009
+ opts. get_disposition ( ) ?,
1010
+ & object_attributes,
1011
+ share,
1012
+ false ,
1013
+ )
1014
+ }
1015
+ . io_result ( )
996
1016
}
997
1017
998
- fn create_dir_native ( & self , path : & WCStr , opts : & OpenOptions ) -> io:: Result < Handle > {
1018
+ fn create_dir_native ( & self , path : & [ u16 ] , opts : & OpenOptions ) -> io:: Result < Handle > {
999
1019
let name = c:: UNICODE_STRING {
1000
- Length : path. count_bytes ( ) as _ ,
1001
- MaximumLength : path. count_bytes ( ) as _ ,
1020
+ Length : path. len ( ) as _ ,
1021
+ MaximumLength : path. len ( ) as _ ,
1002
1022
Buffer : path. as_ptr ( ) as * mut _ ,
1003
1023
} ;
1004
1024
let object_attributes = c:: OBJECT_ATTRIBUTES {
@@ -1010,11 +1030,19 @@ impl Dir {
1010
1030
SecurityQualityOfService : ptr:: null ( ) ,
1011
1031
} ;
1012
1032
let share = c:: FILE_SHARE_READ | c:: FILE_SHARE_WRITE | c:: FILE_SHARE_DELETE ;
1013
- unsafe { nt_create_file ( opts. get_access_mode ( ) ?, & object_attributes, share, true ) }
1014
- . io_result ( )
1033
+ unsafe {
1034
+ nt_create_file (
1035
+ opts. get_access_mode ( ) ?,
1036
+ opts. get_disposition ( ) ?,
1037
+ & object_attributes,
1038
+ share,
1039
+ true ,
1040
+ )
1041
+ }
1042
+ . io_result ( )
1015
1043
}
1016
1044
1017
- fn remove_native ( & self , path : & WCStr , dir : bool ) -> io:: Result < ( ) > {
1045
+ fn remove_native ( & self , path : & [ u16 ] , dir : bool ) -> io:: Result < ( ) > {
1018
1046
let mut opts = OpenOptions :: new ( ) ;
1019
1047
opts. access_mode ( c:: GENERIC_WRITE ) ;
1020
1048
let handle =
@@ -1031,24 +1059,54 @@ impl Dir {
1031
1059
if result == 0 { Err ( api:: get_last_error ( ) ) . io_result ( ) } else { Ok ( ( ) ) }
1032
1060
}
1033
1061
1034
- fn rename_native ( & self , from : & WCStr , to_dir : & Self , to : & WCStr ) -> io:: Result < ( ) > {
1062
+ fn rename_native ( & self , from : & Path , to_dir : & Self , to : & WCStr ) -> io:: Result < ( ) > {
1035
1063
let mut opts = OpenOptions :: new ( ) ;
1036
1064
opts. access_mode ( c:: GENERIC_WRITE ) ;
1037
- let handle = self . open_native ( from, & opts) ?;
1038
- let info = c:: FILE_RENAME_INFO {
1039
- Anonymous : c:: FILE_RENAME_INFO_0 { ReplaceIfExists : true } ,
1040
- RootDirectory : to_dir. handle . as_raw_handle ( ) ,
1041
- FileNameLength : to. count_bytes ( ) as _ ,
1042
- FileName : [ to. as_ptr ( ) as u16 ] ,
1065
+ let handle = run_path_with_utf16 ( from, & |u| self . open_native ( u, & opts) ) ?;
1066
+ // Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation`
1067
+ // This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size.
1068
+ let Ok ( new_len_without_nul_in_bytes) : Result < u32 , _ > =
1069
+ ( ( to. count_bytes ( ) - 1 ) * 2 ) . try_into ( )
1070
+ else {
1071
+ return Err ( io:: Error :: new ( io:: ErrorKind :: InvalidFilename , "Filename too long" ) ) ;
1043
1072
} ;
1073
+ let offset: u32 = offset_of ! ( c:: FILE_RENAME_INFO , FileName ) . try_into ( ) . unwrap ( ) ;
1074
+ let struct_size = offset + new_len_without_nul_in_bytes + 2 ;
1075
+ let layout =
1076
+ Layout :: from_size_align ( struct_size as usize , align_of :: < c:: FILE_RENAME_INFO > ( ) )
1077
+ . unwrap ( ) ;
1078
+
1079
+ // SAFETY: We allocate enough memory for a full FILE_RENAME_INFO struct and a filename.
1080
+ let file_rename_info;
1081
+ unsafe {
1082
+ file_rename_info = alloc ( layout) . cast :: < c:: FILE_RENAME_INFO > ( ) ;
1083
+ if file_rename_info. is_null ( ) {
1084
+ return Err ( io:: ErrorKind :: OutOfMemory . into ( ) ) ;
1085
+ }
1086
+
1087
+ ( & raw mut ( * file_rename_info) . Anonymous ) . write ( c:: FILE_RENAME_INFO_0 {
1088
+ Flags : c:: FILE_RENAME_FLAG_REPLACE_IF_EXISTS | c:: FILE_RENAME_FLAG_POSIX_SEMANTICS ,
1089
+ } ) ;
1090
+
1091
+ ( & raw mut ( * file_rename_info) . RootDirectory ) . write ( to_dir. handle . as_raw_handle ( ) ) ;
1092
+ // Don't include the NULL in the size
1093
+ ( & raw mut ( * file_rename_info) . FileNameLength ) . write ( new_len_without_nul_in_bytes) ;
1094
+
1095
+ to. as_ptr ( ) . copy_to_nonoverlapping (
1096
+ ( & raw mut ( * file_rename_info) . FileName ) . cast :: < u16 > ( ) ,
1097
+ run_path_with_wcstr ( from, & |s| Ok ( s. count_bytes ( ) ) ) . unwrap ( ) ,
1098
+ ) ;
1099
+ }
1100
+
1044
1101
let result = unsafe {
1045
1102
c:: SetFileInformationByHandle (
1046
1103
handle. as_raw_handle ( ) ,
1047
- c:: FileRenameInfo ,
1048
- ptr :: addr_of! ( info ) as _ ,
1049
- size_of :: < c :: FILE_RENAME_INFO > ( ) as _ ,
1104
+ c:: FileRenameInfoEx ,
1105
+ file_rename_info . cast :: < c_void > ( ) ,
1106
+ struct_size ,
1050
1107
)
1051
1108
} ;
1109
+ unsafe { dealloc ( file_rename_info. cast :: < u8 > ( ) , layout) } ;
1052
1110
if result == 0 { Err ( api:: get_last_error ( ) ) . io_result ( ) } else { Ok ( ( ) ) }
1053
1111
}
1054
1112
}
0 commit comments