I'm trying to understand permissions better, so I'm doing some "exercises". Here's a sequence of commands that I'm using with their respective output:
$ umask
0022
$ touch file1
$ ls -l file1
-rw-r--r-- 1 user group 0 Mar 16 12:55 file1
$ mkdir dir1
$ ls -ld dir1
drwxr-xr-x 2 user group 4096 Mar 16 12:55 dir1
That makes sense because we know that the default file permissions are 666
(rw-rw-rw-
) and directories default permissions are 777
(rwxrwxrwx
).
If I subtract the umask value from these default permissions I have
666-022=644
, rw-r--r--
, for the file1
, so it's coherent with the previous output;
777-022=755
, rwx-r-x-r-x
, for the dir1
, also coherent.
But if I change the umask from 022
to 021
it isn't any more.
Here is the example for the file:
$ umask 0021
$ touch file2
$ ls -l file2
-rw-r--rw- user group 0 Mar 16 13:33 file2
-rw-r--rw-
is 646
but it should be 666-021=645
. So it doesn't work according to the previous computation.
Here is the example for the directory:
$ touch dir2
$ ls -ld dir2
drwxr-xrw- 2 user group 4096 Mar 16 13:35 dir2
drwxr-xrw-
is 756
, 777-021=756
. So in this case the result is coherent with the previous computation.
I've read the man but I haven't found anything about this behaviour.
Can somebody explain why?
EXPLANATION
As pointed out in the answers: umask
's value is not mathematically subtracted from default directory and file's permissions.
The operation effectively involved is a combination of AND (&) and NOT (!) boolean operators. Given:
R = resulting permissions
D = default permissions
U = current umask
R = D & !U
For example:
666& !0053 = 110 110 110 & !000 101 011 110 110 110 & 111 010 100 = 110 010 100 = 624 = rw--w-r--
777& !0022 = 111 111 111 & !000 010 010 111 111 111 & 111 101 101 = 111 101 101 = 755 = rwxr--xr-x
TIP
An easy way to quickly know the resulting permissions (at least it helped me) is to think that we can use just 3 decimal values:
r = 100 = 4
w = 010 = 2
x = 001 = 1
Permissions will be a combination of these 3 values.
" "
is used to indicate that the relative permission is not given.
666 = 4+2+" " 4+2+" " 4+2+" " = rw rw rw
So if my current umask is 0053
I know I'm removing read and execution (4+1)
permission from group and write and execution (2+1)
from other resulting in
4+2 " "+2+" " 4+" "+" " = 624 = rw--w-r--
(group and other already hadn't execution permission)