私は、以下のコードで何が起こっているのかを正確に理解しようとしています。しかし、私はそれを理解することができません。
$mode = (stat($filename))[2];
printf "Permissions are %04o\n", $mode & 07777;
私の$ mode値が33188だとしましょう
$ mode&07777は値= 420を生成します
$ mode値は10進数ですか?
07777を選択する理由と、ビット単位の操作を行う理由。私はここの論理を理解することができません。
あなたの質問のモードは、644の権限(所有者には読み取り/書き込み、他のすべての人には読み取り専用)を持つ通常のファイルに対応していますが、私の言葉を受け入れないでください。
$ touch foo $ chmod 644 foo $ Perl -le'print +(stat "foo")[2] ' 33188
_$mode
_ canの値は、10進整数と見なされますが、そうすることは特に啓発的ではありません。 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
これを行うためのより良い方法は以下のとおりです。詳細については、以下をお読みください。
stat
から返される3番目の要素(_st_mode
_の_struct stat
_に対応)は ビットフィールド で、異なるビット位置はバイナリフラグです。
たとえば、_st_mode
_ POSIXの1ビットは_S_IWUSR
_に名前を付けます。モードにこのビットが設定されているファイルまたはディレクトリは、その所有者が書き込み可能です。関連するビットは_S_IROTH
_であり、設定すると、他のユーザー(つまり、所有者もグループ内も)がその特定のファイルまたはディレクトリを読み取ることができないことを意味します。
stat
のperlfuncドキュメントには、一般的に使用可能なモードビットの名前が記載されています。それらの値を調べることができます。
_#! /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 40000 S_IFCHR-20000 S_IFIFO-10000 S_ISUID-4000 S_ISGID-2000 S_ISVTX-1000 S_IRWXU-700 [ .________________ 。] 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 は111000です2。後者の例は、前後の変換がいかに簡単であるかを示しています。
ビットフィールドを使用すると、正確に気にする必要はありませんwhatその位置のビットの値はかどうかゼロかゼロ以外か。
_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進数の3ビットへの直接マッピングは、3つのグループで提供されるため、Unixのアクセス許可に便利です。たとえば、上記の出力を生成したプログラムの権限は次のとおりです。
-rwxr-xr-x 1gbaconユーザー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
追加の警告はないので、すべてを取得しました。
7777の変換8 バイナリに変換すると、_0b111_111_111_111
_が得られます。その7を思い出してください8 111です2、および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
_または34285です。10。ビットごとのANDは、
_ (dec) (oct) (bin)
34285 102755 1000010111101101
& 4095 = & 7777 = & 111111111111
------- -------- ------------------
1517 = 2755 = 10111101101
_
破棄されるモードの上位ビットは_S_IFREG
_であり、これは通常のファイルであることを示します。 10進数または2進数の同じ情報と比較すると、8進数で表されるモードがどれほど明確であるかに注意してください。
stat
ドキュメント は便利な関数について言及しています。
…そして_
S_IF*
_関数は
S_IMODE($mode)
許可ビットとsetuid/setgid/stickyビットを含む_$mode
_の部分
_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)
_
これらの定数と関数を使用すると、意図をより直接的に表現することで、プログラムがより明確になります。
perldoc -f stat で説明されています。ここで、この例を見つけたと思います。
Because the mode contains both the file type and its
permissions, you should mask off the file type portion and
(s)printf using a "%o" if you want to see the real permissions.
printf "%04o", 420
の出力は0644
で、これはファイルの権限です。 420
は、8進数0644
の10進数表現です。
数値を2進形式で印刷しようとすると、次のことがわかりやすくなります。
Perl -lwe 'printf "%016b\n", 33188'
1000000110100100
Perl -lwe 'printf "%016b\n", 33188 & 07777'
0000000110100100
お気づきのように、ビット単位のand
は、上記の番号の左端のビットを削除します。これはおそらくファイルタイプを表しており、ファイルのアクセス許可のみが残ります。この番号07777は2進数です。
Perl -lwe 'printf "%016b\n", 07777'
0000111111111111
これは、ビット単位のand
で「マスク」として機能します。 1&1 = 1、および0&1 = 0であるため、07777の1と一致しないビットはすべて0に設定されます。