![]() |
|
|
Wie schon erwähnt, können Sie über die Strukturvariable st_mode auch die einfachen Zugriffsrechte der drei Benutzerklassen (rwx|rwx|rwx), die es unter Linux/UNIX gibt, ermitteln. Hier die Tabelle mit den einzelnen Konstanten, womit Sie die Zugriffsrechte überprüfen können.
»Alle anderen« heißt auch wirklich alle anderen, die nicht in der Gruppe sind. So gesehen gibt es im Dateimodus 0705 immer eine gelackmeierte Benutzergruppe. Verändern können Sie die Zugriffsrechte mit der Funktion chmod() oder dem gleichnamigen Befehl in einer Shell. Das folgende Listing demonstriert nun, wie Sie ein komplettes Verzeichnis (hier das Arbeitsverzeichnis) auslesen und die Dateiart und Zugriffsrechte (Linux-/UNIX-gerecht) mithilfe der Funktion stat() und der Strukturvariablen st_mode ermitteln können. /* my_stat.c */ #include <sys/stat.h> #include <sys/types.h> #include <unistd. h.> #include <stdio.h> #include <string.h> #include <errno.h> #include <dirent.h> #include <stdlib.h> int main (int argc, char **argv) { DIR *dir; struct dirent *dirzeiger; const char *rwx = "rwxrwxrwx"; int bits[]= { S_IRUSR,S_IWUSR,S_IXUSR,/*Zugriffsrechte User*/ S_IRGRP,S_IWGRP,S_IXGRP,/*Zugriffsrechte Gruppe*/ S_IROTH,S_IWOTH,S_IXOTH /*Zugriffsrechte der Rest*/ }; /* Arbeitsverzeichnis öffnen */ if((dir=opendir(".")) == NULL) { fprintf(stderr,"Fehler bei opendir: %s\n", strerror(errno)); return (EXIT_FAILURE); } /* Das komplette Verzeichnis auslesen */ while((dirzeiger=readdir(dir)) != NULL) { struct stat attribut; int i; char l_rwx[10]; l_rwx[9] = '\0'; if(stat(dirzeiger->d_name, &attribut) == -1) { fprintf(stderr,"Fehler bei stat: %s\n", strerror(errno)); return (EXIT_FAILURE); } /* Dateiart erfragen */ if( S_ISREG(attribut.st_mode) ) printf("Reguläre Datei : "); else if( S_ISDIR(attribut.st_mode) ) printf("Verzeichnis : "); else if( S_ISCHR(attribut.st_mode) ) printf("zeichenorient. Gerätedatei : "); else if( S_ISBLK(attribut.st_mode) ) printf("blockorient. Gerätedatei : "); else if( S_ISFIFO(attribut.st_mode) ) printf("FIFO oder named Pipe : "); else printf("Unbekannte Datei : "); /* Dateinamen ausgeben */ printf("%-20s [",dirzeiger->d_name); /* Einfache Zugriffsrechte erfragen */ l_rwx[0]='\0'; for(i=0; i<9; i++) { /*Wenn nicht 0, dann gesetzt*/ l_rwx[i]=(attribut.st_mode & bits[i]) ? rwx[i] : '-'; } l_rwx[9]='\0'; printf("%s]\n",l_rwx); } closedir(dir); return EXIT_SUCCESS; } Das Programm bei der Ausführung: $ gcc –o my_stat my_stat.c $ ./my_stat Verzeichnis : . [rwxrwx---] Verzeichnis : .. [rwxrwx---] Verzeichnis : bin [rwxrwx---] Reguläre Datei : dir1.c [rwx------] Verzeichnis : etc [rwxrwx---] Reguläre Datei : file [rwxr-xr-x] Reguläre Datei : file1.txt [rw-r--r--] Verzeichnis : lib [rwxrwx---] Verzeichnis : mails [rwx------] Reguläre Datei : my_stat.c [rwx------] Reguläre Datei : my_stat [rwxr-xr-x] Reguläre Datei : out.txt [rw-r--r--] Reguläre Datei : reformime [rwx------] Verzeichnis : sbin [rwxrwx---] Reguläre Datei : test [rwxrwxrwx] Reguläre Datei : test.txt [rwx------] Reguläre Datei : testfile.txt [rwx------] Verzeichnis : tmp [rwxrwx---] Reguläre Datei : Unbenannt2.cpp [rwx------] Verzeichnis : usr [rwxrwx---] Verzeichnis : var [rwxrwx---] Sollten Sie Probleme mit den Makros S_IS* haben, dann arbeiten Sie vermutlich mit einem älteren UNIX-/Linux-System, das die Makros noch nicht unterstützt. In solch einem Fall müssen Sie die Konstanten S_IF* als Bitmask verwenden, z. B.: if(attribut.st_mode & S_IFREG)
printf("Reguläre Datei\n");
else if(attribut.st_mode & S_IFDIR)
printf("Directory\n");
3.1.2 User-ID-Bit und Group-ID-Bit – st_uid und st_gid
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Hinweis Sie werden es wahrscheinlich geahnt haben: Die meisten Informationen der Struktur stat werden aus diesem Inode gelesen. |
Jetzt wissen Sie, was die Inode-Nummer bedeutet, und somit auch, was Sie mit st_ino für Informationen erhalten. Ein Listing dazu kann ich mir ersparen, da die Ermittlung von st_ino genauso abläuft wie im Listing zuvor (siehe Abschnitt 3.1.2).
Ein Link ist unter Linux/UNIX eine einfache Möglichkeit, einen Alias für eine Originaldatei anzulegen. Damit können Sie auf ein und dieselbe Datei unter mehreren Namen und an einer anderen Stelle, als sich die Originaldatei befindet, zugreifen. Es gibt viele Gründe, so etwas zu tun. Z. B. befindet sich eine Datei oder eine Anwendung im tiefsten Dschungel der Verzeichnishierarchie, und Sie wollen nicht immer wieder einen ellenlangen Text in die Kommandozeile eingeben. Dafür können Sie in Ihrem Arbeitsverzeichnis einen Link (= Verbindung) zu dieser Datei anlegen. Sie können dabei (fast) beliebig viele Links anlegen.
Ein Beispiel. Sie wollen ein Programm aus Ihrem /home-Verzeichnis aufrufen, das sich im Pfad /opt/kde/bin/ befindet. Anstatt das Programm jedes Mal mit folgendem Aufruf zu starten:
/opt/kde/bin/programmname
können Sie hierzu einen Link zu diesem Programm erstellen. In der Kommandozeile können Sie dabei folgendermaßen vorgehen:
$ ln /opt/kde/bin/programmname programmname
Von jetzt an können Sie aus Ihrem /home-Verzeichnis auf das Programm mit programmname zugreifen. Natürlich müssen Sie den Programmnamen dabei nicht einbehalten. Sie können genauso gut einen anderen Namen dafür verwenden:
$ ln /opt/kde/bin/programmname neuer_name
|
Hinweis Eine Datei existiert so lange, bis der letzte Link auf diese Datei gelöscht wurde. |
Man unterscheidet generell zwischen einem harten Link und einem symbolischen Link. Mit einem symbolischen Link kann man im Gegensatz zu harten Links auch partitionsübergreifend Dateien verlinken. Des Weiteren können symbolische Links auch auf ein Verzeichnis zeigen, was bei harten Links nicht möglich ist. Symbolische Links erkennen Sie bei der Ausgabe von Verzeichnissen mit ls -l an einem Pfeil und einem l (für Link) als erstes Zeichen der Ausgabe:
$ ls –l lrwxrwxrwx 1 juergen users 10 Nov 6 00:13 hallo -> /var/hallo
Die »Größe« eines Symlinks ist immer die Länge seines Ziels, also dem Textstring hinter »–>« in ls.
Wollen Sie aus Ihrem Programm heraus einen harten oder einen symbolischen Link erstellen, bieten sich dazu zwei Funktionen an:
#include <unistd. h.> int link(const char *name, const char *linkname); int symlink(const char *pfadname, const char *symlink);
Beide Funktionen geben bei Erfolg 0, ansonsten bei einem Fehler -1 zurück. Mit der Funktion link() erzeugen Sie einen harten Link linkname auf die existierende Datei name. Mit symlink() erzeugen Sie einen symbolischen Link mit dem Namen symlink auf pfadname.
Es muss erwähnt werden, dass st_nlink keinen symbolischen Link mitzählt. Dies liegt daran, dass Symlinks selbst einen Inode besitzen und somit außer dem Zielnamen (der ja nicht immer existieren muss) keine Beziehung zu der referenzierten Datei haben. Weiterhin referenziert ein Symlink eine potenzielle Datei, während ein dentry (Verzeichniseintrag) einen Inode referenziert, inkl. gleicher Inodes für mehrere dentries. Ein Symlink dagegen ist ein dentry mit eigenständigem Inode.
Anders als beim harten Link kann es passieren, dass der symbolische Link ins Nichts zeigt (auch genannt »Dangling Symlink«). Linux überprüft nicht, ob ein symbolischer Link noch gültig ist, das müssen die Anwendungen machen. Das ist eigentlich auch logisch. Denn haben Sie z. B. einen symbolischen Link auf einem anderen Rechner über ein Netzwerk gesetzt, würde dies bedeuten, dass dieser Rechner dauerhaft überprüft werden muss. Einen symbolischen Link kann man eher mit der »grausamen« Verknüpfung von MS-Systemen vergleichen. Wollen Sie abfragen, auf welche Originaldatei oder welches Verzeichnis der symbolische Link verweist, so können Sie dies mit der Funktion readlink() in Erfahrung bringen.
#include <unistd. h.> int readlink(const char *sym_link, char *buf, int buf_size);
Gibt diese Funktion -1 zurück, ist etwas nicht in Ordnung mit dem symbolischen Link (siehe z. B. /proc/2/exe). Natürlich sagt ein Rückgabewert von 0 noch nichts über die Existenz der referenzierten Datei aus. Somit bleibt bei den symbolischen Links immer ein wenig Ungewissheit übrig. Die Funktion readlink() terminiert den String buf übrigens nicht. Aber da die Funktion als Rückgabewert die Anzahl der gelesenen Bytes zurückgibt, sollte dies kein Problem sein.
Ob eine Datei/ein Verzeichnis, die/das durch einen Symlink referenziert wird, nun tatsächlich existiert, kann man entweder mit einem stat() nach readlink() oder einem open() überprüfen. Existiert die Zieldatei nicht, wird in beiden Fällen (stat/open) ENOENT in errno zurückgegeben.
Natürlich gibt es noch viel mehr zu den Links zu sagen, aber dies ist nicht im Sinne eines Buchs zur Programmierung. Dazu seien entsprechende Manual Pages oder eines der vielen guten Linux-Bücher empfohlen (oder ein Blick auf den Inhalt der Buch-CD).
Hierzu nun ein Listing, das die Anzahl von Links (st_nlink) einer Datei überprüft, die Sie als erstes Argument in der Kommandozeile übergeben. Anschließend wird jeweils ein harter und ein symbolischer Link zu dieser Datei erzeugt und die Anzahl von Links ausgegeben. Worauf der symbolische Link verweist, wird mit readlink() ebenso ausgegeben. Am Ende werden der harte und der symbolische Link mit unlink() gelöscht. Hier das Listing:
/* my_link.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd. h.> #define HARD_LINK "hard_link" #define SYM_LINK "sym_link" #define MAX 255 static int attribute( const char *name ) { struct stat st; if(stat(name , &st) < 0) { fprintf(stderr, "Fehler bei stat: %s\n", strerror(errno)); return -1; } printf("Anzahl Links : %d\n",st.st_nlink); return 1; } int main(int argc, char **argv) { const char *ptr; char buf[MAX]; int n; if(argc < 2) { printf("usage: %s datei\n", argv[0]); return EXIT_FAILURE; } ptr = argv[1]; /* Anzahl der Links erfragen */ if( attribute( ptr ) < 0) return EXIT_FAILURE; /* Einen harten Link erzeugen */ if((link(ptr, HARD_LINK)) == -1) { printf("Konnte keinen Hardlink erstellen\n"); return EXIT_FAILURE; } printf("Nach dem Funktionsaufruf von link()\n"); /* Wieder die Anzahl der Links erfragen */ if(attribute( ptr ) < 0) return EXIT_FAILURE; if((symlink(ptr, SYM_LINK)) == -1) { printf("Konnte keinen sym. Link erstellen\n"); return EXIT_FAILURE; } printf("Nach dem Funktionsaufruf von symlink()\n"); /* Wieder die Anzahl der Links erfragen */ if(attribute( ptr ) < 0) return EXIT_FAILURE; /* Namen anzeigen, worauf der symbolische Link verweist */ n=readlink(SYM_LINK, buf, MAX); printf("Der symbolische Link \"%s\" zeigt auf" " \"%.*s\"\n",SYM_LINK, n, buf); /* Links wieder entfernen */ unlink(HARD_LINK); unlink(SYM_LINK); return EXIT_SUCCESS; }
Das Programm bei der Ausführung:
$ gcc –o my_link my_link.c $ ./my_link test_file Anzahl Links : 1 Nach dem Funktionsaufruf von link() Anzahl Links : 2 Nach dem Funktionsaufruf von symlink() Anzahl Links : 2 Der symbolische Link "sym_link" zeigt auf "test_file"
Mit der Strukturvariablen st_size können Sie sich die Größe einer Datei in Bytes ermitteln lassen. Bei regulären Dateien erhalten Sie dabei die Anzahl von Bytes, die in die Datei geschrieben wurden. Diese Größe muss sich nicht auf den reinen physikalischen Speicherplatz beziehen, da dieser in der Regel immer ein Vielfaches der Blockgröße ist (Gleiches gilt auch umgekehrt, siehe den Abschnitt über ftruncate() in Kapitel 2). Bei Verzeichnissen ist der Wert abhängig vom Filesystem, und bei symbolischen Links enthält st_size die Länge in Bytes (nicht immer, siehe /proc/xxx/fd, wo alle 64 lang sind), die der Dateiname belegt (ohne abschließendes \0), auf den der symbolische Link verweist. In SVR4 enthält st_size außerdem bei den Pipes die Anzahl der zu lesenden Bytes.
|
Hinweis Der Speicherplatz wird bei einem Filesystem nicht in Bytes, sondern immer in Blöcken von Bytes angegeben. Die Blockgröße hängt vom Filesystem ab. In SVR4 und BSD haben Sie dabei die Möglichkeit, die beiden Strukturvariablen st_blocks und st_blksize, die in der Struktur stat definiert sind, zu verwenden. Aus der Multiplikation von st_blocks * st_blksize bekommen Sie dann den physikalischen Speicher, den das Dateisystem für die Datei wirklich belegt. Wollen Sie wissen, wie viele Blöcke eine Datei belegt, können Sie auch das Kommando du verwenden (oder st_blocks inspizieren). |
Hierzu ein Beispiel:
/* file_size.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd. h.> static int filesize( const char *name ) { struct stat st; if(stat(name , &st) < 0) { fprintf(stderr, "Fehler bei stat: %s\n", strerror(errno)); return -1; } printf("Größe in st_size : %d Bytes\n",(int)st.st_size); return 1; } int main(int argc, char **argv) { const char *ptr; if(argc < 2) { printf("usage: %s datei\n",argv[0]); return EXIT_FAILURE; } ptr = argv[1]; /* Größe der Datei abfragen */ if( filesize( ptr ) < 0) return EXIT_FAILURE; return EXIT_SUCCESS; }
Das Programm bei seiner Ausführung:
$ gcc –o file_size file_size.c $ ./file_size file_size.c Größe in st_size: 643 Bytes ---[Linux]--- $ du -h file_size.c 4,0K file_size.c ---[BSD]--- $ du -h file_size.c 2,0K file_size.c
Zur Demonstration, wie viel physikalischen Speicher die Datei (hier file_size.c) tatsächlich verwendet, wurde das Kommando du der Option -h verwendet.
Für Zeitdaten stehen Ihnen in der Struktur stat gleich drei Variablen zur Verfügung:
| st_atime = Zeit des letzten Lesezugriffs (dazu gehören nicht stat(), open()) |
| st_mtime = Zeit des letzten Schreibzugriffs |
| st_ctime = Zeit der letzten Inode-Änderung (z. B. chmod()) |
Und auch hierzu ein Listing:
/* file_times.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd. h.> #include <time.h> static int file_times(const char *name) { struct stat st; if(stat(name , &st) < 0) { fprintf(stderr, "Fehler bei stat: %s\n", strerror(errno)); return -1; } printf("Letzter Zugriff : %s", ctime( &st.st_atime )); printf("Letzte Änderung (Inhalt) :%s", ctime( &st.st_mtime )); printf("Letzte Änderung (Inode) : %s", ctime( &st.st_ctime )); return 1; } int main(int argc, char **argv) { const char *ptr; if(argc < 2) { printf("usage: %s datei\n",argv[0]); return EXIT_FAILURE; } ptr = argv[1]; /* Größe der Datei abfragen */ if( file_times( ptr ) < 0) return EXIT_FAILURE; return EXIT_SUCCESS; }
In diesem Beispiel wurde außerdem die Standardfunktion ctime() verwendet, die in der Headerdatei <time.h> definiert ist, womit aus dem Zeitformat time_t, aus dem die Strukturvariablen st_atime, st_mtime und st_ctime gebildet sind (primitive Datentypen), in einen String konvertiert wird. Hier das Programm bei der Ausführung:
$ gcc –o file_times file_times.c $ ./file_times file_times.c Letzter Zugriff : Tue Nov 4 23:28:36 2003 Letzte Änderung (Inhalt) : Fri Nov 7 00:10:36 2003 Letzte Änderung (Inode) : Tue Nov 4 23:28:36 2003 $ touch file_times.c $ ./file_times file_times.c Letzter Zugriff : Fri Nov 7 00:23:56 2003 Letzte Änderung (Inhalt) : Fri Nov 7 00:23:56 2003 Letzte Änderung (Inode) : Fri Nov 7 00:23:56 2003
Wollen Sie die Zugriffs- und/oder Modifikationszeit verändern, können Sie dies mit der Funktion utime() realisieren.
#include <sys/types.h> #include <utime.h> int utime(const char *pfad, const struct utimbuf *time_ptr);
Bei Erfolg gibt diese Funktion 0, ansonsten bei einem Fehler -1 zurück. Die Struktur utimbuf sieht wie folgt aus:
struct utime {
time_t actime; /* access time -> st_atime */
time_t modtime /* modification time -> st_mtime */
};
Damit können Sie die Zugriffs- und Modifikationszeit auf mindestens den 01. Januar 1970, 01:00:00 Uhr, zurücksetzen. In der Praxis:
/* backward.c */ #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd. h.> #include <utime.h> int main(int argc, char **argv) { const char *ptr; struct utimbuf zeit; if(argc < 2) { printf("usage: %s datei\n",argv[0]); return EXIT_FAILURE; } ptr = argv[1]; zeit.actime = 0; zeit.modtime =0; /* Größe der Datei abfragen */ if( utime( ptr, &zeit ) < 0) { perror("uptime"); return EXIT_FAILURE; } return EXIT_SUCCESS; }
Das Programm bei der Ausführung:
$ gcc –o backward backward.c $ ./file_times file_times.c Letzter Zugriff : Fri Nov 7 00:23:56 2003 Letzte Änderung (Inhalt) : Fri Nov 7 00:23:56 2003 Letzte Änderung (Inode) : Tue Nov 4 23:28:36 2003 $ ./backward file_times.c $ file_times file_times.c Letzter Zugriff : Thu Jan 1 01:00:00 1970 Letzte Änderung (Inhalt) : Thu Jan 1 01:00:00 1970 Letzte Änderung (Inode) : Tue Nov 4 23:28:36 2003
| << zurück |
|
||||||||||||
|
||||||||||||
|
||||||||||||
Copyright © Rheinwerk Verlag GmbH 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich
ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen,
wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist
urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der
Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und
Verarbeitung in elektronischen Systemen.