8 ŚRODOWISKO SYSTEMU UNIX , 6 PRZYKŁAD - WYPISYWANIE ZAWARTOŚCI SKOROWIDZÓW_ 1
Zilustrujemy to na przykładzie programu fsize, który jest specjalną wersją progra^ ls: wypisuje rozmiary wszystkich plików wymienionych z nazwy w wierszu polece. nia. Jeśli jednym z nich jest skorowidz, to podprogram fsize rekurencyjnie wywołuje sam siebie dla tego skorowidza. Jeżeli w ogóle nie podano argumentów, to program przetwarza bieżący skorowidz. tK
Na początek podamy krótki zarys struktury plików systemu Unix. Skorowidz jest pij. kiem zawierającym listę nazw plików wraz z pewnymi wskazówkami dotyczącym ich położenia. „Położenie” jest indeksem pewnej tablicy zwanej „tablicą węzłów informacyjnych” (ang. inode table). W węźle są przechowywane wszystkie informacje o pliku z wyjątkiem jego nazwy. Pozycja w skorowidzu zwykle składa się tylk0 z dwóch obiektów: numeru węzła i nazwy pliku.
Pożałowania godny jest fakt, że format i szczegółowa zawartość skorowidza nie są takie same we wszystkich wersjach systemu. Zatem, aby wyodrębnić fragmenty zależne od systemu, musimy podzielić zadanie na dwie części. Na najwyższym poziomie zdefiniujemy typ strukturowy o nazwie Dirent (pozycja skorowidza) oraz trzy podprogramy opendir, readdir i closedir, które mają zapewnić niezależny od systemu dostęp do nazwy pliku i numeru węzła w pozycji skorowidza. Skorzystamy z tego mechanizmu w programie fsize, a potem pokażemy, jak go zrealizować w systemach, w których struktura skorowidza jest taka sama, jak w systemach Unix Version 7 czy Unix System V; warianty pozostawiamy jako ćwiczenia.
Struktura Dirent zawiera numer węzła i nazwę. Maksymalna długość składowej nazwy jest określona przez stałą symboliczną NAME_MAX, której wartość zależy od systemu. Funkcja opendir zwraca wskaźnik do struktury o typie nazwanym DIR przez analogię do typu FILE; z tego wskaźnika korzystają funkcje readdir i closedir. Wszystkie te informacje zebraliśmy w pliku nagłówkowym o nazwie dirent.h:
Odwołanie systemowe stat dla danej nazwv nlit a ■
* W WęŹ" “so P,ik“- ™ca -1, jeśli "“""“J
char *name;
struct stat stbuf;
int stat(char *, struct stat *);
stat(name, &stbuf);
e zawar-
Funkcja stat wypełnia strukturę stbuf informacjami z węzła pliku wskazanego
argument name. Struktura opisująca wartości zwracane przez funkcję stat JnSfc sif w nagłówku <sys/stat.h> i zwykle wygląda tak: J J
struct stat
{
dev_t ino_t short short short short dev_t
off_t
time_t time_t time_t
/* informacje z węzła zwracane przez stat
przez
#define NAME_MAX 14 /* najdłuższa nazwa pliku; */
/* zależy od systemu */
typedef struct { /* przenośny opis pozycji skorowidza: */
long ino; /* numer węzła */
char name[NAME_MAX+1]; /* nazwa + kończący znak ’\0’ */ } Dirent;
)
st_dev;
st_ino;
st_mode;
st_nlink;
st_uid;
st_gid;
st_rdev;
st_size;
st_atime;
st_mtime;
st_ctime;
/* urządzenie związane z węzłem */ I* numer węzła */
/* bity atrybutów pliku */
/* liczba dowiązań do pliku */
I* identyfikator właściciela */
I* identyfikator zespołu */
I* dla plików specjalnych */
/* rozmiar pliku w znakach */
/* data ostatniego dostępu */
I* data ostatniej modyfikacji */
/* data ostatniej zmiany w węźle */
'tększość tych wartości objaśniają komentarze. Typy danych, jak dev_t czy ino_t, są definiowane w nagłówku <sys/types.h>, który także należy dołączyć do programu.
dadowa st_mode zawiera zbiór znaczników opisujących atrybuty pliku. Definicje
eh znaczników są również zawarte w nagłówku <sys/stat.h>; tutaj potrzebujemy Iko kilku z nich, dotyczących rodzaju pliku:
typedef struct { int fd;
Dirent d;
} DIR;
I* min. opis DIR: bez buforowania itp. */ I* deskryptor pliku skorowidza */ I* pozycja skorowidza */
DIR *opendir(char *dimame); Dirent *readdir(DIR *dfd); void closedir(DIR *dfd);
#define #define łfdefine # define #define
S_IFMT 0160000 S-IFDIR 0040000
S.IFCHR
S-IFBLK
S-IFREG
0020000
0060000
0100000
/* rodzaj pliku: */
/* skorowidz */
/* specjalny znakowy */ /* specjalny blokowy */ I* zwyczajny */
I* ... */