CGI-BBS > CGI > Perl > otherIDをもとにパーミッションチェックを行うとき


カレッヂ
カレッヂ


質問者 yaku sima  投稿日 7/20(金) 00:24:53
下のコードは、otherIDがreadableなら真になる条件文のつもりです。

substr(sprintf("%04o",(stat($_))[2] & 07777),3,1) >= 4

otherIDでのpermission checkは、userID、groupIDでのファイルテスト演算子(-r,-w,-x,-o)で行えないので、stat関数で返ってきたモード値をマスクする、こうした形しかないんですかね? ご教授ください。
回答者 呑兵衛  [削除]  投稿日 7/20(金) 18:28:12
呑兵衛です。先日はどうも。

そんな難しく考えないで、 各ファイルに対して
open 関数で読み込み可能なら真、
という風に持っていけば良いのでは。
この場合、other のパーミッションが
---、-w-、-wx、--x はすべて偽が返りますよね。
質問者 yaku sima  [削除]  投稿日 7/21(土) 01:07:21

またまた、お世話になります。

質問が言足らずでした。m(__)m コードも足らなかったようです。

こんな感じでファイル名を展開して、以前のソートをするわけでして、(また、mapしてます。(^_^;)

my $omode=4;
my $ar;
push_array{
        map{
                substr(sprintf("%04o",(stat($_))[2] & 07777),3,1) >= $omode and -d $_ ? push_array($_) : push(@$ar,$_)
        }glob($_[0]."/*");
}
push_array("./tmp");

と大量のファイル名を扱うのでいちいちファイルをopenするのはどうかと。closeしなくてはならないし、permissionがreadableだけとは限らないようにするので。
回答者 呑兵衛  [削除]  投稿日 7/21(土) 17:37:06
全体のコーディングが変わるかもしれませんが、
あるディレクトリ($dir)以下を

grep(/^[-dl]/, (`ls -lR $dir`));
で引っ張ってきて
drwxr-xr-x    1 nonbei    nonbeigrp    70295 Jul 20 02:26 www_html
-rwxr-xr-x    1 nonbei    nonbeigrp    53294 Jul 20 02:26 hoge.cgi
-rw-r--r--    1 nonbei    nonbeigrp     2286 Jul 20 02:26 hoge_1.dat
-rw-------    1 nonbei    nonbeigrp      802 Jul 20 04:34 hoge_2.dat
-rw-r--r--    1 nonbei    nonbeigrp    11807 Jul 20 19:30 foo.cgi

パーミッション値の部分を選別し
index $_ , 'r', 7;

drwxr-xr-x    1 nonbei    nonbeigrp    70295 Jul 20 02:26 www_html
-rwxr-xr-x    1 nonbei    nonbeigrp    53294 Jul 20 02:26 hoge.cgi
-rw-r--r--    1 nonbei    nonbeigrp     2286 Jul 20 02:26 hoge_1.dat
-rw-r--r--    1 nonbei    nonbeigrp    11807 Jul 20 19:30 foo.cgi

必要な文字列(ファイル名)だけ取り出し、
$_ =~ s/.*\s//g;
(場合によってはディレクトリ名をリスト名に)
'@' .= $_ !~ /\./);

www_html
hoge.cgi
hoge_1.dat
foo.cgi

リストにぶち込む、
push(@www_html, $_);

という方法もあるような・・・。
map は自分で書いてくだされ。
質問者 yaku sima  [削除]  投稿日 7/22(日) 06:21:14

こういうやりかたもあったんですね。思い付きませんでした。

shellコマンドでのls -lRですか。何か邪道ですね。(笑)

しっかし、ディレクトリを付けてファイル名を取り出すのは、けっこう面倒ですね。挫折しました。うまく取り出せたら教えて。

コードはこんな感じです。

my @ar=grep{(index $_->[0],'r',7)>0}map{my($a,$b)=(split /\s+/,$_)[0,8];[$a,$b]}grep{/^[-d]/}`ls -lR pds`;

for(0..$#ar){print "mode = $ar[$_]->[0] fname = $ar[$_]->[1]\n";}

どちらかというと、pure perlがわたしは好きなんですけど、これからどうもうまくいかない時shellコマンドっていう最後の選択も考えておきます。



またまた、以前のコードに致命的な欠陥がありました。パーミッションチェックです。コードを見て比較してみて。

あまりに不細工(結構速いが)だったので、修正さしてください。m(__)m

基本的に同じですが、File::Findを使った関数にしました。実行効率を犠牲に分りやすさを重視しました。

use File::Find;

my $ar;

my $mode={
        'r'=>[4,5,6,7],
        'w'=>[2,3,6,7],
        'x'=>[1,3,5,7]
        };

my $ugo=[1,2,3];

sub permchk{grep{$_[0] == $omode->{$_[1]}->[$_]}0..3}

sub push_array{
        !-d and
                !-l and
                        permchk(substr(sprintf("%04o",(stat($_))[2] & 0777),$ugo->[2],1),'r') and
                                push(@$ar,$File::Find::name);
}

find(\&push_array,'tmp');


余談ですが、Benchmarkするとこうなりました。

reflexはglobでの再帰で、filefindはその名のとおりモジュールを使ったもので、shellは、コマンドlsを使ったものです。

Benchmark: timing 1000 iterations of filefind, reflex, shell...
  filefind: 12 wallclock secs ( 6.57 usr  2.71 sys +  1.77 cusr  1.64 csys = 12.69 CPU) @ 107.76/s (n=1000)
    reflex:  9 wallclock secs ( 5.51 usr +  2.68 sys =  8.19 CPU) @ 122.10/s (n=1000)
     shell: 24 wallclock secs ( 6.48 usr  4.97 sys +  7.48 cusr  5.02 csys = 23.95 CPU) @ 87.34/s (n=1000)
           Rate    shell filefind   reflex
shell    87.3/s       --     -19%     -28%
filefind  108/s      23%       --     -12%
reflex    122/s      40%      13%       --

globが速かったようです。残念ですが、shellはかなり遅かったです。

返信(回答)する


Web裏技