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
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
| Name | What it does |
|---|---|
| AT_EMPTY_PATH | Get a handle for the file referred to by dirfd itself, ignoring pathname (which must be ""). No path traversal. |
| AT_SYMLINK_FOLLOW | Follow a trailing symlink in pathname (default behavior; included for clarity). |
Errors you will actually hit
| errno | Meaning |
|---|---|
| EOVERFLOW | handle->handle_bytes was too small; the kernel has written the required size into handle_bytes. Reallocate and retry. |
| EOPNOTSUPP | The filesystem (e.g. tmpfs) does not implement the export operations required by this syscall. |
| EPERM | open_by_handle_at requires CAP_DAC_READ_SEARCH. Without it, the call is refused. |
| ESTALE | The 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
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
