Filehandles, files, directories
link#
Create a hard link from NEWFILE to the existing OLDFILE.
link adds a second directory entry that refers to the same underlying
file as OLDFILE. After a successful call, the file has two names:
OLDFILE and NEWFILE. Both names are equal citizens — the file
itself is not deleted until every name is removed and no process holds
the file open. The call is a thin wrapper around the link(2) system
call and inherits its constraints: both paths must resolve on the
same filesystem, and on POSIX systems only the superuser may hard-
link a directory (most Linux kernels refuse even for root).
Synopsis#
link OLDFILE, NEWFILE
What you get back#
1 on success, 0 on failure. On failure, $! is set to the
system error — typical values are EXDEV (cross-device link),
EPERM (target is a directory, or filesystem forbids hard links),
EEXIST (NEWFILE already exists), EACCES (insufficient
permission), and ENOENT (OLDFILE missing).
link $src, $dst
or die "link $src -> $dst failed: $!";
Global state it touches#
$!— set on failure to the system error code.
Examples#
Create a second name for an existing file:
link "report.txt", "report.bak"
or die "link failed: $!";
Use stat to observe the link count going up. The third element of
the stat list is the number of hard links pointing at the
inode:
link "data", "data.alt" or die $!;
my $nlink = (stat "data")[3];
print "data has $nlink names\n"; # "data has 2 names"
Atomically replace a file by building the new version under a
temporary name, then swapping with link + rename:
open my $fh, ">", "config.new" or die $!;
print $fh $new_contents;
close $fh;
rename "config.new", "config" or die "rename: $!";
(For the genuinely atomic-under-crash variant you want link +
unlink + rename; see the commentary in perlport.)
Detect a cross-device failure and fall back to copying:
use Errno qw(EXDEV);
unless (link $src, $dst) {
if ($! == EXDEV) {
# /tmp and $HOME are typically different filesystems
copy_file($src, $dst);
} else {
die "link $src -> $dst: $!";
}
}
Edge cases#
Directories:
linkon a directory fails withEPERMon effectively every modern system. POSIX forbids it for non-root, and Linux forbids it even for root. Usesymlinkwhen you want a second name for a directory.Cross-filesystem: the kernel returns
EXDEVifOLDFILEandNEWFILEresolve to different filesystems. Hard links cannot span mount points because they share an inode number, which is only meaningful within one filesystem.Existing target: if
NEWFILEalready exists, the call fails withEEXIST.linknever overwrites. Remove the target first withunlinkif replacement is intended.Symbolic link as
OLDFILE: the link is made to the symlink’s target, not to the symlink itself, on most systems. If you need to link the symlink, dereference it explicitly or use a platform that exposeslinkatwithAT_SYMLINK_FOLLOWcleared (not available through Perl core).Relative paths are resolved against the current working directory at the moment of the call, for both operands.
Permissions:
linkdoes not require write permission onOLDFILE— only search permission on its directory and write permission on the directory containingNEWFILE.Same path both sides:
link $f, $ffails withEEXIST.Unlinking: removing
OLDFILEwithunlinkafter a successfullinkleaves the file fully reachable throughNEWFILE. The data is freed only when the last name is unlinked and no open file descriptor refers to it.Portability: not every filesystem supports hard links. FAT, exFAT, and many network filesystems either refuse or silently behave as copies. See
perlportfor the platform matrix.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
symlink— create a symbolic link instead of a hard link; works across filesystems and on directoriesunlink— remove a directory entry; the file itself survives as long as another link or open descriptor remainsrename— move or rename a file within one filesystem; atomic wherelink+unlinkis notstat— inspect the link count (field 3) to see how many names refer to the same inode$!— the system error set whenlinkreturns0