@@ -146,123 +146,9 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
146146 fs:: symlink ( src, dest)
147147 }
148148
149- // Creating a directory junction on windows involves dealing with reparse
150- // points and the DeviceIoControl function, and this code is a skeleton of
151- // what can be found here:
152- //
153- // http://www.flexhex.com/docs/articles/hard-links.phtml
154149 #[ cfg( windows) ]
155150 fn symlink_dir_inner ( target : & Path , junction : & Path ) -> io:: Result < ( ) > {
156- use std:: ffi:: OsStr ;
157- use std:: os:: windows:: ffi:: OsStrExt ;
158-
159- use windows:: {
160- core:: PCWSTR ,
161- Win32 :: Foundation :: { CloseHandle , HANDLE } ,
162- Win32 :: Storage :: FileSystem :: {
163- CreateFileW , FILE_ACCESS_FLAGS , FILE_FLAG_BACKUP_SEMANTICS ,
164- FILE_FLAG_OPEN_REPARSE_POINT , FILE_SHARE_DELETE , FILE_SHARE_READ , FILE_SHARE_WRITE ,
165- MAXIMUM_REPARSE_DATA_BUFFER_SIZE , OPEN_EXISTING ,
166- } ,
167- Win32 :: System :: Ioctl :: FSCTL_SET_REPARSE_POINT ,
168- Win32 :: System :: SystemServices :: { GENERIC_WRITE , IO_REPARSE_TAG_MOUNT_POINT } ,
169- Win32 :: System :: IO :: DeviceIoControl ,
170- } ;
171-
172- #[ allow( non_snake_case) ]
173- #[ repr( C ) ]
174- struct REPARSE_MOUNTPOINT_DATA_BUFFER {
175- ReparseTag : u32 ,
176- ReparseDataLength : u32 ,
177- Reserved : u16 ,
178- ReparseTargetLength : u16 ,
179- ReparseTargetMaximumLength : u16 ,
180- Reserved1 : u16 ,
181- ReparseTarget : u16 ,
182- }
183-
184- fn to_u16s < S : AsRef < OsStr > > ( s : S ) -> io:: Result < Vec < u16 > > {
185- Ok ( s. as_ref ( ) . encode_wide ( ) . chain ( Some ( 0 ) ) . collect ( ) )
186- }
187-
188- // We're using low-level APIs to create the junction, and these are more
189- // picky about paths. For example, forward slashes cannot be used as a
190- // path separator, so we should try to canonicalize the path first.
191- let target = fs:: canonicalize ( target) ?;
192-
193- fs:: create_dir ( junction) ?;
194-
195- let path = to_u16s ( junction) ?;
196-
197- let h = unsafe {
198- CreateFileW (
199- PCWSTR ( path. as_ptr ( ) ) ,
200- FILE_ACCESS_FLAGS ( GENERIC_WRITE ) ,
201- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE ,
202- None ,
203- OPEN_EXISTING ,
204- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS ,
205- HANDLE :: default ( ) ,
206- )
207- }
208- . map_err ( |_| io:: Error :: last_os_error ( ) ) ?;
209-
210- unsafe {
211- #[ repr( C , align( 8 ) ) ]
212- struct Align8 < T > ( T ) ;
213- let mut data = Align8 ( [ 0u8 ; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize ] ) ;
214- let db = data. 0 . as_mut_ptr ( ) as * mut REPARSE_MOUNTPOINT_DATA_BUFFER ;
215- let end = db. cast :: < u8 > ( ) . add ( MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize ) ;
216- let reparse_target_slice = {
217- let buf_start = core:: ptr:: addr_of_mut!( ( * db) . ReparseTarget ) . cast :: < u16 > ( ) ;
218- // Compute offset in bytes and then divide so that we round down
219- // rather than hit any UB (admittedly this arithmetic should work
220- // out so that this isn't necessary)
221- let buf_len_bytes =
222- usize:: try_from ( end. offset_from ( buf_start. cast :: < u8 > ( ) ) ) . unwrap ( ) ;
223- let buf_len_wchars = buf_len_bytes / core:: mem:: size_of :: < u16 > ( ) ;
224- core:: slice:: from_raw_parts_mut ( buf_start, buf_len_wchars)
225- } ;
226-
227- // FIXME: this conversion is very hacky
228- let iter = br"\??\"
229- . iter ( )
230- . map ( |x| * x as u16 )
231- . chain ( path. iter ( ) . copied ( ) )
232- . chain ( core:: iter:: once ( 0 ) ) ;
233- let mut i = 0 ;
234- for c in iter {
235- if i >= reparse_target_slice. len ( ) {
236- return Err ( io:: Error :: new (
237- io:: ErrorKind :: Other ,
238- format ! ( "path too long for reparse target: {target:?}" ) ,
239- ) ) ;
240- }
241- reparse_target_slice[ i] = c;
242- i += 1 ;
243- }
244- ( * db) . ReparseTag = IO_REPARSE_TAG_MOUNT_POINT ;
245- ( * db) . ReparseTargetMaximumLength = ( i * 2 ) as u16 ;
246- ( * db) . ReparseTargetLength = ( ( i - 1 ) * 2 ) as u16 ;
247- ( * db) . ReparseDataLength = ( ( * db) . ReparseTargetLength + 12 ) as u32 ;
248-
249- let mut ret = 0u32 ;
250- DeviceIoControl (
251- h,
252- FSCTL_SET_REPARSE_POINT ,
253- Some ( db. cast ( ) ) ,
254- ( * db) . ReparseDataLength + 8 ,
255- None ,
256- 0 ,
257- Some ( & mut ret) ,
258- None ,
259- )
260- . ok ( )
261- . map_err ( |_| io:: Error :: last_os_error ( ) ) ?;
262- }
263-
264- unsafe { CloseHandle ( h) } ;
265- Ok ( ( ) )
151+ junction:: create ( & target, & junction)
266152 }
267153}
268154
0 commit comments