/* Version 2.0 modified by Usurper 11/12/99

   1. Will now accept the -r switch if you're not using the standard /etc/glftpd.conf
   2. Fully recursive, will count subdirectories when counting the size of directories
      that it's updating
   3. Will not strip the leading '/' if your rootpath is set to "/"

*/

#include 	<sys/param.h>
#include 	<sys/stat.h>
#include	<unistd.h>
#include	<string.h>
#include	<syslog.h>
#include 	<sys/file.h>
#include	<fcntl.h>
#include	<dirent.h>
#include 	<stdio.h>

static char rootpath[MAXPATHLEN];
static char datapath[MAXPATHLEN];

struct dirlog {
        ushort status;     // 0 = NEWDIR, 1 = NUKE, 2 = UNNUKE, 3 = DELETED
        time_t uptime;
        ushort uploader;    /* Libc6 systems use ushort in place of uid_t/gid_t */
        ushort group;
        ushort files;
        long bytes;
        char dirname[255];
        struct dirlog *nxt;
        struct dirlog *prv;
};

void load_sysconfig( void );
void update_log (struct dirlog log);
char *trim(char *str);
char config_file[MAXPATHLEN];

/****************************************************************************
        UPDATE DIRLOG DATABASE
****************************************************************************/
int main(int argc, char **argv) {
        DIR *dirf;
        struct dirent *dn;
        struct stat st;
 	struct dirlog log;
        char temppath [MAXPATHLEN];
        char nambuf [MAXPATHLEN];
	long bytes;
	int files;
	int arg=0;

	strcpy(config_file, "/etc/glftpd.conf");
	if (argc < 2) {
		printf("\n\
glFtpD DIRLOG update utility v2.0\n\n\
Usage: %s [-r /pathto/glftpd.conf] <full directory path>\n\n",argv[0]);
	exit(0);
	}
		
	if (argv[++arg][0] == '-' && argv[arg][1] == 'r') {
	  char *ptr;
	  if (strlen(argv[arg]) == 2)
	    arg++;
	  if (arg == 2)
	    strncpy(config_file, argv[arg++], sizeof(config_file));
	  else
	    strncpy(config_file, argv[arg++]+2, sizeof(config_file));
	  ptr = strchr(config_file, ' ');
	  if (ptr)
	    *ptr = '\0';
	}
        (void)load_sysconfig();

	strncpy(nambuf, argv[arg], sizeof(nambuf));
        dirf = opendir (nambuf);
        if (!dirf) {
                printf("Cannot read from directory (%s).\n", nambuf);
                exit(1);
        }
        while (1)
        {
                dn = readdir(dirf);
                if (!dn)
                        break;
                if (!strcmp(dn->d_name, ".") || !strcmp(dn->d_name, "..") ||
			strstr(dn->d_name, "NUKED") != NULL)
                        continue;
                snprintf(temppath, MAXPATHLEN, "%s/%s", nambuf, dn->d_name);
                stat (temppath, &st);
                if ( S_ISDIR(st.st_mode) )
                {   	
                        log.status = 0;
			log.uptime = (time_t)st.st_mtime;
			log.uploader = (ushort)st.st_uid;
			log.group = (ushort)st.st_gid;
			strncpy(log.dirname, temppath, sizeof(log.dirname));
			bytes = 0L;
			files = 0;
			get_dir_size(temppath, &files, &bytes);
			log.files = files;
			log.bytes = bytes;
			(void)update_log(log);
                }
        }
        closedir(dirf);
	exit(0);
}

get_dir_size(char *dirname, int *files, long *bytes) {
	DIR *dirg;
	struct dirent *dp;
        struct stat st;
	char temppath[MAXPATHLEN];

	dirg = opendir(dirname);
	if (dirg) {
	  while (1) {
	     dp = readdir(dirg);
	     if (!dp)
	     	break;
	     if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..") ||
		 !strcasecmp(dp->d_name, "file_id.diz") || !strcmp(dp->d_name, ".message"))
		continue;
	     if (strlen(dp->d_name) > 3)
	       if (!strcasecmp(dp->d_name+strlen(dp->d_name)-4, ".nfo"))
		 continue; 

	     snprintf(temppath, MAXPATHLEN, "%s/%s", dirname, dp->d_name);
	     stat (temppath, &st);
	     if (S_ISREG(st.st_mode)) {
	     	*(files) += 1;
	     	*(bytes) += st.st_size;
	     } else if ( S_ISDIR(st.st_mode) )
		get_dir_size(temppath, files, bytes);
	  }
 	closedir(dirg);
	}
}

/*-------------------------end of SITE UPDATE-----------------------------*/

/***************************************************************************
	UPDATE_LOG
***************************************************************************/

void
update_log(log)
struct dirlog log;
{
	struct dirlog newlog;
	char work_buf[MAXPATHLEN];
	char actname[MAXPATHLEN];
	FILE *file;
	int x, y;

	if (strrchr(log.dirname, '/') == NULL)
		strncpy(actname, log.dirname, sizeof(actname));
	else
		strncpy(actname, strrchr(log.dirname, '/') + sizeof(char), sizeof(actname));

	snprintf(work_buf, MAXPATHLEN, "%s/%s/logs/dirlog", rootpath, datapath);
	file = fopen(work_buf, "r+b");
	if (file == NULL) {
		printf("Cannot open %s\n", work_buf);
		exit(1);
	}
	
	if (strcmp(rootpath, "/") != 0) {
	bzero(work_buf, sizeof(work_buf));
	y = 0;
	for (x = 0; x < strlen(log.dirname); x++) {
		if (rootpath[x] == log.dirname[x])
			continue;
		work_buf[y++] = log.dirname[x];
	}
	work_buf[y] = '\0';
	strncpy(log.dirname, work_buf, sizeof(log.dirname));
	}
	printf("Updating: %s\n",actname);
	while (1)
	{
		fread(&newlog, sizeof(struct dirlog), 1, file);
		if (feof(file)) {
			fwrite(&log, sizeof(struct dirlog), 1, file);
			fclose(file);
			return;
		}
		if (strstr(newlog.dirname, actname) != NULL) {
			fseek(file, -(sizeof(struct dirlog)), SEEK_CUR);
			fwrite(&log, sizeof(struct dirlog), 1, file);
			fclose(file);
			return;
		}
	}
}
/***************************************************************************
        LOAD_SYSCONFIG
        Loads data from system configuration file.
***************************************************************************/

void
load_sysconfig( void )
{
   FILE *configfile;
   char lvalue[ 64 ];
   char rvalue[ MAXPATHLEN ];
   int  x, y;
   char work_buff[ MAXPATHLEN ];

   strncpy( work_buff, config_file, MAXPATHLEN);

   if ( ( configfile = fopen( work_buff, "r" ) ) == NULL )
        {
                fprintf( stderr, "Bad or missing config file (%s), using defaults\n", config_file);
		      return;
        }

   while ( 1 )
   {
      if ( fgets( work_buff, sizeof( work_buff ), configfile ) == NULL )
      {
         fclose( configfile );
         return;
      }

      /* Clip out comments */
      for ( x = 0; x < strlen( work_buff ); x++ )
         if ( work_buff[ x ] == '#' )
            work_buff[ x ] = '\0';

                /* Trim */
                (void)trim( work_buff );

      /* Clear out old values */
      memset( lvalue, '\0', sizeof( lvalue ) );
      memset( rvalue, '\0', sizeof( rvalue ) );

      /* Parse lvalue */
      y = 0;
      for ( x = 0; x < strlen( work_buff ) && work_buff[ x ] != ' '; x++ )
         if ( isprint( work_buff[ x ] ) )
            lvalue[ y++ ] = work_buff[ x ];

      /* Parse rvalue */
      y = 0; x++;
      for ( ; x < strlen( work_buff ); x++ )
         if ( isprint( work_buff[ x ] ) )
            rvalue[ y++ ] = work_buff[ x ];

      if ( strcasecmp( lvalue, "datapath" ) == 0 )
                strncpy( datapath, rvalue, sizeof( datapath ) );
      if ( strcasecmp( lvalue, "rootpath" ) == 0 )
                strncpy( rootpath, rvalue, sizeof( rootpath ) );
   }
   return;
}
/*-- end of load_sysconfig() ----------------------------------------------*/

/***************************************************************************
        TRIM
        Trims a string. ("    TEST    BBOY    " becomes "TEST BBOY")
***************************************************************************/

char *
trim( char *str )
{
        char *ibuf;
        char *obuf;

   if ( str )
   {
        for ( ibuf = obuf = str; *ibuf; )
      {
                while ( *ibuf && ( isspace ( *ibuf ) ) )
                ibuf++;
                if ( *ibuf && ( obuf != str ) )
            *( obuf++ ) = ' ';
                while ( *ibuf && ( !isspace ( *ibuf ) ) )
            *( obuf++ ) = *( ibuf++ );
      }
      *obuf = '\0';
   }
   return( str );
}
/*-- end of trim() -------------------------------------------------------*/





