/* 03Jul24: Beispiel für das Auslesen der Einträge in einem * Verzeichnis (opendir+readdir+closedir) und dem Abfragen von * Metadaten einer Datei (stat+lstat). * * Idee: Gebe alle symbolischen Verweise in dem jetzigem Verzeichnis * aus. */ #include #include #include #include #include #include #include int main() { /* Mit opendir(2) bekommen wir ein "undurchsichtiges" Objekt, was * als "Strom an Dateien" aus einem Verzeichnis interpretiert * werden kann, genau wie man mit fopen(3) ein "Strom an Bytes" * bekommt. */ DIR *dir = opendir("."); struct dirent *ent; for (;;) { /* Die Fehlerbehandlung von readir(2) muss unterschieden * zwischen einem "echtem" Fehler und dem Ende des * Verzeichnisses. Bei FILE* konnte man da `feof' und * `ferror' benutzen, was aber vom Betriebsystem nicht * angeboten wird für DIR*. Stattdessen, gibt readdir(2) * vor, dass es `errno' /nicht/ setzen wird, wenn kein * Fehler passiert (allgemein nicht der Fall, `errno' ist * üblicherweise nur "gültig" wenn die Funktion einen Fehler * andeutet). Das kann man dann ausnutzen, um zwischen den * beiden möglichen "Fehlerfällen" zu unterscheiden. Wenn * jedoch beides nicht eingetreten ist, haben wir einen * weiteren Eintrag aus dem Verzeichnis gelesen. */ errno = 0; ent = readdir(dir); if (ent == NULL) { /* Problem? */ if (errno == 0) { /* End-Of-Directory */ break; } else { /* Real Problem */ perror("readdir"); exit(EXIT_FAILURE); } } char *path = ent->d_name; /* Wenn wir den Pfad (in unserem Fall relativ zu dem * jetzigem Arbeitsverzeichnis), haben, können wir mit * `stat' bzw. `lstat' Informationen über die Datei * beantragen. Wir müssen dabei selbst den Speicher für * diese Information bereitstellen, in diesem Fall auf dem * Stack. Der Unterschied zwischen `stat' und `lstat' liegt * darin, ob ein symbolischer Verweis (eine Datei welche * üblicherweise beim öffnen, vom Betriebsystem so * interpretiert wird, dass es gleich eine andere Datei * stattdessen aufmacht) aufgelöst wird (stat) oder nicht * (lstat). */ struct stat sbuf; /* siehe sys_stat.h(0p) */ if (-1 == lstat(path, &sbuf)) { perror("stat"); continue; } /* In .st_mode feld eines "struct stat" buffers beschreibt * zusammen sowohl die Art von Datei (Regulär, Verzeichnis, * Symlink, Pipe, Socket, Block Device, ...) und dessen * Berechtigungen. Mit einem Makro wie S_ISLNK können wir * leicht prüfen ob die Datei von einem spezifischem Typen * ist (hier ein symbolischer Verweis), und unser Programm * dann davon abhängig steuern. */ if (S_ISLNK(sbuf.st_mode)) { puts(path); } } /* Am ende sollte man natürlich nicht vergessen alle Ressourcen * wieder freizugeben, in diesem Fall Lese-Kopf für das * Verzeichnis. Dahingehenden muss `ent' und `stat' nicht * freigegeben werden, weil beim ersten `readdir' für den * Speicher verantworlich ist, und beim zweiten der Speicher auf * dem Stack angelegt wurde. */ closedir(dir); return 0; }