I was skimming through K&R C and I noticed that to read the entries in a directories, they used:
while (read(dp->fd, (char *) &dirbuf, sizeof(dirbuf))
In K&R (actually, Unix up through SVr2 at least, perhaps SVr3), directory entries were 16 bytes, using 2 bytes for the inode and 14 bytes for filenames.
Using read
made sense, because the directory entries on the disk were all the same size. 16 bytes (a power of 2) also made sense, because it did not require hardware multiply to compute offsets. (I recall someone telling me around 1978 that the Unix disk driver used floating point and was slow... but that's second hand, although amusing).
Later improvements to directories allowed longer names, which meant that the sizes differed (there being no point to making huge entries all the same as the largest possible name). A newer interface was provided, readdir
.
Linux provides a lower-level interface. According to its manual page:
These are not the interfaces you are interested in. Look at readdir(3) for the POSIX-conforming C library interface. This page documents the bare kernel system call interfaces.
As illustrated in your example, getdents
is a system call, useful for implementing readdir
. The manner in which readdir
is implemented is unspecified. There is no particular reason why the early readdir
(from about 30 years ago) could not have been implemented as a library function using read
and malloc
and similar functions to manage the long filenames read from the directory.
Moving features into the kernel was done (probably) in this case to improve performance. Because getdents
reads several directory entries at a time (unlike readdir
), that may reduce the overhead of reading all of the entries for a small directory (by reducing the number of system calls).
Further reading: