サブフィールドコーディング

ビット演算でマスキングしてファイル種別を判定する方法を紹介します。

マスキング

次のような郵便番号があります。

100-6002
100-6009
100-6090
101-0029
101-0063
...

100-6002、100-6009と100-6090は東京都千代田区霞が関霞が関ビルを表わしています。
これは100-60XXという事から判断ができます。

上記のような郵便番号から霞が関ビルを表わす番号を調べる場合は、先頭の5ケタ以外を0に変換してからそれが100-6000と一致するかどうかを考える事ができます。

このように、必要でない数字を0に置き換えて、必要なフィールドだけが見える状態にすることをマスキングと呼びます。

マスキングとビット演算

ビット演算を使うと次のようにマスキングを行う事ができます。

サンプルコード

#!/usr/bin/perl
use strict;
use warnings;

my $hoge = "1_010";
my $fuga = "1_100";

print $hoge & $fuga, "\n";

my $foo = "0_110_101_101";
my $bar = "0_110_000_000";

print $foo & $bar, "\n";

実行

:!perl %
1_000
0_110_000_000

8進法にする

2進法の3桁の整数を、1桁の8進法にまとめると人間に優しくなるそうです。

my $foo = "0755";
my $bar = "0700";

print $foo & $bar;
:!perl mask1.pl
0700

どこかで見たことがある数値だと思いますが、その他ユーザーがこのファイルを実行できるか、という判定をするアレです。

#!/usr/bin/perl
use strict;
use warnings;

my $foo = "0755";
my $bar = "0001";

print $foo & $bar;
:!perl %
0001

ということでマスキングはわりと身近で使われる処理ということです。

ファイルタイプ解読

stat構造体

stat構造体はsys/stat.h(もしかしたらbits/stat.h)に記述があり、次のメンバで構成されています。

st_mode タイプとパーミッション
st_uid オーナーのID
st_gid グループのID
st_size ファイルのバイト数
st_nlink ファイルに対するリンクの数
st_mtime 最終変更日時
st_atime 最終アクセス日時
st_ctime 最終プロパティ変更日時
ファイル種別

Linuxでは以下のファイル種別が存在します。

これはst_modeの最初の4ビットで表現されています。
具体的には次のような処理で判定できます。

#!/usr/bin/perl
use strict;
use warnings;

=pod

SEE ALSO: sys/stat.h and bits/stat.h

=cut

my $s_ifmt   = 0170000; # ファイルのタイプ
my $s_ifreg  = 0100000; # 通常
my $s_ifdir  = 0040000; # ディレクトリ
my $s_ifblk  = 0060000; # ブロックデバイス
my $s_ifchr  = 0020000; # キャラクタデバイス
my $s_ififo  = 0010000; # FIFO(名前付きパイプ)
my $s_iflnk  = 0120000; # シンボリックリンク
my $s_ifsock = 0140000; # ソケット

print "this is regular file\n" if is_reg(100664);

sub is_reg {
    my $mode = shift;

    return ($mode & $s_ifmt) == $s_ifreg ? 1 : 0;
}

とりあえずst_modeの先頭4bitを調べるだけで、ファイルの種別を判定する事ができました。ほかにもsuid,sgid,スティッキービット、ユーザー権限、グループ権限、その他ユーザー権限の情報もst_modeにふくまれています。

というわけでサブフィールドコーディングと呼ばれる手法をかけあしで紹介しました。