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

 /* dirwatch.c  v1.01  by ajax@mobis.com  March 1998
 
    this program monitors a directory and all the files in it for
    any changes, any files that have new data added to them, that data
    logged to a file.
    
    I can think of only two uses for this program offhand, that of
    monitoring /var/spool/mail to log all new mail traffic on the system
    and of course the other use being to g0bbl3 k0d3z, its primary
    function.  
 
 
TODO:        
    
    1.Add a function to check for new files, add them to the original
      struct file_size_mtime table, and increment the number_of_files.
    
    2.Use intelligent file buffering instead of crappy system() calls.
    
    3.Command line options to bind to socket, log to file or dump
      data to stdout.
      
*/


/* GLOBALS */
int seconds;              /* seconds between stat's, set by argv[3] */
char *outfile;

/* first structured array with which we will 
 * save file stat information
 */
struct file_size_mtime        
 { char *filename;
   size_t file_size;
   time_t file_mtime;
 };
struct file_size_mtime table[1024];  /* 1024 max files per directory */





int chk_stat(struct file_size_mtime *tabletwo)
{
  FILE *infile_fp, *outfile_fp;
  int result;
  char buf[200];
  struct stat stat;
  char buffer[65535]; /* if it changes more than 64k between passes, we
  overrun this buffer. to fix: while(bytesread=fread(4096..))fwrite */
  off_t file_pos;
  lstat(tabletwo->filename, &stat);

  /* check to see if the newly stat'd mtime is greater than the
     previous mtime in the old structure, if it is, check to make
     sure the filesize also is greater than that of the old stat'd
     structure. */
  if(stat.st_mtime > tabletwo->file_mtime)
  {
   
 /* if file size is smaller make 
  * the assumption that it is all new data 
  */     
      if(stat.st_size < tabletwo->file_size)
          tabletwo->file_size = 0;
     
      if ((infile_fp = fopen(tabletwo->filename,"rb"))==NULL)
      {
         printf("fopen: error opening infile_fp for reading\n");
         return 0;
      }
/* swapped terms of -, SEEK_END is bytes+eof */      
      file_pos = tabletwo->file_size-stat.st_size;
      if ((result=fseek(infile_fp,file_pos,SEEK_END))!=0)
      {
         printf("fseek: error during seek of %s.\n",tabletwo->filename);
         return 0;
      }
/* there was a sizeof here. inexplicable. -fb */
/* swapped size and count, stdio sucks -fb*/
      result = fread(buffer,1,stat.st_size-tabletwo->file_size,infile_fp);    
      if (ferror(infile_fp)) {
        perror("fread");
      }
      fclose(infile_fp);
      if ((outfile_fp = fopen(outfile,"ab"))==NULL) {
         printf("fopen: error opening %s for writing.\n",outfile);
                 return 0;
      }
      result = fwrite(buffer,1,result,outfile_fp);
      fclose(outfile_fp);

    }

  tabletwo->file_size=stat.st_size;
  tabletwo->file_mtime=stat.st_mtime;
} 


void usage(char *program_name){
  printf("usage: %s pathname outfile seconds\n", program_name); return;}

main(argc, argv)
int argc;
char *argv[];
{   DIR *directory;
    /* int end_of_entries = 0; CAN BE DELETED */
    char *directory_to_open;
	int count;                     /* interval of stat array structure */
	int number_of_files;           /* complete number of files to work with */
	struct dirent *directory_entry;

    if (argc < 4)
     {
       usage(argv[0]);
       exit(1);
     } 
    directory_to_open=argv[1];
    outfile=argv[2];
    seconds=atoi(argv[3]);
    
/* open directory_to_open pointed to by argv[1] and go into a while
   loop using readdir to read each directory_entry_pointer until
   it reaches the end of the directory (NULL). */
    chdir(directory_to_open);        /* Change to that directory */
    directory = opendir(directory_to_open);
    if(!directory)                   /* Error opening directory? */
    {
    	perror(directory_to_open);   /* Print the error and exit */
    	exit(1);
    }

    count = 0;                   /* initialize struct array number to 0 */
 
    while((directory_entry = readdir(directory)) != NULL)
    {
	struct stat stat;
	lstat(directory_entry->d_name, &stat);
	if(!S_ISREG(stat.st_mode))		/* not a normal file */
	    continue;
	table[count].filename = strdup(directory_entry->d_name);
	table[count].file_size = stat.st_size;
	table[count].file_mtime = stat.st_mtime;  
	++count;          
    }
    closedir(directory);
    number_of_files = count;        /* save the number of files in dir */

/* ok, the table has been constructed.  Now, its time to process
   whats given and keep stat'ing it, comparing what is put into
   the new struct temp_filetable to what was in the original table. */
    while(1)
    {
        count = 0;                   /* reset counter again */
        sleep(seconds);
        while (count < number_of_files)
        {
            chk_stat(&table[count]);
            ++count;
        }
    }
    return 0;
}

