There is no good way to interact with network file systems in Swift without a third-party library. This leaves us needing to mount a share in order to use normal
FileManager and various
.write(…) methods. Unfortunately leaving the task of mounting a server to the User (and thus, the Finder) has a few problems.
The main hurdle is that the Finder doesn’t mound servers consistently. Behind the scenes directories are created at
/Volumes and the shares mounted to them. While they show up as expected to the user they don’t behave deterministically as far as UNIX paths are concerned. A network share I was testing left behind dozens of hidden folders with no good way to determine where the drive was actually mounted.
There are a few ways of programmatically mounting a network share.
The easiest option to mount a network share is to spin up an
AppleScript object and run
mount afp://someshare. While this works it does exactly what the Finder does, so it’s a no-go.
Ok, AppleScript is clunky anyway. That’s what
Process is for. Using
mount we can mount any file system anywhere we want! Sadly this was spitting out errors saying my destination path didn’t exist. I could copy the exact command into the Terminal and it would work. Moving right along…
Finally, there is
NetFS. This has almost no documentation outside of some header files buried in system directories. Fortunately it doesn’t require dropping down to Objective-C and it actually works.
There isn’t a reference page for any of the
NetFS methods, but if there was this is what one of them would look like. A network drive can be mounted either synchronously or asynchronously. I’ve documented the synchronous method, but the async version is similar.
Mounts a network file share at the specified file system node
NetFSMountURLSync( _ url: CFURL!, _ mountpath: CFURL!, _ user: CFString!, _ passwd: CFString!, _ open_options: CFMutableDictionary!, _ mount_options: CFMutableDictionary!, _ mountpoints: UnsafeMutablePointer<Unmanaged<CFArray>?>! ) -> Int32
url URL to mount, e.g. nfs://server/path
mountpath Path for the mountpoint
user Auth user name (overrides URL)
passwd Auth password (overrides URL)
open_options Options for session open (see below)
mount_options Options for mounting (see below)
mountpoints Array of mountpoints
Returns 0 if successful, or an error code from /usr/include/sys/errno.h
Most of the options are fairly self-explanatory. You can pass
nil for any parameters you don’t need. In fact, only the server URL is required.
If the server requires authentication and a username or password aren’t supplied the standard system prompt will open.
Information from the mount header file
The following dictionary keys for
open_options are supported:
kNetFSUseGuestKey: Bool Login as a guest user.
kNetFSAllowLoopbackKey: Bool Allow a loopback mount.
If this key is set to
UIOption: Suppress authentication dialog UI.
There are a number of options that can be passed in to
mount_options as an NSMutableDictionary.
Information from the NetFS header file
There are two options for this key:
MNT_DONTBROWSE the share won’t be visible to the user as a drive.
MNT_RDONLY the share will be mounted as read-only.
Allow a mount from a dir beneath the share point. If this key is
true a subdirectory of the share will be mounted directly instead of mounting the root the the share.
Mount with “soft” failure semantics. If this key isn’t specified it defaults to
Network errors, e.g. timeouts, will be retried for a much shorter amount of time. If the network errors persist, then the mount will be force unmounted.
kNetFSMountAtMountDirKey: Bool Mount on the specified mountpath instead of below it.
Information from the error number header file
The header file contains far more error numbers than
NetFS returns, so you’ll just have to cross reference.