Filehandles, files, directories

umask#

Set or read the process file-creation mode mask.

umask controls which permission bits are cleared from the MODE argument of every file- or directory-creation call made by this process from now on. It is a property of the running process, not of any particular filehandle, and it is inherited by child processes. Call umask EXPR to install a new mask and receive the previous one; call bare umask to read the current mask without changing it.

Synopsis#

umask EXPR
umask

What you get back#

The previous umask as an integer, so you can save it and restore it later:

my $old = umask 0077;
# ... create private files ...
umask $old;

Bare umask returns the current mask without changing it. If the system has no umask(2) call and the caller is trying to restrict access for itself ((EXPR & 0700) > 0), an exception is raised; if the call is not implemented and the caller is not restricting its own access, undef is returned. On Linux this case does not arise.

How the mask is applied#

The mask is subtractive. Every bit set in the umask is cleared from the MODE passed to mkdir, sysopen, open in creation modes, and the underlying creat(2) / mkdir(2) system calls. The effective permissions of the new file are MODE & ~umask.

A Unix permission like rwxr-x--- is three sets of three bits, or three octal digits — 0750. The leading 0 marks the literal as octal and is not itself a permission digit. A umask is written the same way and names the bits you want disabled for newly created files.

Worked example. With umask 0022, asking sysopen for 0666 actually creates a file with mode 0644:

  0666  &~  0022   =   0644
  rw-rw-rw-    ----w--w-      rw-r--r--

With umask 0027 (group may not write, others may not read, write, or execute), the same 0666 request yields 0640 (0666 & ~0027 == 0640).

Global state it touches#

The mask itself is process-global kernel state set via umask(2). umask does not read or write any Perl special variable directly, but every creation call in the process observes it, and $! is set by the underlying system calls that consume the mask (mkdir, sysopen, open), not by umask itself. Child processes spawned via fork, exec, or system inherit the current value.

Examples#

Install a mask that hides the file from everyone but the owner, keeping the previous value for restoration:

my $old = umask 0077;
open my $fh, ">", "secret.txt" or die "open: $!";
# secret.txt is created mode 0666 & ~0077 == 0600
close $fh;
umask $old;

Read the current mask without changing it — useful for logging or diagnostics:

printf "current umask: %04o\n", umask;      # e.g. "current umask: 0022"

Typical values to pass — these are the three masks actually used in practice:

umask 0022;   # group + other: read/execute, no write   (default on most systems)
umask 0027;   # group: read/execute; other: nothing
umask 0077;   # owner-only; nothing for group or other

Scoped change around a block of file-creating code. umask has no local magic of its own — save and restore explicitly:

sub write_private_file {
    my ($path, $data) = @_;
    my $old = umask 0077;
    open my $fh, ">", $path or do {
        umask $old;
        die "open $path: $!";
    };
    print $fh $data;
    close $fh;
    umask $old;
}

Octal literal vs. string — a common trap. A umask is a number, not a string of octal digits. Reading one from configuration requires oct:

my $from_config = "0027";                   # string
umask oct $from_config;                     # correct: 0027 as a number
umask $from_config;                         # WRONG: decimal 27 == 033 octal

Edge cases#

  • Bare umask in list context still returns a single integer. The function is scalar-valued.

  • Negative or out-of-range values are masked to the nine low-order permission bits by the kernel; only bits 0777 survive. Passing 0777 disables all permissions on every newly created file, which is almost never what you want.

  • umask does not affect existing files. It only filters the MODE argument of creation calls. To change an existing file’s permissions use chmod.

  • umask does not affect open for an existing file — opening a file that already exists does not re-apply the mask. It applies only when a file is being created (O_CREAT in sysopen, or >/>>/+> modes creating a new pathname in open).

  • Inheritance across fork/exec. Children start with the parent’s current umask. Setting the mask before system or exec changes the environment the child inherits; restore it afterwards if the parent still cares.

  • Threads. The umask is a per-process attribute in the kernel, so on systems where Perl threads share a process (the usual case) every thread sees the same mask. Changing it in one thread changes it for all.

  • umask(2) not implemented. The POD documents a fallback path for systems without the syscall: raise on attempts to restrict the owner’s own access, otherwise return undef. Every platform pperl targets has umask(2), so this path is effectively unreachable here.

  • Octal presentation. Print the mask with printf "%04o"; the default %d prints decimal, which is unreadable as permission bits.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • chmod — change permissions on an existing file; the counterpart to the creation-time filtering umask performs

  • mkdir — directory creation call whose MODE argument is filtered through the current umask

  • sysopen — low-level file creation whose MODE argument is filtered through the current umask; the canonical place where the mask is felt

  • open — in creation modes (>, >>, +>) the underlying creat(2) applies the umask to the default 0666

  • oct — convert a string like "0027" to the integer value umask expects

  • $! — set by the creation calls that consume the mask, not by umask itself; check it after the open / sysopen / mkdir that fails