Linux下的umask
2015年05月16日 Linux

​ 偶然看到一本书上写umask(掩码)的计算,说是用户的实际文件(夹)权限是通过默认文件(夹)权限与掩码相减得到的。感觉不太对。

​ 先说掩码,Linux下的文件有三个权限“段”,一个文件所有者的权限,一个同用户组的权限,一个是其他用户的权限,三个“段”又分了三个部分,可读,可写,可执行,每个部分用一个八进制数表示,那么权限也就可以表示成000à777之间的数字(例如421,就表示文件拥有者有读权限,同用户组的有写权限,其他用户有执行权限)。而Linux针对文件和文件夹又有一个默认的原始权限,文件的是666,也就是三个不同有用户都有读写权限没有执行权限,文件夹是777,也就是三个不同的用户拥有所有的权限,而掩码,就是对文件(夹)默认权限的“遮掩”,通过对umask的设置,对文件(夹)重新设置了权限。使用umask命令可以查看用户当前的掩码。具体参考man umask。
​ 而通过掩码又是怎么算得到对应的权限呢,比如大多用户的掩码都是0002,那通过这个掩码和文件(夹)默认权限如何得到最终文件的权限,很多书上都说是默认权限减去掩码,或者默认权限与掩码作异或,再或者就是对掩码取反,也就是从默认权限上“抽离”对应的“段”里面的位。像上面所说,掩码0002,文件默认权限0666,第一种,相减,结果当然是0664,正确了,第二种,异或,结果0664,也正确了,第三种,对0002的二进制取反,结果也是0664,也正确了。好像都是对的,但是假如,是说假如,把对应的0002改成0033,那么这几种还能正确吗?
其实所有的上面的说法都是在二个前提下的,也就是掩码的“遮掩”的规则:

Linux下文件的默认权限都是0666,也就是都没有执行权限。

Linux下的文件夹的默认权限是0777,也就是都有执行权限。

​ 在这二个前提下,上面的无论是异或,取反,都要考虑到文件的特殊性就是没有可执行权限,一旦出现一个像0033这样的“奇葩”掩码,就要考虑到文件的默认权限里没有可执行权限,就是三个位中的421中的1是没有的,知道了这个,那0033,也就相当于0022了,因为对应的可执行权限是本来就没有的。可以像下边这样试一下:

1
2
3
% umask 033
% touch test
% ls –al test

应该可以看到对应的文件权限还是-rwxr–r–,也就是644。

​ Linux下还有一个umask的函数,通过umask函数设置文件掩码,此时文件的权限就是由创建文件的函数来指定了(也就是说文件的权限不是666了,而是由创建文件函数来指定的)。下机是一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int permission = 00777;
umask(0000);//相当于没有设置掩码
if (creat("test_file", permission) < 0)//创建一个文件,以查看权限
{
printf("Create File Error!\n");
exit(-1);
}
int mask = 0033;
umask(mask);//设置文件权限掩码
if (creat("test_mask_file", permission) < 0)//掩码作用于同用户组和其他的写和执行权限
{
printf("Create File Error!\n");
exit(-1);
}

return 0;
}

% gcc –Wall –std=c99 test_umask.c –o test_umask

执行后产生二个文件,详细如下(centOS编译):

也就是没有设置掩码的文件权限是777,设置了033掩码的文件权限是755,有人说不对啊,掩码是033,原来的是777,最终的应该是744啊,没错,这里的确有点儿小问题,问题就在creat函数上,creat函数在生成文件的时候只取与读和写相关的参数,也就是没有与执行相关的参数,到这里就又回来上面去了,也就是掩码其实就是0022,总结出来就是,掩码如果含有奇数,要么直接计算,然后在结果的奇数对应位上各加上1,或者,直接参与运算的时候把掩码位中含有奇数的位直接减去1。这样也就是最终的777 与 022 ,生成的最终的文件权限就是755。

​ 综上,与文件相关,掩码含有奇数,直接在奇数位减去1,再计算,如果为偶数,就直接算出权限。