PDA

View Full Version : trying to emulate recursive ls command(very new to c)


FYAD
Feb23-05, 04:24 PM
I'm very new to programming in c, and I'm trying to write a program that recursivley lists all the files in a directory, as well as all of the subdirectores and their files. I'm having some problems.

On my first go I was able to get all of the files of the current directory to be listed. That was easy. I'm having trouble getting my program to jump into all of the subdirectories and then get back to the original directory and list its files. My code seems to jump into the first subdirectory and list its files, but it ends with a Segmentation fault. I googled the error and found out what it means, but I have no idea how to go about remedying it.



#include <stdio.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <dirent.h>
#include <unistd.h>


int x = 0;
struct dirent *dp;

void listit(DIR *dirp,DIR *tdirp,int level){
errno = 0;
if (!(dp = readdir(dirp))) {
if (errno == 0) {
printf("porblem\n");
}
else {
printf("Error reading entry in directory\n");
return;
}
}
else {
tdirp = (opendir(dp->d_name));
if(tdirp){
if(!((strcmp(dp->d_name,".")) == 0 || strcmp(dp->d_name,"..") == 0)){
printf("-----------NEW DIRECTORY--------------\n");
printf(" %s\n",dp-> d_name);
dirp = opendir(dp->d_name);
listit(dirp,tdirp,level);
}
else{
printf("%s\n",dp->d_name);
listit(dirp,tdirp,level);
}
}
printf("%s\n",dp->d_name);
listit(dirp,tdirp,level);
}
}



int main(int argc, char *argv[]){
struct timeval t;
int i, status = 0;
int count = 0;
int level = 0;
DIR *dirp;
DIR *tdirp;
dirp = opendir(argv[1]);

if (argc < 2) { exit(-1); }

if ((status = gettimeofday(&t,0)) != 0) {
printf("Error - time call failed\n");
}

if (!dirp) {
if (access(argv[1],F_OK)) {
printf("Error - couldn't interpret %s as directory.\n", argv[1]);
printf("----------------------------------\n\n");
}
else {
printf("%s\n", argv[1]);
printf("----------------------------------\n\n");
}
}
else {
printf("Contents of directory %s:\n", argv[1]);
listit(dirp,tdirp,level);

}
}

NateTG
Feb23-05, 04:55 PM
The c compiler is complaining because there is a 'porblem' in your code. (Just kidding.)

I don't see anything particularly obvious. I'm guessing that dp gets clobbered somwhere. Are you sure it should be global?

chroot
Feb23-05, 05:17 PM
Nate's got it. It's a very bad idea for a recursive function to use globals, by the way.

- Warren

dduardo
Feb23-05, 05:34 PM
If you can include stdlib.h then you can simply do this:

system("ls -R")

NateTG
Feb23-05, 06:17 PM
If you can include stdlib.h then you can simply do this:

system("ls -R")

That wouldn't exactly be emulating ls now, would it?

dduardo
Feb23-05, 06:32 PM
Well, if that doesn't work then you can always look at the source code to ls here:

http://ftp.gnu.org/pub/gnu/coreutils/coreutils-5.2.1.tar.gz

FYAD
Feb23-05, 09:42 PM
I changed dp to a local and passed it into listit. Directores still aren't getting read though?

Maybe my understanding of what's going on is incorrect.

In my main method I have dirp = opendir(argv[1]);, which reads in a directory name from the command line and attempts to open the directory.

If dirp is a valid directory name, it opens the directory and then passes the name up to function listit.

In listit, it checks to see if there are files in the directory ( the line if (!(dp = readdir(dirp))) { ), if so, it goes to the else where tdirp reads in the first file in the directory and checks if it is a sub-directory.

If it is a directory, it checks to see if the directory is "." or "..". If it is not, it prints the directory name and opens it, followed by a recursive call to listit. So, listit gets called with the new directory name and the whole thing starts over.

If it's "." or "..", it calls listit again. dp is set to the next file in the directory and it starts again.

If it's not a directory, it's a file, and the file name is printed. listit is called and the whole thing starts over.

Except new directories are never entered. gah!

janaki8581
Oct14-09, 12:03 AM
Hi:
if (!(dp = readdir(dirp)))

shouldn't this be:
if (!(dp == readdir(dirp)))?

Jeff Reid
Oct14-09, 01:57 AM
You might consider using a loop in listit() to process each "current" directory, then recursively calling listit() for each sub-directory encountered. You already mentioned changing dp to be a local variable. I don't understand why you pass dirp or tdirp or level as parameters, as dirp also needs to be a local variable. The only thing you need to pass to listit() is the name string for the directory. Then the local copy of dirp gets the result from doing an opendir(...name...).

Another alternative is to have two loops in listit(). The first loop processes all files, the second loop processes all directories (via recursive calls). This keeps all the files in a directory adjacent to each other the list.