FileManager contentsOfDirectory fails on root volume

Im sure this is user error, but I can't seem to get the contents of a volume on windows.

print("\(fileURL)")
let directoryContents = try FileManager.default.contentsOfDirectory(at: fileURL)

throws with Error Domain=NSCocoaErrorDomain Code=257 "You don’t have permission."UserInfo={NSUnderlyingError=Error Domain=org.swift.Foundation.WindowsError Code=5 "(null)"}

when I pass the URL file:///D:/

Passing any directory inside the same volume works.

any ideas?

Do you know what contentsOfDirectory(at: URL) API you're calling here? Additionally, what swift toolchain are you using?

swift-foundation offers contentsOfDirectory(atPath: String) in FoundationEssentials and swift-corelibs-foundation offers contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options mask: DirectoryEnumerationOptions = []) in Foundation but I don't believe any of the Foundation modules provide an API for contentsOfDirectory that'd accept a URL instead of a String with no additional arguments, so it seems possible that this might be an API coming from another module that you're importing which might have a different implementation (although that org.swift.Foundation error does seem to point to the error at least being produced by the Foundation module in swift-corelibs-foundation).

My mistake, I thought there was a default for the keys param, so I removed for readability, I'm actually calling:

let directoryContents = try FileManager.default.contentsOfDirectory(at: fileURL, includingPropertiesForKeys: nil)

but I've tried the path based variant as well... and get different (still seemingly wrong) results.

toolchain is:

Swift version 6.1-dev (LLVM 6f0a61d8ba20c6a, Swift cf2af6809ecd52c)
Target: x86_64-unknown-windows-msvc

Ah ok and for full context what results do you get with the path-based variant? The String variant is coming from swift-foundation which was rewritten to be aligned with Darwin and Linux in Swift 6.0, whereas the URL variant has not (yet) been rewritten and is relatively the same as it has been for the past few years so there might be a latent bug there.

OK, after further testing it appears the path based api does behave correctly. However, there is another bug where URL.resolvingSymlinksInPath() converts volume paths relative to the executable's path

let url = URL(fileURLWithPath: "D:/")
print(url)
let std1 = url.resolvingSymlinksInPath()
print (std1)
let std2 = std1.standardizedFileURL
print (std2)

returns

file:///D:/
D%3A/ -- file:///C:/Users/mike/windir-swift/
file:///C:/Users/mike/windir-swift/D:/

And another bug

let url = URL(fileURLWithPath: "D:")
print(url)
let std1 = url.resolvingSymlinksInPath()
print (std1)
let std2 = std1.standardizedFileURL
print (std2)

returns

D%3A -- file:///C:/Users/mike/windir-swift/
file:///C:/Users/mike/windir-swift/D:
file:///C:/Users/mike/windir-swift/D:
1 Like

Ouch, that D: URL is ... well, painful. I think that @jrflat might've fixed part of that already.

The problem is that D: is really a relative-absolute path. It is the current working directory on the D drive, which would be an absolute path. That is, that is a relative path that needs to be resolved prior to use.

The problem is similar to the other relative-absolute paths: \relative or /absolute are both relative paths. They are relative to the current drive and need to be resolved before they can be used.

Now that final painful part that you are exploring: resolving relative paths across drives. I don't really know what that would really mean. How do you create a path on an unrelated volume? It seems that macOS removed support for the alternate root (as per POSIX) in recent releases. It would be interesting to know what Foundation would do if you were to attempt to resolve say /tmp against //.