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