I'm new to C and trying to recurse through all directories/files from the current working directory and output their information. The problem I'm running into that I can't think of a good way to solve is when there are two folders in the same directory the path gets built wrong the second time. For instance if dir1 and dir2 are in the same path after "/something/dir1" is completed the path should become "/something/dir2" but becomes "/something/dir1/dir2" because of the way I have things written. I thought of just keeping track of the previous path, but I'm not sure of a way to do that without it constantly being rewritten every recursive call.
Update: I have since fixed the original bug I was having and figured I'd post my new code here. The trick I was unaware about was opendir(".") and changedir("..") would actually translate the period into the full current or previous path. As far as changing the type = 8 and type = 4 statements to the more readable S_ISDIR(statbuf.st_mode) and S_ISREG(statbuf.st_mode) statements, they appear not to work at all while the type statements do. Not sure what's wrong with the syntax and the way I tried using them.
Update 2: I solved the S_ISDIR/S_ISREG problem here - How to use S_ISREG() and S_ISDIR() POSIX Macros?
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
void helper(DIR *, struct dirent *, struct stat, char *, int);
void dircheck(DIR *, struct dirent *, struct stat, char *, int);
int main(int argc, char *argv[]){
DIR *dip;
struct dirent *dit;
struct stat statbuf;
char currentPath[FILENAME_MAX];
int depth = 0; /*Used to correctly space output*/
dip = opendir(".");
getcwd(currentPath, FILENAME_MAX);
while((dit = readdir(dip)) != NULL){
/*Skips . and ..*/
if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0)
continue;
stat(currentPath, &statbuf);
/*Checks if current item is of the type file (type 8)*/
if(dit->d_type == 8)
printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);
/*Checks if current item is of the type directory (type 4)*/
if(dit->d_type == 4)
dircheck(dip, dit, statbuf, currentPath, depth);
}
return 0;
}
/*Recursively called helper function*/
void helper(DIR *dip, struct dirent *dit, struct stat statbuf, char currentPath[FILENAME_MAX], int depth){
int i = 0;
dip = opendir(currentPath);
while((dit = readdir(dip)) != NULL){
if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0)
continue;
stat(currentPath, &statbuf);
if(dit->d_type == 8){
for(i = 0; i < depth; i++)
printf(" ");
printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size);
}
if(dit->d_type == 4)
dircheck(dip, dit, statbuf, currentPath, depth);
}
}
void dircheck(DIR *dip, struct dirent *dit, struct stat statbuf, char currentPath[FILENAME_MAX], int depth){
int i = 0;
strcat(currentPath, "/");
strcat(currentPath, dit->d_name);
/*If two directories exist at the same levelt the path
is built wrong and needs to be corrected*/
if((chdir(currentPath)) == -1){
chdir("..");
getcwd(currentPath, FILENAME_MAX);
strcat(currentPath, "/");
strcat(currentPath, dit->d_name);
for(i = 0; i < depth; i++)
printf (" ");
printf("%s (subdirectory)\n", dit->d_name);
depth++;
helper(dip, dit, statbuf, currentPath, depth);
}
else{
for(i =0; i < depth; i++)
printf(" ");
printf("%s (subdirectory)\n", dit->d_name);
chdir(currentPath);
depth++;
helper(dip, dit, statbuf, currentPath, depth);
}
}