I’m doing a school assignment and the task at hand is to count the files and folders recursively. I use the readdir() function, it seems to iterate through the directory I gave it.
int listdir(const char *path)
{
struct dirent *entry;
DIR *dp;
dp = opendir(path);
if (dp == NULL)
{
perror("opendir");
return -1;
}
while((entry = readdir(dp)))
puts(entry->d_name);
closedir(dp);
return 0;
}
I want to see the "something++;" step of this function, there should be one, right? All I can find is this line in glibc’s dirent/dirent.h
extern struct dirent *readdir (DIR *__dirp) __nonnull ((1));
and
struct dirent *
__readdir (DIR *dirp)
{
__set_errno (ENOSYS);
return NULL;
}
weak_alias (__readdir, readdir)
in dirent/readdir.c
Where does the iteration happen?
Maybe a duplicate of How readdir function is working inside while loop in C?
I tried to grep through glibc source code for readdir – didn’t find, searched the Internet – didn’t find, although some say there is an obsolete linux system call also called readdir.
There is also this
"
The readdir() function returns a pointer to a dirent structure
representing the next directory entry in the directory stream
pointed to by dirp. It returns NULL on reaching the end of the
directory stream or if an error occurred."
and this
"
The order in which filenames are read by successive calls to readdir()
depends on the filesystem implementation; it is unlikely that the names
will be sorted in any fashion."
in man readdir .
From this answer – https://stackoverflow.com/a/9344137/12847376
I assume OS can hijack functions with LD_PRELOAD, I see no such variable in my default shell. And too many hits in the Debian source search.
I also grepped through the Linux kernel for LD_PRELOAD and readdir and got too many results on the syscall.
2
Answers
I’m not sure exactly what you are trying to accomplish. I have implemented something similar to this for another language’s core library, so I can say there is not a
++something
. The reason for that, is that the structures returned by the operating system do not have a consistent size. The structure is something like the following:You pass a buffer to the system call (I used
getdents64
), and it fills it in with a bunch of these dirent structures. Thatd_name[]
does not have an officially known size. The size of the entire structure is defined by thatd_reclen
member of the struct.In memory, you could have many
struct dirent
like this:Here is a rough translation of how it works:
Notice the way we increment
i
. Since thed_name
member does not have an official size, we cannot just saystruct dirent d[COUNT];
. We don’t know how big each struct will be.On Linux, it happens here. As you can see, the code repeatedly calls getdents (system call) to obtain a set of entries from the kernel, and "advances" the
dp
by updatingdirp->offset
, etc.