Reputation: 339
I am working on a POSIX C learning exercise that involves recursively listing files/folders in a specified directory. The program takes in as arguments of one or more directories. I can list the contents of the initial directory fine but having a problem with the recursion. Is something wrong with the way I am passing in the argument for the recursive function call?
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
void listdir(char *argv[])
{
DIR *mydirhandle;
struct dirent *mydirent;
struct stat statinfo;
int n = 1;
while(argv[n] != NULL)
{
if((mydirhandle = opendir(argv[n])) == NULL)
{
perror("opendir");
exit(1);
}
printf("%s/\n", argv[n]);
while((mydirent = readdir(mydirhandle)) != NULL)
{
if((strcmp(mydirent->d_name, ".") == 0) || (strcmp(mydirent->d_name, "..") == 0))
{
continue;
}
else
{
printf("\t%s\n", mydirent->d_name);
//check if next entry is a directory
if(mydirent->d_type == DT_DIR)
{
//is current directory being passed correctly here?
listdir(mydirent->d_name);
}
}
}
n++;
closedir(mydirhandle);
}
}
int main(int argc, char *argv[])
{
if(argc < 2)
{
printf("usage: %s <directory>\n", argv[0]);
return 0;
}
listdir(argv);
return 0;
}
Upvotes: 3
Views: 5151
Reputation: 800
You should use ftw
for this, it calls a given callback on every item of the subtree. This way, you avoid using explicit recursion yourself, and your code will get much shorter.
Upvotes: 2
Reputation: 434575
The d_name
member of struct dirent
is the basename of the item in question. So, if you're going through a directory like this:
.
..
where-is/
pancakes/
.
..
house
Once you're in where-is
, you'll try to listdir("pancakes")
but that won't work because you need to listdir("where-is/pancakes")
.
You need to combine that with the name of the directory that you're looking before you have something that you can pass to the next listdir
call.
You'll want to replace things like this:
listdir(mydirent->d_name);
with things like this:
char *next_dir = malloc(strlen(argv[n]) + strlen(mydirent->d_name) + 1 + 1);
sprintf(next_dir, "%s/%s", argv[n], mydirent->d_name);
listdir(next_dir);
free(next_dir);
Alternatively, you could chdir
into the directories as you enter them and then chdir
back up when you're done.
Upvotes: 5
Reputation: 215173
Turning on warnings will show that you're passing the wrong type when making the recursive function call. I would simply make listdir
take a char *
argument rather than char **
, and then use a for loop in main
to loop over multiple arguments if you need to.
Upvotes: 2