@@ -969,15 +969,15 @@ fn run_path_with_utf16<T, P: AsRef<Path>>(
969
969
impl Dir {
970
970
pub fn new < P : AsRef < Path > > ( path : P ) -> io:: Result < Self > {
971
971
let opts = OpenOptions :: new ( ) ;
972
- Self :: new_with_native ( path. as_ref ( ) , & opts ) . map ( |handle | Self { handle } )
972
+ run_path_with_wcstr ( path. as_ref ( ) , & |path | Self :: new_with_native ( path , & opts ) )
973
973
}
974
974
975
975
pub fn new_with < P : AsRef < Path > > ( path : P , opts : & OpenOptions ) -> io:: Result < Self > {
976
- Self :: new_with_native ( path. as_ref ( ) , & opts ) . map ( |handle | Self { handle } )
976
+ run_path_with_wcstr ( path. as_ref ( ) , & |path | Self :: new_with_native ( path , & opts ) )
977
977
}
978
978
979
979
pub fn new_for_traversal < P : AsRef < Path > > ( path : P ) -> io:: Result < Self > {
980
- Self :: new_native ( path. as_ref ( ) ) . map ( |handle | Self { handle } )
980
+ run_path_with_wcstr ( path. as_ref ( ) , & |path | Self :: new_native ( path ) )
981
981
}
982
982
983
983
pub fn open < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < File > {
@@ -1027,14 +1027,35 @@ impl Dir {
1027
1027
run_path_with_wcstr ( to. as_ref ( ) , & |to| self . rename_native ( from. as_ref ( ) , to_dir, to) )
1028
1028
}
1029
1029
1030
- fn new_native ( path : & Path ) -> io:: Result < Handle > {
1030
+ pub fn symlink < P : AsRef < Path > , Q : AsRef < Path > > ( & self , original : P , link : Q ) -> io:: Result < ( ) > {
1031
+ run_path_with_utf16 ( original. as_ref ( ) , & |orig| {
1032
+ self . symlink_native ( orig, link. as_ref ( ) , original. as_ref ( ) . is_relative ( ) )
1033
+ } )
1034
+ }
1035
+
1036
+ fn new_native ( path : & WCStr ) -> io:: Result < Self > {
1031
1037
let mut opts = OpenOptions :: new ( ) ;
1032
1038
opts. access_mode ( c:: FILE_TRAVERSE ) ;
1033
- File :: open ( path, & opts) . map ( |file| file . into_inner ( ) )
1039
+ Self :: new_with_native ( path, & opts)
1034
1040
}
1035
1041
1036
- fn new_with_native ( path : & Path , opts : & OpenOptions ) -> io:: Result < Handle > {
1037
- File :: open ( path, opts) . map ( |file| file. into_inner ( ) )
1042
+ fn new_with_native ( path : & WCStr , opts : & OpenOptions ) -> io:: Result < Self > {
1043
+ let creation = opts. get_creation_mode ( ) ?;
1044
+ let handle = unsafe {
1045
+ c:: CreateFileW (
1046
+ path. as_ptr ( ) ,
1047
+ opts. get_access_mode ( ) ?,
1048
+ opts. share_mode ,
1049
+ opts. security_attributes ,
1050
+ creation,
1051
+ opts. get_flags_and_attributes ( ) | c:: FILE_FLAG_BACKUP_SEMANTICS ,
1052
+ ptr:: null_mut ( ) ,
1053
+ )
1054
+ } ;
1055
+ match OwnedHandle :: try_from ( unsafe { HandleOrInvalid :: from_raw_handle ( handle) } ) {
1056
+ Ok ( handle) => Ok ( Self { handle : Handle :: from_inner ( handle) } ) ,
1057
+ Err ( _) => Err ( Error :: last_os_error ( ) ) ,
1058
+ }
1038
1059
}
1039
1060
1040
1061
fn open_native ( & self , path : & [ u16 ] , opts : & OpenOptions ) -> io:: Result < Handle > {
@@ -1160,6 +1181,71 @@ impl Dir {
1160
1181
unsafe { dealloc ( file_rename_info. cast :: < u8 > ( ) , layout) } ;
1161
1182
if result == 0 { Err ( api:: get_last_error ( ) ) . io_result ( ) } else { Ok ( ( ) ) }
1162
1183
}
1184
+
1185
+ fn symlink_native ( & self , original : & [ u16 ] , link : & Path , relative : bool ) -> io:: Result < ( ) > {
1186
+ const TOO_LONG_ERR : io:: Error =
1187
+ io:: const_error!( io:: ErrorKind :: InvalidFilename , "File name is too long" ) ;
1188
+ let mut opts = OpenOptions :: new ( ) ;
1189
+ opts. write ( true ) ;
1190
+ let linkfile = File :: open ( link, & opts) ?;
1191
+ let utf16: Vec < u16 > = original. iter ( ) . chain ( original) . copied ( ) . collect ( ) ;
1192
+ let file_name_len = u16:: try_from ( original. len ( ) ) . or ( Err ( TOO_LONG_ERR ) ) ?;
1193
+ let sym_buffer = c:: SYMBOLIC_LINK_REPARSE_BUFFER {
1194
+ SubstituteNameOffset : 0 ,
1195
+ SubstituteNameLength : file_name_len,
1196
+ PrintNameOffset : file_name_len,
1197
+ PrintNameLength : file_name_len,
1198
+ Flags : if relative { c:: SYMLINK_FLAG_RELATIVE } else { 0 } ,
1199
+ PathBuffer : 0 ,
1200
+ } ;
1201
+ let layout = Layout :: new :: < c:: REPARSE_DATA_BUFFER > ( ) ;
1202
+ let layout = layout
1203
+ . extend ( Layout :: new :: < c:: SYMBOLIC_LINK_REPARSE_BUFFER > ( ) )
1204
+ . or ( Err ( TOO_LONG_ERR ) ) ?
1205
+ . 0 ;
1206
+ let layout = Layout :: array :: < u16 > ( original. len ( ) * 2 )
1207
+ . and_then ( |arr| layout. extend ( arr) )
1208
+ . or ( Err ( TOO_LONG_ERR ) ) ?
1209
+ . 0 ;
1210
+ let buffer = unsafe { alloc ( layout) } . cast :: < c:: REPARSE_DATA_BUFFER > ( ) ;
1211
+ unsafe {
1212
+ buffer. write ( c:: REPARSE_DATA_BUFFER {
1213
+ ReparseTag : c:: IO_REPARSE_TAG_SYMLINK ,
1214
+ ReparseDataLength : u16:: try_from ( size_of_val ( & sym_buffer) ) . or ( Err ( TOO_LONG_ERR ) ) ?,
1215
+ Reserved : 0 ,
1216
+ rest : ( ) ,
1217
+ } ) ;
1218
+ buffer
1219
+ . add ( offset_of ! ( c:: REPARSE_DATA_BUFFER , rest) )
1220
+ . cast :: < c:: SYMBOLIC_LINK_REPARSE_BUFFER > ( )
1221
+ . write ( sym_buffer) ;
1222
+ ptr:: copy_nonoverlapping (
1223
+ utf16. as_ptr ( ) ,
1224
+ buffer
1225
+ . add ( offset_of ! ( c:: REPARSE_DATA_BUFFER , rest) )
1226
+ . add ( offset_of ! ( c:: SYMBOLIC_LINK_REPARSE_BUFFER , PathBuffer ) )
1227
+ . cast :: < u16 > ( ) ,
1228
+ original. len ( ) * 2 ,
1229
+ ) ;
1230
+ } ;
1231
+ let result = unsafe {
1232
+ c:: DeviceIoControl (
1233
+ linkfile. handle . as_raw_handle ( ) ,
1234
+ c:: FSCTL_SET_REPARSE_POINT ,
1235
+ & raw const buffer as * const c_void ,
1236
+ u32:: try_from ( size_of_val ( & buffer) ) . or ( Err ( TOO_LONG_ERR ) ) ?,
1237
+ ptr:: null_mut ( ) ,
1238
+ 0 ,
1239
+ ptr:: null_mut ( ) ,
1240
+ ptr:: null_mut ( ) ,
1241
+ )
1242
+ } ;
1243
+ unsafe {
1244
+ dealloc ( buffer. cast ( ) , layout) ;
1245
+ }
1246
+
1247
+ if result == 0 { Err ( api:: get_last_error ( ) ) . io_result ( ) } else { Ok ( ( ) ) }
1248
+ }
1163
1249
}
1164
1250
1165
1251
impl fmt:: Debug for Dir {
0 commit comments