]> git.ipfire.org Git - thirdparty/sarg.git/blobdiff - lastlog.c
Optimize away a useless strcpy.
[thirdparty/sarg.git] / lastlog.c
index 09a079e5d8e92a91cc9edee1fd6c062a899ec8a0..0ff25aa2c1b2a8435f8ca0c5b9482b414cf4709e 100644 (file)
--- a/lastlog.c
+++ b/lastlog.c
@@ -1,6 +1,6 @@
 /*
  * SARG Squid Analysis Report Generator      http://sarg.sourceforge.net
- *                                                            1998, 2013
+ *                                                            1998, 2015
  *
  * SARG donations:
  *      please look at http://sarg.sourceforge.net/donations.php
 #include "include/conf.h"
 #include "include/defs.h"
 
-void mklastlog(const char *outdir)
+struct DirEntry
+{
+       struct DirEntry *Next;
+       time_t Time;
+       char *Name;
+};
+
+static void DeleteDirList(struct DirEntry *List)
+{
+       struct DirEntry *Next;
+
+       while (List)
+       {
+               Next=List->Next;
+               if (List->Name) free(List->Name);
+               free(List);
+               List=Next;
+       }
+}
+
+static struct DirEntry *AppendDirEntry(struct DirEntry *List,time_t CreationTime,const char *Name,int NameLen)
+{
+       struct DirEntry *entry;
+       struct DirEntry *prev;
+       struct DirEntry *ptr;
+
+       entry=malloc(sizeof(*entry));
+       if (!entry) {
+               debuga(__FILE__,__LINE__,_("Not enough memory to store a report to purge\n"));
+               DeleteDirList(List);
+               return(NULL);
+       }
+       entry->Name=malloc((NameLen+1)*sizeof(char));
+       if (!entry->Name) {
+               free(entry);
+               debuga(__FILE__,__LINE__,_("Not enough memory to store a report to purge\n"));
+               DeleteDirList(List);
+               return(NULL);
+       }
+       entry->Time=CreationTime;
+       strcpy(entry->Name,Name);
+
+       // store most recent file first
+       prev=NULL;
+       for (ptr=List ; ptr ; ptr=ptr->Next)
+       {
+               if (ptr->Time>CreationTime) break;
+               prev=ptr;
+       }
+       entry->Next=ptr;
+       if (prev)
+               prev->Next=entry;
+       else
+               List=entry;
+
+       return(List);
+}
+
+static struct DirEntry *BuildDirDateList(struct DirEntry *List,char *Path,int PathSize,int RootPos,int Length,int Level)
 {
-       FILE *fp_in, *fp_ou;
        DIR *dirp;
        struct dirent *direntp;
-       char buf[MAXLEN];
-       char temp[MAXLEN];
-       char warea[MAXLEN];
-       char ftime[128];
-       int  ftot=0;
-       time_t t;
-       struct tm *local;
        struct stat statb;
-       int cstatus;
-       struct getwordstruct gwarea;
-
-       if(LastLog <= 0)
-               return;
+       int name_len;
 
-       snprintf(temp,sizeof(temp),"%slastlog1",outdir);
-       if((fp_ou=fopen(temp,"w"))==NULL) {
-               debuga(_("(lastlog) Cannot open temporary file %s: %s\n"),temp,strerror(errno));
+       if ((dirp = opendir(Path)) == NULL) {
+               debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),Path,strerror(errno));
                exit(EXIT_FAILURE);
        }
+       while ((direntp = readdir( dirp )) != NULL )
+       {
+               name_len=strlen(direntp->d_name);
+               if (RootPos+name_len+1>=PathSize) {
+                       debuga(__FILE__,__LINE__,_("Directory entry \"%s%s\" too long to purge the old reports\n"),Path,direntp->d_name);
+                       exit(EXIT_FAILURE);
+               }
+               strcpy(Path+Length,direntp->d_name);
+               if (stat(Path,&statb) == -1) {
+                       debuga(__FILE__,__LINE__,_("Failed to get the statistics of file \"%s\": %s\n"),Path,strerror(errno));
+                       continue;
+               }
+               if (!S_ISDIR(statb.st_mode)) continue;
+               if (Level==0)
+               {
+                       if (IsTreeMonthFileName(direntp->d_name))
+                       {
+                               Path[Length+name_len]='/';
+                               Path[Length+name_len+1]='\0';
+                               List=BuildDirDateList(List,Path,PathSize,RootPos,Length+name_len+1,1);
+                               if (!List)
+                               {
+                                       debuga(__FILE__,__LINE__,_("Old reports deletion not undertaken due to previous error\n"));
+                                       break;
+                               }
+                       }
+               }
+               else if (Level==1)
+               {
+                       if (IsTreeDayFileName(direntp->d_name))
+                       {
+                               List=AppendDirEntry(List,statb.st_mtime,Path+RootPos,Length-RootPos+name_len);
+                               if (!List)
+                               {
+                                       debuga(__FILE__,__LINE__,_("Old reports deletion not undertaken due to previous error\n"));
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       closedir(dirp);
+       return(List);
+}
 
+static struct DirEntry *BuildDirList(const char *Path)
+{
+       DIR *dirp;
+       struct dirent *direntp;
+       struct stat statb;
+       char warea[MAXLEN];
+       int name_pos;
+       int name_len;
+       struct DirEntry *List=NULL;
+
+       name_pos=strlen(Path);
+       if (name_pos>=sizeof(warea)) {
+               debuga(__FILE__,__LINE__,_("The directory name \"%s\" containing the old reports to purge is too long\n"),Path);
+               exit(EXIT_FAILURE);
+       }
+       strcpy(warea,Path);
        if ((dirp = opendir(outdir)) == NULL) {
-               debuga(_("Failed to open directory %s - %s\n"),outdir,strerror(errno));
+               debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),outdir,strerror(errno));
                exit(EXIT_FAILURE);
        }
-       while ((direntp = readdir( dirp )) != NULL ){
-               if(strchr(direntp->d_name,'-') == 0)
-                       continue;
-
-               snprintf(warea,sizeof(warea),"%s%s",outdir,direntp->d_name);
+       while ((direntp = readdir( dirp )) != NULL )
+       {
+               name_len=strlen(direntp->d_name);
+               if (name_pos+name_len+1>=sizeof(warea)) {
+                       debuga(__FILE__,__LINE__,_("Directory entry \"%s%s\" too long to purge the old reports\n"),Path,direntp->d_name);
+                       exit(EXIT_FAILURE);
+               }
+               strcpy(warea+name_pos,direntp->d_name);
                if (stat(warea,&statb) == -1) {
-                       debuga(_("Failed to get the creation time of %s\n"),warea);
+                       debuga(__FILE__,__LINE__,_("Failed to get the statistics of file \"%s\": %s\n"),warea,strerror(errno));
                        continue;
                }
-               t=statb.st_ctime;
-               local = localtime(&t);
-               strftime(ftime, sizeof(ftime), "%Y%m%d%H%M%S", local);
-               fprintf(fp_ou,"%s\t%s\n",ftime,direntp->d_name);
-               ftot++;
+               if (!S_ISDIR(statb.st_mode)) continue;
+               if (IsTreeFileDirName(direntp->d_name))
+               {
+                       List=AppendDirEntry(List,statb.st_mtime,direntp->d_name,name_len);
+                       if (!List)
+                       {
+                               debuga(__FILE__,__LINE__,_("Old reports deletion not undertaken due to previous error\n"));
+                               break;
+                       }
+               }
+               else if (IsTreeYearFileName(direntp->d_name))
+               {
+                       warea[name_pos+name_len]='/';
+                       warea[name_pos+name_len+1]='\0';
+                       List=BuildDirDateList(List,warea,sizeof(warea),name_pos,name_pos+name_len+1,0);
+                       if (!List)
+                       {
+                               debuga(__FILE__,__LINE__,_("Old reports deletion not undertaken due to previous error\n"));
+                               break;
+                       }
+               }
        }
 
-       closedir( dirp );
-       if (fclose(fp_ou)==EOF) {
-               debuga(_("Write error in %s: %s\n"),temp,strerror(errno));
-               exit(EXIT_FAILURE);
-       }
+       closedir(dirp);
+       return(List);
+}
 
-       snprintf(buf,sizeof(buf),"sort -n -t \"\t\" -k 1,1 -o \"%slastlog\" \"%s\"",outdir,temp);
-       cstatus=system(buf);
-       if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
-               debuga(_("sort command return status %d\n"),WEXITSTATUS(cstatus));
-               debuga(_("sort command: %s\n"),buf);
-               exit(EXIT_FAILURE);
-       }
+static void DeleteEmptyDirs(char *Path,int PathSize,int BasePos)
+{
+       char *Dir;
+       DIR *dirp;
+       struct dirent *direntp;
+       bool index;
 
-       if (unlink(temp)) {
-               debuga(_("Cannot delete \"%s\": %s\n"),temp,strerror(errno));
-               exit(EXIT_FAILURE);
+       while ((Dir=strrchr(Path,'/'))!=NULL)
+       {
+               if (Dir-Path<=BasePos) break;
+               *Dir='\0';
+               if ((dirp = opendir(Path)) == NULL) {
+                       debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),Path,strerror(errno));
+                       return;
+               }
+               index=false;
+               while ((direntp = readdir( dirp )) != NULL )
+               {
+                       if (direntp->d_name[0]=='.' && (direntp->d_name[1]=='\0' || (direntp->d_name[1]=='.' && direntp->d_name[2]=='\0'))) continue;
+                       if (!strcmp(direntp->d_name,INDEX_HTML_FILE))
+                       {
+                               index=true;
+                               continue;
+                       }
+                       break;
+               }
+               closedir(dirp);
+               if (direntp!=NULL) {
+                       // at least one file exists in the directory, don't delete the directory
+                       break;
+               }
+               if (debug)
+                       debuga(__FILE__,__LINE__,_("Deleting empty directory \"%s\"\n"),Path);
+               if (index) {
+                       if (strlen(Path)+strlen(INDEX_HTML_FILE)+2>=PathSize) {
+                               debuga(__FILE__,__LINE__,_("Buffer too small to delete index file \"%s/%s\""),Path,INDEX_HTML_FILE);
+                               exit(EXIT_FAILURE);
+                       }
+                       strcat(Path,"/"INDEX_HTML_FILE);
+                       if (unlink(Path)==-1) {
+                               debuga(__FILE__,__LINE__,_("Failed to delete \"%s\": %s\n"),Path,strerror(errno));
+                               exit(EXIT_FAILURE);
+                       }
+                       *Dir='\0';
+               }
+               if (rmdir(Path)) {
+                       debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),Path,strerror(errno));
+                       exit(EXIT_FAILURE);
+               }
        }
+       //! \todo Rebuild the surviving index file
+}
+
+void mklastlog(const char *outdir)
+{
+       char warea[MAXLEN];
+       int name_pos;
+       int  ftot=0;
+       struct DirEntry *List;
+       struct DirEntry *ptr;
+
+       if(LastLog <= 0)
+               return;
+
+       List=BuildDirList(outdir);
+       if (!List) return;
+
+       for (ptr=List ; ptr ; ptr=ptr->Next) ftot++;
+       if (debug)
+               debuga(__FILE__,__LINE__,ngettext("%d report directory found\n","%d report directories found\n",ftot),ftot);
 
        if(ftot<=LastLog) {
-               snprintf(temp,sizeof(temp),"%slastlog",outdir);
-               if(access(temp, R_OK) == 0) {
-                       if (unlink(temp)) {
-                               debuga(_("Cannot delete \"%s\": %s\n"),temp,strerror(errno));
-                               exit(EXIT_FAILURE);
-                       }
+               DeleteDirList(List);
+               if (debug) {
+                       debuga(__FILE__,__LINE__,ngettext("No old reports to delete as only %d report currently exists\n",
+                                               "No old reports to delete as only %d reports currently exist\n",ftot),ftot);
                }
                return;
        }
 
        ftot-=LastLog;
+       if (debug)
+               debuga(__FILE__,__LINE__,ngettext("%d old report to delete\n","%d old reports to delete\n",ftot),ftot);
 
-       snprintf(temp,sizeof(temp),"%slastlog",outdir);
-       if((fp_in=fopen(temp,"r"))==NULL) {
-               debuga(_("(lastlog) Cannot open temporary file %s: %s\n"),temp,strerror(errno));
+       name_pos=strlen(outdir);
+       if (name_pos>=sizeof(warea)) {
+               DeleteDirList(List);
+               debuga(__FILE__,__LINE__,_("The directory name \"%s\" containing the old reports to purge is too long\n"),outdir);
                exit(EXIT_FAILURE);
        }
-
-       while(ftot>0 && fgets(buf,sizeof(buf),fp_in)!=NULL) {
-               fixendofline(buf);
-               getword_start(&gwarea,buf);
-               if (getword(warea,sizeof(warea),&gwarea,'\t')<0) {
-                       debuga(_("Maybe you have a broken record or garbage in your %s file\n"),temp);
-                       exit(EXIT_FAILURE);
-               }
-
+       strcpy(warea,outdir);
+       for (ptr=List ; ptr && ftot>0 ; ptr=ptr->Next)
+       {
                if(debug)
-                       debuga(_("Removing old report file %s\n"),gwarea.current);
-               if (snprintf(temp,sizeof(temp),"%s%s",outdir,gwarea.current)>=sizeof(temp)) {
-                       debuga(_("Directory name too long: %s%s\n"),outdir,gwarea.current);
+                       debuga(__FILE__,__LINE__,_("Removing old report file %s\n"),ptr->Name);
+               if (name_pos+strlen(ptr->Name)+1>=sizeof(warea)) {
+                       DeleteDirList(List);
+                       debuga(__FILE__,__LINE__,_("Path too long: "));
+                       debuga_more("%s%s\n",outdir,ptr->Name);
                        exit(EXIT_FAILURE);
                }
-               unlinkdir(temp,0);
+               strcpy(warea+name_pos,ptr->Name);
+               unlinkdir(warea,0);
+               DeleteEmptyDirs(warea,sizeof(warea),name_pos);
                ftot--;
        }
 
-       fclose(fp_in);
-       snprintf(temp,sizeof(temp),"%slastlog",outdir);
-       if (unlink(temp) == -1) {
-               debuga(_("Cannot delete \"%s\": %s\n"),temp,strerror(errno));
-       }
-
+       DeleteDirList(List);
        return;
 }