static int fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
        off_t offset, struct fuse_file_info *fi)
{
    char file_name[MAXFILENAME];
    printf("Readddir\n");
    
    if (strcmp(path, "/") != 0)
        return -ENOENT;
    
    filler(buf, ".", NULL, 0);
    filler(buf, "..", NULL, 0);
    
    while(sfs_getnextfilename(file_name)) {
        filler(buf, &file_name[0], NULL, 0);
    }
    
    return 0;
}
/* The main testing program
 */
int
main(int argc, char **argv)
{
  int i, j, k;
  int chunksize;
  int readsize;
  char *buffer;
  char fixedbuf[1024];
  int fds[MAX_FD];
  char *names[MAX_FD];
  int filesize[MAX_FD];
  int nopen;                    /* Number of files simultaneously open */
  int ncreate;                  /* Number of files created in directory */
  int error_count = 0;
  int tmp;

  mksfs(1);                     /* Initialize the file system. */

  /* First we open two files and attempt to write data to them.
   */
  {
  char fname[MAX_FILE_NAME+10];
  int i;

  for (i = 0; i < MAX_FILE_NAME+10; i++) {
    if (i != 8) {
      fname[i] = 'A' + (rand() % 26);
    }
    else {
      fname[i] = '.';
    }
  }
  fname[i] = '\0';

  int derp = sfs_fopen(fname);
  if (derp >= 0) {
    fprintf(stderr, "ERROR: creating file with too long name\n");
    error_count++;
  }
  }

  for (i = 0; i < 2; i++) {
    names[i] = rand_name();
    fds[i] = sfs_fopen(names[i]);
    if (fds[i] < 0) {
      fprintf(stderr, "ERROR: creating first test file %s\n", names[i]);
      error_count++;
    }
    tmp = sfs_fopen(names[i]);
    if (tmp >= 0 && tmp != fds[i]) {
      fprintf(stderr, "ERROR: file %s was opened twice\n", names[i]);
      error_count++;
    }
    filesize[i] = (rand() % (MAX_BYTES-MIN_BYTES)) + MIN_BYTES;
  }

  for (i = 0; i < 2; i++) {
    for (j = i + 1; j < 2; j++) {
      if (fds[i] == fds[j]) {
        fprintf(stderr, "Warning: the file descriptors probably shouldn't be the same?\n");
      }
    }
  }

  printf("Two files created with zero length:\n");

  for (i = 0; i < 2; i++) {
    for (j = 0; j < filesize[i]; j += chunksize) {
      if ((filesize[i] - j) < 10) {
        chunksize = filesize[i] - j;
      }
      else {
        chunksize = (rand() % (filesize[i] - j)) + 1;
      }

      if ((buffer = malloc(chunksize)) == NULL) {
        fprintf(stderr, "ABORT: Out of memory!\n");
        exit(-1);
      }
      for (k = 0; k < chunksize; k++) {
        buffer[k] = (char) (j+k);
      }
      tmp = sfs_fwrite(fds[i], buffer, chunksize);
      if (tmp != chunksize) {
        fprintf(stderr, "ERROR: Tried to write %d bytes, but wrote %d\n", 
                chunksize, tmp);
        error_count++;
      }
      free(buffer);
    }
    int tmp = sfs_getfilesize(names[i]);
    if (filesize[i] != tmp) {
      fprintf(stderr, "ERROR: mismatch file size %d, %d\n", filesize[i], tmp);
      error_count++;
    }
  }

  if (sfs_fclose(fds[1]) != 0) {
    fprintf(stderr, "ERROR: close of handle %d failed\n", fds[1]);
    error_count++;
  }

  /* Sneaky attempt to close already closed file handle. */
  if (sfs_fclose(fds[1]) == 0) {
    fprintf(stderr, "ERROR: close of stale handle %d succeeded\n", fds[1]);
    error_count++;
  }

  printf("File %s now has length %d and %s now has length %d:\n",
         names[0], filesize[0], names[1], filesize[1]);

  /* Just to be cruel - attempt to read from a closed file handle. 
   */
  if (sfs_fread(fds[1], fixedbuf, sizeof(fixedbuf)) > 0) {
    fprintf(stderr, "ERROR: read from a closed file handle?\n");
    error_count++;
  }

  fds[1] = sfs_fopen(names[1]);
  
  sfs_fseek(fds[0], 0);
  sfs_fseek(fds[1], 0);
  
  for (i = 0; i < 2; i++) {
    for (j = 0; j < filesize[i]; j += chunksize) {
      if ((filesize[i] - j) < 10) {
        chunksize = filesize[i] - j;
      }
      else {
        chunksize = (rand() % (filesize[i] - j)) + 1;
      }
      if ((buffer = malloc(chunksize)) == NULL) {
        fprintf(stderr, "ABORT: Out of memory!\n");
        exit(-1);
      }
      readsize = sfs_fread(fds[i], buffer, chunksize);

      if (readsize != chunksize) {
        fprintf(stderr, "ERROR: Requested %d bytes, read %d\n", chunksize, readsize);
        readsize = chunksize;
      }
      for (k = 0; k < readsize; k++) {
        if (buffer[k] != (char)(j+k)) {
          fprintf(stderr, "ERROR: data error at offset %d in file %s (%d,%d)\n",
                  j+k, names[i], buffer[k], (char)(j+k));
          error_count++;
          break;
        }
      }
      free(buffer);
    }
  }

  for (i = 0; i < 2; i++) {
    if (sfs_fclose(fds[i]) != 0) {
      fprintf(stderr, "ERROR: closing file %s\n", names[i]);
      error_count++;
    }
  }

  /* Now try to close the files. Don't
   * care about the return codes, really, but just want to make sure
   * this doesn't cause a problem.
   */
  for (i = 0; i < 2; i++) {
    if (sfs_fclose(fds[i]) == 0) {
      fprintf(stderr, "Warning: closing already closed file %s\n", names[i]);
    }
  }

  sfs_remove(names[0]);
  sfs_remove(names[1]);
  /* Now just try to open up a bunch of files.
   */
  ncreate = 0;
  for (i = 0; i < MAX_FD; i++) {
    names[i] = rand_name();
    fds[i] = sfs_fopen(names[i]);
    if (fds[i] < 0) {
      break;
    }
    sfs_fclose(fds[i]);
    ncreate++;
  }

  printf("Created %d files in the root directory\n", ncreate);

  nopen = 0;
  for (i = 0; i < ncreate; i++) {
    fds[i] = sfs_fopen(names[i]);
    if (fds[i] < 0) {
      break;
    }
    nopen++;
  }
  printf("Simultaneously opened %d files\n", nopen);

  for (i = 0; i < nopen; i++) {
    tmp = sfs_fwrite(fds[i], test_str, strlen(test_str));
    if (tmp != strlen(test_str)) {
      fprintf(stderr, "ERROR: Tried to write %d, returned %d\n", 
              (int)strlen(test_str), tmp);
      error_count++;
    }
    if (sfs_fclose(fds[i]) != 0) {
      fprintf(stderr, "ERROR: close of handle %d failed\n", fds[i]);
      error_count++;
    }
  }

  /* Re-open in reverse order */
  for (i = nopen-1; i >= 0; i--) {
    fds[i] = sfs_fopen(names[i]);
    if (fds[i] < 0) {
      fprintf(stderr, "ERROR: can't re-open file %s\n", names[i]);
    }
  }

  /* Now test the file contents.
   */
  for (i = 0; i < nopen; i++) {
      sfs_fseek(fds[i], 0);
  }

  for (j = 0; j < strlen(test_str); j++) {
    for (i = 0; i < nopen; i++) {
      char ch;

      if (sfs_fread(fds[i], &ch, 1) != 1) {
        fprintf(stderr, "ERROR: Failed to read 1 character\n");
        error_count++;
      }
      if (ch != test_str[j]) {
        fprintf(stderr, "ERROR: Read wrong byte from %s at %d (%d,%d)\n", 
                names[i], j, ch, test_str[j]);
        error_count++;
        break;
      }
    }
  }

  /* Now close all of the open file handles.
   */
  for (i = 0; i < nopen; i++) {
    if (sfs_fclose(fds[i]) != 0) {
      fprintf(stderr, "ERROR: close of handle %d failed\n", fds[i]);
      error_count++;
    }
  }

  /* Now we try to re-initialize the system.
   */
  mksfs(0);

  for (i = 0; i < nopen; i++) {
    fds[i] = sfs_fopen(names[i]);
    sfs_fseek(fds[i], 0);
    if (fds[i] >= 0) {
      readsize = sfs_fread(fds[i], fixedbuf, sizeof(fixedbuf));
      if (readsize != strlen(test_str)) {
        fprintf(stderr, "ERROR: Read wrong number of bytes\n");
        error_count++;
      }

      for (j = 0; j < strlen(test_str); j++) {
        if (test_str[j] != fixedbuf[j]) {
          fprintf(stderr, "ERROR: Wrong byte in %s at %d (%d,%d)\n", 
                  names[i], j, fixedbuf[j], test_str[j]);
          printf("%d\n", fixedbuf[1]);
          error_count++;
          break;
        }
      }

      if (sfs_fclose(fds[i]) != 0) {
        fprintf(stderr, "ERROR: close of handle %d failed\n", fds[i]);
        error_count++;
      }
    }
  }

  printf("Trying to fill up the disk with repeated writes to %s.\n", names[0]);
  printf("(This may take a while).\n");

  /* Now try opening the first file, and just write a huge bunch of junk.
   * This is just to try to fill up the disk, to see what happens.
   */
  fds[0] = sfs_fopen(names[0]);
  if (fds[0] >= 0) {
    for (i = 0; i < 100000; i++) {
      int x;

      if ((i % 100) == 0) {
        fprintf(stderr, "%d\r", i);
      }

      memset(fixedbuf, (char)i, sizeof(fixedbuf));
      x = sfs_fwrite(fds[0], fixedbuf, sizeof(fixedbuf));
      if (x != sizeof(fixedbuf)) {
        /* Sooner or later, this write should fail. The only thing is that
         * it should fail gracefully, without any catastrophic errors.
         */
        printf("Write failed after %d iterations.\n", i);
        printf("If the emulated disk contains just over %d bytes, this is OK\n",
               (i * (int)sizeof(fixedbuf)));
        break;
      }
    }
    sfs_fclose(fds[0]);
  }
  else {
    fprintf(stderr, "ERROR: re-opening file %s\n", names[0]);
  }

  printf("Directory listing\n");
  char *filename = (char *)malloc(MAX_FILE_NAME);
  int max = 0;
  while (sfs_getnextfilename(filename)) {
	  if (strcmp(filename, names[max]) != 0) {
	  	printf("ERROR misnamed file %d: %s %s\n", max, filename, names[max]);
		error_count++;
	  }
	  max++;
  }
 
  /* Now, having filled up the disk, try one more time to read the
   * contents of the files we created.
   */
  for (i = 0; i < nopen; i++) {
    fds[i] = sfs_fopen(names[i]);
    sfs_fseek(fds[i], 0);
    if (fds[i] >= 0) {
      readsize = sfs_fread(fds[i], fixedbuf, sizeof(fixedbuf));
      if (readsize < strlen(test_str)) {
        fprintf(stderr, "ERROR: Read wrong number of bytes\n");
        error_count++;
      }

      for (j = 0; j < strlen(test_str); j++) {
        if (test_str[j] != fixedbuf[j]) {
          fprintf(stderr, "ERROR: Wrong byte in %s at position %d (%d,%d)\n", 
                  names[i], j, fixedbuf[j], test_str[j]);
          error_count++;
          break;
        }
      }

      if (sfs_fclose(fds[i]) != 0) {
        fprintf(stderr, "ERROR: close of handle %d failed\n", fds[i]);
        error_count++;
      }
    }
  }

  for (i = 0; i < max; i++) {
	  sfs_remove(names[i]);
  }

  if (sfs_getnextfilename(filename)) {
	  fprintf(stderr, "ERROR: should be empty dir\n");
	  error_count++;
  }
 
  fprintf(stderr, "Test program exiting with %d errors\n", error_count);
  return (error_count);
}