--- name: symlink signature: 'symlink OLDFILE,NEWFILE' since: 5.0 status: documented categories: ["Filehandles, files, directories"] --- ```{index} single: symlink; Perl built-in ``` *[Filehandles, files, directories](../perlfunc-by-category)* # symlink Create a symbolic link at `NEWFILE` that points at the string `OLDFILE`. `symlink` is the thin wrapper around the POSIX `symlink(2)` system call. It does not copy anything, does not read `OLDFILE`, and does not require `OLDFILE` to exist. It writes a new directory entry at `NEWFILE` whose payload is the literal bytes of `OLDFILE`, and the kernel later resolves that payload whenever something opens, stats, or traverses the link. ## Synopsis ```perl symlink OLDFILE, NEWFILE ``` ## What you get back `1` on success, `0` on failure (with [`$!`](../perlvar) set). On systems that do not support symbolic links at all, `symlink` raises an exception rather than returning `0`. To probe for support at runtime without dying, wrap a harmless call in [`eval`](eval): ```perl my $symlink_exists = eval { symlink("", ""); 1 }; ``` The [`eval`](eval) pattern is the idiomatic capability check — it runs a no-op `symlink` whose only job is to fail cheaply on platforms where the call exists, and to throw on platforms where it does not. ## How symlinks differ from hard links A symlink and a hard link ([`link`](link)) look similar from the shell but behave very differently: - [`link`](link) creates a second directory entry pointing at the same inode. Both names are equal; deleting either one leaves the file alive under the other. - `symlink` creates a tiny file of type `lnk` whose contents are a *pathname*. The target is resolved by name at every lookup. The two names are **not** equal — the symlink has its own inode, its own permissions bits (mostly ignored), and its own timestamps. Practical consequences: - `OLDFILE` is stored **verbatim**. It is not canonicalised, not resolved against the current working directory, and not checked for existence. A symlink can be created pointing at a path that does not exist yet (a *dangling* symlink) and will start working the moment the target appears. - Because `OLDFILE` is just a string, it can be relative. Relative symlink targets are resolved at lookup time relative to the directory containing `NEWFILE`, **not** the process's current working directory. This is the single biggest source of surprise. - Symlinks can cross filesystem boundaries. Hard links cannot. - Symlinks can point at directories. Hard links to directories are forbidden on every mainstream Unix. - [`unlink`](unlink) on a symlink removes the **link**, not the target. To remove the target, unlink the target's path directly. ## Examples Create a symlink to an existing file: ```perl symlink "/etc/hostname", "hostname.lnk" or die "symlink failed: $!"; ``` Dangling symlink — the target does not exist yet, and that is fine: ```perl symlink "/will/appear/later", "pending.lnk" or die "symlink failed: $!"; # opening pending.lnk now fails with ENOENT; # it will start working once /will/appear/later exists. ``` Relative target resolved against the link's directory, not the cwd: ```perl chdir "/var/log" or die $!; symlink "syslog", "/tmp/current.lnk" or die "symlink failed: $!"; # readlink("/tmp/current.lnk") eq "syslog" # opening /tmp/current.lnk resolves syslog in /tmp, not /var/log. ``` Symlink to a directory — this works, unlike [`link`](link): ```perl symlink "/var/log", "logs" or die "symlink failed: $!"; opendir my $dh, "logs" or die $!; # traverses the symlink ``` Inspect and remove a symlink without touching its target: ```perl my $target = readlink "hostname.lnk"; # the stored OLDFILE string unlink "hostname.lnk" or die $!; # removes the link only # /etc/hostname is untouched. ``` Atomic-swap pattern — replace a symlink pointing at the "current" release directory by writing a new symlink and renaming over it: ```perl symlink "release-2", "current.new" or die $!; rename "current.new", "current" or die $!; # rename over an existing symlink is atomic on POSIX filesystems. ``` ## Edge cases - **`OLDFILE` is stored verbatim.** No normalisation, no resolution, no existence check. `symlink "", "foo"` succeeds on most systems and creates an empty-target symlink that every lookup rejects with `ENOENT`. This is why the capability-probe idiom uses `("", "")` — a cheap call that always fails on supporting platforms. - **Relative `OLDFILE`** is resolved relative to the directory of `NEWFILE`, not the current working directory. If you build `NEWFILE` from a relative path, think carefully about what directory the kernel will see it in. - **`NEWFILE` already exists** → failure with [`$!`](../perlvar) set to `EEXIST`. There is no "replace" flag; to overwrite, write to a fresh name and [`rename`](rename) over the old one (atomic). - **Permissions on the symlink itself** are almost always ignored. The kernel enforces the permissions of the *target*. On most filesystems the symlink is reported as `lrwxrwxrwx` regardless of what [`chmod`](chmod) is called on it. - **`stat` follows symlinks, `lstat` does not.** To examine the link itself — its type, its link count, the length of its target string — use [`lstat`](lstat). To examine what the link points at, use [`stat`](stat). - **[`unlink`](unlink) removes the link, not the target.** There is no way to delete the target through the symlink except by resolving it first. - **Platforms without symlink support** raise an exception on any call, even one that would otherwise fail. Use the `eval` probe shown above rather than assuming a return value. - **Filesystems without symlink support** (some FAT variants, certain network mounts) fail with `EPERM` or `EOPNOTSUPP` even on a kernel that implements `symlink(2)`. Check [`$!`](../perlvar) on failure rather than assuming the call was rejected for the obvious reason. - **Symlink loops** are not detected at creation time. `symlink "a", "b"` followed by `symlink "b", "a"` succeeds; the loop only surfaces when something tries to resolve either name, which fails with `ELOOP` after the kernel hits its chase limit (typically 40). ## Differences from upstream Fully compatible with upstream Perl 5.42. ## See also - [`link`](link) — create a hard link (same inode, same filesystem, file only); the strict counterpart to `symlink` - [`readlink`](readlink) — read the `OLDFILE` string stored in a symlink without resolving it - [`lstat`](lstat) — stat the symlink itself rather than its target; the only way to see that a path is a symlink from Perl - [`stat`](stat) — stat what the symlink points at, following the chain of links - [`unlink`](unlink) — remove a symlink (the link, not the target); also the way to remove a dangling symlink - [`$!`](../perlvar) — `errno` set on failure; inspect it to distinguish `EEXIST`, `EPERM`, `EOPNOTSUPP`, `ENOENT` on the parent directory