@@ -88,7 +88,7 @@ public struct AbsolutePath: Hashable, Sendable {
8888 }
8989 defer { LocalFree ( pwszResult) }
9090
91- self . init ( String ( decodingCString: pwszResult, as: UTF16 . self) )
91+ try self . init ( validating : String ( decodingCString: pwszResult, as: UTF16 . self) )
9292#else
9393 try self . init ( basePath, RelativePath ( validating: str) )
9494#endif
@@ -515,12 +515,29 @@ private struct WindowsPath: Path, Sendable {
515515 }
516516
517517 init ( string: String ) {
518- if string. first? . isASCII ?? false , string. first? . isLetter ?? false , string. first? . isLowercase ?? false ,
518+ let path : String
519+ let hasDrive : Bool
520+ if string. first? . isASCII ?? false , string. first? . isLetter ?? false ,
519521 string. count > 1 , string [ string. index ( string. startIndex, offsetBy: 1 ) ] == " : "
520522 {
521- self . string = " \( string. first!. uppercased ( ) ) \( string. dropFirst ( 1 ) ) "
523+ hasDrive = true
524+ path = " \( string. first!. uppercased ( ) ) \( string. dropFirst ( 1 ) ) "
522525 } else {
523- self . string = string
526+ hasDrive = false
527+ path = string
528+ }
529+ var droppedTailing : Bool = false
530+ // There seems to be many assumptions around paths and trailing '\'
531+ var substring = path [ path. startIndex..< path. endIndex]
532+ while !substring. isEmpty && substring. utf8. last == UInt8 ( ascii: " \\ " ) {
533+ substring = substring. dropLast ( )
534+ droppedTailing = true
535+ }
536+ // Don't use stripped substring is we only have <drive>: left
537+ if hasDrive && substring. count == 2 && droppedTailing {
538+ self . string = Self . repr ( path) + " \\ "
539+ } else {
540+ self . string = Self . repr ( String ( substring) )
524541 }
525542 }
526543
@@ -544,7 +561,7 @@ private struct WindowsPath: Path, Sendable {
544561 self . init ( string: " . " )
545562 } else {
546563 let realpath : String = Self . repr ( path)
547- // Treat a relative path as an invalid relative path...
564+ // Treat an absolute path as an invalid relative path
548565 if Self . isAbsolutePath ( realpath) || realpath. first == " \\ " {
549566 throw PathValidationError . invalidRelativePath ( path)
550567 }
@@ -568,6 +585,7 @@ private struct WindowsPath: Path, Sendable {
568585 _ = string. withCString ( encodedAs: UTF16 . self) { root in
569586 name. withCString ( encodedAs: UTF16 . self) { path in
570587 PathAllocCombine ( root, path, ULONG ( PATHCCH_ALLOW_LONG_PATHS . rawValue) , & result)
588+ _ = PathCchStripPrefix ( result, wcslen ( result) )
571589 }
572590 }
573591 defer { LocalFree ( result) }
@@ -579,6 +597,7 @@ private struct WindowsPath: Path, Sendable {
579597 _ = string. withCString ( encodedAs: UTF16 . self) { root in
580598 relativePath. string. withCString ( encodedAs: UTF16 . self) { path in
581599 PathAllocCombine ( root, path, ULONG ( PATHCCH_ALLOW_LONG_PATHS . rawValue) , & result)
600+ _ = PathCchStripPrefix ( result, wcslen ( result) )
582601 }
583602 }
584603 defer { LocalFree ( result) }
@@ -965,8 +984,7 @@ extension AbsolutePath {
965984 preconditionFailure ( " invalid relative path computed from \( pathString) " )
966985 }
967986 }
968-
969- assert ( AbsolutePath ( base, result) == self )
987+ assert ( AbsolutePath ( base, result) == self , " \( AbsolutePath ( base, result) ) != \( self ) " )
970988 return result
971989 }
972990
0 commit comments