@@ -102,21 +102,6 @@ private func walk(directory path: URL, _ body: (String, DWORD) throws -> Void) r
102102 }
103103}
104104
105- internal func joinPath( prefix: String , suffix: String ) -> String {
106- var pszPath : PWSTR ?
107-
108- guard !prefix. isEmpty else { return suffix }
109- guard !suffix. isEmpty else { return prefix }
110-
111- _ = try ! FileManager . default. _fileSystemRepresentation ( withPath: prefix, andPath: suffix) {
112- PathAllocCombine ( $0, $1, ULONG ( PATHCCH_ALLOW_LONG_PATHS . rawValue) , & pszPath)
113- }
114-
115- let path : String = String ( decodingCString: pszPath!, as: UTF16 . self)
116- LocalFree ( pszPath)
117- return path
118- }
119-
120105extension FileManager {
121106 internal func _mountedVolumeURLs( includingResourceValuesForKeys propertyKeys: [ URLResourceKey ] ? , options: VolumeEnumerationOptions = [ ] ) -> [ URL ] ? {
122107 var urls : [ URL ] = [ ]
@@ -168,145 +153,11 @@ extension FileManager {
168153 }
169154
170155 internal func _attributesOfFileSystemIncludingBlockSize( forPath path: String ) throws -> ( attributes: [ FileAttributeKey : Any ] , blockSize: UInt64 ? ) {
171- return ( attributes: try _attributesOfFileSystem ( forPath: path) , blockSize: nil )
172- }
173-
174- internal func _attributesOfFileSystem( forPath path: String ) throws -> [ FileAttributeKey : Any ] {
175- var result : [ FileAttributeKey : Any ] = [ : ]
176-
177- try FileManager . default. _fileSystemRepresentation ( withPath: path) {
178- let dwLength : DWORD = GetFullPathNameW ( $0, 0 , nil , nil )
179- guard dwLength > 0 else {
180- throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: true , paths: [ path] )
181- }
182-
183- var szVolumePath : [ WCHAR ] = Array < WCHAR > ( repeating: 0 , count: Int ( dwLength + 1 ) )
184- guard GetVolumePathNameW ( $0, & szVolumePath, dwLength) else {
185- throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: true , paths: [ path] )
186- }
187-
188- var liTotal : ULARGE_INTEGER = ULARGE_INTEGER ( )
189- var liFree : ULARGE_INTEGER = ULARGE_INTEGER ( )
190- guard GetDiskFreeSpaceExW ( & szVolumePath, nil , & liTotal, & liFree) else {
191- throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: true , paths: [ path] )
192- }
193-
194- let hr : HRESULT = PathCchStripToRoot ( & szVolumePath, szVolumePath. count)
195- guard hr == S_OK || hr == S_FALSE else {
196- throw _NSErrorWithWindowsError ( DWORD ( hr & 0xffff ) , reading: true , paths: [ path] )
197- }
198-
199- var volumeSerialNumber : DWORD = 0
200- guard GetVolumeInformationW ( & szVolumePath, nil , 0 , & volumeSerialNumber, nil , nil , nil , 0 ) else {
201- throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: true , paths: [ path] )
202- }
203-
204- result [ . systemSize] = NSNumber ( value: liTotal. QuadPart)
205- result [ . systemFreeSize] = NSNumber ( value: liFree. QuadPart)
206- result [ . systemNumber] = NSNumber ( value: volumeSerialNumber)
207- // FIXME(compnerd): what about .systemNodes, .systemFreeNodes?
208- }
209- return result
210- }
211-
212- internal func _destinationOfSymbolicLink( atPath path: String ) throws -> String {
213- let faAttributes = try windowsFileAttributes ( atPath: path)
214- guard faAttributes. dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT else {
215- throw _NSErrorWithWindowsError ( DWORD ( ERROR_BAD_ARGUMENTS) , reading: false )
216- }
217-
218- let handle : HANDLE = try FileManager . default. _fileSystemRepresentation ( withPath: path) {
219- CreateFileW ( $0, GENERIC_READ,
220- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
221- nil , OPEN_EXISTING,
222- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
223- nil )
224- }
225- if handle == INVALID_HANDLE_VALUE {
226- throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: true )
227- }
228- defer { CloseHandle ( handle) }
229-
230- // Since REPARSE_DATA_BUFFER ends with an arbitrarily long buffer, we
231- // have to manually get the path buffer out of it since binding it to a
232- // type will truncate the path buffer.
233- //
234- // 20 is the sum of the offsets of:
235- // ULONG ReparseTag
236- // USHORT ReparseDataLength
237- // USHORT Reserved
238- // USHORT SubstituteNameOffset
239- // USHORT SubstituteNameLength
240- // USHORT PrintNameOffset
241- // USHORT PrintNameLength
242- // ULONG Flags (Symlink only)
243- let symLinkPathBufferOffset = 20 // 4 + 2 + 2 + 2 + 2 + 2 + 2 + 4
244- let mountPointPathBufferOffset = 16 // 4 + 2 + 2 + 2 + 2 + 2 + 2
245- let buff = UnsafeMutableRawBufferPointer . allocate ( byteCount: Int ( MAXIMUM_REPARSE_DATA_BUFFER_SIZE) ,
246- alignment: 8 )
247-
248- guard let buffBase = buff. baseAddress else {
249- throw _NSErrorWithWindowsError ( DWORD ( ERROR_INVALID_DATA) , reading: false )
250- }
251-
252- var bytesWritten : DWORD = 0
253- guard DeviceIoControl ( handle, FSCTL_GET_REPARSE_POINT, nil , 0 ,
254- buffBase, DWORD ( MAXIMUM_REPARSE_DATA_BUFFER_SIZE) ,
255- & bytesWritten, nil ) else {
256- throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: true )
257- }
258-
259- guard bytesWritten >= MemoryLayout< REPARSE_DATA_BUFFER> . size else {
260- throw _NSErrorWithWindowsError ( DWORD ( ERROR_INVALID_DATA) , reading: false )
261- }
262-
263- let bound = buff. bindMemory ( to: REPARSE_DATA_BUFFER . self)
264- guard let reparseDataBuffer = bound. first else {
265- throw _NSErrorWithWindowsError ( DWORD ( ERROR_INVALID_DATA) , reading: false )
266- }
267-
268- guard reparseDataBuffer. ReparseTag == IO_REPARSE_TAG_SYMLINK
269- || reparseDataBuffer. ReparseTag == IO_REPARSE_TAG_MOUNT_POINT else {
270- throw _NSErrorWithWindowsError ( DWORD ( ERROR_BAD_ARGUMENTS) , reading: false )
271- }
272-
273- let pathBufferPtr : UnsafeMutableRawPointer
274- let substituteNameBytes : Int
275- let substituteNameOffset : Int
276- switch reparseDataBuffer. ReparseTag {
277- case IO_REPARSE_TAG_SYMLINK:
278- pathBufferPtr = buffBase + symLinkPathBufferOffset
279- substituteNameBytes = Int ( reparseDataBuffer. SymbolicLinkReparseBuffer. SubstituteNameLength)
280- substituteNameOffset = Int ( reparseDataBuffer. SymbolicLinkReparseBuffer. SubstituteNameOffset)
281- case IO_REPARSE_TAG_MOUNT_POINT:
282- pathBufferPtr = buffBase + mountPointPathBufferOffset
283- substituteNameBytes = Int ( reparseDataBuffer. MountPointReparseBuffer. SubstituteNameLength)
284- substituteNameOffset = Int ( reparseDataBuffer. MountPointReparseBuffer. SubstituteNameOffset)
285- default :
286- throw _NSErrorWithWindowsError ( DWORD ( ERROR_BAD_ARGUMENTS) , reading: false )
287- }
288-
289- guard substituteNameBytes + substituteNameOffset <= bytesWritten else {
290- throw _NSErrorWithWindowsError ( DWORD ( ERROR_INVALID_DATA) , reading: false )
291- }
292-
293- let substituteNameBuff = Data ( bytes: pathBufferPtr + substituteNameOffset, count: substituteNameBytes)
294- guard var substitutePath = String ( data: substituteNameBuff, encoding: . utf16LittleEndian) else {
295- throw _NSErrorWithWindowsError ( DWORD ( ERROR_INVALID_DATA) , reading: false )
296- }
297-
298- // Canonicalize the NT Object Manager Path to the DOS style path
299- // instead. Unfortunately, there is no nice API which can allow us to
300- // do this in a guranteed way.
301- let kObjectManagerPrefix = " \\ ?? \\ "
302- if substitutePath. hasPrefix ( kObjectManagerPrefix) {
303- substitutePath = String ( substitutePath. dropFirst ( kObjectManagerPrefix. count) )
304- }
305- return substitutePath
156+ return ( attributes: try attributesOfFileSystem ( forPath: path) , blockSize: nil )
306157 }
307158
308159 private func _realpath( _ path: String ) -> String {
309- return ( try ? _destinationOfSymbolicLink ( atPath: path) ) ?? path
160+ return ( try ? destinationOfSymbolicLink ( atPath: path) ) ?? path
310161 }
311162
312163 internal func _recursiveDestinationOfSymbolicLink( atPath path: String ) throws -> String {
0 commit comments