-
Notifications
You must be signed in to change notification settings - Fork 130
Improve path normalization and judgment on Windows #191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
c13a770
4aff4de
c048ed9
f3bc044
8fd9767
a279f53
9aef445
acc3eaa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,11 +12,7 @@ import Foundation | |
import WinSDK | ||
#endif | ||
|
||
#if os(Windows) | ||
private typealias PathImpl = UNIXPath | ||
#else | ||
private typealias PathImpl = UNIXPath | ||
#endif | ||
|
||
/// Represents an absolute file system path, independently of what (or whether | ||
/// anything at all) exists at that path in the file system at any given time. | ||
|
@@ -453,11 +449,12 @@ private struct UNIXPath: Path { | |
defer { fsr.deallocate() } | ||
|
||
let path: String = String(cString: fsr) | ||
return path.withCString(encodedAs: UTF16.self) { | ||
let result: String = path.withCString(encodedAs: UTF16.self) { | ||
let data = UnsafeMutablePointer(mutating: $0) | ||
PathCchRemoveFileSpec(data, path.count) | ||
return String(decodingCString: data, as: UTF16.self) | ||
} | ||
return result.isEmpty ? "." : result | ||
#else | ||
// FIXME: This method seems too complicated; it should be simplified, | ||
// if possible, and certainly optimized (using UTF8View). | ||
|
@@ -544,11 +541,13 @@ private struct UNIXPath: Path { | |
|
||
init(normalizingAbsolutePath path: String) { | ||
#if os(Windows) | ||
var buffer: [WCHAR] = Array<WCHAR>(repeating: 0, count: Int(MAX_PATH + 1)) | ||
var result: PWSTR? | ||
defer { LocalFree(result) } | ||
|
||
_ = path.withCString(encodedAs: UTF16.self) { | ||
PathCanonicalizeW(&buffer, $0) | ||
PathAllocCanonicalize($0, ULONG(PATHCCH_ALLOW_LONG_PATHS.rawValue), &result) | ||
} | ||
stevapple marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.init(string: String(decodingCString: buffer, as: UTF16.self)) | ||
self.init(string: String(decodingCString: result!, as: UTF16.self)) | ||
#else | ||
compnerd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
precondition(path.first == "/", "Failure normalizing \(path), absolute paths should start with '/'") | ||
|
||
|
@@ -613,14 +612,14 @@ private struct UNIXPath: Path { | |
} | ||
|
||
init(normalizingRelativePath path: String) { | ||
#if os(Windows) | ||
var buffer: [WCHAR] = Array<WCHAR>(repeating: 0, count: Int(MAX_PATH + 1)) | ||
_ = path.replacingOccurrences(of: "/", with: "\\").withCString(encodedAs: UTF16.self) { | ||
PathCanonicalizeW(&buffer, $0) | ||
} | ||
self.init(string: String(decodingCString: buffer, as: UTF16.self)) | ||
#else | ||
precondition(path.first != "/") | ||
let pathSeparator: Character | ||
#if os(Windows) | ||
pathSeparator = "\\" | ||
let path = path.replacingOccurrences(of: "/", with: "\\") | ||
#else | ||
pathSeparator = "/" | ||
#endif | ||
precondition(path.first != pathSeparator) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This precondition doesn't hold. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although it is literally "relative", Windows Shell (and Swift which depends on it) regards There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. UNC paths are always absolute. It is just a drive relative path which is not absolute. That distinction is important as it impacts the lexical traversal of the path string. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ping @compnerd There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still think that the differences are material and need to be addressed. Paths in Windows do not behave like Unix, and so you will have differences. e.g. path1 = "C:\Users\compnerd" because the current directory on D: happened to be "....\Windows\System32\WindowsMetadata" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’ll look into more critical cases here. However, if I regard There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO I believe this PR is fully capable of fixing faulty behavior without changing the current judgement of relative paths and absolute paths. To fully support Windows path system, we’d better work on another one which may contain a complete refactoring. What this PR mainly addressed and fixed is the problem of |
||
|
||
// FIXME: Here we should also keep track of whether anything actually has | ||
// to be changed in the string, and if not, just return the existing one. | ||
|
@@ -630,7 +629,7 @@ private struct UNIXPath: Path { | |
// the normalized string representation. | ||
var parts: [String] = [] | ||
var capacity = 0 | ||
for part in path.split(separator: "/") { | ||
for part in path.split(separator: pathSeparator) { | ||
switch part.count { | ||
case 0: | ||
// Ignore empty path components. | ||
|
@@ -669,7 +668,7 @@ private struct UNIXPath: Path { | |
if let first = iter.next() { | ||
result.append(contentsOf: first) | ||
while let next = iter.next() { | ||
result.append("/") | ||
result.append(pathSeparator) | ||
result.append(contentsOf: next) | ||
} | ||
} | ||
|
@@ -680,11 +679,13 @@ private struct UNIXPath: Path { | |
|
||
// If the result is empty, return `.`, otherwise we return it as a string. | ||
self.init(string: result.isEmpty ? "." : result) | ||
compnerd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#endif | ||
} | ||
|
||
init(validatingAbsolutePath path: String) throws { | ||
#if os(Windows) | ||
#if os(Windows) | ||
guard path != "" else { | ||
throw PathValidationError.invalidAbsolutePath(path) | ||
} | ||
let fsr: UnsafePointer<Int8> = path.fileSystemRepresentation | ||
defer { fsr.deallocate() } | ||
|
||
|
@@ -693,7 +694,7 @@ private struct UNIXPath: Path { | |
throw PathValidationError.invalidAbsolutePath(path) | ||
} | ||
self.init(normalizingAbsolutePath: path) | ||
#else | ||
#else | ||
switch path.first { | ||
case "/": | ||
self.init(normalizingAbsolutePath: path) | ||
|
@@ -702,11 +703,15 @@ private struct UNIXPath: Path { | |
default: | ||
throw PathValidationError.invalidAbsolutePath(path) | ||
} | ||
#endif | ||
#endif | ||
} | ||
|
||
init(validatingRelativePath path: String) throws { | ||
#if os(Windows) | ||
#if os(Windows) | ||
guard path != "" else { | ||
self.init(normalizingRelativePath: path) | ||
return | ||
} | ||
compnerd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let fsr: UnsafePointer<Int8> = path.fileSystemRepresentation | ||
defer { fsr.deallocate() } | ||
|
||
|
@@ -715,14 +720,14 @@ private struct UNIXPath: Path { | |
throw PathValidationError.invalidRelativePath(path) | ||
} | ||
self.init(normalizingRelativePath: path) | ||
#else | ||
#else | ||
switch path.first { | ||
case "/", "~": | ||
throw PathValidationError.invalidRelativePath(path) | ||
default: | ||
self.init(normalizingRelativePath: path) | ||
} | ||
#endif | ||
#endif | ||
} | ||
|
||
func suffix(withDot: Bool) -> String? { | ||
|
Uh oh!
There was an error while loading. Please reload this page.