Trying to emulate recursive ls command(very new to c)

  • Thread starter Thread starter FYAD
  • Start date Start date
AI Thread Summary
The discussion revolves around a user attempting to write a C program that recursively lists all files and subdirectories within a specified directory. The user successfully lists files in the current directory but encounters a segmentation fault when trying to access subdirectories. The primary issue identified is the use of a global variable for the directory entry pointer, which can lead to unexpected behavior in recursive calls. Suggestions include changing the global variable to a local one, passing only necessary parameters to the recursive function, and implementing a loop structure to handle file and directory processing separately. Additionally, there are recommendations to use `chdir()` to change the current working directory before entering a subdirectory. Overall, the focus is on correcting the recursive logic and ensuring proper directory handling to avoid segmentation faults.
FYAD
Messages
5
Reaction score
0
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.


Code:
#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);     

   }
}
 
Technology news on Phys.org
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?
 
Nate's got it. It's a very bad idea for a recursive function to use globals, by the way.

- Warren
 
If you can include stdlib.h then you can simply do this:

system("ls -R")
 
dduardo said:
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?
 
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!
 
Hi:
if (!(dp = readdir(dirp)))

shouldn't this be:
if (!(dp == readdir(dirp)))?
 
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.
 
  • #10
If you didn't find the solution yet.
when you find new directory you have to call.

chdir(dir); in order to enter il.
 

Similar threads

Back
Top