#include <stdlib.h>
#include <stdio.h>
#include <linux/ext3_fs.h>
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <libgen.h>

static char *help = 
"This tool attempts to recover inode numbers and file names\nfrom inode dumps made with dumpem.sh.\n\nTHIS IS OPEN SOURCE SOFTWARE\n\nPhilip J. Mucci (mucci@cs.utk.edu)\nhttp://www.cs.utk.edu/~mucci";

int main(int argc, char **argv)
{
  int fd, i = 0;
  int bytes;
  char iname[PATH_MAX];
  char name[PATH_MAX], *basen = NULL;
  struct ext3_dir_entry_2 dirent;
  struct stat stb;

  if (argc != 2)
    {
    help:
      fprintf(stderr,"Usage: %s [-h] <inode_dump_file_number>\n",argv[0]);
      fprintf(stderr,"%s\n",help);
      exit(1);
    }
  if (strcmp(argv[1],"-h") == 0)
    goto help;
  if (stat(argv[1],&stb) == -1)
    {
      perror("stat()");
      exit(1);
    }
  if (stb.st_size % 4096)
    {
#ifdef DEBUG
      fprintf(stderr,"Error: %s does not appear to be a directory file. (size%%4096.ne.0)\n",argv[0]);
#endif
      exit(1);
    }

fd = open(argv[1],O_RDONLY);
  if (fd == -1)
    {
      perror("open()");
      exit(1);
    }
  
  basen = basename(strdup(argv[1]));
  if ((basen == NULL) || (strlen(basen) == 0))
    {
      fprintf(stderr,"Error: bad argv[1] %s\n",argv[1]);
      exit(1);
    }
#ifdef DEBUG
      printf(stderr,"ARGUMENT %s\n",argv[1]);
      printf(stderr,"BASENAME %s\n",basen);
#endif
  while(1)
    {
      bytes = read(fd,&dirent,sizeof(dirent));
      if (bytes < 0)
	{
	  perror("read()");
	  exit(1);
	}
      else if (bytes == 0)
	{
	  exit(0);
	}
      else if (bytes < sizeof(dirent))
	{
	  fprintf(stderr,"Error: short read %d vs %d bytes.\n",bytes,sizeof(dirent));
	  exit(1);
	}
      
      strncpy(name,dirent.name,dirent.name_len);
      name[dirent.name_len] = '\0';
#ifdef DEBUG
      fprintf(stderr,"INODE %d\n",dirent.inode);
      fprintf(stderr,"REC LEN %d\n",(int)dirent.rec_len);
      fprintf(stderr,"NAME LEN %d\n",(int)dirent.name_len);
      fprintf(stderr,"FILE TYPE %d\n",(int)dirent.file_type);
      fprintf(stderr,"FILE NAME %s\n",name);
#endif
      sprintf(iname,"%d",dirent.inode);
      if (i == 0)
	{
	  if (strcmp(iname,basen) != 0)
	    {
#ifdef DEBUG
	      fprintf(stderr,"Error: %s does not appear to be a directory file. (inode.ne.name)\n",argv[0]);
#endif
	      exit(1);
	    }
	}
      if (dirent.file_type == 1)
	{
	  printf("%d %s\n",dirent.inode,name);
	  symlink(iname,name);
	}
      i++;
      if (lseek(fd,-(bytes-(int)dirent.rec_len),SEEK_CUR) == -1)
	{
	  perror("lseek()");
	  exit(1);
	}
    }
}

