paper_bullets
paper_bullets

Reputation: 13

Sorting and printing directories and subdirectories in C

I'm trying to sort a current working directory, sub-directories, and then display them. My program behavior begins the process and works for the first sub-directory but none after that. A few prints are to check behavior of the code. While there is a complete working version of this on stackoverflow, I just want to better understand where my code logic is failing. Any help is greatly appreciated. Here is the code:

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

void sortArr(char array[256][256], int amt) {

  char temp[1000];
    for(int i=0; i<amt; i++) {
      for(int j=0; j<(amt-1-i); j++) {
    if(strcmp(array[j], array[j+1]) > 0) {
      strcpy(temp, array[j]);
      strcpy(array[j], array[j+1]);
      strcpy(array[j+1], temp);
    }
      }
    }

    printf("SortList: %s\n", array[0]);
}



void build(char *s_path, const int root) {
  char path[1000];
  strcat(path, s_path);
  int amt=0,index;
  struct dirent *dp;
  DIR *dir =opendir(path);
  char list[256][256];
  struct stat statbuf;
  
  if(!dir)
    return;

  while((dp =readdir(dir)) != NULL) {
    if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0) {
      strcpy(list[amt], dp->d_name);
      amt++;
    }
  }
  
  sortArr(list, amt);

  for(int i=0; i <amt;i++) {
     for (index=0; index<root; index++)  {
    if (index%2 == 0 || index == 0)
      printf("%c", ' ');
    else
      printf(" ");
      }
    
    printf("%c %s\n", '-', list[i]);

    strcpy(path, s_path);
    strcat(path, "/");
    strcat(path, list[i]);
    stat(path, &statbuf);
    
    if((S_ISDIR(statbuf.st_mode)) != 0 && (S_ISREG(statbuf.st_mode)) ==0) {
      printf("DIR: %s\n", path);
      build(path,root +2);
    }
  }
  closedir(dir);
}

int main() {

  build(".", 0);
  
};

Upvotes: 1

Views: 148

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 754060

Based on my comments.

The key problem is that you've no idea what's in path when you call build(), so concatenating on the end does nothing reliable. Either add path[0] = '\0'; before the call to strcat(), or (simpler) use strcpy().

That fixes your problems as long as your directories do not have more than 256 entries (other than . and ..) in them.

If you do have bigger directories, you run into problems. Those would be resolved by using dynamic memory allocation — malloc() et al, and using strdup(), probably. That which you allocate you should free, too, of course.

You should check that the calls to stat() succeed, but they won't often fail. One time they could fail is if a file is removed between the when readdir() returns the name and the time when the code calls stat() for the file.

There are POSIX tools for scanning directories. These include:

Amended source code (including some uncommented upon changes):

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

static
void sortArr(char array[356][256], int amt)
{
    char temp[1000];
    for (int i = 0; i < amt; i++)
    {
        for (int j = 0; j < (amt - 1 - i); j++)
        {
            if (strcmp(array[j], array[j + 1]) > 0)
            {
                strcpy(temp, array[j]);
                strcpy(array[j], array[j + 1]);
                strcpy(array[j + 1], temp);
            }
        }
    }

    printf("SortList: %s\n", array[0]);
}

static
void build(const char *s_path, int root)
{
    char path[1000];
    strcpy(path, s_path);
    int amt = 0;
    struct dirent *dp;
    DIR *dir = opendir(path);
    char list[356][256];
    struct stat statbuf;

    if (!dir)
        return;

    while ((dp = readdir(dir)) != NULL)
    {
        if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
        {
            strcpy(list[amt], dp->d_name);
            amt++;
        }
    }

    sortArr(list, amt);

    for (int i = 0; i < amt; i++)
    {
        printf("%*s", root, "");
        /*for (int index = 0; index < root; index++)*/
        /*    putchar(' ');*/

        printf("%c %s\n", '-', list[i]);

        strcpy(path, s_path);
        strcat(path, "/");
        strcat(path, list[i]);
        if (stat(path, &statbuf) != 0)
        {
            fprintf(stderr, "failed to stat name '%s' (%d: %s)\n", path, errno, strerror(errno));
            continue;
        }

        if ((S_ISDIR(statbuf.st_mode)) != 0 && (S_ISREG(statbuf.st_mode)) == 0)
        {
            printf("DIR: %s\n", path);
            build(path, root + 2);
        }
    }
    closedir(dir);
}

int main(void)
{
    build(".", 0);
}

Upvotes: 1

Related Questions