SSHMount Field Notes

macOS files on remote servers

A Mac file carries more than its contents. Most remote-workflow surprises come from macOS trying to preserve something the server has nowhere to put.

A file on a Mac carries more than its contents. It has extended attributes, possibly an access control list, possibly a resource fork, and a block of Finder information. A file on a typical Linux server has contents, a mode, an owner and a timestamp. Every remote workflow on macOS lives in the gap between those two descriptions, and most of the surprises — the stray files, the duplicate names that are not duplicates, the permissions that reset themselves — come from macOS trying to preserve something the other end has nowhere to keep.

This section is about that gap. It is not about which app to use, and it is not about mounting. It is about what happens to your files, which is worth understanding whichever tool you have chosen.

  • .DS_Store and ._ files

    Two different files from two different mechanisms. What is inside each, and why the famous defaults write fix only ever addressed one of them.

Why do two files with the same name collide on my Mac but not on the server?

Because the default macOS volume format does not distinguish between README.md and readme.md, and a typical Linux filesystem does. On the server those are two separate files that can coexist in one directory. Copy that directory to a Mac and one of them overwrites the other, quietly, with no error — you simply end up with fewer files than you started with. The reverse case is just as common: a project that builds on your Mac fails on the server because an import refers to Utils.js while the file is actually utils.js, a mismatch the Mac never had reason to complain about. Neither system is wrong. They disagree, and the disagreement surfaces only at the boundary between them.

Testing which behaviour you have

touch /tmp/CaseTest && ls /tmp/casetest 2>/dev/null \
  && echo "case-insensitive" || echo "case-sensitive"

Run the same two commands on the server to see its answer. If they differ, that is a constraint on every transfer between the two, and it is better discovered now than during a deployment. It is possible to create a case-sensitive volume on macOS for exactly this reason, though some commercial software refuses to run from one, so it is a decision with consequences rather than a free fix.

What are extended attributes, and what happens to them?

Extended attributes are arbitrary named pieces of data attached to a file alongside its contents. macOS uses them heavily: the quarantine flag that makes Gatekeeper check a downloaded application, Finder tags, the "where from" URL recorded on downloads, and custom icons are all extended attributes rather than part of the file. You can list them with xattr -l on any file. When such a file is written to a filesystem that has no equivalent facility, the attributes have to go somewhere or be discarded, and macOS chooses to write them into a companion file rather than lose them. That single decision is the origin of every ._ file you have ever seen on a server, and it is covered in full on the page linked above.

xattr -l ~/Downloads/some-file.dmg

Why do permissions and ownership look wrong after a transfer?

Because ownership is a property of the server, not of your file. Your Mac knows your local user ID; the server assigns files to the account you authenticated as, and applies its own umask when deciding the mode of anything newly created. A file that was 644 on your Mac may arrive as 664 or 600 depending on how the server is configured, and a file that was executable may or may not stay that way depending on the transfer mechanism. This is not corruption and it is not the client misbehaving. If exact modes matter — deployment scripts and anything with an executable bit are the usual cases — set them explicitly on the server after transfer rather than assuming they survived the trip.

Should Spotlight index a remote volume?

Generally not, and the reason is cost rather than correctness. Indexing means reading every file, and reading every file over a network connection means transferring the entire contents of the server so that a search index can be built from it. On a large remote directory this is slow, saturates the link, and can be expensive if the connection is metered. The visible symptom is a mount that is inexplicably busy shortly after you connect it, with sustained transfer you did not ask for. Search behaviour on remote volumes varies by how the volume is presented to the system, so the practical approach is to watch what happens on first connect rather than to assume any particular default.

Accented filenames that look identical but are not

Two filenames can display identically and still be different sequences of bytes, because a character such as é can be encoded as one code point or as e followed by a combining accent. macOS and Linux have historically made different choices here, which produces a specific and confusing failure: a file that appears to exist, that you can see in a listing, and that a script cannot open because the name it constructs does not byte-match the name on disk. Version control amplifies it, since a repository records the bytes. If you work with filenames outside plain ASCII and something "cannot find" a file you are looking straight at, compare the raw bytes rather than the rendering.

ls | LC_ALL=C od -c | head

What this section deliberately leaves alone

How macOS makes a remote server appear as a volume in the first place — file providers, FSKit, FUSE and the kernel extension history behind them — is a substantial subject and it is already covered thoroughly, with a comparison table and primary sources, on our product site's macFUSE alternatives guide. Rewriting it here would produce a worse version of a page that already exists. This section stays on the files themselves.

Disclosure. Published by OnePasswordManager Ltd, developers of SSHMount for macOS. Everything on this page is macOS and filesystem behaviour, reproducible with the tools already on your machine. About this site.

Sources

Every technical claim above is checked against one of these. Where a manual page is quoted, it is the copy shipped by the vendor named, not a third-party summary of it.

  1. xattr(1), the manual page shipped with macOS — https://keith.github.io/xcode-man-pages/xattr.1.html
  2. copyfile(3), the manual page shipped with macOS — what AppleDouble preserves — https://keith.github.io/xcode-man-pages/copyfile.3.html
  3. dot_clean(1), the manual page shipped with macOS — https://keith.github.io/xcode-man-pages/dot_clean.1.html