Skip to content
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

URL.path should not strip trailing slash for root paths on Windows #1038

Merged
merged 2 commits into from
Nov 11, 2024

Conversation

jrflat
Copy link
Contributor

@jrflat jrflat commented Nov 8, 2024

We should not strip the trailing slash when getting the fileSystemPath for C:\ on Windows, since C:\ represents the root while C: does not. Similarly, we should not strip the trailing slash for any UNC path, since the trailing slash might be root.

Resolves #976 and #977

@jrflat
Copy link
Contributor Author

jrflat commented Nov 8, 2024

@swift-ci please test

@jrflat jrflat requested review from jmschonfeld and ahoppen November 8, 2024 16:16
return posixPath
private static func windowsPath(for urlPath: String) -> String {
let utf8 = urlPath.utf8
guard !utf8.starts(with: [._slash, ._slash]) else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about \\server\share\directory\? Should that not be \\server\share\directory?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, yeah. I think it gets a bit complicated to make sure we do the right thing for all paths, though. I'm not super familiar with UNC paths, so please correct me if I'm wrong, but I think we could have:

\\.\c:\
\\.\BootPartition\
\\server\share\
\\.\server\share\
\\.\UNC\server\share\

so we couldn't rely on just stripping after X segments. And it still might be complex to check for . or ? in the first segment since we could have either driveName or server\share following it.

Do you think we should call PathIsRootW to determine whether we should strip the slash? I'm a bit hesitant to do filesystem I/O in URL.path, but I think that would get us the correct answer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, PathIsRootW is the right thing to use IMO. \\.\ paths are device paths, there are also kernel paths \\?\. Additionally, you might also encounter a root local path with a \??\ prefix. For the UNC path, you can also label it via link, e.g. \\?\UNC\server\share\directory\.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to checking PathIsRootW for non-drive letter paths in 9d325ee

array[2] == ._colon,
array[3] == ._slash {
return String(Substring(utf8.dropFirst()))
var iter = utf8.makeIterator()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we assert that the path starts with [._slash, alpha, ._colon, ._slash]?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I don't think we can check for alpha like that.

@jrflat jrflat force-pushed the trailing-slash-windows branch from e540a0b to 9d325ee Compare November 9, 2024 03:34
@jrflat
Copy link
Contributor Author

jrflat commented Nov 9, 2024

@swift-ci please test

let path = decodeFilePath(urlPath)
return path.replacing(._slash, with: ._backslash).withCString(encodedAs: UTF16.self) { pwszPath in
guard !PathIsRootW(pwszPath) else {
return path
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we still get one path incorrect now: /S:. This a non-UNC, drive-relative path. We could either resolve that to an absolute path or return it as S:. You can also have a more complex path such as S:utils\build.ps1 (which I believe would be encoded as /s:utils/build.ps1.

Copy link
Contributor Author

@jrflat jrflat Nov 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, more work definitely needs to be done to support drive-relative paths in URL. Currently, S:utils\build.ps1 is actually treated as a relative path, relative to the current working directory (but not necessarily the cwd of S:), so .path won't resolve it correctly.

I think we should get the cwd of S: during URL(filePath:) initialization and use that cwd path as the base URL, then strip S: from the relative path. If that sounds good I can open up a follow-on PR, since it'll be slightly more involved than this change, which fixes C:\ and other absolute paths' behaviors.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we should do some checking if the call needs to be done, but otherwise, this sounds like a good way forward. Doing that in a follow up is totally fine.

@jrflat jrflat merged commit 13c8aeb into swiftlang:main Nov 11, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

URL.withUnsafeFileSystemRepresentation drops trailing backslash even if it is significant on Windows
3 participants