Memra

umask and default permissions

◈ 13 cards

Computing the permissions a new file or directory receives under a given umask, showing the work in binary rather than guessing at a subtraction.

A mask of bits to withhold

Nothing you create asks you for a mode. touch, mkdir, cc -o, a redirection like cat > notes.txt — each one hands the kernel a requested mode and the kernel takes bits away before creating the object. The thing that decides which bits get taken away is your umask, a per-process value inherited by every command you run.

umask [-S] [mask]

With no argument it prints the current mask in octal, four digits, e.g. 0022. The rightmost three digits are owner, group and other; the leftmost is the special-bit field (SUID, SGID, sticky), which is almost always 0. With an argument it sets the mask.

The critical thing to fix in your head before any arithmetic: the numeric mask names the bits you are withholding, not the bits you are granting. umask 022 does not mean give everybody write; it means never hand out group-write or other-write.

The formula

Stated as Boolean algebra, which is how the exam wants it shown:

A = B AND C'
  • A — the permissions the new object actually gets.
  • B — the base: the default permissions for that kind of object.
  • C — the umask.
  • C' — the one’s complement of C, every bit flipped.

ANDing with the complement clears exactly the bits the mask names and leaves everything else alone.

The base B is where the real lesson is

B is not always 777:

  • 777 for a directory, and for an executable produced by a compiler or linker.
  • 666 for an ordinary text or data file.

That is the answer to why does a new text file never come out executable. It is not the mask — a mask of 000 still produces rw-rw-rw- for a text file. The execute bits were never in B to begin with. cat > notes.txt asks for 666, and 666 has no execute bit anywhere in it. Say that in an exam and you have the whole of §5.5.4 in one sentence.

Worked example — the same mask, two bases

Mask 022 on a directory (mkdir courses):

C  = 022 = 000 010 010
C' =       111 101 101
B  = 777 = 111 111 111
A  =       111 101 101 = 755 = rwxr-xr-x

Mask 022 on a text file (cat > notes.txt):

C' =       111 101 101
B  = 666 = 110 110 110
A  =       110 100 100 = 644 = rw-r--r--

Same mask, same complement, different base — and that alone is the difference between 755 and 644. Now tighten the mask:

Mask 077 on a text file:

C  = 077 = 000 111 111
C' =       111 000 000
B  = 666 = 110 110 110
A  =       110 000 000 = 600 = rw-------

Verify, do not trust

The habit that makes this stick is prediction followed by measurement. Set a mask, create one of each kind of object, and list all three at once:

$ umask 022
$ mkdir courses
$ cat > notes.txt
hello
^D
$ ls -ld courses notes.txt
drwxr-xr-x  2 ada  dev  4096 Sep  1 12:31 courses
-rw-r--r--  1 ada  dev     6 Sep  1 12:31 notes.txt

755 and 644, exactly as predicted. Repeat under umask 077 and you get 700 and 600. Two commands, six predictions checked.

Going backwards

The assignments also ask the inverse — what mask yields this result? Since A = B AND C', the mask you need is exactly the bits that B has and A must not: C = B AND NOT A. To get rwxr-x--- (750) on a new directory, B is 777, so C = 777 AND NOT 750 = 027. Set umask 027 and the next mkdir produces drwxr-x---. The same 027 applied to a text file gives 666 AND NOT 027 = 640.

flip every bit777 because it is a directoryrwxr-xr-xC = 022000 010 010complementC' = 111 101 101AND B = 777111 111 111A = 755111 101 101Swap B to 666 and the same maskyields 644 instead.
Read the binary column downward and the whole formula is visible at once: flip the mask, AND it with the base, and what survives is the mode.
NORMAL ~/memra/learn/comp-325/umask-and-default-permissions utf-8 LF