Resolving URL from bookmark data doesn't automatically mount SMB volume on iOS

On macOS, the Finder allows to connect to a server and store the login credentials. When creating a bookmark to a file on a server and resolving it again, the server is mounted automatically (unless I provide the option URL.BookmarkResolutionOptions.withoutMounting).

I just tried connecting to my Mac from my iPad via SMB in the Files app and storing a bookmark to a file on the server, but disconnecting the server and trying to resolve the bookmark throws the error (I translated the English text from Italian):

Error Domain=NSFileProviderErrorDomain Code=-2001 "No file provider was found with the identifier "com.apple.SMBClientProvider.FileProvider"'" UserInfo={NSLocalizedDescription=No file provider was found with the identifier "com.apple.SMBClientProvider.FileProvider"., NSUnderlyingError=0x302a1a340 {Error Domain=NSFileProviderErrorDomain Code=-2013 "(null) "}}

Every time I disconnect and reconnect to the server, selecting the same file returns a different path. The first time I got

/private/var/mobile/Library/LiveFiles/com.apple.filesystems.smbclientd/WtFD3Ausername/path/to/file.txt

The next time WtFD3A changed to EqHc2g and so on.

Is it not possible to automatically mount a server when resolving a bookmark on iOS?

The following code allows to reproduce the issue:

struct ContentView: View {
    @State private var isPresentingFilePicker = false
    @AppStorage("bookmarkData") private var bookmarkData: Data?
    @State private var url: URL?
    @State private var stale = false
    @State private var error: Error?

    var body: some View {
        VStack {
            Button("Open") {
                isPresentingFilePicker = true
            }
            if let url = url {
                Text(url.path)
            } else if bookmarkData != nil {
                Text("couldn't resolve bookmark data")
            } else {
                Text("no bookmark data")
            }
            if stale {
                Text("bookmark is stale")
            }
            if let error = error {
                Text("\(error)")
                    .foregroundStyle(.red)
            }
        }
        .padding()
        .fileImporter(isPresented: $isPresentingFilePicker, allowedContentTypes: [.data]) { result in
            do {
                let url = try result.get()
                if url.startAccessingSecurityScopedResource() {
                    bookmarkData = try url.bookmarkData()
                }
            } catch {
                self.error = error
            }
        }
        .onChange(of: bookmarkData, initial: true) { _, bookmarkData in
            if let bookmarkData = bookmarkData {
                do {
                    url = try URL(resolvingBookmarkData: bookmarkData, bookmarkDataIsStale: &stale)
                } catch {
                    self.error = error
                }
            }
        }
    }
}

So, first off, I want to clarify that the issue ISN'T this:

Every time I disconnect and reconnect to the server, selecting the same file returns a different path. The first time I got

Bookmark resolution does not depend on the mount (or full) path and never has. While the full path on macOS tends to be relatively stable, that's simply a side effect of the macOS volume mounting convention, NOT something the bookmark system actually relies on. You can easily prove this yourself by setting up two different SMB shares that with names such that they both mount as "foo". Whichever is mounted first will mount "/Volumes/foo/" and the second will mount at "/Volumes/foo 1/". If you create a boomark to an object "bar" on one of those two shares, then macOS will happily resolve the bookmark to that object to either "/Volumes/foo/bar" or "/Volumes/foo 1/bar", depending on which order the shares happen to have been mounted when you resolve the bookmark.

That leads to here:

Is it not possible to automatically mount a server when resolving a bookmark on iOS?

First off, please file a bug on this and post the bug number back here. The full details of what's going on are below, but the biggest thing you can do to help get this fixed is filing bugs on the issue. As part of that bug, please make sure you describe the "why" (what app this is in and what you're trying to do with this functionality), not just the "what". Your bug is really about documenting how this bug is hurting your product, not just informing us of that specific problem.

Next, while I haven't specifically tested this, I strongly suspect that it actually is mounting the volume. That is, if you do the following:

  1. Mount an smb share.
  2. Bookmark an object on that share.
  3. Unmount the smb share in Files.app.
  4. Resolve the bookmark (which will fail).
  5. Check in Files.app to see if the smb share is mounted.

...then I think you'll find that the smb share IS in fact mounted in Files.app after step #5. That's because, unfortunately, the issue here isn't actually with mounting network volumes, it's actually a bug (r.102995804) in resolving bookmarks "across" mounts. That is, the following sequence and any variation on it:

  1. Mount an external volume.
  2. Bookmark an object on that share.
  3. Unmount that external volume in Files.app.
  4. Remount that external volume in Files.app.
  5. Resolve the bookmark (which will fail).

...fails on iOS 16 or later. This will occur on both network volume (smb/afp) and local volumes (APFS/HFS+/FAT). This forum post is an example of the local volume variant of this bug.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thanks for the detailed explanation. I filed FB16470722.

I ran the sample app again but after unmounting the volume and resolving the bookmark with an error, the Files app doesn't show the volume.

Resolving URL from bookmark data doesn't automatically mount SMB volume on iOS
 
 
Q