2010-09-17 9 views
5

En la segunda edición de "El Lenguaje de Programación C" de Kernighan y Ritchie se implemento una versión simplificada del comando UNIX ls (sección 8.6 "Ejemplo - directorios enumerando", p 179.). Para este fin, crean la siguiente interfaz que proporciona un acceso independiente del sistema al nombre y al número de inodo de los archivos almacenados en un directorio.Interfaz K & R para leer directorios: estructura 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); 

Luego implementan esta interfaz para los sistemas UNIX versión 7 y System V.

  • opendir() básicamente utiliza el sistema llamada open() para abrir un directorio y malloc() para asignar espacio para una estructura DIR. El descriptor de archivo devuelto por open() se almacena entonces en la variable fd de ese DIR. No se almacena nada en el componente Dirent .

  • readdir() utiliza la llamada al sistema read() para obtener la siguiente entrada directorio (dependiente del sistema) de un directorio abierto y copia el modo obtenido el número de inodo y nombre de archivo en un Dirent estructura estática (a cual una se devuelve el puntero). La información solo necesaria por readdir() es el descriptor de archivo almacenado en la estructura DIR.

Ahora a mi pregunta: ¿Cuál es el punto de tener una estructura DIR? Si mi comprensión de este programa es correcta, el componente Dirent de DIR nunca se utiliza, entonces ¿por qué no reemplazar toda la estructura con un descriptor de archivo y usar directamente open() y close()?

Gracias.

Ps: Soy consciente de que en los sistemas UNIX modernos read() ya no se pueden usar en directorios (he probado este programa en Ubuntu 10.04), pero aún quiero asegurarme de no haber pasado por alto algo importante en este ejemplo.

Respuesta

4

Desde K & R:

Lamentablemente, el contenido de formato y precisas de un directorio no son los mismos en todos los versiones del sistema. Por lo tanto, dividiremos la tarea en dos partes para intentar aislar las partes no portátiles. El nivel exterior define una estructura llamada Dirent y tres rutinas Opendir, readdir y closedir para proporcionar un acceso independiente del sistema para el nombre y el número de i-nodo en una entrada de directorio.

El motivo es la portabilidad. Quieren definir una interfaz que pueda sobrevivir en sistemas que tienen diferentes estructuras estadísticas o no estándar open() y close(). Luego construyen un conjunto de herramientas reutilizables, que ni siquiera les importa si están en un sistema tipo Unix. Ese es el punto de los envoltorios.

Tal vez no se usa porque comenzaron definiendo sus estructuras de datos (con un Dirent dentro de DIR) pero terminaron por no usarlo. Mantener las estructuras de datos agrupadas así es un buen diseño.

+0

La portabilidad también fue mi primera suposición, pero después de pensarlo no veo cómo 'DIR' podría contribuir a esto. La única información relevante que puede pasar a 'readdir()' es el descriptor del archivo. Todavía no veo el uso del componente 'Dirent' en' DIR'. Independientemente del sistema, cualquier implementación de 'readdir()' puede tener un 'Dirent' estático al que puede devolver un puntero, por lo que no debería ser un problema de portabilidad. Es cierto que 'dirwalk()' accede al contenido de un 'Dirent', pero este es el estático de' readdir() ', no el contenido en' DIR'. ¿Me falta algo? – qfab

+1

Oye, parece que tienes razón. Supongo que comenzaron definiendo sus estructuras de datos (con un 'Dirent' dentro de' DIR') pero terminaron sin usarlo. Agrupar datos relacionados juntos en estructuras es bueno juju. Un buen ejercicio sería reescribir el código para hacer uso de 'DIR.d' en lugar de hacer que' readdir() 'los llamadores tengan sus propios punteros' Dirent'. – nmichaels

+0

Sí, esta es una explicación plausible. Pero teniendo en cuenta que el libro se publicó hace más de 20 años (segunda edición), es extraño que algo así no se menciona en la [errata] (http://cm.bell-labs.com/cm/cs/cbook/ 2ediffs.html). – qfab

0

Es así que no tienen que asignar memoria para la estructura Dirent que devuelve readdir. De esta forma, pueden reutilizar el Dirent entre las llamadas del subconsciente a readdir.

+0

Pero no tienen que asignar memoria de todos modos porque 'readdir()' almacena el 'Dirent' como una variable estática. – qfab

+2

@qfab: Sí, pero ese es un diseño realmente malo. Una implementación hipotética mejorada colocaría el búfer dentro de la estructura 'DIR' para que la lectura simultánea de múltiples directorios no bloquee los datos (y por lo tanto sería seguro para subprocesos siempre que no use un solo objeto' DIR' de más de un hilo a la vez). Espero que las implementaciones modernas hagan esto; la mía ciertamente lo hace. –

Cuestiones relacionadas