0
votes

I am trying to open a directory and read the files and folders and add '/' at the end of if it is a folder. This is my current code.

#include <dirent.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int isDir(const char* target)
{
   struct stat statbuf;
   stat(target, &statbuf);
   return S_ISDIR(statbuf.st_mode);
}

int main(int argc, char * argv[])
{
    puts("");
  struct stat sfile;
    struct dirent *dp;
    char * dir;
    if(argc != 2) 
        dir = getenv("PWD"); //default
    else
        dir = argv[1];

    DIR *dirp = opendir(dir);
    dp = readdir(dirp);
    while ( dp != NULL ) 
    {
    stat(dp->d_name,&sfile);
    //opendir(dp->d_name);
    printf("Size : %ld      ",sfile.st_size);
        if (isDir(dp->d_name))
        {
            printf("%s/\n",dp->d_name);
        }
        else
        {
            printf("%s      \n",dp->d_name);
        }
        dp = readdir(dirp);
  }
  printf("\n");
    closedir(dirp);
}

This works when I pass no arguments, ie, it is reading files and folders in the current working directory. When I pass a directory as argument, it fails to detect further folders in that as directories. Curiously, when tried using errno when I try to open using opendir(), all the contents are detected as directories.

int isDir2(const char* target)
{
    opendir(target);
    if(errno == ENOTDIR)
    {
            puts("Not directory");
            return 0;
    }       
    else
    {
        puts("Directory"); //only this is getting printed
        return 1;
    }
}

In either case, when both '.' and '..' are detected as directories but the rest as either directories or files depending on whether I am using opendir()'s errno or S_ISDIR.

2
Checking errno before validating the result was not success is not a good idea. Not all functions set errno back to zero on success.selbie

2 Answers

1
votes

Your isDir function isn't actually checking the return value from stat to validate that it succeeded. And since your statbuf variable is uninitialized, it's undefined behavior.

Better:

int isDir(const char* target)
{
   struct stat statbuf = {0};
   int result = 0;
   if (stat(target, &statbuf) != -1)
   {
       result = S_ISDIR(statbuf.st_mode);
   }
   return result;
}

Further, you are invoking opendir without assigning it's return value:

while ( dp != NULL ) 
    {
    stat(dp->d_name,&sfile);
        opendir(dp->d_name);  // WHERE'S THE RESULT?

You need to rethink your logic in this while loop with regards to invoking opendir, readdir, and don't forget to invoke closedir.

0
votes

So the issue was of working directories. When I checked what the stat function in the isDir() function was returning, it was returning -1. It wasn't able to find the file/folder because it's current working directory was not the folder it was given, rather the cwd where the program was run. What I did was change the directory to the given folder and it works.

The code now:

#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int isDir(const char* target)
{
   struct stat statbuf = {0};
   int result = 0;
   int err = stat(target, &statbuf);
   if (err != -1)
   {
       result = S_ISDIR(statbuf.st_mode);
   }
   return result;
}

int main(int argc, char * argv[])
{
    puts("");
    struct stat sfile;
    struct dirent *dp;
    char * dir;
    if(argc != 2) 
        dir = getenv("PWD"); //default
    else
        dir = argv[1];
    DIR *dirp = opendir(dir);
    dp = readdir(dirp);
    chdir(dir);
    while ( dp != NULL ) 
    {
        stat(dp->d_name,&sfile);
        printf("Size : %ld      ",sfile.st_size);
        if (isDir(dp->d_name))
        {
            printf("%s/\n",dp->d_name);
        }
        else
        {   
            printf("%s      \n",dp->d_name);
        }
        dp = readdir(dirp);
  }
  printf("\n");
  closedir(dirp);
}