来自您的问题的模式对应于具有644个权限的常规文件(对所有者进行读写,对于所有其他人都是只读的),但是不要使用我的话.
$touch foo
$chmod 644 foo
$perl -le 'print +(stat "foo")[2]'
33188
$mode的值可以看作十进制整数,但这样做并不是特别有启发性.看到八进制表示给了一些更加熟悉的东西.
$perl -e 'printf "%o\n", (stat "foo")[2]'
100644
按位AND与07777给出一个数字二进制表示的最后十二位.使用Unix模式,此操作会给出权限或模式位,并丢弃任何类型的信息.
$perl -e 'printf "%d\n", (stat "foo")[2] & 07777' # decimal, not useful
420
$perl -e 'printf "%o\n", (stat "foo")[2] & 07777' # octal, eureka!
644
一个更好的方法是这样做.请继续阅读所有细节.
模式位
从stat返回的第三个元素(对应于struct stat中的st_mode)是bit field,其中不同的位位置是二进制标志.
例如,st_mode中的一位POSIX名称为S_IWUSR.其模式具有此位的文件或目录可由其所有者写入.相关的位是S_IROTH,当设置意味着其他用户(即所有者和组中都不能)读取该特定文件或目录时.
#! /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 =~ /\b(S_I\w+)\b/g) {
my $val = eval { no strict 'refs'; &$sym() };
if (defined $val) {
$mask{$sym} = $val;
}
else {
printf "%-10s - undefined\n", $sym;
}
}
my @descending = sort { $mask{$b} <=> $mask{$a} } keys %mask;
printf "%-10s - %9o\n", $_, $mask{$_} for @descending;
在Red Hat Enterprise Linux和System V系列中的其他操作系统中,上述程序的输出将是
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是基数点左侧的零位数.要查看它们如何映射到位,八进制具有方便的属性,每个数字对应于三位.四,二和一个都是两个精确的幂,所以在二进制中,它们分别是100,10和1.二进制中的七(= 4 2 1)是111,那么708是1110002.后一个例子显示了来回转换是如何直接的.
有了一个字段,你并不在乎这个位置的一点是什么,但是它是零还是非零,所以
if ($mode & $mask) {
测试是否设置了与$mask对应的$mode中的任何位.对于一个简单的例子,给定4位整数1011和掩码0100,它们的按位与
1011
& 0100
------
0000
所以在这个位置的一点是明确的,而不是一个例如0010或1100的掩码.
清除1011的最重要位看起来像
1011 1011
& ~(1000) = & 0111
------
0011
回想一下,在Perl中是按位补码.
为了完整,按位或OR进行设置
$bits |= $mask;
八进制和文件权限
八位数的直接映射到三位是非常方便的Unix权限,因为它们分为三组.例如,生成上面输出的程序的权限是
-rwxr-xr-x 1 gbacon users 1096 Feb 24 20:34 modebits
也就是说,所有者可以读,写和执行;但是其他人都可以读取和执行.在八进制,这是755 – 一个紧凑的速记.在上表中,模式中的设置位为
> S_IRUSR
> S_IWUSR
> S_IXUSR
> S_IRGRP
> S_IXGRP
> S_IROTH
> S_IXOTH
我们可以通过在上面的程序中添加几行来分解你的问题的模式.
my $mode = 33188;
print "\nBits set in mode $mode:\n";
foreach my $sym (@descending) {
if (($mode & $mask{$sym}) == $mask{$sym}) {
print " - $sym\n";
$mode &= ~$mask{$sym};
}
}
printf "extra bits: %o\n", $mode if $mode;
模式测试必须更加小心,因为一些掩码是多位的缩写.测试我们得到确切的掩码,避免了当某些位被设置但不是全部时的误报.
循环也可以清除所有检测到的命中中的位,所以最后我们可以检查我们已经占了每一位.输出是
Bits set in mode 33188:
- S_IFREG
- S_IRUSR
- S_IWUSR
- S_IRGRP
- S_IROTH
没有额外的警告,所以我们得到了一切.
那魔法07777
将77778转换为二进制给出0b111_111_111_111.回想一下78是1112,4 7对应4×3.该掩码对于在过去十二年中选择设置的位有用.回顾我们之前生成的位掩码
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就可以
(dec) (oct) (bin)
34285 102755 1000010111101101
& 4095 = & 7777 = & 111111111111
------- -------- ------------------
1517 = 2755 = 10111101101
被丢弃的模式中的高位是S_IFREG,它是一个常规文件的指示符.注意与十进制或二进制相同的信息相比,以八进制表示的模式多清楚一点.
… and the S_IF* functions are
S_IMODE($mode)
the part of $mode containing the permission bits and the setuid/setgid/sticky bits
In ext/Fcntl/Fcntl.xs,我们发现它的实现和一个熟悉的常数在最后一行.
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);
为了避免magic numbers在源代码中的不良做法,写
my $permissions = S_IMODE $mode;
使用S_IMODE和Fcntl模块提供的其他功能也可以隐藏低级别的位置,并将重点放在程序所需的域级信息上.文档继续
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
060016
使用这些常量和函数将使您的程序更直接地表达您的意图.