@@ -434,12 +434,17 @@ private struct UNIXPath: Path {
434
434
static let root = UNIXPath ( string: " / " )
435
435
436
436
static func isValidComponent( _ name: String ) -> Bool {
437
+ #if os(Windows)
438
+ if name. contains ( " \\ " ) {
439
+ return false
440
+ }
441
+ #endif
437
442
return name != " " && name != " . " && name != " .. " && !name. contains ( " / " )
438
443
}
439
444
440
445
#if os(Windows)
441
446
static func isAbsolutePath( _ path: String ) -> Bool {
442
- return !path. withCString ( encodedAs: UTF16 . self, PathIsRelativeW)
447
+ return !path. prenormalized ( ) . withCString ( encodedAs: UTF16 . self, PathIsRelativeW)
443
448
}
444
449
#endif
445
450
@@ -541,13 +546,13 @@ private struct UNIXPath: Path {
541
546
542
547
init ( normalizingAbsolutePath path: String ) {
543
548
#if os(Windows)
544
- var result : PWSTR ?
549
+ var result : [ WCHAR ] = Array < WCHAR > ( repeating : 0 , count : Int ( MAX_PATH + 1 ) )
545
550
defer { LocalFree ( result) }
546
551
547
- _ = path. withCString ( encodedAs: UTF16 . self) {
548
- PathAllocCanonicalize ( $0, ULONG ( PATHCCH_ALLOW_LONG_PATHS . rawValue ) , & result )
552
+ _ = path. prenormalized ( ) . withCString ( encodedAs: UTF16 . self) {
553
+ PathCchCanonicalize ( $0, result . length , $0 )
549
554
}
550
- self . init ( string: String ( decodingCString: result! , as: UTF16 . self) )
555
+ self . init ( string: String ( decodingCString: result, as: UTF16 . self) )
551
556
#else
552
557
precondition ( path. first == " / " , " Failure normalizing \( path) , absolute paths should start with '/' " )
553
558
@@ -615,7 +620,7 @@ private struct UNIXPath: Path {
615
620
let pathSeparator : Character
616
621
#if os(Windows)
617
622
pathSeparator = " \\ "
618
- let path = path. replacingOccurrences ( of : " / " , with : " \\ " )
623
+ let path = path. prenormalized ( )
619
624
#else
620
625
pathSeparator = " / "
621
626
#endif
@@ -683,7 +688,9 @@ private struct UNIXPath: Path {
683
688
684
689
init ( validatingAbsolutePath path: String ) throws {
685
690
#if os(Windows)
686
- guard path != " " else {
691
+ // Explicitly handle the empty path, since retrieving
692
+ // `fileSystemRepresentation` of it is illegal.
693
+ guard !path. isEmpty else {
687
694
throw PathValidationError . invalidAbsolutePath ( path)
688
695
}
689
696
let fsr : UnsafePointer < Int8 > = path. fileSystemRepresentation
@@ -708,7 +715,9 @@ private struct UNIXPath: Path {
708
715
709
716
init ( validatingRelativePath path: String ) throws {
710
717
#if os(Windows)
711
- guard path != " " else {
718
+ // Explicitly handle the empty path, since retrieving
719
+ // `fileSystemRepresentation` of it is illegal.
720
+ guard !path. isEmpty else {
712
721
self . init ( normalizingRelativePath: path)
713
722
return
714
723
}
@@ -946,3 +955,11 @@ private func mayNeedNormalization(absolute string: String) -> Bool {
946
955
}
947
956
return false
948
957
}
958
+
959
+ #if os(Windows)
960
+ fileprivate extension String {
961
+ func prenormalized( ) -> String {
962
+ return self . replacingOccurrences ( of: " / " , with: " \\ " )
963
+ }
964
+ }
965
+ #endif
0 commit comments