理解和解码来自 stat 函数输出的文件模式值 [英] understanding and decoding the file mode value from stat function output

查看:22
本文介绍了理解和解码来自 stat 函数输出的文件模式值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直试图了解下面提到的代码中到底发生了什么.但我无法理解.

I have been trying to understand what exactly is happening in the below mentioned code. But i am not able to understand it.

$mode = (stat($filename))[2];
printf "Permissions are %04o
", $mode & 07777;

假设我的 $mode 值为 33188

$mode &07777 产生一个值 = 420

  • $mode 值是十进制数吗?

  • is the $mode value a decimal number ?

为什么我们选择 07777 以及我们为什么要进行按位运算.我无法理解这里的逻辑.

why we are choosing 07777 and why we are doing a bitwise and operation. I am not able to underand the logic in here.

推荐答案

您问题中的模式对应于具有 644 权限的常规文件(所有者为读写,其他人为只读),但不要相信我的话.

The mode from your question corresponds to a regular file with 644 permissions (read-write for the owner and read-only for everyone else), but don’t take my word for it.

$ touch foo
$ chmod 644 foo
$ perl -le 'print +(stat "foo")[2]'
33188

$mode 的值可以看作是一个十进制整数,但这样做并不是特别有启发性.看到八进制表示会让人更熟悉一些.

The value of $mode can be viewed as a decimal integer, but doing so is not particularly enlightening. Seeing the octal representation gives something a bit more familiar.

$ perl -e 'printf "%o
", (stat "foo")[2]'
100644

按位 AND 与 07777 给出数字二进制表示的最后十二位.在 Unix 模式下,此操作提供权限或模式位并丢弃任何类型信息.

Bitwise AND with 07777 gives the last twelve bits of a number’s binary representation. With a Unix mode, this operation gives the permission or mode bits and discards any type information.

$ perl -e 'printf "%d
", (stat "foo")[2] & 07777'  # decimal, not useful
420
$ perl -e 'printf "%o
", (stat "foo")[2] & 07777'  # octal, eureka!
644

下面是一个更好的方法.请继续阅读以了解所有详细信息.

A nicer way to do this is below. Read on for all the details.

stat 返回的第三个元素(对应于 struct stat 中的 st_mode)是一个 位字段,其中不同的位位置是二进制标志.

The third element returned from stat (which corresponds to st_mode in struct stat) is a bit field where the different bit positions are binary flags.

例如,st_mode POSIX 中的一位命名 S_IWUSR.模式设置了此位的文件或目录可由其所有者写入.一个相关的位是 S_IROTH,设置后意味着其他用户(,既不是所有者也不是组中的)可以读取该特定文件或目录.

For example, one bit in st_mode POSIX names S_IWUSR. A file or directory whose mode has this bit set is writable by its owner. A related bit is S_IROTH that when set means other users (i.e., neither the owner nor in the group) may read that particular file or directory.

stat 的 perlfunc 文档给出了常用模式位的名称.我们可以检查它们的值.

The perlfunc documentation for stat gives the names of commonly available mode bits. We can examine their values.

#! /usr/bin/env perl

use strict;
use warnings;
use Fcntl ':mode';

my $perldoc_f_stat = q(
  # Permissions: read, write, execute, for user, group, others.
  S_IRWXU S_IRUSR S_IWUSR S_IXUSR
  S_IRWXG S_IRGRP S_IWGRP S_IXGRP
  S_IRWXO S_IROTH S_IWOTH S_IXOTH

  # Setuid/Setgid/Stickiness/SaveText.
  # Note that the exact meaning of these is system dependent.
  S_ISUID S_ISGID S_ISVTX S_ISTXT

  # File types.  Not necessarily all are available on your system.
  S_IFREG S_IFDIR S_IFLNK S_IFBLK S_IFCHR S_IFIFO S_IFSOCK S_IFWHT S_ENFMT
);

my %mask;
foreach my $sym ($perldoc_f_stat =~ /(S_Iw+)/g) {
  my $val = eval { no strict 'refs'; &$sym() };
  if (defined $val) {
    $mask{$sym} = $val;
  }
  else {
    printf "%-10s - undefined
", $sym;
  }
}

my @descending = sort { $mask{$b} <=> $mask{$a} } keys %mask;
printf "%-10s - %9o
", $_, $mask{$_} for @descending;

在 Red Hat Enterprise Linux 和 System V 系列的其他操作系统上,上述程序的输出将是

On Red Hat Enterprise Linux and other operating systems in the System V family, the output of the above program will be

S_ISTXT    - undefined
S_IFWHT    - undefined
S_IFSOCK   -    140000
S_IFLNK    -    120000
S_IFREG    -    100000
S_IFBLK    -     60000
S_IFDIR    -     40000
S_IFCHR    -     20000
S_IFIFO    -     10000
S_ISUID    -      4000
S_ISGID    -      2000
S_ISVTX    -      1000
S_IRWXU    -       700
S_IRUSR    -       400
S_IWUSR    -       200
S_IXUSR    -       100
S_IRWXG    -        70
S_IRGRP    -        40
S_IWGRP    -        20
S_IXGRP    -        10
S_IRWXO    -         7
S_IROTH    -         4
S_IWOTH    -         2
S_IXOTH    -         1

点点滴滴

上面的数字是八进制(以 8 为基数),因此任何给定的数字都必须是 0-7 且位值为 8n,其中 n 是小数点左侧的从零开始的位置数.为了查看它们如何映射到位,八进制具有每个数字对应三位的方便属性.四、二和 1 都是 2 的精确幂,所以在二进制中,它们分别是 100、10 和 1.二进制中的 7 (= 4 + 2 + 1) 是 111,所以 708 是 1110002.后一个例子展示了来回转换是多么简单.

Bit twiddling

The numbers above are octal (base 8), so any given digit must be 0-7 and has place value 8n, where n is the zero-based number of places to the left of the radix point. To see how they map to bits, octal has the convenient property that each digit corresponds to three bits. Four, two, and 1 are all exact powers of two, so in binary, they are 100, 10, and 1 respectively. Seven (= 4 + 2 + 1) in binary is 111, so then 708 is 1110002. The latter example shows how converting back and forth is straightforward.

对于位域,您并不关心 在那个位置的位的确切值是什么,而是 它是零还是非零,所以

With a bit field, you don’t care exactly what the value of a bit in that position is but whether it is zero or non-zero, so

if ($mode & $mask) {

测试$mode中与$mask对应的位是否被设置.举个简单的例子,给定4位整数1011和掩码0100,它们的按位与是

tests whether any bit in $mode corresponding to $mask is set. For a simple example, given the 4-bit integer 1011 and a mask 0100, their bitwise AND is

  1011
& 0100
------
  0000

所以那个位置的位是明确的——而不是像 0010 或 1100 这样的掩码.

So the bit in that position is clear—as opposed to a mask of, say, 0010 or 1100.

清除 1011 的最高位看起来像

Clearing the most significant bit of 1011 looks like

    1011      1011
& ~(1000) = & 0111
            ------
              0011

回忆一下 Perl 中的 ~ 是按位补码.

Recall that ~ in Perl is bitwise complement.

为了完整起见,使用按位 OR 设置位

For completeness, set a bit with bitwise OR as in

$bits |= $mask;

八进制和文件权限

八进制数字直接映射到三位对于 Unix 权限来说很方便,因为它们以三个为一组.例如,产生上述输出的程序的权限是

Octal and file permissions

An octal digit’s direct mapping to three bits is convenient for Unix permissions because they come in groups of three. For example, the permissions for the program that produced the output above are

-rwxr-xr-x 1 gbacon users 1096 Feb 24 20:34 modebits

即拥有者可以读、写、执行;但其他所有人都可以阅读和执行.在八进制中,这是 755——一个紧凑的速记.根据上表,模式中的设置位为

That is, the owner may read, write, and execute; but everyone else may read and execute. In octal, this is 755—a compact shorthand. In terms of the table above, the set bits in the mode are

  • S_IRUSR
  • S_IWUSR
  • S_IXUSR
  • S_IRGRP
  • S_IXGRP
  • S_IROTH
  • S_IXOTH

通过在上面的程序中添加几行,我们可以从您的问题中分解出模式.

We can decompose the mode from your question by adding a few lines to the program above.

my $mode = 33188;
print "
Bits set in mode $mode:
";
foreach my $sym (@descending) {
    if (($mode & $mask{$sym}) == $mask{$sym}) {
        print "  - $sym
";
        $mode &= ~$mask{$sym};
    }
}

printf "extra bits: %o
", $mode if $mode;

模式测试必须更加小心,因为一些掩码是多位的简写.测试我们获得准确的掩码可以避免在设置了某些位而不是全部位时出现误报.

The mode test has to be more careful because some of the masks are shorthand for multiple bits. Testing that we get the exact mask back avoids false positives when some of the bits are set but not all.

循环还会清除所有检测到的命中中的位,因此最后我们可以检查我们是否已经考虑了每个位.输出是

The loop also clears the bits from all detected hits so at the end we can check that we have accounted for each bit. The output is

Bits set in mode 33188:
  - S_IFREG
  - S_IRUSR
  - S_IWUSR
  - S_IRGRP
  - S_IROTH

没有额外的警告,所以我们得到了一切.

No extra warning, so we got everything.

将 77778 转换为二进制会得到 0b111_111_111_111.回想一下,78 是 1112,4 个 7 对应 4×3 个.此掩码可用于选择最后十二个中的设置位.回顾我们之前生成的位掩码

Converting 77778 to binary gives 0b111_111_111_111. Recall that 78 is 1112, and four 7s correspond to 4×3 ones. This mask is useful for selecting the set bits in the last twelve. Looking back at the bit masks we generated earlier

S_ISUID    -      4000
S_ISGID    -      2000
S_ISVTX    -      1000
S_IRWXU    -       700
S_IRWXG    -        70
S_IRWXO    -         7

我们看到最后 9 位是用户、组和其他的权限.前面的三个位是 setuid、setgroupid 和有时称为粘滞位的内容.例如,我系统上sendmail的完整模式是-rwxr-sr-x或3428510.按位 AND 结果为

we see that the last 9 bits are the permissions for user, group, and other. The three bits preceding those are the setuid, setgroupid, and what is sometimes called the sticky bit. For example, the full mode of sendmail on my system is -rwxr-sr-x or 3428510. The bitwise AND works out to be

  (dec)      (oct)                (bin)
  34285     102755     1000010111101101
&  4095 = &   7777 = &     111111111111
-------   --------   ------------------
   1517 =     2755 =        10111101101

被丢弃的模式中的高位是S_IFREG,表明它是一个普通文件.请注意,与十进制或二进制的相同信息相比,八进制表示的模式清晰得多.

The high bit in the mode that gets discarded is S_IFREG, the indicator that it is a regular file. Notice how much clearer the mode expressed in octal is when compared with the same information in decimal or binary.

stat 文档 提到了一个有用的功能.

The stat documentation mentions a helpful function.

…而 S_IF* 函数是

… and the S_IF* functions are

S_IMODE($mode)
$mode 包含权限位和 setuid/setgid/sticky 位的部分

S_IMODE($mode)
the part of $mode containing the permission bits and the setuid/setgid/sticky bits

ext/Fcntl/Fcntl.xs,我们在最后一行找到它的实现和一个熟悉的常量.

In ext/Fcntl/Fcntl.xs, we find its implementation and a familiar constant on the last line.

void
S_IMODE(...)
    PREINIT:
        dXSTARG;
        SV *mode;
    PPCODE:
        if (items > 0)
            mode = ST(0);
        else {
            mode = &PL_sv_undef;
            EXTEND(SP, 1);
        }
        PUSHu(SvUV(mode) & 07777);

为避免源代码中幻数的不良做法,请编写

To avoid the bad practice of magic numbers in source code, write

my $permissions = S_IMODE $mode;

使用 S_IMODE 和 Fcntl 模块中可用的其他函数还隐藏了低级位操作并专注于程序所需的域级信息.文档继续

Using S_IMODE and other functions available from the Fcntl module also hides the low-level bit twiddling and focuses on the domain-level information the program wants. The documentation continues

S_IFMT($mode)
$mode 包含文件类型的部分,可以与(例如)S_IFREG 或以下函数进行位与运算

S_IFMT($mode)
the part of $mode containing the file type which can be bit-anded with (for example) S_IFREG or with the following functions

# The operators -f, -d, -l, -b, -c, -p, and -S.
S_ISREG($mode) S_ISDIR($mode) S_ISLNK($mode)
S_ISBLK($mode) S_ISCHR($mode) S_ISFIFO($mode) S_ISSOCK($mode)

# No direct -X operator counterpart, but for the first one
# the -g operator is often equivalent.  The ENFMT stands for
# record flocking enforcement, a platform-dependent feature.
S_ISENFMT($mode) S_ISWHT($mode)

使用这些常量和函数可以更直接地表达您的意图,从而使您的程序更清晰.

Using these constants and functions will make your programs clearer by more directly expressing your intent.

这篇关于理解和解码来自 stat 函数输出的文件模式值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆