什么是屏蔽模式?

-7 shell bash umask terminology syntax

我知道在 GNU/Linux 中,文件权限也称为文件模式,并且术语掩码至少可以表示以下不同的含义:

  1. 所述的umask shell内建(通常含义)。
  2. umask的shell内建的相应数系统调用
  3. umask的shell内建的相应数命令umask
  4. shell 进程值也称为文件创建掩码,以及位掩码或只是掩码
  5. 用户特定的文件创建掩码影响该用户独有的过程(然后它称为用户掩码?用户的文件创建掩码)。

内置的umask外壳

可以通过执行带有适当参数的命令来使用内置的umask shell umask
通过这样做,我们为当前的shell 进程树设置了一个掩码; 要么针对当前 shell 进程树中的所有用户,要么仅针对我们自己的用户; 然而,一般来说,任何此类更改都将继承到新进程,可能是另一个 shell)。

数理逻辑基础

我知道数学逻辑包括连接AKA anding ( ?)的操作,它是内置umask shell的基础。因此:

一组操作数的 and 为真,当且仅当,其所有操作数为真

我进一步了解到,有一个基于该逻辑的同名按位运算。Anding 与数字相加 ( x + y ? z) 或字符串串联 ( x alongside y ? xy) 不同。

我的问题

我知道人们可以通过这种方式“屏蔽一种模式”:

  OCTAL  BINARY       HUMAN-READABLE
  0666   0110110110  -rw-rw-rw-
? 0555   0101101101  -r-xr-xr-x
  0444   0100100100  -r--r--r-- 
Run Code Online (Sandbox Code Playgroud)

但我不确定这是正确的。

我的问题

什么是屏蔽模式(以及怎么来的0666 ? 0555 ? 0444)?

Ste*_*itt 14

umask, shell 命令和umask, 函数都设置文件创建掩码,也称为umask.

您已将其改写为

Aumask表示 shell 内置命令和基于该命令的 shell 函数,它包含一个通常称为文件创建掩码的变量,其值称为位掩码或只是掩码

这在许多方面是不正确的:

  • umask函数不是 shell 函数;见上面的链接;
  • 该函数不包含变量;它设置当前进程的文件创建掩码;
  • 作用于的值不仅通常被称为“文件创建掩码”,它文件创建掩码(并且它的值不称为“位掩码”或“掩码”)。

掩模效果一些公用事业在当前过程树包括其中可以改变其他shell(因此壳ý不一定会壳X的掩模)。

口罩一般不会影响任何事情。该文件创建掩码影响当前进程,并通过继承所有新创建的子进程。子进程可以自由地再次更改它。

此文件创建掩码作用于新创建文件的权限。文件权限,也称为文件模式,是一组十二位编码的文件所有者、组和其他用户的访问权限;有关详细信息,请参阅此规范答案。它们通常表示为四位或三位八进制值。它们不是比特流。

新创建文件的权限要么由创建给定文件的程序指定,要么默认指定(由它们用于创建文件的函数指定)。前者的例子包括使用openorcreat或来创建文件(或目录)的程序mkdir,它们必须明确指定他们想要的模式。后者的示例包括使用 的程序fopen,其中文件以默认的 0666 模式结束。当前umask值屏蔽此模式。

你把它改写为

  1. 一些实用程序如mkdir创建具有独立模式的文件(忽略掩码)。
  2. 一些实用程序使用该fopen()功能,其中文件首先使用默认的 0666 模式创建,但在创建后立即将umask其模式更改为掩码的模式。

这在许多方面是不正确的:

  • 在创建文件之前,而不是之后,将掩码应用于请求的模式;
  • mkdir(这是这里的功能,而不是一个工具,但同样适用于同一个名字的实用程序)肯定也不会忽略文件创建掩码。

umask考虑到,所得模式是施加的umask作为位掩码来请求的模式的结果:在所请求的模式的每个比特组被核对在相应的位umask,且仅当后者没有设置保留。在二进制操作方面,请求的模式是与umask. 因此umask,模式为 0666 的 0022 的结果为 0644;不是减法,而是因为 0666 和 0755(0022 的补码)是 0644。同样,umask模式为 0666 的 0011 的 a 结果为 0666。

让我们更详细地看一下计算。它通常表示为减法,包括在您链接到的答案中,但重要的是要了解它不是;umask被用作面膜。因此应用 0022 值:

       Octal Binary
Mode   0666  000110110110
Mask   0022  000000010010  Bits set here mask bits above
Result 0644  000110100100

       Octal Binary
Mode   0644  000110100100
Mask   0022  000000010010
Result 0644  000110100100
Run Code Online (Sandbox Code Playgroud)

这通常是通过使用掩码的补码对模式进行按位与运算来计算的:

       Octal Binary
Mask   0022  000000010010
Compl. 7755  111111101101
Mode   0666  000110110110
Result 0644  000110100100
Run Code Online (Sandbox Code Playgroud)

chmod应用在其命令行中指定的模式而不考虑umask。其他工具也会这样做,即使在创建文件时也是如此;因此,当指示保留权限时,cpandtar将复制权限或恢复权限而不考虑umask

这个答案更详细。

你最后的问题是

我的理解是否足够准确,0666 怎么来的?0555?0444?

第一个答案显然不是。第二个的答案是因为这就是按位和工作的方式。用二进制重写操作数:

Octal  Binary
0666   000110110110
0555   000101101101
Run Code Online (Sandbox Code Playgroud)

现在对每个位位置执行按位和。这意味着取每对垂直对齐的位,以及它们(在上面的示例中,0 ? 0 三次,然后是 1 ? 1, 1 ? 0, 0 ? 1, 1 ? 1 等):

       000100100100
Run Code Online (Sandbox Code Playgroud)

(0 ? 0 是 0, 0 ? 1 是 0, 1 ? 0 是 0, 1 ? 1 是 1)。将上面的转换回八进制,你最终得到 0444。


ste*_*fan 9

什么模式

术语“文件模式”是指 Linux 系统上可用的标准文件权限(不考虑不同种类的访问控制列表)。

一个文件的模式由 12 位组成,每一位代表一个可以被授予或不被授予的权限(所以一位就足以表明这一点)。
例如,权限“文件可以被组成员读取”是从右数第 6 位。

为便于使用,这 12 位被分成 4 组,每组 3 位。一个 3 位二进制数可以有 8 个不同的值,这与八进制数字 (0–7) 可以表示的值的数量完全相同。
因此,十二个权限可以表示为 0-7777 范围内的 4 位八进制数。
为了让它更容易混淆,通常用一个额外的前导零来表示一个八进制数(就像十六进制数0x按照惯例加前缀一样),所以模式是 0-07777。

简单起见:在大多数情况下,您只会对低九位感兴趣,因此从这里开始我将重点关注 0–0777。

为什么用八进制写

为什么要使用八进制?它使阅读模式更容易!

模式的最低九位表示以下权限位,按此顺序。代替二进制表示,我将以八进制显示相应位的值(从chmod(2)复制):

00400 read by owner
00200 write by owner
00100 execute/search by owner
00040 read by group
00020 write by group
00010 execute/search by group
00004 read by others
00002 write by others
00001 execute/search by others
Run Code Online (Sandbox Code Playgroud)

看到图案了吗?1总是代表执行/搜索,2总是写,4总是读。如果允许读取和执行,但不允许写入,则始终为 digit 5,所有 3 个读/写/执行权限始终为7。要进行比较,请查看十进制值:

Allow read/execute for others:          0005, decimal   5.
Allow read/execute for group:           0050, decimal  40.
Allow read/execute for owner:           0500, decimal 320.
Allow read/execute for owner and group: 0550, decimal 360.
Allow read/execute for all, write
only for owner:                         0755, decimal 493.
Run Code Online (Sandbox Code Playgroud)

所以八进制使它更加一致:数字的位置是所有者/组/其他,数字告诉你关于三个读/写/执行位的所有信息。

umask 是什么

umask 是进程(即正在运行的程序,例如您的shell)的一个属性,并且每个进程都有一个。它确定在该进程创建新文件时不设置的权限。shell 命令umask设置shell的掩码。当这个shell 启动另一个程序时,它会从调用 shell 继承 umask。因此,在一个 shell 中设置 umask不会影响其他程序,除非它们是第一个 shell 的后代并且是设置 umask之后创建的。这就是为什么 umask 应该在会话的早期由脚本设置的原因。

不管别人怎么说,使用077;-)

当程序创建新文件时,程序会将所需的权限传递给open(2) 系统调用。操作系统删除 umask 中设置的位,并将结果用于创建文件。您可以使用以下 C 程序进行测试:

#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <err.h>
#include <stdio.h>

int main(int argc, char **argv) {

    // check for enough command line arguments
    if (argc < 3)
        errx(1, "Usage: %s <filename> <octalmode>", argv[0]);

    // parse 2nd argument as octal integer
    char *endptr = NULL;
    int mode = (int)strtol(argv[2], &endptr, 8);
    if (!*argv[2] || *endptr || mode < 0)
        errx(2, "Not an octal mode: %s", argv[2]);

    // create new file with given mode
    int fd = open(
        argv[1],
        O_WRONLY|O_CREAT|O_EXCL,
        mode
    );
    if (fd < 0)
        err(1, "Failed to create file %s", argv[1]);

    printf("open(\"%s\", ..., 0%03o) successful\n", argv[1], mode);

    close(fd);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译:

#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <err.h>
#include <stdio.h>

int main(int argc, char **argv) {

    // check for enough command line arguments
    if (argc < 3)
        errx(1, "Usage: %s <filename> <octalmode>", argv[0]);

    // parse 2nd argument as octal integer
    char *endptr = NULL;
    int mode = (int)strtol(argv[2], &endptr, 8);
    if (!*argv[2] || *endptr || mode < 0)
        errx(2, "Not an octal mode: %s", argv[2]);

    // create new file with given mode
    int fd = open(
        argv[1],
        O_WRONLY|O_CREAT|O_EXCL,
        mode
    );
    if (fd < 0)
        err(1, "Failed to create file %s", argv[1]);

    printf("open(\"%s\", ..., 0%03o) successful\n", argv[1], mode);

    close(fd);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

按照这个例子:

$ gcc -o mkfile mkfile.c
Run Code Online (Sandbox Code Playgroud)

请注意程序如何请求权限 rw-rw----,即模式 0660,但组的权限被 umask 完全剥离。

$ umask 77   # set umask to 0077
$ umask      # check umask
0077
$ rm -f foo           # delete old to make sure a new file will be created
$ ./mkfile foo 660    # create file `foo` with mode 0660
open("foo", ..., 0660) successful
$ ls -l foo
-rw------- 1 sk users 0 Nov  6 12:09 foo
Run Code Online (Sandbox Code Playgroud)

一般来说,程序应该建议在最宽松的情况下它认为有用的权限,并将权限的剥离留给操作系统的 umask。所以使用mkdir(2)创建目录时使用0777 ,使用(2)创建纯文件时使用0666 open。仅在有意义时才进行偏差,例如,加密工具可能会使用open0600 来存储其私钥,而编译器可能会使用0755它创建的可执行二进制文件。在所有这些情况下,umask 会在实际创建文件时从文件中删除不需要的权限。

这是编译器尝试创建一个文件的示例,该文件对每个人都可读和可执行,但只能由用户(模式 0755)在 umask 077 的设置中写入:

$ rm -f foo
$ umask 77
$ ./mkfile foo 0755
open("foo", ..., 0755) successful
$ ls -l foo
-rwx------ 1 sk users 0 Nov  6 12:15 foo
Run Code Online (Sandbox Code Playgroud)

在 umask 0 的设置中(允许程序请求的所有位):

$ rm -f foo
$ umask 0
$ ./mkfile foo 0755
open("foo", ..., 0755) successful
$ ls -l foo
-rwxr-xr-x 1 sk users 0 Nov  6 12:16 foo
Run Code Online (Sandbox Code Playgroud)

实际上,gcc甚至会请求模式 0777:

$ umask 0
$ rm -f mkfile
$ gcc -o mkfile mkfile.c
$ ls -l mkfile
-rwxrwxrwx 1 sk users 17k Nov  6 12:19 mkfile
Run Code Online (Sandbox Code Playgroud)

所以不要使用 umask 0。