@@ -974,15 +974,15 @@ fn run_path_with_utf16<T, P: AsRef<Path>>(
974974impl Dir {
975975 pub fn new < P : AsRef < Path > > ( path : P ) -> io:: Result < Self > {
976976 let opts = OpenOptions :: new ( ) ;
977- Self :: new_with_native ( path. as_ref ( ) , & opts ) . map ( |handle | Self { handle } )
977+ run_path_with_wcstr ( path. as_ref ( ) , & |path | Self :: new_with_native ( path , & opts ) )
978978 }
979979
980980 pub fn new_with < P : AsRef < Path > > ( path : P , opts : & OpenOptions ) -> io:: Result < Self > {
981- Self :: new_with_native ( path. as_ref ( ) , & opts ) . map ( |handle | Self { handle } )
981+ run_path_with_wcstr ( path. as_ref ( ) , & |path | Self :: new_with_native ( path , & opts ) )
982982 }
983983
984984 pub fn new_for_traversal < P : AsRef < Path > > ( path : P ) -> io:: Result < Self > {
985- Self :: new_native ( path. as_ref ( ) ) . map ( |handle | Self { handle } )
985+ run_path_with_wcstr ( path. as_ref ( ) , & |path | Self :: new_native ( path ) )
986986 }
987987
988988 pub fn open < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < File > {
@@ -1032,14 +1032,35 @@ impl Dir {
10321032 run_path_with_wcstr ( to. as_ref ( ) , & |to| self . rename_native ( from. as_ref ( ) , to_dir, to) )
10331033 }
10341034
1035- fn new_native ( path : & Path ) -> io:: Result < Handle > {
1035+ pub fn symlink < P : AsRef < Path > , Q : AsRef < Path > > ( & self , original : P , link : Q ) -> io:: Result < ( ) > {
1036+ run_path_with_utf16 ( original. as_ref ( ) , & |orig| {
1037+ self . symlink_native ( orig, link. as_ref ( ) , original. as_ref ( ) . is_relative ( ) )
1038+ } )
1039+ }
1040+
1041+ fn new_native ( path : & WCStr ) -> io:: Result < Self > {
10361042 let mut opts = OpenOptions :: new ( ) ;
10371043 opts. access_mode ( c:: FILE_TRAVERSE ) ;
1038- File :: open ( path, & opts) . map ( |file| file . into_inner ( ) )
1044+ Self :: new_with_native ( path, & opts)
10391045 }
10401046
1041- fn new_with_native ( path : & Path , opts : & OpenOptions ) -> io:: Result < Handle > {
1042- File :: open ( path, opts) . map ( |file| file. into_inner ( ) )
1047+ fn new_with_native ( path : & WCStr , opts : & OpenOptions ) -> io:: Result < Self > {
1048+ let creation = opts. get_creation_mode ( ) ?;
1049+ let handle = unsafe {
1050+ c:: CreateFileW (
1051+ path. as_ptr ( ) ,
1052+ opts. get_access_mode ( ) ?,
1053+ opts. share_mode ,
1054+ opts. security_attributes ,
1055+ creation,
1056+ opts. get_flags_and_attributes ( ) | c:: FILE_FLAG_BACKUP_SEMANTICS ,
1057+ ptr:: null_mut ( ) ,
1058+ )
1059+ } ;
1060+ match OwnedHandle :: try_from ( unsafe { HandleOrInvalid :: from_raw_handle ( handle) } ) {
1061+ Ok ( handle) => Ok ( Self { handle : Handle :: from_inner ( handle) } ) ,
1062+ Err ( _) => Err ( Error :: last_os_error ( ) ) ,
1063+ }
10431064 }
10441065
10451066 fn open_native ( & self , path : & [ u16 ] , opts : & OpenOptions ) -> io:: Result < Handle > {
@@ -1165,6 +1186,71 @@ impl Dir {
11651186 unsafe { dealloc ( file_rename_info. cast :: < u8 > ( ) , layout) } ;
11661187 if result == 0 { Err ( api:: get_last_error ( ) ) . io_result ( ) } else { Ok ( ( ) ) }
11671188 }
1189+
1190+ fn symlink_native ( & self , original : & [ u16 ] , link : & Path , relative : bool ) -> io:: Result < ( ) > {
1191+ const TOO_LONG_ERR : io:: Error =
1192+ io:: const_error!( io:: ErrorKind :: InvalidFilename , "File name is too long" ) ;
1193+ let mut opts = OpenOptions :: new ( ) ;
1194+ opts. write ( true ) ;
1195+ let linkfile = File :: open ( link, & opts) ?;
1196+ let utf16: Vec < u16 > = original. iter ( ) . chain ( original) . copied ( ) . collect ( ) ;
1197+ let file_name_len = u16:: try_from ( original. len ( ) ) . or ( Err ( TOO_LONG_ERR ) ) ?;
1198+ let sym_buffer = c:: SYMBOLIC_LINK_REPARSE_BUFFER {
1199+ SubstituteNameOffset : 0 ,
1200+ SubstituteNameLength : file_name_len,
1201+ PrintNameOffset : file_name_len,
1202+ PrintNameLength : file_name_len,
1203+ Flags : if relative { c:: SYMLINK_FLAG_RELATIVE } else { 0 } ,
1204+ PathBuffer : 0 ,
1205+ } ;
1206+ let layout = Layout :: new :: < c:: REPARSE_DATA_BUFFER > ( ) ;
1207+ let layout = layout
1208+ . extend ( Layout :: new :: < c:: SYMBOLIC_LINK_REPARSE_BUFFER > ( ) )
1209+ . or ( Err ( TOO_LONG_ERR ) ) ?
1210+ . 0 ;
1211+ let layout = Layout :: array :: < u16 > ( original. len ( ) * 2 )
1212+ . and_then ( |arr| layout. extend ( arr) )
1213+ . or ( Err ( TOO_LONG_ERR ) ) ?
1214+ . 0 ;
1215+ let buffer = unsafe { alloc ( layout) } . cast :: < c:: REPARSE_DATA_BUFFER > ( ) ;
1216+ unsafe {
1217+ buffer. write ( c:: REPARSE_DATA_BUFFER {
1218+ ReparseTag : c:: IO_REPARSE_TAG_SYMLINK ,
1219+ ReparseDataLength : u16:: try_from ( size_of_val ( & sym_buffer) ) . or ( Err ( TOO_LONG_ERR ) ) ?,
1220+ Reserved : 0 ,
1221+ rest : ( ) ,
1222+ } ) ;
1223+ buffer
1224+ . add ( offset_of ! ( c:: REPARSE_DATA_BUFFER , rest) )
1225+ . cast :: < c:: SYMBOLIC_LINK_REPARSE_BUFFER > ( )
1226+ . write ( sym_buffer) ;
1227+ ptr:: copy_nonoverlapping (
1228+ utf16. as_ptr ( ) ,
1229+ buffer
1230+ . add ( offset_of ! ( c:: REPARSE_DATA_BUFFER , rest) )
1231+ . add ( offset_of ! ( c:: SYMBOLIC_LINK_REPARSE_BUFFER , PathBuffer ) )
1232+ . cast :: < u16 > ( ) ,
1233+ original. len ( ) * 2 ,
1234+ ) ;
1235+ } ;
1236+ let result = unsafe {
1237+ c:: DeviceIoControl (
1238+ linkfile. handle . as_raw_handle ( ) ,
1239+ c:: FSCTL_SET_REPARSE_POINT ,
1240+ & raw const buffer as * const c_void ,
1241+ u32:: try_from ( size_of_val ( & buffer) ) . or ( Err ( TOO_LONG_ERR ) ) ?,
1242+ ptr:: null_mut ( ) ,
1243+ 0 ,
1244+ ptr:: null_mut ( ) ,
1245+ ptr:: null_mut ( ) ,
1246+ )
1247+ } ;
1248+ unsafe {
1249+ dealloc ( buffer. cast ( ) , layout) ;
1250+ }
1251+
1252+ if result == 0 { Err ( api:: get_last_error ( ) ) . io_result ( ) } else { Ok ( ( ) ) }
1253+ }
11681254}
11691255
11701256impl fmt:: Debug for Dir {
0 commit comments