1

Program:

#include<stdio.h>
#include<stdlib.h>
#include<dirent.h>
#include<sys/stat.h>
int main(int argc, char *argv[])
{
    DIR *dp;
    struct dirent *dirp;
    struct stat stbuf;
    if (argc != 2)
        printf("usage: ls directory_name\n");

    if ((dp = opendir(argv[1])) == NULL)
        printf("can’t open %s", argv[1]);

    while ((dirp = readdir(dp)) != NULL){
        stat(dirp->d_name,&stbuf);
        if(S_ISDIR(stbuf.st_mode)){
            printf("Directory: ");
        }
        printf("%s\n",dirp->d_name);
    }

    closedir(dp);
    exit(0);
}

Output:

$ ./a.out test/
dir3
d
c
Directory: .
Directory: a
Directory: ..
Directory: dir4
Directory: dir2
Directory: dir0
Directory: b
Directory: e
Directory: dir1
$

The following are the list of files that the directory "test" contains.

$ ls -F test/
a  b  c  d  dir0/  dir1/  dir2/  dir3/  dir4/  e
$ 

The expected output is, if the file is directory the output will be "Directory: dir1/". Else only the file name. But, the output of the program is not as expected. Is the program contains any error?. Is there any let me know.

Thanks in Advance...

mohangraj
  • 9,842
  • 19
  • 59
  • 94
  • possible duplicate of [Accessing Directories in C](http://stackoverflow.com/questions/3536781/accessing-directories-in-c) – Kninnug Aug 18 '15 at 10:27
  • 3
    (1) You need to check the return value from `stat()` to see if there are any errors. (2) You are calling `stat()` on (for example) `dir2` but you need to pass `test/dir2`. – psmears Aug 18 '15 at 10:28
  • I suggest you check what `stat` return, I'll bet it's `-1` (meaning it failed) on most of the names. – Some programmer dude Aug 18 '15 at 10:28
  • @JoachimPileborg Yeah, stat returns -1. But, the directory "test" is available in my current working directory. Then how stat returns -1. – mohangraj Aug 18 '15 at 10:33
  • 2
    @mohanraj Yes, but that's because you try to access e.g. the file `a` in the process working directory (the directory where you started the program), and not in the `test` directory. Read the comment by psmears more closely. – Some programmer dude Aug 18 '15 at 10:34

1 Answers1

2

Lets break it down into steps:

  1. You start your program from some directory. This directory will become the process current working directory (CWD).

  2. You call opendir on the directory test. This is actually the directory test in the CWD.

  3. You call readdir to get the first entry in the directory.

  4. This first entry is the . directory, which is short for current directory, all directories have it.

  5. You call stat with ., meaning you call stat on the CWD. It of course succeeds and stat fills in the structure with all the details of the CWD.

  6. Next iteration you get the entry a and you call stat on that entry. However since there is no a in the CWD, the stat call fails. You however doesn't check for that, and uses the stat structure that was filled in from the previous call (from the successful stat of the . directory).

And so on...

You need to tell stat to look for the entries in the given directory instead of the CWD. This can basically be done in only two ways:

  • Format a string so that you prefix the entry with the directory you passed to opendir. E.g.

    char path[PATH_MAX];
    snprintf(path, sizeof(path), "%s/%s", argv[1] ,dirp->p_name);
    if (stat(path, &stbuf) != -1)
    {
        // `stat` call succeeded, do something
    }
    
  • After calling opendir, but before looping that directory, change the CWD:

    // Opendir call etc...
    
    chdir(argv[1]);
    
    // Loop using readdir etc.
    

Alternatively, start the program from the directory you want to check:

$ cd test
$ ../a.out .
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621