Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Local

The local backend serves a directory of the server’s file system, its root (root). Each mount has its own subdirectory there, home_dir.

[[backends]]
name = "disque"
type = "local"
root = "/srv/sftp"

[[roles]]
name = "utilisateurs"

[[roles.mounts]]
backend = "disque"
home_dir = "/{username}"
create_home = true
acl = [{ path = "/", rights = ["read", "write", "list", "delete", "rename"], recursive = true }]

alice uploads /rapport.txt: the file is /srv/sftp/alice/rapport.txt.

The keys

All keys: Reference [[backends]] type = “local”; common keys: Backends.

No operation leaves the mount’s root + home_dir, whatever links are there, including what the server does itself (in-flight file, lock, sweep). A link to another mount’s home_dir leaves it just as much as a link outside the root.

SettingA link within the mountA link that leaves it
follow_symlinks = false (default)never followednever followed
follow_symlinks = truefollowed if it stays under root + home_dirnever followed
  • A link is listed as a link (type l; "is_symlink": true in REST), or, when followed, as its target. Deleting or renaming acts on the link.
  • With hidden_stores, an upload onto a file link replaces the link; the target stays intact.
  • No door creates links: they come from another process or a restore.
  • The root and its ancestors are trusted (a root through a link is followed): writable by the administrator only.
  • On a shared volume (NFS…), mount the root nosymfollow (Linux 5.10 and later).

Case of ACL paths

On a storage that ignores case (NTFS, APFS and HFS+ by default, SMB/CIFS, ext4 or tmpfs casefold), the ACL compares folded paths: NFD, removal of ignorable code points (U+200B…), full case folding (straße = strasse), NFC.

SettingComparison of ACL paths
case_insensitive = truefolded
case_insensitive = falsebyte by byte, without normalization
key absenta probe decides, at startup and at each roles reload

The probe creates a lowercase file and looks for it in uppercase in each directory where an entry resolves (folding is set per directory, chattr +F): one folding directory makes the backend fold, an inconclusive result counts as folding. A missing directory or one under {username} is not probed, and a case-sensitive APFS volume stays insensitive to normalization: when in doubt, case_insensitive = true.

Where the ACL folds, and on a Windows server, a short 8.3 name (PROTEG~1) or one ending in . or a space is not a valid path: disable short names (fsutil 8dot3name).

The common keys on a local backend

KeyOn a local backend
home_dir (mount)a subdirectory of root: /partenaire/in/x of a mount at /partenaire with home_dir = "/partenaires/acme" is /srv/sftp/partenaires/acme/in/x
create_home (mount)true: creates home_dir if missing, when the session opens, one level at a time, never through a link
hidden_storesa file being transferred next to the destination, published by rename
stale_partialsthe sweep of those files, on the file system’s clock
cross_instance_reservationa lock file next to the destination; false by default on Windows: one instance per root
lock_prefixthe name of those locks

The process acts under its own uid; file modes follow its umask.

On Linux 5.6 and later, the kernel enforces the confinement (openat2(2), RESOLVE_BENEATH); without openat2, each component is opened O_NOFOLLOW (reported once as INFO); on Windows, the parent is checked just before the call.

Performance and limits

  • A rename and the publication of an upload use RENAME_NOREPLACE. Where the file system lacks it (NFS, FUSE including sshfs, 9p), they fall back to rename(2): a concurrent overwrite is not detected there, and the audit of an upload that overwrites says replaced=unknown.
  • No fsync: a success does not promise durability on disk.
  • mkdir creates one level; the missing parents of an upload are created one by one, each judged by the ACL.
  • Deleting a tree is not counted: the audit says removed=unknown.

What you will see

WhenLine
startup, case probeINFO with backend, acl_paths = folded or exact
create_home creates a directoryINFO created missing home directory, field home_dir
startup, sweep of leftoversINFO stale in-flight files: ..., fields backend, grace_secs, age_check