Filehandles, files, directories
sysopen#
Open a file the low-level way, passing an integer MODE bitmask
straight through to the underlying open(2) system
call.
sysopen is the escape hatch for when open’s string-mode
DWIM is in your way — when you need O_EXCL for an atomic
create-if-not-exist, O_NOFOLLOW to refuse symlinks, O_NONBLOCK on
a FIFO, or any other flag that has no corresponding "<" / ">" /
">>" string. The flag constants live in Fcntl and
are combined with |.
Synopsis#
sysopen FILEHANDLE, FILENAME, MODE
sysopen FILEHANDLE, FILENAME, MODE, PERMS
What you get back#
1 on success, undef on failure (with $!
set to the errno from the failed syscall). Unlike open,
there is no magic — FILENAME is taken literally, no leading >,
<, |, or - is interpreted, no layered mode string is parsed.
If FILEHANDLE is an undefined scalar, it is autovivified into a
fresh handle:
sysopen my $fh, $path, O_RDONLY
or die "sysopen $path: $!";
MODE — the Fcntl bitmask#
MODE is an integer built by OR-ing constants from
Fcntl. The access mode is mandatory and mutually
exclusive; the modifier flags are optional and combined freely:
Flag |
Meaning |
|---|---|
|
Open for reading only. |
|
Open for writing only. |
|
Open for reading and writing. |
|
Create the file if it does not exist. |
|
With |
|
Every write seeks to end-of-file first (atomic append). |
|
Truncate the file to zero length on open. |
|
Non-blocking mode for the resulting descriptor. |
|
Fail with |
Import them by name or with a tag:
use Fcntl qw(O_RDWR O_CREAT O_EXCL O_APPEND);
# or
use Fcntl ':DEFAULT';
The legacy values 0, 1, 2 for read-only, write-only, read-write
also work on every system Perl supports, but name the constants — the
resulting code survives cross-platform review and reads without a
glossary.
PERMS — the create-time permission bits#
PERMS is an octal mode (like chmod takes) applied to the
inode only when O_CREAT actually creates the file. If PERMS
is omitted, Perl passes 0666. The process umask is
applied by the kernel on top, so a default umask of 022 yields
0644 on disk.
sysopen my $fh, $path, O_WRONLY | O_CREAT | O_EXCL, 0600
or die "create $path: $!";
Do not write 0644 as the PERMS argument without a reason. A
hard-coded 0644 strips group-write even from users who deliberately
set a permissive umask; 0666 plus the user’s umask is the
portable default and is what sysopen uses when you omit the
argument entirely.
Global state it touches#
${^OPEN}— theopenpragma’s layer configuration.sysopenapplies the same default PerlIO stackopenwould apply for a layer-less call. Usebinmodeimmediately after a successfulsysopenwhen you need to override or strip layers (typical for binary files, sockets-as-files, orO_NONBLOCKdescriptors).Process
umask— masksPERMSwhenO_CREATcreates the file.
Examples#
Atomic create-if-not-exist — the canonical reason to reach for
sysopen:
use Fcntl qw(O_WRONLY O_CREAT O_EXCL);
sysopen my $fh, "lock.pid", O_WRONLY | O_CREAT | O_EXCL, 0644
or die "another instance is already running: $!";
print $fh "$$\n";
close $fh;
Open-or-create for read/write, preserving existing contents:
use Fcntl qw(O_RDWR O_CREAT);
sysopen my $fh, $path, O_RDWR | O_CREAT, 0666
or die "sysopen $path: $!";
Append-only log with the append guarantee — every write lands at EOF regardless of interleaving with other writers:
use Fcntl qw(O_WRONLY O_CREAT O_APPEND);
sysopen my $log, "/var/log/app.log", O_WRONLY | O_CREAT | O_APPEND, 0644
or die "open log: $!";
print $log "startup\n";
Open a FIFO without blocking on the reader-side handshake:
use Fcntl qw(O_RDONLY O_NONBLOCK);
sysopen my $fifo, "/tmp/q", O_RDONLY | O_NONBLOCK
or die "sysopen fifo: $!";
Refuse to follow a symlink at the leaf — useful in directories writable by untrusted users:
use Fcntl qw(O_RDONLY O_NOFOLLOW);
sysopen my $fh, "$dir/config", O_RDONLY | O_NOFOLLOW
or die "sysopen config: $!";
Force byte-level I/O after opening — strip any :utf8 or :crlf
layer the default PerlIO stack would otherwise install:
sysopen my $fh, $path, O_RDONLY or die $!;
binmode $fh;
Edge cases#
O_EXCLwithoutO_CREATis a no-op. The exclusivity check only triggers whenO_CREATasks the kernel to create the file. Always write them together:O_CREAT | O_EXCL.O_EXCLis not a lock. It prevents a successful open on an already-existing file, nothing more. Once the file exists, every subsequentsysopenwithO_CREAT | O_EXCLfails. It does not serialize access to the contents — useflockfor that.O_EXCLon network filesystems. NFS implementations vary; older NFS versions silently lose the exclusive semantics. Do not rely onO_EXCLacross NFSv2.O_CREAT | O_EXCLand symlinks. With both flags set, the kernel refuses to open a pre-existing symlink at the final path component. It does not protect intermediate path components; useO_NOFOLLOWor resolve the directory withopendirplusopenatsemantics if you need that.O_TRUNCwithO_RDONLY. Behavior is undefined by POSIX. Do not combine them.Omitted
PERMS. The default is0666, masked byumask. It is not0644. OmitPERMSunless you actively want to override the user’sumask.FILEHANDLEas expression. IfFILEHANDLEis a bareword, it names a package global. If it is an expression evaluating to a glob, globref, orIO::Handle, that handle is opened. If it is an undefined scalar, a fresh handle is autovivified into it — the lexical form used throughout these examples.No magic on
FILENAME. AFILENAMEof"-"opens a file literally named-, notSTDIN. A leading>opens a file literally named>filename, not a write tofilename. This is the entire point ofsysopenversusopen.Default PerlIO layers still apply.
sysopenis “low-level” relative to the mode string, not relative to PerlIO. The resulting handle has the same layer stack as a layer-lessopen; callbinmodeto change it.Closed or invalid
FILEHANDLEexpression. Returnsundefwith$!set (typicallyEBADFfor a bad existing descriptor;ENOENT,EACCES,EEXIST,ELOOPfor the path-level errors).
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
open— higher-level opener with string-mode parsing, pipes,-asSTDIN/STDOUT, and layered modes; use it unless you specifically need a flagsysopenexposesfcntl— change flags on an already-open descriptor (e.g. setO_NONBLOCKafter the fact); shares theFcntlconstant vocabularysysread— unbuffered read; works on any handle, not just one obtained fromsysopen, despite the namesyswrite— unbuffered write, same noteFcntl— the module that exportsO_*constants and the:DEFAULT/:flock/:modetagsbinmode— set or strip PerlIO layers on the handle after openingumask— the process mask that subtracts bits fromPERMSwhenO_CREATcreates the file