Question

Problem 1: what's the best data structure to save the directory structure?

Problem 2: I have tried to use a general tree to solve it, but there are a lot of problems:

  • The number of files under a directory is not certain. So the number of child nodes under a tree node is also not certain. and I try to add a keyword nchild to each node, showing nchild child nodes. so there are nchild pointers (saved with **child) to the child nodes. And once that, **child and *child should be dynamically allocated space with no certain child nodes. So you know, this is really difficult to release these spaces(and the program below is not called free()). Is there a better way to solve it?
  • And sometimes the program below would get the garbage characters when I output the directory tree, which make me really confused. while debugging it, found that is the function ent=readdir(pDir); has read garbage characters. But when I write another simple program to read the same directory, that goes well. I think the problem is the recursive function, but I didn't get any idea. I will be appreciated if some one can give me a idea. Thanks!

```

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

typedef struct tree_file_s
{
  char path[512];
  time_t date;
  char type;
  long size;
  int nchild;

  struct tree_file_s **child;
} tree_file_t;

int dir_child_len(const char *dir)
{
  int nchild = 0;
  DIR *pDir;
  struct dirent *ent;

  pDir = opendir(dir);
  while((ent=readdir(pDir)) != NULL)
  {
    if (strcmp(ent->d_name, ".")==0 || strcmp(ent->d_name, "..")==0) 
    {
      continue; 
    }
    nchild++;
  }

  return nchild;
}

void tree_create(tree_file_t *tft, const char *dir)
{
  int nchild; // the tft has n child
  DIR *pDir;
  struct dirent *ent; // the directory dir dirent info
  struct stat file_stat; // the new file's stat info

  stat(dir, &file_stat);
  nchild = dir_child_len(dir);
  pDir = opendir(dir);

  // Initialize the parent
  //tft->path = calloc(1, strlen(dir)+1);
  strcpy(tft->path, dir);
  tft->date = file_stat.st_mtime;
  tft->type = 'D';
  tft->size = file_stat.st_size;
  tft->nchild = nchild;
  tft->child = calloc(1, nchild);

  nchild = 0;
   while ((ent=readdir(pDir)) != NULL) 
   {
      if (ent->d_type & DT_DIR) 
      {
         if (strcmp(ent->d_name, ".")==0 || strcmp(ent->d_name, "..")==0) 
         {
           continue; 
         }
         tree_file_t *new_dir = calloc(1, sizeof(tree_file_t));
         tft->child[nchild] = new_dir;

         char *new_path = calloc(1, strlen(dir)+strlen(ent->d_name)+1);
         sprintf(new_path, "%s/%s", dir, ent->d_name);
         tree_create(new_dir, new_path);
         free(new_path);
      } else {
        tree_file_t *new_file = calloc(1, sizeof(tree_file_t));
        char *new_path = calloc(1, strlen(dir)+strlen(ent->d_name)+1);
        // new_file->path = calloc(1, strlen(dir)+strlen(ent->d_name)+1);
        sprintf(new_path, "%s/%s", dir, ent->d_name);
        stat(new_path, &file_stat);
        strcpy(new_file->path, new_path);
        free(new_path);
        new_file->date = file_stat.st_mtime;
        new_file->type = 'F';
        new_file->size = file_stat.st_size;
        new_file->nchild = 0;
        new_file->child = 0;

        tft->child[nchild] = new_file;
      }
      //free(new_path);
      //new_path = 0;
      nchild++;
   }
}

void display_tree(tree_file_t *tft)
{
  int nchild, i;

  nchild = tft->nchild;

  printf("%c: %s\n", tft->type, tft->path);

  for(i = 0; i < nchild; i++)
  {
    if(tft->child[i]->type == 'F')
    {
      printf("%c: %s\n",  tft->child[i]->type, tft->child[i]->path);
    } else {
      display_tree(tft->child[i]);
    }
  }
}

int main(int argc, const char *argv[])
{
  if(argc != 2)
  {
    printf("Usage: a.out dir\n");
    exit(0);
  }

  char dir[512];
  strcpy(dir, argv[1]);
  tree_file_t *tft = calloc(1, sizeof(tree_file_t));
  tree_create(tft, dir);
  display_tree(tft);

  return 0;
}

```

Was it helpful?

Solution

When you allocate space for new_path you need to add 2 (one for the slash, one for the null terminator). And you never close the directories you open (use closedir()).

An even more serious error is this line:

tft->child = calloc(1, nchild);

which only allocates nchild bytes, not enough to hold nchild pointers! Try:

tft->child = calloc(nchild, sizeof(*tft->child));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top