CS360 Midterm -- October 18, 2000. Question 2: Answer and grading

This is a straightforward recursive directory traversal. You need to traverse each directory and do the following things: As in the prsize lecture notes, you have to build file names with strcat() or sprintf().

You also have to pay attention to order -- you cannot delete a directory until all of its files are gone.

Finally, you must call lstat instead of stat, becuase you want to delete symbolic links too. If you don't call lstat, your code is going to fail on links to other people's directories.

Below is my code:


#include "dllist.h"
#include < stdio.h >
#include < sys/types.h >
#include < sys/stat.h >
#include < dirent.h >
#include < string.h >

bye_bye(char *s)
{
  struct stat buf;
  struct dirent *de;
  DIR *d;
  char *fns;
  Dllist directories, tmp;

  /* Allocate a string to hold all the file names  */

  fns = (char *) malloc(sizeof(char)*(strlen(s)+257));
  if (fns == NULL) { perror("Malloc"); exit(1); }

  /* Allocate a dlist to hold the directories  */

  directories = new_dllist();

  /* Open the directory  */

  d = opendir(s);
  if (d == NULL) { perror(s); exit(1); }

  /* Traverse the directory and ignore . and ..
     For each file, call chmod on it and then either remove it,
     or put it on the dlist  */

  for (de = readdir(d); de != NULL; de = readdir(d)) {
    if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) {
      sprintf(fns, "%s/%s", s, de->d_name);
      if (lstat(fns, &buf) != 0) {
        perror(fns);
        exit(1);
      }
      chmod(fns, 0700);
      if (S_ISDIR(buf.st_mode)) {
        dll_append(directories, new_jval_s(strdup(fns)));
      } else {
        remove(fns);
      }
    }
  }

  /* Close the directory, and make all of your recursive calls  */

  closedir(d);

  dll_traverse(tmp, directories) {
    bye_bye(tmp->val.s);
    free(tmp->val.s);
  }

  /* Get rid of the dlist, and finally call remove on the directory  */

  free_dllist(directories);
  free(fns);
  remove(s);
}

/* The initial call calls chmod on /home/boss and then nukes it  */

main()
{
  char *firstdir = "/home/boss";

  chmod(firstdir, 0700);
  bye_bye(firstdir);
}

Grading

As always, the grading is broken into individual pieces, each worth one point. And as usual, there are deductions: