2010-09-17 6 views
5

Nel 2 ° edizione di "The C Programming Language" da Kernighan e Ritchie implementano una versione semplificata del comando UNIX ls (sezione 8.6 "Esempio - directory listing", p 179).. A tale scopo creano la seguente interfaccia che fornisce un accesso indipendente dal sistema al nome e al numero di inode dei file memorizzati in una directory.Interfaccia K & R per la lettura di directory: struttura DIR superflua?

#define NAME_MAX 14 /* longest filename component; */ 
           /* system dependent */ 

typedef struct {  /* portable director-entry */ 
    long ino;     /* inode number */ 
    char name[NAME_MAX+1]; /* name + '\0' terminator */ 
} Dirent; 

typedef struct {  /* minimal DIR: no buffering, etc. */ 
    int fd;     /* file descriptor for directory */ 
    Dirent d;     /* the directory entry */ 
} DIR; 

DIR *opendir(char *dirname); 
Dirent *readdir(DIR *dfd); 
void closedir(DIR *dfd); 

Quindi implementano questa interfaccia per i sistemi UNIX versione 7 e System V.

  • opendir() utilizza fondamentalmente il sistema chiamata open() per aprire una directory e malloc() allocare spazio per una struttura DIR. Il descrittore di file restituito da open() viene quindi memorizzato nella variabile fd di quello DIR. Nessun componente è stato memorizzato nel componente Dirent .

  • readdir() utilizza la chiamata di sistema read() per ottenere la voce successiva directory (dipendente dal sistema) di una directory aperta e copia il modo ottenuto il numero di inode e il nome in una Dirent struttura statica (ad cui un il puntatore viene restituito). Le informazioni necessarie solo da readdir() sono il descrittore di file memorizzato nella struttura DIR.

Ora alla mia domanda: Qual è il punto di avere una struttura DIR? Se la mia comprensione di questo programma è corretta, il componente Dirent di DIR non viene mai utilizzato, quindi perché non sostituire l'intera struttura con un descrittore di file e utilizzare direttamente open() e close()?

Grazie.

Ps: Sono consapevole che sui moderni sistemi UNIX read() non è più possibile utilizzare le directory (ho provato questo programma su Ubuntu 10.04), ma voglio comunque assicurarmi di non aver trascurato qualcosa di importante in questo esempio.

risposta

4

Da K & R:

Purtroppo, il formato e precisi contenuti di una directory non sono gli stessi in tutte le versioni del sistema. Quindi suddivideremo l'attività in due parti per provare a isolare le parti non portatili . Il livello esterno definisce una struttura chiamata Dirent e tre routine opendir, readdir, e closedir per fornire un accesso indipendente dal sistema per il nome e il numero inode in una voce di directory.

Quindi la ragione è la portabilità. Vogliono definire un'interfaccia che possa sopravvivere su sistemi che hanno diverse strutture di statistiche o non standard open() e close(). Continuano a costruire attorno a sé un mucchio di strumenti riutilizzabili, a cui non importa nemmeno se si trovano su un sistema simile a Unix. Questo è il punto di wrapper.

Forse non viene utilizzato perché sono stati avviati definendo le loro strutture dati (con una Dirent all'interno di DIR) ma finì per non usarlo. Mantenere raggruppate le strutture dati in questo modo è un buon design.

+0

La portabilità è stata anche la mia prima ipotesi, ma dopo aver riflettuto su non vedo come 'DIR' potrebbe contribuire a questo. L'unica informazione rilevante che può passare a 'readdir()' è il descrittore del file. Ancora non vedo l'uso del componente 'Dirent' in' DIR'. Indipendentemente dal sistema, qualsiasi implementazione di 'readdir()' può avere un 'Dirent' statico a cui può restituire un puntatore, quindi questo non dovrebbe essere un problema di portabilità. È vero che 'dirwalk()' accede al contenuto di un 'Dirent', ma questo è quello statico di' readdir() ', non quello contenuto in' DIR'. Mi manca qualcosa? – qfab

+1

Ehi, sembra che tu abbia ragione. La mia ipotesi è che iniziarono definendo le loro strutture di dati (con un 'Dirent' all'interno di' DIR') ma finirono per non usarlo. Raggruppare i dati correlati insieme nelle strutture è buono. Un buon esercizio sarebbe quello di riscrivere il codice per fare uso di 'DIR.d' invece di avere' readdir() 'i chiamanti hanno i propri puntatori' Dirent'. – nmichaels

+0

Sì, questa è una spiegazione plausibile. Ma considerando che il libro è stato pubblicato più di 20 anni fa (2a edizione), è strano che qualcosa di simile non sia menzionato nella [errata] (http://cm.bell-labs.com/cm/cs/cbook/ 2ediffs.html). – qfab

0

È così che non è necessario allocare memoria per la struttura Dirent restituita da readdir. In questo modo possono riutilizzare la Corrente tra chiamate secondarie a readdir.

+0

Ma non devono allocare memoria comunque perché 'readdir()' memorizza il 'Dirent' come variabile statica. – qfab

+2

@qfab: Sì, ma è un design davvero pessimo. Un'ipotetica implementazione migliorata avrebbe messo il buffer all'interno della struttura 'DIR' in modo che la lettura simultanea di più directory non avrebbe danneggiato i dati (e quindi sarebbe thread-safe finché non si usa un solo oggetto' DIR' da più di un thread alla volta). Mi aspetto che le moderne implementazioni facciano questo; il mio certamente lo fa. –