Klaus Mock: Permission-Check von Dateien mit Perl

Beitrag lesen

Hallo,

Ich habe die ganze stat()-Beschreibung ein paar mal durchgelesen, und war danach immer noch verwirrter als vorher.

Ok, villeicht kann ich doch noch etwas Licht in die Angelegenheit bringen.
(Anm.: das was da jetzt kommt, ist eigentlich aus der Unixwelt, andere Perlports, wie für Windows (NT/2k) emulieren AFAIK das nur)

$mode = (stat($filename))[2];
Liefert also den Filemode zurück, das ist schon mal klar.
In $mode stehen jetzt zweierlei Dinger, erstens der Dateityp, zweitens die Dateirechte.
Beschränken wir uns mal auf die Dateirechte.

Mit
$permissions = $mode & 07777;
'filterst' Du den Dateityp raus. Das erfolgt durch eine Bitoperation (& bzw. AND), das heißt nur jene Bits, welche in 07777 und $mode gesetzt sind, werden auch in $permission übernommen, die restlichen Bits von $mode werden 'ignoriert'.
(näheres zu Bitoperationen findest Du in jedem guten EDV-Einsteigerbuch).

Jetzt solltest Du noch wissen, was eine Oktalzahl ist. Das ist eine Zahl mit der Basis 8 anstelle 10 für Dezimalzahlen oder 16 für Hexadezimalzahlen. Jede Ziffer einer Oktalzahl wird durch drei Bits repräsentiert.
Das ist für die Dateirechte wunderbar, da hier für Besitzer, Gruppe [1] und Other (=Alle) jeweils die Rechte Lesen, Schreiben und Ausführen angegeben werden können, also auch drei Rechte pro 'Gruppe'. Die vierte Gruppe beinhaltet Setuid/Setgid/Stickiness, aber das lassen wir mal beiseite.
Nochmals zurück zu $permissions. Durch das Ausmaskieren mit 07777 bleibt eine 4-stellige Oktalzahl übrig. Auch das passt herrlich mit unseren Dateirechten zusammen, da da ja vier Definitionen notwendig sind (user,group,other und Setuid/Setgid/Stickiness [wie heißen die eigentlich, hmm Stickibits, denk ich]).
Wenn Du jetzt $permission als Oktalzahl ausgibst (printf("%04o",$permission);), dann kriegst Du meist folgende Werte:
0755
0600
0777
0644
oder was auch immer.
Nehmen wir uns 0755 vor, und zwar von Links nach Rechts.

Die erste  (0) steht für die 'Stickibits'. Es sind keine gesetzt.

Die zweite (7) repräsentiert die Rechte des Besitzers der Datei. Wenn Du oktal 7 in eine Binärzahl umwandeln würdest, ergäbe das 111, wobei die einzelnen Bits , wieder von Links nach Rechts gelesen, für die Rechte Lesen, Schreiben und Ausführen stehen.
Jedes gesetzte Bit (1) heißt hier, daß der Besitzer das entsprechende Recht erteilt bekommen hat. In diesem konkreten Fall hat der Besitzer also alle Rechte.

Die dritte (5) steht für die Gruppenrechte, und ist wieder wie beim Besitzer zu interpretieren, also hat die (zugeordnete) Gruppe die Rechte Lesen und Ausführen (oktal 5 == binär 101).

Die vierte (5) steht für die Rechte aller anderen (other) und ist, wie bei der Gruppe auch auf Lesen und Ausführen gesetzt.

Soweit zu den Internas.

Weil allerdings das Ermitteln von Dateirechten durch dieses maskieren und bitweise lesen etwas unübersichtlich werden würde, gibts da ab Perl 5.6 ein Modul, welches standardmäßich bei allen Perlports mit 'geliefert' wird (ein sog. Core-Modul), mit dem das Ganze einfacher abzufragen ist.

use Fcntl ':mode';
$mode = (stat($filename))[2];

>>6 schiebt die Bits um 6 stellen nach links, um so die gleichen

Werte für user,group und other zu erhalten

$user_rights  = ($mode & S_IRWXU) >> 6;
$user_read    = ($mode & S_IRUSR) >> 6;
$user_write   = ($mode & S_IWUSR) >> 6;
$user_execute = ($mode & S_IXUSR) >> 6;

für group wird nur um 3 Bits verschoben

$group_rights  = ($mode & S_IRWXG) >> 3;
$group_read    = ($mode & S_IRGRP) >> 3;
$group_write   = ($mode & S_IWGRP) >> 3;
$group_execute = ($mode & S_IXGRP) >> 3;

hier wird nichts mehr geschoben, weil das sowieso schon links ist

$other_rights  = ($mode & S_IRWXO);
$other_read    = ($mode & S_IROTH);
$other_write   = ($mode & S_IWOTH);
$other_execute = ($mode & S_IXOTH);

Du könntest z.B. eine Ausgabe, wie es unter Unix (ls -l) üblich ist zusammenbasteln:

#!/usr/bin/perl
use Fcntl ':mode';

opendir(DIRHDL,'.');
@files = readdir(DIRHDL);
foreach $file (@files)
{
$mode = (stat($file))[2];

$permissions = '';
$permissions .= ($mode & S_IRUSR)?'r':'-';
$permissions .= ($mode & S_IWUSR)?'w':'-';
$permissions .= ($mode & S_IXUSR)?'x':'-';
$permissions .= ($mode & S_IRGRP)?'r':'-';
$permissions .= ($mode & S_IWGRP)?'w':'-';
$permissions .= ($mode & S_IXGRP)?'x':'-';
$permissions .= ($mode & S_IROTH)?'r':'-';
$permissions .= ($mode & S_IWOTH)?'w':'-';
$permissions .= ($mode & S_IXOTH)?'x':'-';

print "$permissions $file \n";
}

Das Dumme an diesem Beispiel ist nur, daß es Perl 5.6 voraussetzt. Bei älteren Versionen kannst Du aber afgrund der obigen Erklärungen sicherlich etwas ähnliches nachbauen.

Hab' ich das nun richtig verstanden ich muss einfach vor die variable die diese zahl beinhält diesen -f Operator setzten?

Äh, ich vermute Du meinst das -f von 'perldoc -f'. Nein, das hat was mit dem 'Programm' perldoc zu tun, nicht mit Deinem Problem.

Grüße
 Klaus

[1] Unter Unix wird jeder Datei ein Besitzer und eine Gruppe zugeordnet, deren ID  mit (stat($filename))[4] bzw. (stat($filename))[5] ausgelesen werden kann. Mit diesen Werten kann dann mittels 'getpwuid' bzw. 'getgrgid' deren Daten ermittelt werden. (Aber das kann bei Nicht-Unixports von Perl nicht als zuverlässig gegeben angenommen werden)