@@ -301,9 +301,59 @@ extension FileManager {
301
301
}
302
302
303
303
internal func _destinationOfSymbolicLink( atPath path: String ) throws -> String {
304
- return try _canonicalizedPath ( toFileAtPath: path)
304
+ let handle = path. withCString ( encodedAs: UTF16 . self) { symlink in
305
+ CreateFileW ( symlink,
306
+ GENERIC_READ,
307
+ DWORD ( FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) ,
308
+ nil ,
309
+ DWORD ( OPEN_EXISTING) ,
310
+ DWORD ( FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS) ,
311
+ nil )
312
+ }
313
+
314
+ guard handle != INVALID_HANDLE_VALUE else {
315
+ throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: true )
316
+ }
317
+ defer { CloseHandle ( handle) }
318
+
319
+ // Since REPARSE_DATA_BUFFER ends with an arbitrarily long buffer, we
320
+ // have to manually get the path buffer out of it since binding it to a
321
+ // type will truncate the path buffer
322
+ let pathBufferOffset =
323
+ MemoryLayout < ULONG > . size //ULONG ReparseTag
324
+ + MemoryLayout < USHORT > . size //ULONG ReparseDataLength
325
+ + MemoryLayout < USHORT > . size //ULONG Reserved
326
+ + MemoryLayout < USHORT > . size //ULONG SubstituteNameOffset
327
+ + MemoryLayout < USHORT > . size //ULONG SubstituteNameLength
328
+ + MemoryLayout < USHORT > . size //ULONG PrintNameOffset
329
+ + MemoryLayout < USHORT > . size //ULONG PrintNameLength
330
+ + MemoryLayout < ULONG > . size //ULONG Flags
331
+
332
+ var buff = Array ( repeating: 0 , count: MemoryLayout< REPARSE_DATA_BUFFER> . size + Int( 2 * MAX_PATH) )
333
+
334
+ return try buff. withUnsafeMutableBytes {
335
+ var bytesWritten : DWORD = 0
336
+ guard DeviceIoControl ( handle, FSCTL_GET_REPARSE_POINT, nil , 0 ,
337
+ $0. baseAddress, DWORD ( $0. count) , & bytesWritten, nil ) else {
338
+ throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: true )
339
+ }
340
+
341
+ let bound = $0. bindMemory ( to: REPARSE_DATA_BUFFER . self)
342
+ guard let reparseDataBuffer = bound. first else {
343
+ fatalError ( )
344
+ }
345
+
346
+ let pathBufferPtr = $0. baseAddress! + pathBufferOffset
347
+ let printNameBytes = Int ( reparseDataBuffer. SymbolicLinkReparseBuffer. PrintNameLength)
348
+ let printNameOffset = Int ( reparseDataBuffer. SymbolicLinkReparseBuffer. PrintNameOffset)
349
+ let printNameBuff = Data ( bytes: pathBufferPtr + printNameOffset, count: printNameBytes)
350
+ guard let printPath = String ( data: printNameBuff, encoding: . utf16LittleEndian) else {
351
+ fatalError ( )
352
+ }
353
+ return printPath
354
+ }
305
355
}
306
-
356
+
307
357
internal func _canonicalizedPath( toFileAtPath path: String ) throws -> String {
308
358
var hFile : HANDLE = INVALID_HANDLE_VALUE
309
359
path. withCString ( encodedAs: UTF16 . self) { link in
0 commit comments