$RodHat_/search
Syscall reference · Filesystem

name_to_handle_at / open_by_handle_at(2)

Get a stable opaque file handle for a path and reopen it later, surviving remounts and bind-mount rearrangement.

Since
Linux 2.6.39check your kernel →
glibc
2.14
System
Linux
Man page
name_to_handle_at / open_by_handle_at(2)

Synopsis

#define _GNU_SOURCE
#include <sys/stat.h>
#include <fcntl.h>

int name_to_handle_at(int dirfd, const char *pathname,
                      struct file_handle *handle,
                      int *mount_id, int flags);

int open_by_handle_at(int mount_fd,
                      struct file_handle *handle, int flags);

Rod's take

Two-call pattern: first call with handle_bytes=0 to discover the required size (EOVERFLOW is expected), then reallocate and retry. Serialize both the f_handle bytes and handle_type; the type is filesystem-specific and required for reopening. CAP_DAC_READ_SEARCH gates open_by_handle_at because a handle bypasses normal path permission checks. Works on ext4, XFS, Btrfs; fails with EOPNOTSUPP on tmpfs. Store the filesystem UUID alongside handles to detect filesystem replacement.

Flags and arguments that matter

NameWhat it does
AT_EMPTY_PATHGet a handle for the file referred to by dirfd itself, ignoring pathname (which must be ""). No path traversal.
AT_SYMLINK_FOLLOWFollow a trailing symlink in pathname (default behavior; included for clarity).

Errors you will actually hit

errnoMeaning
EOVERFLOWhandle->handle_bytes was too small; the kernel has written the required size into handle_bytes. Reallocate and retry.
EOPNOTSUPPThe filesystem (e.g. tmpfs) does not implement the export operations required by this syscall.
EPERMopen_by_handle_at requires CAP_DAC_READ_SEARCH. Without it, the call is refused.
ESTALEThe inode encoded in the handle no longer exists on the filesystem.

Example

#define _GNU_SOURCE
#include <sys/stat.h>
#include <fcntl.h>

struct file_handle *fh = malloc(sizeof(*fh));
fh->handle_bytes = 0;
int mount_id;

/* discover size */
name_to_handle_at(AT_FDCWD, "/path/to/file", fh, &mount_id, 0);
/* errno == EOVERFLOW; reallocate */
fh = realloc(fh, sizeof(*fh) + fh->handle_bytes);
name_to_handle_at(AT_FDCWD, "/path/to/file", fh, &mount_id, 0);

/* later, in a privileged process */
int mfd = open("/path/to/mountpoint", O_RDONLY);
int fd  = open_by_handle_at(mfd, fh, O_RDONLY);

Trimmed from the full walkthrough in name_to_handle_at(2): file handles that survive remounts.

BSD equivalent

No equivalent. FreeBSD has fhopen(2) for NFS file handles (superuser only). macOS has nothing.

The long version, from the console

Sources

  1. name_to_handle_at(2), man7.org

Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.