Filehandles, files, directories
lstat#
Return the 13-element status list for a path without following a symbolic link.
lstat does exactly what stat does — same 13-element result,
same special _ filehandle cache, same failure semantics — with one
difference: if the argument names a symbolic link, lstat returns
information about the link itself (its own mode, owner, size, mtime),
not the target the link points to. For anything that is not a symbolic
link, lstat and stat are indistinguishable. On systems
without symbolic links lstat silently degrades to stat.
Synopsis#
lstat FILEHANDLE
lstat EXPR
lstat DIRHANDLE
lstat
What you get back#
In list context, the same 13-element list as stat:
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks)
= lstat($path);
Field meanings are identical to stat — device, inode, mode
(type + permissions), link count, owner uid/gid, rdev, size, atime,
mtime, ctime, preferred I/O block size, and allocated blocks. The
type bits in $mode are what distinguish a symbolic link: on the
link itself they report S_IFLNK, whereas stat on the same
name would report the type of the target.
In scalar context lstat returns a true value on success and the
empty string on failure. On failure the list form returns the empty
list and $! is set to the reason (ENOENT, EACCES, etc.).
If EXPR is omitted, lstat operates on $_.
The _ filehandle#
Every successful lstat (and every successful stat or filetest)
populates the interpreter’s internal “last stat buffer”. Passing the
bareword _ as the argument reuses that buffer instead of making
another system call:
if (-l $path && (my @s = lstat(_))) {
# $path was a symlink; @s describes the link, not the target
}
Because -l itself does an lstat under the hood, the lstat(_)
above costs nothing extra. This is the canonical way to “ask several
questions about one file without re-stat’ing it”. Note that a
filetest on a bareword filename (-l $path) leaves the buffer
describing the link; a filetest on a filehandle follows the open
descriptor and thus leaves a stat-shaped buffer. When you
want symlink data, reach for lstat explicitly.
Global state it touches#
Examples#
Distinguish a symlink from its target. stat on a symlink silently
follows it; lstat does not:
symlink "/etc/passwd", "link.tmp";
my $via_stat = (stat "link.tmp")[7]; # size of /etc/passwd
my $via_lstat = (lstat "link.tmp")[7]; # size of the link inode
# (length of "/etc/passwd")
Walk a directory and separate links from regular files without a
second syscall per entry, using the _ buffer:
use Fcntl ':mode';
for my $name (readdir $dh) {
next if $name eq '.' || $name eq '..';
lstat "$dir/$name" or next;
if (S_ISLNK((lstat(_))[2])) {
print "link: $name\n";
} elsif (-f _) {
print "file: $name\n";
} elsif (-d _) {
print "dir: $name\n";
}
}
Detect a dangling symlink — lstat succeeds on the link, stat
fails because the target is gone:
if (lstat $path and not stat $path) {
warn "$path is a dangling symlink: $!\n";
}
Follow the link manually when you want both pieces of information:
my @link = lstat $path or die "lstat $path: $!";
my $target = readlink $path // die "readlink $path: $!";
my @target = stat $path or die "stat $path: $!";
No-argument form operating on $_, idiomatic in File::Find
preprocess blocks and grep filters:
my @symlinks = grep { lstat; -l _ } @paths;
Edge cases#
Not a symlink:
lstatbehaves exactly likestat— there is no penalty to preferringlstatwhen you are about to branch on-l.Systems without symlinks:
lstatsilently falls back tostat. Code written againstlstatstays portable; it just loses the distinguishing behaviour.Filehandle / dirhandle argument: a passed FILEHANDLE or DIRHANDLE refers to an already-opened descriptor, which cannot itself be a symlink (the kernel resolved the link at
opentime).lstat FILEHANDLEtherefore returns the same result asstaton that handle. Use the EXPR form on the path when you need the link metadata.lstat(_)after a failedlstat: the_buffer is left in whatever state the last successful stat put it in. A failedlstatdoes not clear it. Always check the return value before reading_.Relative paths: resolved against the process’s current working directory, same as
stat.Permission to
lstat: requires search (x) permission on every directory component of the path, but — unlikestat— does not require any permission on the link target.lstattherefore succeeds on links into directories you cannot read.Bareword vs expression:
lstat $fhwhere$fhholds a filehandle stats the handle;lstat "$fh"stringifies$fhand stats the resulting (usually meaningless) pathname. Quote intentionally.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
stat— the link-following counterpart; identical return shape and_semanticsreadlink— read the target string of a symbolic link without stat’ing itsymlink— create a symbolic link-l— filetest operator for “is a symbolic link”; internally performs anlstatand leaves the result in_$_— default argument whenEXPRis omitted$!— reason for failure whenlstatreturns the empty list