什么是屏蔽模式?

什么是屏蔽模式?

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

  1. 掩码shell内置(通常的意思)。
  2. 掩码shell内置的相应系统调用
  3. 掩码shell内置的相应命令umask
  4. shell 过程值也称为文件创建掩码, 也位掩码要不就面具
  5. 一个特定于用户的文件创建掩码,影响该用户独有的进程(然后它称为用户掩码→ 用户的文件创建掩码)。

掩码外壳内置

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

数理逻辑基础

我明白那个数理逻辑包括操作连词又名安定( ) 的基础是掩码外壳内置。因此:

一组操作数的 and 为真,当且仅当,它的所有操作数都为 true

我进一步了解有一个同名的按位运算基于这个逻辑。 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-- 

但我不确定这是否正确。

我的问题

什么是屏蔽模式(以及如何实现0666 ∧ 0555 → 0444)?

答案1

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

你已经将其改写为

Aumask表示 shell 内置命令和基于该命令并包含通常称为变量的 shell 函数文件创建掩码其值为位掩码要不就面具

这在很多方面都是不正确的:

  • umask函数不是 shell 函数;请参阅上面的链接;
  • 该函数不包含变量;它设置当前进程的文件创建掩码;
  • 所依据的价值不仅仅是通常提到的作为“文件创建掩码”,它文件创建掩码(其值不称为“位掩码”或“掩码”)。

A面具影响当前进程树中的一些实用程序,包括可以更改的其他 shell(因此 shell Y 不一定具有 shell X 的掩码)。

口罩一般不会产生任何影响。文件创建掩码影响当前进程并被继承全部新创建的子进程。子进程可以自由地再次更改它自己。

此文件创建掩码作用于新创建文件的权限。文件权限,也称为文件模式,是一组 12 位编码文件所有者、组和其他用户的访问权限;看这个规范的答案了解详情。它们通常表示为四位或三位八进制值。他们不是比特流。

新创建的文件的权限要么由创建给定文件的程序指定,要么默认指定(IE由它们用来创建文件的函数指定)。前者的示例包括使用以下命令创建文件(或目录)的程序open或者creat或者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 的结果是 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

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

       Octal Binary
Mask   0022  000000010010
Compl. 7755  111111101101
Mode   0666  000110110110
Result 0644  000110100100

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

这个答案更详细的内容。

你的最后问题是

我的理解够准确吗?怎么会是0666∧0555→0444?

第一个问题的答案显然是否定的。第二个问题的答案是因为这就是按位和的工作原理。将操作数重写为二进制:

Octal  Binary
0666   000110110110
0555   000101101101

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

       000100100100

(0 ∧ 0 为 0,0 ∧ 1 为 0,1 ∧ 0 为 0,1 ∧ 1 为 1)。将上面的内容转换回八进制,最终得到 0444。

答案2

模式是什么

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

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

为了便于使用,这 12 位被分为 4 组,每组 3 位。 3 位二进制数可以采用 8 个不同的值,这与八进制数字 (0–7) 可以表示的值数量完全相同。
因此,这 12 个权限可以表示为 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

看到图案了吗?1总是表示执行/搜索,2总是写入,并且4总是读取。如果允许读取和执行,但不允许写入,则始终为数字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.

因此八进制使其更加一致:数字的位置是所有者/组/其他,并且数字告诉您有关三个读/写/执行位的所有信息。

umask 是什么

umask 是一个进程的属性(即,一个正在运行的程序,例如您的 shell),每个进程都有一个。它确定该进程时不设置的权限创建一个新文件。外壳命令umask设置 shell 的掩码。什么时候shell 启动另一个程序,然后该程序从调用 shell 继承 umask。因此,在一个 shell 中设置 umask 将不是影响其他程序,除非它们是第一个贝壳的后代并被创造设置 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;
}

编译:

$ gcc -o mkfile mkfile.c

按照这个例子:

$ 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

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

umask:                              0077    000 000 111 111
umask bitwise negated:             07700    111 111 000 000
open's argument:                    0660    000 110 110 000

(open's argument) AND (NEG umask)   0600    000 110 000 000

一般来说,程序应该建议在最宽松的情况下它认为有用的权限,并将权限的剥离留给操作系统的 umask。因此,使用(2)创建目录时使用0777 mkdir,使用(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

在 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

实际上,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

所以不要使用 umask 0。

答案3

在Linux中,默认文件权限为0644,默认目录权限为0755,默认umask为0022。

现在,由于文件的完全权限是 0666,因此默认权限来自 (0666 - 0022 = 0644),目录的默认权限是 (0777 - 0022 = 0755)。

您可以使用 设置掩码#umask 0000,它将创建具有完整 666/777 权限的文件和目录(但这非常不安全)。

答案4

我无法理解 GNU/Linux 中的 umask 是什么

好的。

以及用 anding 计算它。

我给了你这个公式:

mode=$(printf "%04o\n" "$(( (8#$default) & (~(8#$umask)) ))")

使用 default=0666 和 umask=0022 你会得到:

$ printf "%04o\n" "$(( (8#0666) & (~(8#0022)) ))"
0644

在 Linux 中,umask 既意味着 shell 内置命令,也意味着更改系统值的内核函数,通常称为文件创建掩码,也称为位掩码或只是掩码,由内置命令通过参数调用。

应写为:

在linux中,umask是shell内置函数的名称、内核函数的名称和进程值的名称。内置函数和函数都可以更改过程值。

  • 它不是系统值。每个进程都有一个 umask,该 umask 会被复制到其子进程。
  • 过程值不是通常命名为文件创建掩码, 它文件创建掩码
  • 它不称为位掩码或掩码。

掩码会影响当前进程树中的一些子进程,包括可以更改它的其他 shell(因此 shell Y 不一定具有 shell X 的掩码)。

掩码影响定义的进程以及从该进程启动的子进程。

  • 每个孩子都可以改变自己的掩码

文件权限,也称为文件模式,是一组 12 个二进制位,编码文件的用户、组和其他用户对该文件的访问权限(ugo → bbbbbbbbbbbb 的流)。

文件模式是一个数字(12个二进制数字或4个八进制数字或3个十六进制数字)

$ bc <<<'ibase=8; mask=1644; obase=2; mask; obase=8; mask; obase=16; mask'
1110100100
1644
4A8

然而,文件权限通常表示为四到三位八进制值(例如 - 0644 或 644)。

模式是一个带有 3 的数字或者四位数。
就像1230123一样是十进制数。

数学逻辑包括合取运算,又称“与”(∧),当“一组操作数的与为真当且仅当其所有操作数为真时”时发生。基于该逻辑有一个同名的按位运算。

好的。

Anding 与数字相加 (x + y → z) 或字符串串联 (x 与 y → xy) 不同。

好的。

设置不带或带 umask 的模式(通过其掩码)

模式始终使用 umask 设置。

一些实用程序(例如 mkdir)会创建具有独立模式的文件,而不使用 umask(因此这些文件的模式不会被屏蔽)。

不,umask 始终有效。

其他一些实用程序创建具有某些“屏蔽”权限的文件(即,权限是由屏蔽产生的)。例如,实用程序使用 fopen() 函数创建文件,其中首先识别掩码,然后使用基于它的权限创建文件。

该模式是以下结果:

mode=$(printf "%04o\n" "$(( (8#$default) & (~(8#$umask)) ))")

屏蔽模式是通过按位与完成的,结果如下:

模式是与默认值进行和运算的结果否定的掩码。

             OCTAL  BINARY        HUMAN-READABLE
umask        0222   000010010010  --w--w--w-
not-umask    7555   111101101101  N/A
default    ∧ 0666   000110110110  -rw-rw-rw-
result       0444   000100100100  -r--r--r-- 

我的理解够准确吗?怎么会是0666∧0555→0444?

有几个问题需要改进,只有 anding(不带否定)是:

0666 → 0 011 011 011
0555 → 0 101 101 101

如果你匹配垂直这些二进制数字,遵循以下规则: - 如果它们相等,则在下面写另一个相同的数字 - 如果它们不同,则在下面写一个零。

0666 → 0 110 110 110
0555 → 0 101 101 101
       0 100 100 100
       0  4   4   4
0444 → 0 100 100 100

相关内容