Linux权限模式位的表达,linux – 从stat函数输出中理解和解码文件模式值

来自您的问题的模式对应于具有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

使用这些常量和函数将使您的程序更直接地表达您的意图.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用inotify机制来检测文件更新,它是Linux内核提供的一种通知机制,可以监视文件系统文件或目录,当这些文件或目录发生变化时,内核会发送通知给用户空间程序。相比于使用stat函数轮询文件状态的方法,inotify机制能够有效地减少CPU资源的占用和系统调用的次数,提高程序的效率。 使用inotify机制需要使用以下步骤: 1. 调用inotify_init函数创建一个inotify实例。 2. 调用inotify_add_watch函数向inotify实例添加要监视的文件或目录。 3. 调用read函数读取inotify实例的通知信息,处理文件或目录的变化。 4. 调用inotify_rm_watch函数从inotify实例移除不再需要监视的文件或目录。 以下是使用inotify机制检测文件更新的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/inotify.h> #define EVENT_SIZE (sizeof(struct inotify_event)) #define BUF_LEN (1024 * (EVENT_SIZE + 16)) int main(int argc, char **argv) { int fd = inotify_init(); if (fd < 0) { perror("inotify_init"); exit(EXIT_FAILURE); } int wd = inotify_add_watch(fd, argv[1], IN_MODIFY); if (wd < 0) { perror("inotify_add_watch"); exit(EXIT_FAILURE); } char buf[BUF_LEN]; while (1) { int len = read(fd, buf, BUF_LEN); if (len < 0) { perror("read"); exit(EXIT_FAILURE); } char *p = buf; while (p < buf + len) { struct inotify_event *event = (struct inotify_event *)p; if (event->mask & IN_MODIFY) { printf("File %s was modified.\n", event->name); } p += EVENT_SIZE + event->len; } } inotify_rm_watch(fd, wd); close(fd); return 0; } ``` 上述代码,调用inotify_add_watch函数时指定了要监视的文件或目录以及要监视的事件类型(IN_MODIFY表示文件被修改)。read函数读取inotify实例的通知信息,并在发现文件被修改的事件时输出相应的信息。最后,调用inotify_rm_watch函数移除不再需要监视的文件或目录。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值