あなたの質問のモードは、644の権限(所有者には読み取り/書き込み、他のすべての人には読み取り専用)を持つ通常のファイルに対応していますが、私の言葉を信じないでください。
$ touch foo
$ chmod 644 foo
$ perl -le'print +(stat "foo")[2]'
33188
の値は10進整数と見なすことが$mode
できますが、そうすることは特に啓蒙的ではありません。8進数の表現を見ると、もう少し馴染みのあるものになります。
$ perl -e'printf "%o \ n"、(stat "foo")[2]'
100644
07777とのビットごとのANDは、数値の2進表現の最後の12ビットを示します。Unixモードでは、この操作は許可ビットまたはモードビットを与え、タイプ情報を破棄します。
$ perl -e'printf "%d \ n"、(stat "foo")[2]&07777'#10進数、役に立たない
420
$ perl -e'printf "%o \ n"、(stat "foo")[2]&07777'#8進数、eureka!
644
これを行うためのより良い方法は以下のとおりです。詳細については、以下をお読みください。
モードビット
から返される3番目の要素( instat
に対応)は、さまざまなビット位置がバイナリフラグであるビットフィールドです。st_mode
struct stat
たとえば、st_mode
POSIX名の1ビットS_IWUSR
。モードにこのビットが設定されているファイルまたはディレクトリは、その所有者が書き込み可能です。関連するビットはS_IROTH
、設定されている場合、他のユーザー(つまり、所有者でもグループ内でもない)がその特定のファイルまたはディレクトリを読み取ることができることを意味します。
のperlfuncドキュメントにstat
は、一般的に使用可能なモードビットの名前が記載されています。それらの値を調べることができます。
#! /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 EnterpriseLinuxおよびSystemVファミリの他のオペレーティングシステムでは、上記のプログラムの出力は次のようになります。
S_ISTXT-未定義
S_IFWHT-未定義
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進数(基数8)であるため、任意の桁は0〜7であり、桁の値は8 nです。ここで、nは基数ポイントの左側のゼロベースの桁数です。それらがビットにどのようにマッピングされるかを確認するために、8進数には各桁が3ビットに対応するという便利な特性があります。4、2、および1はすべて2の正確な累乗であるため、2進数では、それぞれ100、10、および1になります。2進数の7(= 4 + 2 + 1)は111なので、708は1110002です。後者の例は、前後の変換がいかに簡単であるかを示しています。
ビットフィールドを使用すると、その位置にあるビットの値が正確に何であるかは関係ありませんが、それがゼロか非ゼロかは関係ありません。
if ($mode & $mask) {
$mode
に対応するビットが設定されているかどうかをテストします$mask
。簡単な例として、4ビット整数1011とマスク0100が与えられた場合、それらのビット単位のANDは次のようになります。
1011
& 0100
------
0000
したがって、たとえば0010または1100のマスクとは対照的に、その位置のビットは明確です。
1011の最上位ビットをクリアすると次のようになります
1011 1011
& ~(1000) = & 0111
------
0011
~
Perlではビット単位の補集合であることを思い出してください。
完全を期すために、ビット単位のORでビットを設定します。
$bits |= $mask;
8進数とファイルのアクセス許可
8進数の3ビットへの直接マッピングは、3つのグループで提供されるため、Unixパーミッションに便利です。たとえば、上記の出力を生成したプログラムの権限は次のとおりです。
-rwxr-xr-x1gbaconユーザー10962月24日20:34モードビット
つまり、所有者は読み取り、書き込み、および実行を行うことができます。しかし、他の誰もが読んで実行することができます。8進数では、これは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;
一部のマスクは複数ビットの省略形であるため、モードテストはより注意する必要があります。正確なマスクが返されることをテストすることで、すべてではなく一部のビットが設定されている場合の誤検知を回避できます。
ループはまた、検出されたすべてのヒットからビットをクリアするため、最後に各ビットを考慮したことを確認できます。出力は
モード33188で設定されたビット:
-S_IFREG
-S_IRUSR
-S_IWUSR
-S_IRGRP
-S_IROTH
追加の警告はないので、すべてを取得しました。
その魔法07777
7777 8をバイナリに変換すると、が得られ0b111_111_111_111
ます。78は1112であり、 4つの7は4×3のものに対応することを思い出してください。このマスクは、最後の12のセットビットを選択するのに役立ちます。以前に生成したビットマスクを振り返って
S_ISUID-4000
S_ISGID-2000
S_ISVTX-1000
S_IRWXU-700
S_IRWXG-70
S_IRWXO-7
最後の9ビットは、ユーザー、グループ、およびその他の権限であることがわかります。それらの前の3つのビットは、setuid、setgroupid、およびスティッキービットと呼ばれることもあります。たとえば、sendmail
私のシステムのフルモードは-rwxr-sr-x
または3428510です。ビットごとのANDは次のようになります
(dec) (oct) (bin)
34285 102755 1000010111101101
& 4095 = & 7777 = & 111111111111
------- -------- ------------------
1517 = 2755 = 10111101101
破棄されるモードの上位ビットS_IFREG
は、通常のファイルであることを示すインジケーターです。10進数または2進数の同じ情報と比較すると、8進数で表現されたモードがどれほど明確であるかに注意してください。
stat
ドキュメントには、役立つ機能が記載されています。
…そしてS_IF*
機能は
S_IMODE($mode)
$mode
パーミッションビットとsetuid/setgid/stickyビットを含む
部分
で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);
ソースコードでのマジックナンバーの悪い習慣を避けるために、
my $permissions = S_IMODE $mode;
S_IMODE
Fcntlモジュールから利用可能なその他の関数を使用すると、低レベルのビットのいじりが隠され、プログラムが必要とするドメインレベルの情報に焦点が当てられます。ドキュメントは続きます
S_IFMT($mode)
(たとえば)または次の関数$mode
でビットアンドできるファイルタイプを含む
部分S_IFREG
# 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)
これらの定数と関数を使用すると、意図をより直接的に表現することで、プログラムがより明確になります。