Filehandles, files, directories

stat#

Get a file’s status information.

stat asks the operating system for the metadata record of a file — size, ownership, permissions, timestamps, inode — and returns it as a 13-element list. It is the underlying primitive behind the -X file tests (-e, -f, -r, …), behind modules like File::stat, and behind any script that needs to inspect a file without opening it. stat dereferences symlinks and reports on the target; use lstat to get the link itself.

Synopsis#

stat FILEHANDLE
stat EXPR
stat DIRHANDLE
stat
stat _

What you get back#

In list context, a 13-element list of numeric fields. In scalar context, a boolean: true on success, false on failure. Either way, on success the kernel’s stat buffer is cached in the special filehandle _, which any subsequent stat, lstat, or -X test can re-use without a new syscall.

On failure, list context returns the empty list and $! is set to the errno value from the failed stat(2).

The fields, in order:

Index

Field

Meaning

0

dev

device number of the filesystem holding the file

1

ino

inode number

2

mode

file mode — type bits and permission bits combined

3

nlink

number of hard links to the file

4

uid

numeric user ID of the owner

5

gid

numeric group ID of the owner

6

rdev

device identifier, for character/block special files

7

size

total size in bytes

8

atime

last access time, seconds since the epoch (1970-01-01 00:00 GMT)

9

mtime

last modify time, seconds since the epoch

10

ctime

inode change time, seconds since the epoch — not creation time

11

blksize

preferred I/O block size for reads/writes against this file

12

blocks

number of filesystem blocks actually allocated (often 512 B each)

Field 2 (mode) packs both the file type and the permission bits into one number. Mask with 07777 to see just the permissions; use the S_IF* constants and S_IS* helpers from Fcntl to test the type portably.

my $mode = (stat($filename))[2];
printf "permissions are %04o\n", $mode & 07777;

Not every filesystem populates every field. atime, blksize, and blocks may come back as 0 on filesystems that do not track them (for instance some FUSE mounts or network filesystems); ctime is not a portable “creation time” — it tracks the last change to the inode itself (permissions, ownership, link count), not when the file was first created.

Global state it touches#

  • $_ — read when stat is called with no argument. stat with no EXPR stats the filename held in $_, not the cached _ handle.

  • $! — set to the errno of the failed stat(2) syscall when the call fails.

  • The special _ filehandle — a per-interpreter cache of the most recent successful stat, lstat, or -X result. Passing _ as the argument reuses that cached buffer and issues no syscall. Successful calls refresh it; failed calls leave the previous contents in place.

Examples#

Basic list-context unpack:

my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
    $atime, $mtime, $ctime, $blksize, $blocks) = stat($filename);

Pick out a single field with a list slice:

my $size  = (stat($filename))[7];
my $mtime = (stat($filename))[9];

Scalar context as an existence-plus-readable-metadata probe:

if (stat($path)) {
    my $size = (stat _)[7];          # reuse the cached buffer
    print "size = $size\n";
} else {
    warn "stat $path: $!";
}

Reusing the cache across an -X test and a stat:

if (-x $file && (($d) = stat(_)) && $d < 0) {
    print "$file is executable NFS file\n";
}

Named-accessor access through File::stat:

use File::stat;
my $sb = stat($filename);
printf "file %s, size %s, perm %04o, mtime %s\n",
       $filename, $sb->size, $sb->mode & 07777,
       scalar localtime $sb->mtime;

Decoding the mode with Fcntl:

use Fcntl ':mode';
my $mode = (stat($filename))[2];
printf "permissions %04o\n", S_IMODE($mode);
print "is a directory\n" if S_ISDIR($mode);

Edge cases#

  • No argument: stat; stats $_, not the cached _ handle. To re-read the cache you must write stat(_) with the underscore as an explicit bareword.

  • The _ bareword is special: it names the stat cache, not a file. Quoting it (stat("_")) stats a file literally called _ in the current directory.

  • Symlinks are followed: stat reports on the target of a symlink. For the link itself, use lstat. A broken symlink makes stat fail with ENOENT; lstat on the same path succeeds.

  • DIRHANDLE form: passing a directory handle from opendir returns the stat of the open directory itself. Not every platform supports this; on those that do not, the call fails and $! is set.

  • Inode numbers may overflow integers: on filesystems with 64-bit inode numbers beyond Perl’s integer range, ino is returned as a decimal string to preserve the full value. Compare inode numbers with eq, not ==, to stay correct on those filesystems. eq works fine on numeric inodes too.

  • ctime is not creation time: it is the inode-change time — updated by chmod, chown, rename, link-count changes, and the file’s own writes. Linux exposes a true creation time (btime) via statx(2), but that is not part of stat’s return list.

  • Zero fields on some filesystems: atime (on noatime mounts), blksize, and blocks may be reported as 0. Treat 0 as “unavailable”, not as a meaningful value.

  • Scalar context does not populate _ on failure: a failed stat leaves the previous cached buffer untouched. Always check the return value before a follow-up stat(_) or -X _.

  • Race windows: the metadata returned is a snapshot. Anything that acts on a path based on stat’s result (permission checks, TOCTOU patterns) must be written to tolerate the file changing between the stat and the follow-up operation — or better, open the file first and stat the filehandle.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • lstat — like stat but does not follow symlinks; reports on the link itself

  • -X file-test operators (-e, -f, -r, -w, -x, …) — built on top of the same stat buffer; share the _ cache with stat and lstat

  • chmod — change the permission bits reported in field 2 (mode)

  • chown — change the uid and gid reported in fields 4 and 5

  • File::stat — named accessors ($sb->size, $sb->mtime, …) over the same 13-field list; use File::stat overrides stat in the current scope

  • Fcntl:mode tag exports the S_I* constants and S_IS* helpers for decoding field 2