Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

K&R interface for reading directories: superfluous DIR structure?

Tags:

c

unix

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.

like image 929
qfab Avatar asked Sep 17 '10 13:09

qfab


1 Answers

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.

like image 140
nmichaels Avatar answered Oct 15 '22 13:10

nmichaels