$RodHat_
Syscall reference · Filesystem

statx(2)

Extended stat: request specific fields, get birth time, inode attribute flags and mount ID.

Since
Linux 4.11check your kernel →
glibc
glibc 2.28
System
Linux
Man page
statx(2)

Synopsis

#define _GNU_SOURCE          /* See feature_test_macros(7) */
#include <fcntl.h>           /* Definition of AT_* constants */
#include <sys/stat.h>

int statx(int dirfd, const char *_Nullable restrict path,
          int flags, unsigned int mask,
          struct statx *restrict statxbuf);

Rod's take

stat(2) froze its struct back when a filesystem fit on a floppy: three timestamps, none of them birth time, and ctime still means inode change no matter how many juniors swear otherwise. statx lets you ask for just the fields you want, then tells you through stx_mask which ones it actually filled. Check that mask before trusting anything, btime especially. You also get immutable, append-only, encrypted and verity flags without opening the file and fumbling an ioctl, plus a mount ID. FreeBSD had birth time in stat first, naturally. Still a good syscall.

Flags and arguments that matter

NameWhat it does
STATX_BASIC_STATSMask: everything classic stat(2) returns (type, mode, nlink, uid, gid, times, ino, size, blocks).
STATX_BTIMEMask: request stx_btime, the file creation time. Check stx_mask; not every filesystem has it.
STATX_MNT_IDLinux 5.8Mask: request stx_mnt_id, the ID of the mount containing the file.
STATX_MNT_ID_UNIQUELinux 6.8Mask: request a unique (non-reused) mount ID in stx_mnt_id.
STATX_DIOALIGNLinux 6.1Mask: request direct I/O alignment limits; support varies by filesystem.
STATX_ALLMask: STATX_BASIC_STATS | STATX_BTIME. Deprecated; don't use it.
AT_STATX_SYNC_AS_STATFlags: do whatever stat(2) does about syncing attributes with a remote server.
AT_STATX_FORCE_SYNCFlags: force attribute sync with the server (network filesystems).
AT_STATX_DONT_SYNCFlags: return cached attributes even if stale; no server round trip.
AT_SYMLINK_NOFOLLOWFlags: if path is a symlink, report on the link itself.

Errors you will actually hit

errnoMeaning
ENOENTA path component doesn't exist, or path is empty without AT_EMPTY_PATH.
EACCESSearch permission denied on a directory in the path prefix.
EINVALInvalid flag in flags, or the reserved STATX__RESERVED bit set in mask.
EBADFpath is relative but dirfd is neither AT_FDCWD nor a valid fd.
ENOTDIRA prefix component isn't a directory, or path is relative and dirfd isn't a directory.

Example

struct statx sx;
if (statx(AT_FDCWD, path, AT_STATX_SYNC_AS_STAT,
          STATX_BASIC_STATS | STATX_BTIME, &sx) == 0) {
    if (sx.stx_mask & STATX_BTIME)
        printf("born: %lld.%09u\n",
               (long long)sx.stx_btime.tv_sec, sx.stx_btime.tv_nsec);
    else
        puts("no birth time on this filesystem");

    if ((sx.stx_attributes_mask & STATX_ATTR_IMMUTABLE) &&
        (sx.stx_attributes      & STATX_ATTR_IMMUTABLE))
        puts("immutable");
}

Trimmed from the full walkthrough in statx(2): what stat(2) should have been.

BSD equivalent

FreeBSD: no statx; stat(2) already carries st_birthtim (st_birthtime). OpenBSD: no statx; plain stat(2)/fstatat(2).

The long version, from the console

Sources

  1. statx(2), man7.org
  2. stat(2), FreeBSD

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