8 ŚRODOWISKO SYSTEMU UNIX
Każde wywołanie funkcji readdir zwraca wskaźnik do informacji o następnym pliku lub NULL, jeśli nie ma więcej plików. Każdy skorowidz zawiera pozycję nazwaną odnoszącą się do niego samego, oraz pozycję o nazwie odnoszącą się do jego przodka; pozycje te należy pominąć, inaczej bowiem program będzie działać bez końca.
Dotychczas kod był niezależny od rzeczywistego formatu skorowidza. W następnym kroku pokażemy minimalne wersje funkcji opendir, readdir i closedir, zrealizowane w konkretnym systemie. Napisane przez nas podprogramy są poprawne w systemach Unix Version 7 i Unix System V, korzystają bowiem z informacji o skorowidzu zawartych w nagłówku <sys/dir.h>:
#ifndef DIRSIZ #define DIRSIZ 14 #endif
struct direct /* opis pozycji skorowidza */
ino_t dJno; /* numer węzła */
char d_name|DIRSIZJ; /* długa nazwa nie ma kończącego ’\0’ */
W pewnych wersjach systemu dopuszcza się jeszcze dłuższe nazwy, a struktura pozycji skorowidza jest bardziej skomplikowana.
Typ ino_t, skonstruowany za pomocą typedef, opisuje indeks węzła w tablicy węzłów. Zdarza się, że jest nim unsigned short - jak w systemie, którego regularnie użyv/2my. Niemniej jednak informacji tego rodzaju nie włącza się do programu: w różnych systemach może być różnie, dlatego też lepiej zastosować typedef. Kompletny zestaw typów „systemowych*' można znaleźć w nagłówku <sys/types.h>.
funkcja opendir otwiera plik podany jako skorowidz i sprawdza, czy rzeczywiście jest on skorowiuzcm (tym razem zastosowaliśmy funkcję fstat, która różni się od stat tylko tym, że korzysta z deskryptora pliku). Następnie skorowidzowi przydziela się strukturę DIR i rejestruje w niej uzyskane informacje*:
Uwaga: tak napisana funkcja opendir nie zamyka pliku w przypadku niespełnienia jednego z wymaganych warunków. Po dłuższej serii niepowodzeń z różnymi nazwami plików może się wyczerpać zbiór deskryptorów przydzielonych programowi. - Przyp. tłum.
8.6 PRZYKŁAD - WYPISYWANIE ZAWARTOŚCI SKOROWIDZÓW
_jpowered bv
Mi siol
int fstat(int fd, struct stat *);
/* opendir: otwórz skorowidz dla wywołań readdir */
DIR *opendir(char *dirname)
int fd;
struct stat stbuf;
DIR *dp;
if ((fd = open(dirnameł 0_RD0NLY, 0)) == -1 || fstat(fd, &stbuf) == -1 || (stbuf.st_mode & S_IFMT) != S_IFDIR || (dp = (DIR *) malloc(sizeof(DIR))) = = NULL) return NULL; dp->fd = fd; return dp;
Funkcja closedir zamyka skorowidz i zwalnia przydzieloną pamięć:
/* closedir: zamknij skorowidz otwarty przez opendir */ void closedir(DIR *dp)
if (dp) {
close(dp->fd);
free(dp);
I na ostatku funkcja readdir czyta każdą pozycję skorowidza za pomocą funkcji read. Jeśli pozycja w skorowidzu nie jest aktualnie używana (ponieważ plik został usunięty), to numer węzła tej pozycji jest równy zero, zatem taką pozycję się pomija. W pozostałych przypadkach numer węzła i nazwę umieszcza się w statycznej strukturze, a wskaźnik do tej struktury udostępnia użytkownikowi. Każde wywołanie funkcji readdir zamazuje informacje uzyskane w poprzednim wywołaniu.
#include <sys/dir.h> /* opis lokalnej struktury skorowidza */
/* readdir: czytaj kolejno pozycje skorowidza */
Dirent *readdir(D!R *dp)
struct direct dirbuf; /* lokalna struktura skorowidza */ static Dirent d; /* zwracana struktura przenośna */
243