According to strace
, lseek(fd, 0, SEEK_END) = 9223372036854775807
when fd
refers to a directory. Why is this syscall succeeding at all? What does lseek()
mean for a dir fd?
On my test system, if you use opendir()
, and readdir()
through all the entries in the directory, telldir()
then returns the same value:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
int main(int argc, char *argv[]) {
int fd = open(".", O_RDONLY);
if (fd < 0) {
perror("open");
return 1;
}
off_t o = lseek(fd, 0, SEEK_END);
if (o == (off_t)-1) {
perror("lseek");
return 1;
}
printf("Via lseek: %ld\n", (long)o);
close(fd);
DIR *d = opendir(".");
if (!d) {
perror("opendir");
return 1;
}
while (readdir(d)) {
}
printf("via telldir: %ld\n", telldir(d));
closedir(d);
return 0;
}
outputs
Via lseek: 9223372036854775807
via telldir: 9223372036854775807
Quoting from the telldir(3)
man page:
In early filesystems, the value returned by
telldir()
was a simple file offset within a directory. Modern filesystems use tree or hash structures, rather than flat tables, to represent directories. On such filesystems, the value returned bytelldir()
(and used internally byreaddir(3)
) is a "cookie" that is used by the implementation to derive a position within a directory. Application programs should treat this strictly as an opaque value, making no assumptions about its contents.
It's a magic number that indicates that the index into the directory's contents is at the end. Don't count on the number always being the same, or being portable. It's a black box. And stick with the dirent API for traversing directory contents unless you really know exactly what you're doing (Under the hood on Linux + glibc, opendir(3)
calls openat(2)
on the directory, readdir(3)
fetches information about its contents with getdents(2)
, and seekdir(3)
calls lseek(2)
, but that's just implementation details)