In the 2nd edition of "The C Programming Language" by Kernighan and Ritchie they implement a simplified version of the UNIX command ls
(section 8.6 "Example - Listing Directories", p. 179). For this purpose they create the following interface which provides a system-independent access to the name and inode number of the files stored in a directory.
#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);
Then they implement this interface for Version 7 and System V UNIX systems.
opendir()
basically uses the system
call open()
to open a directory and
malloc()
to allocate space for a
DIR
structure. The file descriptor
returned by open()
is then stored
in the variable fd
of that DIR
.
Nothing is stored in the Dirent
component.
readdir()
uses the system call
read()
to get the next
(system-dependent) directory entry of
an opened directory and copies the so
obtained inode number and filename
into a static Dirent
structure (to
which a pointer is returned). The
only information needed by
readdir()
is the file descriptor
stored in the DIR
structure.
Now to my question: What is the point of having a DIR
structure? If my understanding of this program is correct, the Dirent
component of DIR
is never used, so why not replace the whole structure with a file descriptor and directly use open()
and close()
?
Thanks.
Ps: I am aware that on modern UNIX systems read()
can no longer be used on directories (I have tried out this program on Ubuntu 10.04), but I still want to make sure that I have not overlooked something important in this example.
From K&R:
Regrettably, the format and precise contents of a directory are not the same on all versions of the system. So we will divide the task into two pieces to try to isolate the non-portable parts. The outer level defines a structure called a Dirent and three routines opendir, readdir, and closedir to provide system-independent access to the name and inode number in a directory entry.
So the reason is portability. They want to define an interface that can survive on systems that have different stat structs or nonstandard open()
and close()
. They go on to build a bunch of reusable tools around it, which don't even care if they're on a Unix-like system. That's the point of wrappers.
Maybe it's not used because they started out by defining their data structures (with a Dirent inside DIR) but ended up not using it. Keeping data structures grouped like that is good design.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With