ein Kapitel zurück                                           ein Kapitel weiter

Den beiden Funktionen, stat und fstat wird die Adresse der Struktur struct stat zu übergeben. Dort werden dann entsprechende Attribute an der Variablen übergeben die sie mit Adresse die sie in dem Parameter übergeben haben. Hier erst mal der Syntax...

#include <sys/stat.h>    //LINUX/UNIX
#include <sys/types.h>    //LINUX/UNIX
#include <sys\stat.h>    //MS-DOS/WIN9x

int stat(const char *pfadname, struct stat *puffer);
int lstat(const char *pfadname, struct stat *puffer);
int fstat(int handle, struct stat *puffer);

Mit stat schreiben sie die Attribute mit dem Pfadname pfadname in die Strukturvariable *puffer Zum Beispiel...

struct stat attribut;
........................
stat("testprogramm.txt", &attribut);
.........................
if(attribut.st_mode & S_IFCHR) printf("Gerätedatei");
............................

Somit testen wir ob unsere Datei "testprogramm.txt" eine Gerätedatei ist. Die Funktion fstat funktioniert ganauso nur das sie eben anstatt des Pfadnamen den Handle oder Filedeskriptor handle übergeben (siehe Low-Level-Datei-I/O). Nun zum Inhalt der Struktur struct stat. Wobei auch hier anzumerken ist das wieder Unterschiede zu Linux/Unix und MS-Dos/Win vorhanden sind.

struct stat{
            short st_mode; /*Datei-/und Zugriffsrechte*/
            short st_ino;  /*i-node Nummer (nur Linux)*/
            short st_dev;  /*Laufwerk-/Gerätenummer*/
            short st_rdev; /*Gerätenummern für Gerätedateien*/
                           /*bei Dos das selbe wie st_dev*/
            short st_nlink;/*Anzahl der Links (Dos immer 1)*/
            int st_uid;    /*User-ID des Eigentümer (nur Linux)*/
            int st_gid;    /*Group-ID des Eigentümer (nur Linux)*/
            long st_size;  /*Größe in Bytes für normale Dateien*/
            long st_atime; /*Zeit letzter Zugriff*/
            long st_mtime; /*Zeit letzter Änderung*/
                           /*unter DOS Daselbe wie st_atime*/
            long st_ctime; /*Zeit letzter Änderung des i-node*/
                           /*bei DOS wie st_atime*/
           };

Kommen wir zu unserem ersten Parameter in der Struktur struct stat, nämlich...

short st_mode;

Diese Komponente der Struktur informiert sie über die Dateiart. Diese können sie ermitteln in dem sie mit dem bitweise UND (&) Operator den in st_mode gespeicherten Wert mit einer Konstante in der folgenden Tabelle verknüpfen....

Konstante Bedeutung
S_IFREG reguläre Datei
S_IFDIR Directory
S_IFCHR zeichenorientierte Gerätedatei
S_ISBLK blockorientierte Gerätedatei
S_ISFIFO Pipe oder FIFO
S_ISLINK symbolischer Link (nicht POSIX.1 oder SVR4)
S_ISSOCK Socket (nicht POSIX.1 oder SVR4)


Dies wollen wir nun in die Praxis umsetzen. Sie können wieder so viele Dateien in der Kommando-Zeile eingeben wie sie wollen und Abfragen ob es eine reguläre Datei (S_IFREG), eine zeichenorientierte Gerätedatei (S_IFCHR) oder eine Directory (S_IFDIR) ist....

/*Download:stat1.c*/
#include <stdio.h> #include <stdlib.h> #ifdef __unix__ #include <sys/stat.h> #include <sys/types.h> #elif __MSDOS__ #include <sys\stat.h> #endif int main(int argc, char *argv[]) { struct stat attribut; if(argc == 1) { printf("%s = ",*argv); if(stat(*argv, &attribut) == -1) { fprintf(stderr,"Fehler bei stat.....\n"); exit (1); } if(attribut.st_mode & S_IFREG) printf("Reguläre Datei\n"); else if(attribut.st_mode & S_IFDIR) printf("Directory\n"); else if(attribut.st_mode & S_IFCHR) printf("Gerätedatei\n"); else printf("Unbekannte Datei\n"); } else { while(*++argv) { printf("%s = ",*argv); if(stat(*argv, &attribut) == -1) { fprintf(stderr,"Fehler bei stat (2)...\n"); exit (1); } if(attribut.st_mode & S_IFREG) printf("Reguläre Datei\n"); else if(attribut.st_mode & S_IFDIR) printf("Directory\n"); else if(attribut.st_mode & S_IFCHR) printf("Gerätedatei\n"); else printf("Unbekannte Datei\n"); }/*Ende while*/ } return 0; }

Wenn sie jetzt eingeben (ich nenne das Programm einfach mal "attribut" ...

attribut programm.exe windows\temp attribut.c

...würden sie folgende Ausgabe bekommen....

programm.exe = Reguläre Datei
windows\temp = Directory
attribut.c = Reguläre Datei

Unter Linux/Unix funktioniert das selbe genauso. Zuerst übergeben wir eine Variable...

if(stat(*argv, &attribut) == -1)

...*argv als Namen oder Pfad der Datei an unsere Struktur attribut. Anschließend erfragen wir die Attribute mittels.....

if(attribut.st_mode & S_IFREG)
    printf("Reguläre Datei\n");
else if(attribut.st_mode & S_IFDIR)
    printf("Directory\n");
else if(attribut.st_mode & S_IFCHR)
    printf("Gerätedatei\n"); else
    printf("Unbekannte Datei\n"); 

...ab um was für eine Art es sich um *argv handelt. Nun kann man mit dem Parameter st_mode in der Struktur stat die Zugriffsrechte auf die Datei abfragen. Dies funktioniert genauso wie mit der Abfrage der Dateiart wie eben im Programm gemacht. Auch hier Verknüpft man mit dem Bitweisen UND (&) Operator folgende Konstanten unter UNIX/LINUX.....

Konstante Bedeutung
S_IRUSR read(user; Leserecht für Eigentümer)
S_IWUSR write(user; Schreibrecht für Eigentümer)
S_IXUSR execute(user; Ausführrecht für Eigentümer)
S_IRGRP read(group; Leserecht für Gruppe)
S_IWGRP write(group; Schreibrecht für Gruppe)
S_IXGRP execute(group; Ausführungsrecht für Gruppe)
S_IROTH read(other; Leserecht für alle anderen Benutzer)
S_IWOTH write(other; Schreibrecht für alle anderen Benutzer)
S_IXOTH execute(other; Ausführungsrecht für alle anderen Benutzer)


Und unter MS-DOS/WIN gibt es nur folgende 2 Möglichkeiten...

Konstante Bedeutung
S_IWRITE nur schreiben
S_IREAD nur lesen


/*Download:stat2.c*/
#include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> int main(int argc, char *argv[]) { struct stat attribut; int i; char l_rwx[10]; char rwx[] = "rwxrwxrwx"; int bits[] = { S_IRUSR, S_IWUSR, S_IXUSR, /*Zugriffsrechte User*/ S_IRGRP, S_IWGRP, S_IXGRP, /*Zurgriffrechte Gruppe*/ S_IROTH, S_IWOTH, S_IXOTH };/*Zugriffrechte der Rest*/ while(*++argv) /*Einzelne Argumente durchlaufen*/ { l_rwx[0]='\0'; printf("%18s = ",*argv); if(stat(*argv, &attribut) == -1) { fprintf(stderr,"Fehler bei stat?!?...\n"); exit (1); } for(i=0; i<9; i++) { if(attribut.st_mode & bits[i]) /*Wenn nicht 0 dann gesetzt*/ l_rwx[i]=rwx[i]; /*r,w oder x*/ else l_rwx[i] = '-'; /*wenn nicht gesetzt dann '-'*/ } l_rwx[9]='\0'; printf("%s\n",l_rwx); }/*Ende while*/ return 0; }

Hier eine simple Methode wie sie die Zugriffrechte einer Datei oder eines Verzeichnisses Linux-Gewohnt ausgeben können. Für MS-DOS/Win kann ich mir ein Programm getrost sparen da es dafür nur 2 Zugriffsrechte gibt.....

if(attribut.st_mode & S_IREAD)
 { /*Datei darf nur gelesen werden*/ }
else if(attribut.st_mode & S_IWRITE)
 { /*Datei darf beschrieben werden*/ }

Wollen sie hingegen bei Linux die oktale Darstellung der Zugriffsrechte haben können sie dies folgendermaßen machen......

/*Download:stat3.c*/
#include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> int main(int argc, char *argv[]) { struct stat attribut; while(*++argv) /*Einzelne Argumente durchlaufen*/ { printf("%18s = ",*argv); if(stat(*argv, &attribut) == -1) { fprintf(stderr,"Fehler bei stat?!?...\n"); exit (1); } printf("%o\n", attribut.st_mode & 0777); }/*Ende while*/ return 0; }

Kommen zu einem weiteren Parameter in der Struktur struct stat. Dieses mal geht es um Größe einer Datei in Bytes. Dafür haben wir st_size. Den Wert erhalten sie aber nur für Regulären Dateien und Directorys (bei MS-Dos immer 0 bei Directorys). Beim Filesystem werden nicht die einzelnen Bytes angegeben sondern immer Blöcke von Bytes. Typische Blockgrößen sind 512 oder 1024 Bytes. Das heißt die Ausgabe von st_size gibt nicht den physikalischen Speicher einer Datei aus den diese wirklich belegt. Das folgende Programm gibt die Größe aller Dateien auf dem Bildschirm aus die sie in der Kommando-Zeile angeben.

/*Download:stat4.c*/
#include <stdio.h> #include <stdlib.h> #ifdef __unix__ #include <sys/stat.h> #include <sys/types.h> #elif __MSDOS__ #include <sys\stat.h> #endif int main(int argc, char *argv[]) { struct stat attribut; unsigned long sizeofall=0; if(argc == 1) { if(stat(*argv, &attribut) == -1) { fprintf(stderr,"Fehler bei stat....\n"); exit (1); } else { printf("Größe von %s = %ld Bytes\n",*argv,attribut.st_size); exit (1); } } else { while(*++argv) { if(stat(*argv, &attribut) == -1) { fprintf(stderr,"Fehler bei stat....\n"); exit (1); } else { printf("Größe von %s = %ld Bytes\n",*argv,attribut.st_size); sizeofall+=attribut.st_size; } }/*Ende while*/ }/*Ende else*/ printf("Größe aller Dateien in der Kommandozeile = %ld Bytes",sizeofall); printf("= %ld KB\n",sizeofall/=1024); return 0; }

Hiermit werden alle Programme die sie in der Kommandozeile eingeben mit deren Größe ausgegeben. Wie gesagt unter DOS funktioniert es nicht die Größe einer Directory zu erhalten. Bei Unix/Linux hingegen schon da dort Directorys wie normale Dateien gehandhabt werden.

Nun kommen wir zu weiteren 3 Parametern der Struktur struct stat. Und zwar geht es um die Zeiten einer Datei....

st_atime = Zeit des letzten Zugriffs
st_mtime = Zeit der letzten Änderung des Dateiinhalts
st_ctime = Zeit der letzten i-node Änderung 

Diese 3 gelten aber nur für UNIX/Linux. Unter MS-DOS bedeuten alle 3 Dasselbe. Nämlich wann die Datei das letzte mal geändert wurde. Dazu wollen wir auch wieder ein kleines Beispiel schreiben. Der Ablauf des Programms ist wieder derselbe wie zuvor bei den Anderen Programmen oben. Alle Dateien die sie in der Kommando-Zeile eingeben geben zurück die Zeit des letzten Zugriffs und die Zeit der letzten Änderung. Bei DOS wird nur 2x die Zeit der letzten Änderung ausgegeben, da wie schon eben besprochen, bei DOS alle 3 Parameter Dasselbe bewirken. Hier das Programm...

/*Download:stat5.c*/
#include <stdio.h> #include <stdlib.h> #ifdef __unix__ #include <sys/stat.h> #include <sys/types.h> #elif __MSDOS__ #include <sys\stat.h> #endif int main(int argc, char *argv[]) { struct stat attribut; unsigned long sizeofall=0; if(argc == 1) { if(stat(*argv, &attribut) == -1) { fprintf(stderr,"Fehler bei stat....\n"); exit (1); } else { printf("Größe von %s = %ld Bytes\n",*argv,attribut.st_size); printf("letzter Zugriff : %s",ctime(&attribut.st_atime)); printf("letzte Aenderung: %s",ctime(&attribut.st_mtime)); exit (1); } } else { while(*++argv) { if(stat(*argv, &attribut) == -1) { fprintf(stderr,"Fehler bei stat....\n"); exit (1); } else { printf("Größe von %s = %ld Bytes\n",*argv,attribut.st_size); printf("letzter Zugriff : %s",ctime(&attribut.st_atime)); printf("letzte Aenderung: %s\n",ctime(&attribut.st_mtime)); sizeofall+=attribut.st_size; } }/*Ende while*/ }/*Ende else*/ printf("Größe aller Dateien in der Kommandozeile = %ld Bytes",sizeofall); printf("= %ld KB\n",sizeofall/=1024); return 0; }

Ich habe mir erlaubt das Programm mit dem Vorherigen zu vermischen. Somit bekommen sie gleichzeitig die Größe der Dateien inklusive der letzten Änderung und bei Linux/Unix des letzten Zugriffes auf die Datei. Sie merken schon das der Zugriff auf die Struktur struct stat immer der selbe ist.

Unter Linux läßt sich mit Hilfe von st_atime und st_mtime beim Kopieren einer Datei verhindern, das diese beiden Werte verändert werden. Gemeint ist damit wenn sie eine Datei mit cp Kopieren werden ja alle drei Werte auf das aktuelle Datum gesetzt. Wollen sie hingegen das Datum des Orginals erhalten, dann können sie folgendermaßen vorgehen...........

/*Download:stat6.c*/
#include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <utime.h> #include <fcntl.h> int main(int argc, char *argv[]) { FILE *q,*z; struct stat attribut; char buf[1024]; int i; struct utimbuf zeit; /*Siehe Funktion utimes()*/ if(stat(argv[1],&attribut) < 0) { fprintf(stderr, "Fehler bei stat.......\n"); exit(0); } zeit.actime = attribut.st_atime; zeit.modtime= attribut.st_mtime; q=fopen(argv[1],"r"); z=fopen(argv[2],"w"); if(q == NULL || z == NULL) { fprintf(stderr,"Fehler bei fopen.....\n"); exit(0); } while( (i=fread(buf, 1, 1024, q)) > 0 ) fwrite(buf, 1, i, z); /*Wichtig!!! Ohne den Stream zu schließen wird die aktuelle Zeit verwendet, da die Datei erst nach return 0 beendet wird*/ fclose(q);fclose(z); /*Jetzt die Zeit von quelle in ziel eintragen*/ if(utime(argv[2], &zeit) < 0) printf("FEHLER\n"); return 0; }

Sie können eine Datei ja erst mal mittels cp kopieren und die Zeiten mit ls -l , ls -lu , ls -lc ansehen. Anschließend kopieren sie diese Datei mit unserem Programm (Um das Programm kürzer zu halten habe ich auf einige Fehlerüberprüfungen verzichtet) und sehen sich nochmals die Zeiten an. Sollten sie in diesem Programm fclose nicht, oder nach der Funktion utime verwenden, wird wieder die aktuelle Zeitangabe gemacht, da dies den letzten Zugriff dastellt.

Um Herauszufinden wer der Eigentümer und der Gruppeneigentümer einer Datei ist, haben wir die Variablen st_uid (Eigentümer) und st_gid (Gruppeneigent.).

/*Download:stat7.c*/
#include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> int main(int argc, char *argv[]) { struct stat attribut; while(*++argv) { if(stat(*argv,&attribut) < 0) { fprintf(stderr, "Fehler bei stat.......\n"); exit(0); } printf("\n%18s\n",*argv); printf("USER-ID : %d\n",attribut.st_uid); printf("GROUP-ID : %d\n\n",attribut.st_gid); } return 0; }

Weiter Info zu einer Datei (Linux) finden sie noch mit den Variablen st_nlink (Anzahl der Links) und st_ino (Inode Nummer der Datei). Auch hierzu ein kurzes Beispiel...

/*Download:stat8.c*/
#include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> int main(int argc, char *argv[]) { struct stat attribut; while(*++argv) { if(stat(*argv,&attribut) < 0) { fprintf(stderr, "Fehler bei stat.......\n"); exit(0); } printf("\n%18s\n",*argv); printf("Anzahl Links : %d\n",attribut.st_nlink); printf("Inode Nummer : %d\n\n",attribut.st_ino); } return 0; }

Jetzt nur noch zwei weitere Parameter von struct stat. Danach wollen wir es mit diesem Thema belassen. Nun geht es um das Thema Gerätedateien. Dazu stellt uns die Struktur struct stat zwei Parameter zu Verfügung. Bei MS-DOS haben beide wieder die selbe Bedeutung. Und zwar handelt es sich um...

st_dev = enthält für jeden Dateinamen die Gerätenummer des Filesystems, in dem sich diese Dateien und ihr zugehöriger i-node befindet. (DOS und UNIX).

st_rdev = hat nur für zeichen-/und blockorientierte Gerätedateien einen definierten Wert, nämlich die Gerätenummer des zugeordneten Gerätes. Die majornummer leget den Gerätetyp fest während die minornummer die den entsprechenden Gerätetreiber übergeben wird, zur Unterscheidung von verschiedenen Geräten des gleichen Typs dient. (nur UNIX/LINUX)

Beispiel-Programm (nur für MS-DOS, nicht im DOS-Fenster betreiben, kein aktives Windows). Sie können in diesem Programm so viele Dateien in der Kommandozeile eingeben wie sie wollen. Das Programm liefert Ihnen dann zu den angegebenen Dateinamen den Laufwerksnamen zurück...

/*Download:stat9.c*/
#include <stdio.h> #include <stdlib.h> #include <sys\stat.h> int main(int argc, char *argv[]) { struct stat laufwerknr; if(argc==1) { fprintf(stderr,"usage : %s Datei1 Datei2 Datei3 .... \n"); exit (1); } while(*++argv) { printf("%s = Laufwerk : ",*argv); if(stat(*argv, &laufwerknr) == -1) fprintf(stderr,"..Fehler bei stat...!\n"); else printf("%c (%d)\n",laufwerknr.st_dev+'A',laufwerknr.st_dev); } return 0; }

Das Programm funktioniert wie bisher bei allen anderen oben ausgeführten Programme. Erklären möchte ich folgendes...

laufwerknr.st_dev+'A'

Da unser PC intern die Laufwerke nicht wie wir mit...

A:\ = 1. Diskettenlaufwerk
B:\ = 2. Diskettenlaufwerk
C:\ = 1.Fesplatte
D:\ = 2.Festplatte oder CD-ROM-Laufwerk
................usw bis Z:\ falls vorhanden 

...erkennt sondern mit Nummern wie....

0 = 1. Diskettenlaufwerk
1 = 2. Diskettenlaufwerk
2 = 1.Fesplatte
3 = 2.Festplatte oder CD-ROM-Laufwerk

...rechnen wir einfach die Dezimale Ziffer 0+'A', da das Zeichen 'A' intern für den Wert 65 steht (siehe ASCII-Tabelle) und wir anschließend auch das Formatzeichen char für 65 (%c = char) ausgeben. Somit bekommen wir z.B. für das Laufwerk 2 den Buchstaben C zurück (2+'A' = 67 (67 = 'C')). Nur soviel dazu nicht das sie denken dieses +'A' sei irgend etwas magisches. Wenn sie unser Programm jetzt starten mittels....

st_dev a:\programm.exe c:\programm2.exe d:\programm3.exe

...bekommen sie folgende Ausgabe...

programm.exe = Laufwerk : A (0)
programm2.exe = Laufwerk : C (2)
programm3.exe = Laufwerk : D(3)

Nun benötigen wir noch das Beispiel für UNIX/LINUX...

/*Download:stat10.c*/
#include <sys/sysmacros.h> #include <sys/stat.h> #include <stdlib.h> #include <stdio.h> int main(int argc, char *argv[]) { struct stat statpuffer; if(argc==1) { fprintf(stderr,"usage: %s Datei1 Datei2 ......\n",*argv); exit (1); } while(*++argv) { printf("%s: ",*argv); if(stat(*argv, &statpuffer) == -1) fprintf(stderr,"Fehler bei stat...\n"); else { printf("dev = %2d/%2d",major(statpuffer.st_dev), minor(statpuffer.st_dev)); if(S_ISCHR(statpuffer.st_mode)||S_ISBLK(statpuffer.st_mode)) { printf("-> rdev = %2d/%2d (%s", major(statpuffer.st_rdev),minor(statpuffer.st_rdev), (S_ISCHR(statpuffer.st_mode)) ?"zeichen":"block"); printf("orientiert"); } } printf("\n"); }/*Ende while*/ return 0; }

Vielleicht noch ein Wort zu dieser Zeile....

if(S_ISCHR(statpuffer.st_mode)||S_ISBLK(statpuffer.st_mode))

Hiermit überprüfen wir ob es sich um eine Zeichenorientierte (S_ISCHR) oder eine Blockoritientierte (S_ISBLK) Gerätedatei handelt. Wenn ja gibt es eben die dementsprechende Ausgabe.

Der Unterschied von stat und lstat ist falls der Pfadname ein symbolischer Link ist schreibt lstat die Attribute des symbolischen Links selbst und nicht die der Datei, auf die der symbolische Link zeigt, in '*puffer'.

fstat erwartet anstatt eines 'pfadnamens' einen Filedeskriptor einer Datei die sie mit der Funktion open() geöffnet haben (siehe Low-Level-Datei-I/O).

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf