Themen, wie das ermitteln von Eigenschaften einer Datei oder das öffnen eines Verzeichnisses sind Systemabhänging. Denn jedes Betriebssystem verwaltet Dateien und Verzeichnisse anders. Daher wird oftmals in Büchern auf dieses Thema völlig verzichtet. In diesem Kapitel soll versucht werden, dieses Thema so global wie Möglich zu behandeln. C C++ C/C++ Verzeichnis Verzeichnisse Attribute von Dateien Zugriffsrechte stat fstat Arbeitsverzeichis stat fstat Verzeichnis Verzeichnisse Attribute von Dateien Zugriffsrechte stat fstat Arbeitsverzeichis Kapitel 20: Attribute von Dateien und Arbeiten mit Verzeichnissen

Themen, wie das Ermitteln der Eigenschaften einer Datei oder das Öffnen und Auslesen eines Verzeichnisses, sind systemabhängig. Denn jedes Betriebssystem verwaltet Dateien und Verzeichnisse auf andere Art. Daher wird in Büchern oft auf dieses Thema verzichtet. In diesem Kapitel soll versucht werden, dieses Thema so universell wie möglich zu behandeln.

20.1. Attribute einer Datei ermitteln-stat()            zurück  Ein Kapitel tiefer  zum Inhaltsverzeichnis

Der Funktion stat()wird die Adresse der Struktur struct stat übergeben. Aus dieser Struktur können die Attribute der Datei ausgelesen werden. Hierzu die Syntax:

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

int stat(const char *pfad, struct stat *puffer);

Mit stat() werden somit die Attribute der Datei ,welche Sie mit pfad angeben, in die Adresse der Strukturvariable puffer geschrieben. Ein Beispiel:

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

Hiermit wird getestet, ob die Datei "testprogramm.txt" eine Gerätedatei ist.

Es folgt eine Auflistung der einzelnen Variablen der Struktur struct stat, worin sich die jeweiligen Attribute zu einer Datei befinden. Wobei wiederum anzumerken ist, dass es Unterschiede zwischen Linux/UNIX und MS-DOS/Windows gibt. Hier die einzelnen Elemente der Struktur stat:

Variable Bedeutung
st_dev Gerätenummer (Device-Nummer) des Dateisystems
st_ino Inode-Nummer (nur Linux)
st_mode Dateimodus (Dateityp und Zugriffsrechte)
st_nlink Anzahl fester Links auf die Datei (bei MS-DOS/Windows immer 1)
st_uid Numerische UID des Dateieigentümers
st_gid Numerische GID des Dateieigentümers
st_rdev Geräte-ID (nur für Spezialdateien) (bei MS-DOS/Windows st_dev)
st_size Größe der Datei in Bytes
st_atime Datum des letzten Zugriffs
st_mtime Datum der letzten Veränderung (bei MS-DOS/Windows st_atime)
st_ctime Datum der Inode-Änderung (bei MS-DOS/Windows st_atime)

Tabelle 20.1: Bedeutung der einzelnen Strukturvariablen in stat

20.1.1 stat() - st_mode
Mit dem Strukturelement short st_mode in der Struktur stat können Sie die Dateiart erfragen. Dies funktioniert, in dem der bitweise UND-Operator (&) und der in st_mode gespeicherte Wert mit einer der folgenden Konstanten verknüpft wird:

Konstante Bedeutung
S_IFREG Reguläre Datei
S_IFDIR Verzeichnis
S_IFCHR Zeichenorientierte Gerätedatei
S_ISBLK Blockorientierte Gerätedatei
S_ISFIFO Pipe oder FIFO
S_ISLINK Symbolischer Link (nicht bei POSIX.1 oder SVR4)
S_ISSOCK Socket (nicht bei POSIX.1 oder SVR4)

Tabelle 20.2: Dateimodus (Dateityp erfragen)

POSIX schreibt diese Konstanten allerdings nicht vor. Bei Linux/UNIX-Systemen könnten diese Konstanten auch als entsprechende Makros in der Headerdatei <sys/stat.h> implementiert sein. Der Makroname entspricht dabei dem Konstantennamen (S_IFREG(), S_IFDIR(), S_IFCHR(), S_ISBLK(), S_ISFIFO(), S_ISLINK() und S_ISSOCK()). Alle diese Makros geben 1 zurück, wenn Entsprechendes zutrifft, ansonsten 0.

Im folgenden Listing können Sie über Argumente aus der Kommandozeile beliebig viele Dateien dahingehend abfragen, ob es sich um eine reguläre Datei (S_IFREG), eine zeichenorientierte Gerätedatei (S_IFCHR) oder ein Verzeichnis (S_IFDIR) handelt. Hier das Listing:

#include <stdio.h>
#include <stdlib.h>
#ifdef __unix__
      #include <unistd.h>
      #include <sys/stat.h>
      #include <sys/types.h>
#else
      #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;
}

Abbildung 20.1: Erfragen der Dateiart mit st_mode
Abbildung 20.1: Erfragen der Dateiart mit st_mode

Zuerst werden in der Schleife mit

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

die Attribute der Datei *argv in die Adresse der Strukturvariable attribut geschrieben. Anschließend werden einige Attribute mit den folgenden Zeilen abgefragt, um zu ermitteln, um welche Dateiart es sich hierbei handelt.

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");

Danach fährt die Programmausführung mit dem nächsten Argument in der Kommandozeile fort.

Wenn sich das Listing bei Ihnen nicht übersetzen lässt und Sie unter Linux/UNIX arbeiten, sollten Sie es mit den entsprechenden Makros probieren:

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

Mit dem Strukturelement st_mode in der Struktur stat lassen sich die Zugriffsrechte einer Datei ebenfalls abfragen. Dies funktioniert genauso wie bei der Abfrage der Dateiart. Zudem müssen Sie den bitweisen UND-Operator (&) mit einer der unter Linux/UNIX vorgegebenen Konstanten verknüpfen:

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)

Tabelle 20.3: Dateimodus (Rechte erfragen) (Linux/Unix)

Bei MS-DOS/Windows gibt es zum Erfragen der Zugriffsrechte die folgenden Möglichkeiten:

Konstante Bedeutung
S_IWRITE nur Schreibrecht
S_IREAD nur Leserecht
S_IEXEC Ausführen erlaubt bzw. Verzeichnis durchsuchen erlaubt

Tabelle 20.4: Dateimodus (Rechte erfragen) (MS-DOS/Windows)

Hierzu ein Beispiel für Linux/UNIX:

#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,/*Zugriffsrechte 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 (0);
            }
         for(i=0; i<9; i++)
            { /*Wenn nicht 0, dann gesetzt*/
               if(attribut.st_mode & bits[i])
                  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;
}

Abbildung 20.2: Ausgabe der Zugriffsrechte unter Linux/UNIX
Abbildung 20.2: Ausgabe der Zugriffsrechte unter Linux/UNIX

Dieses Listing stellt eine einfache Methode dar, wie die Zugriffsrechte einer Datei oder eines Verzeichnisses Linux-gewohnt ausgegeben werden können. Bei MS-DOS/Windows könnnen Sie so vorgehen:

if(attribut.st_mode & S_IREAD)
 { /*Datei darf nur gelesen werden*/ }
else if(attribut.st_mode & S_IWRITE)
 { /*Datei darf beschrieben werden*/ }
else if(attribut.st_mode & S_IEXEC)
 { /* Datei ist eine ausführbare (bsp. *.exe */ }

Wird hingegen bei Linux/UNIX die oktale Darstellung der Zugriffsrechte benötigt, können Sie dies folgendermaßen erreichen:

#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;
}

20.1.2 stat() - st_size
Nun ein weiterer Parameter der Struktur stat. Um die Größe einer Datei in Bytes zu ermitteln, kann die Strukturvariable st_size verwendet werden. Ein Wert wird aber nur für reguläre Dateien und Verzeichnisse (bei MS-DOS/Windows 0 für Verzeichnisse) zurückgegeben. Beim Filesystem werden dabei nicht die einzelnen Bytes angegeben, sondern immer ganze Blöcke von Bytes. Typische Blockgrößen sind 512 oder 1024 Bytes. Das bedeutet, die Variable 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 Kommandozeile angeben.

#include <stdio.h>
#include <stdlib.h>
#ifdef __unix__
      #include <sys/stat.h>
      #include <sys/types.h>
#else
      #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;
}

Abbildung 20.3: Größe von Dateien mit st_size ermitteln
Abbildung 20.3: Größe von Dateien mit st_size ermitteln

Wie bereits erwähnt, unter Windows/MS-DOS gelingt es nicht, die Größe eines Verzeichnisses zu erhalten. Bei UNIX/Linux hingegen schon, da Verzeichnisse hier wie normale Dateien behandelt werden.

20.1.3 stat() - st_atime, st_mtime und st_ctime
Um spezielle Zeitdaten einer Datei abzufragen, befinden sich in der Struktur stat folgende Variablen:



Hinweis
 

Mit einer Inode werden unter Linux/UNIX Verwaltungsinformationen von den eigentlichen Daten getrennt gespeichert. Diese Inode-Informationen sind dabei Merkmale wie Zugriffszeit, Rechte, Größe und weitere Angaben. Die einzige Information, die nicht zur Inode gehört, ist der Name der Datei.

Die Unterscheidung dieser drei Zeitattribute trifft nur für Linux/UNIX zu. Bei MS-DOS/Windows bedeuten alle drei Zeiten dasselbe; nämlich, wann die Datei das letzte Mal geändert wurde. Dazu ein Beispiel: Von allen Dateien, die Sie in der Kommandozeile eingeben, wird die Zeit des letzten Zugriffs und die Zeit der letzten Änderung ausgegeben. Hier das Listing:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#ifdef __unix__
      #include <sys/stat.h>
      #include <sys/types.h>
#else
      #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;
}

Abbildung 20.4: Abfragen verschiedener Zeitdaten unter Linux
Abbildung 20.4: Abfragen verschiedener Zeitdaten unter Linux

Das Programm wurde mit dem vorherigen Beispiel vermischt. Auf diese Weise wird gleichzeitig die Größe der Datei inklusive der letzten Änderung und des letzten Zugriffs auf die Datei ausgegeben.

Unter Linux lässt sich außerdem mithilfe der Variablen st_atime und st_mtime beim Kopieren einer Datei verhindern, dass diese beiden Werte verändert werden. Gemeint ist damit, wenn Sie eine Datei bspw. mit cp kopieren, werden normalerweise alle drei Werte auf das aktuelle Datum gesetzt. Wollen Sie das Datum des Originals erhalten (letzter Zugriff und Änderung des Inhalts), können Sie folgendermaßen vorgehen:

#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;
}

Kopieren Sie einmal eine Datei mittels cp und sehen Sie sich die Zeiten mit ls -l , ls -lu und ls -lc an. Bei der Überprüfung der Zeitangabe werden Sie feststellen, dass alle drei Zeitdaten auf dieselbe Zeit gesetzt wurden.

Wiederholen Sie dies nun mit dem eben geschriebenen Programm. Bei einem erneuten Blick auf die Zeitdaten sind die Variablen st_atime und st_mtime jetzt identisch mit der Originaldatei. Hätten Sie in diesem Listing fclose() nicht oder erst nach der Funktion utime() verwendet, so würde wieder der aktuelle Zeitstempel gesetzt, da dies den letzten Zugriff darstellt.

Wollen Sie herausfinden, welche von zwei Dateien älter ist, können Sie dies mit der Strukturvariable st_mtime ermitteln:

#include <sys/stat.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

time_t st_mTime(char *name)
{
   struct stat s;
   if (stat(name, &s))
      {
         perror(name);
         exit(0);
      }
   return s.st_mtime;
}

int main(int argc, char **argv)
{
   time_t t1, t2;

   if (argc==3)
      {
         t1=st_mTime(argv[1]),
         t2=st_mTime(argv[2]);
         if(t1 != t2)
            printf("%s ist %s wie %s\n"
                 ,argv[1],(t1>t2?"neuer":"älter"),argv[2]);
         else
            printf("Beide Dateien sind gleich alt\n");
      }
   else
      fprintf(stderr, "Verwendung %s datei1 datei2\n",argv[0]);
   return 0;
}

In diesem Listing wurde die Headerdatei <time.h> verwendet, um den Rückgabetyp time_t zu verwenden. Zu dieser Headerdatei finden Sie im Buch noch einen eigenen Abschnitt in Kapitel 22, Zeitroutinen.

20.1.4 stat() - st_gid und st_uid
Um herauszufinden, wer der Eigentümer und der Gruppeneigentümer einer Datei ist, können Sie sich der Variablen st_uid (Eigentümer) und st_gid (Gruppeneigentümer) bedienen. Hierzu das Listing:

#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;
}

20.1.5 stat() - st_nlink, st_ino
Weitere Informationen zu einer Datei unter Linux lassen sich mit den Variablen st_nlink (Anzahl der Links) und st_ino (Inode-Nummer der Datei) ausgeben.

#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;
}

20.1.6 stat() - st_dev, st_rdev
Die Strukturvariablen st_dev und st_rdev sind recht nützlich für Gerätedateien. Bei MS-DOS/Windows haben beide Variablen dieselbe Bedeutung:

Ein Beispielprogramm nur für MS-DOS/Windows. Das Programm liefert zu angegebenen Dateinamen den Laufwerksnamen zurück:

#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",*argv);
         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;
}

Abbildung 20.5: Ermittlung des Laufwerks, in welchem sich die Datei befindet
Abbildung 20.5: Ermittlung des Laufwerks, in welchem sich die Datei befindet

Ein kurze Erklärung zu

laufwerknr.st_dev + 'A'  

Da der PC die Laufwerke nicht - wie Sie es gewohnt sind - mit

A:\ = 1. Diskettenlaufwerk
B:\ = 2. Diskettenlaufwerk
C:\ = 1.Festplatte
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.Festplatte
3 = 2.Festplatte oder CD-ROM-Laufwerk

wurde einfach die dezimale Ziffer 0 + 'A' hinzuaddiert. Dies gelingt daher, weil das Zeichen 'A' intern für den Wert 65 steht (siehe ASCII-Tabelle) und anschließend auch das Formatzeichen char für 65 (%c = char) ausgegeben wird. Somit wird z.B. für das Laufwerk 2 der Buchstabe C zurückgegeben (2+'A' = 67; ASCII-codiert = 'C').

Das Beispiel dazu für Linux/UNIX:

#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 (0);
      }

   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 wird überprüft, ob es sich um eine zeichenorientierte (S_ISCHR) oder eine blockorientierte (S_ISBLK) Gerätedatei handelt. Wenn ja, erfolgt eine dementsprechende Ausgabe.

20.2. Prüfen des Zugriffrechtes - access            zurück  Ein Kapitel höher  zum Inhaltsverzeichnis

Mit der Funktion access() können Sie feststellen, ob ein Prozess bestimmte Berechtigungen für den Zugriff auf eine Datei hat. Die Syntax zur Funktion access() lautet:

#include <unistd.h>  /* für UNIX/LINUX */
#include <io.h>      /* für MS-DOS */

int access(const char *pfad, int modus);

So wird überprüft, ob der pfad der Datei existiert und die Zugriffsrechte modus besitzt. Folgende Zugriffsrechte (Modus) existieren:

modus Bedeutung
00 oder F_OK Datei existiert
01 oder X_OK Datei ausführbar (nur Linux/UNIX)
02 oder W_OK Datei beschreibbar
04 oder R_OK Datei lesbar
06 oder W_OK|R_OK Datei lesbar und beschreibbar

Tabelle 20.5: Modi zum Prüfen des Zugriffsrechts

Bei Erfolg gibt diese Funktion den Wert 0 zurück, ansonsten bei Fehler -1. Das folgende Listing überprüft die Zugriffsrechte aller in der Kommandozeile eingegebenen Programme mit der Funktion access():

#ifdef __unix__
    #include <unistd.h>
    #define EXIST F_OK
    #define EXEC  X_OK
    #define WRITE W_OK
    #define READ  R_OK
#else
    #include <io.h>
    #define EXIST 00
    #define EXEC  01
    #define WRITE 02
    #define READ  04
#endif
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
   if(argc == 1)
      {
         fprintf(stderr,"Mindestens eine Datei angeben!\n");
         exit (0);
      }

   while(*++argv)
      {
         printf("%s : \n",*argv);
            /*Existiert die Datei?*/
            if(access(*argv, EXIST) != -1)
               { /*Lesen und Schreiben nicht erlaubt*/
                  if(access(*argv, WRITE|READ) == -1)
                     {
                        /*Nur lesen?*/
                        if(access(*argv, READ) != -1)
                           printf("...ist lesbar\n");
                        /*Nur schreiben?*/
                        else if(access(*argv, WRITE) != -1)
                           printf("...ist schreibbar\n");
                     }
                  else
                     printf("ist Lesen und schreiben erlaubt\n");
                  /*Datei ausführbar?*/
                  if(access(*argv, EXEC) != -1)
                     printf("...ist ausführbar\n");
               }
            else
               fprintf(stderr,"...existiert nicht\n");
      } /*Ende while*/
   return 0;
}

Zuerst wird überprüft, ob die Datei überhaupt existiert:

if(access(*argv, EXIST) != -1) 

Ob die Datei zum Lesen und Schreiben freigegeben ist, wird anschließend mit der folgenden Zeile überprüft:

if(access(*argv, WRITE|READ) != -1)

Trifft dies nicht zu, werden die einzelnen Zugriffsmöglichkeiten getestet:

if(access(*argv, READ) != -1)
   printf("...ist lesbar\n");
else if(access(*argv, WRITE) != -1)
   printf("...ist schreibbar\n");

Die Überprüfung, ob die Datei ausführbar ist

if(access(*argv, EXEC) != -1) 

kann bei Windows/MS-DOS entfernt werden, da sie nur unter UNIX/Linux einen Sinn ergibt. In diesem Listing wurden die Konstanten der einzelnen Zugriffsrechte hinter Makros versteckt, damit das Programm möglichst portabel bleibt. Unter Linux/UNIX werden übrigens nur die ersten drei User-Bits UID überprüft (rwx), also die Zugriffsrechte des Datei-Eigentümers. Es ist auch möglich, access() mit mehreren Konstanten zu verknüpfen:

if( (access(*argv,F_OK|R_OK) ) != -1)
/* if( (access(*argv,00|04) ) != -1) */

Hier wird z.B. ermittelt, ob die Datei existiert und ob für sie Leserechte vorhanden sind.

Weiter mit 20.3. Verzeichnis-Funktionen            zum Inhaltsverzeichnis