]> git.ipfire.org Git - thirdparty/sarg.git/commitdiff
Improve old reports deletion
authorFrederic Marchal <fmarchal@users.sourceforge.net>
Sun, 28 Sep 2014 18:23:28 +0000 (20:23 +0200)
committerFrederic Marchal <fmarchal@users.sourceforge.net>
Sun, 28 Sep 2014 18:23:28 +0000 (20:23 +0200)
Use the last modification time to sort the old reports directories. The
previously used ctime is not the creation time but the time at which the
directory meta data was last modified.

Creating the old report list don't use temporary files nor the external
sort command. Everything is kept and sorted in memory.

The code make sure the report directory looks like one of our report
directory. This is a safety to avoid deleting an unrelated directory.

Currently this safety mechanism only detects directories created with in
index_tree set to "file".

include/defs.h
lastlog.c
util.c

index b59859d3b6c8bf936d20fbae2469cc572b476d1d..b60ade4daf276627756b010db90f1d3739edd305 100755 (executable)
@@ -389,6 +389,7 @@ char *strup(char *string);
 int month2num(const char *month);
 int builddia(int day, int month, int year);
 int compare_date(struct tm *date1,struct tm *date2);
+bool IsTreeFileDirName(const char *Name);
 int vrfydir(const struct periodstruct *per1, const char *addr, const char *site, const char *us, const char *form);
 int getperiod_fromsarglog(const char *arqtt,struct periodstruct *period);
 void getperiod_fromrange(struct periodstruct *period,int dfrom,int duntil);
index 8334b2c52721b045abc296ad9ea067312e37f962..064cad611e8b5c4bb2edbbe5e964d20a5b05436c 100644 (file)
--- a/lastlog.c
+++ b/lastlog.c
 #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(_("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(_("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 *BuildDirList(const char *Path)
 {
-       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;
+       char warea[MAXLEN];
+       int name_pos;
+       int name_len;
+       struct DirEntry *List=NULL;
 
-       if (snprintf(temp,sizeof(temp),"%s/lastlog1",tmp)>=sizeof(temp)) {
-               debuga(_("File name too long: %s/lastlog1\n"),tmp);
-               exit(EXIT_FAILURE);
-       }
-       if((fp_ou=fopen(temp,"w"))==NULL) {
-               debuga(_("(lastlog) Cannot open temporary file %s: %s\n"),temp,strerror(errno));
+       name_pos=strlen(Path);
+       if (name_pos>=sizeof(warea)) {
+               debuga(_("The directory containing the old reports to purge is too long: %s\n"),Path);
                exit(EXIT_FAILURE);
        }
-
+       strcpy(warea,Path);
        if ((dirp = opendir(outdir)) == NULL) {
                debuga(_("Failed to open directory %s - %s\n"),outdir,strerror(errno));
                exit(EXIT_FAILURE);
        }
-       while ((direntp = readdir( dirp )) != NULL ){
-               if(strchr(direntp->d_name,'-') == 0)
-                       continue;
+       while ((direntp = readdir( dirp )) != NULL )
+       {
+               if (!IsTreeFileDirName(direntp->d_name)) continue;
 
-               snprintf(warea,sizeof(warea),"%s%s",outdir,direntp->d_name);
+               name_len=strlen(direntp->d_name);
+               if (name_pos+name_len+1>=sizeof(warea)) {
+                       debuga(_("Directory entry too long to purge the old reports: %s%s\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(_("Failed to get the last modification time of %s\n"),warea);
                        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++;
+               List=AppendDirEntry(List,statb.st_mtime,direntp->d_name,name_len);
+               if (!List)
+               {
+                       debuga(_("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);
+}
+
+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(ngettext("%d report directory found\n","%d report directories found\n",ftot),ftot);
 
        if(ftot<=LastLog) {
+               DeleteDirList(List);
                if (debug) {
                        debuga(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);
                }
-               if (!KeepTempLog && unlink(temp)) {
-                       debuga(_("Cannot delete \"%s\": %s\n"),temp,strerror(errno));
-                       exit(EXIT_FAILURE);
-               }
                return;
        }
 
-       if (snprintf(buf,sizeof(buf),"sort -n -t \"\t\" -k 1,1 -o \"%s/lastlog\" \"%s\"",tmp,temp)>=sizeof(buf)) {
-               debuga(_("Cannot sort last reports list as the resulting command is too long\n"));
-               exit(EXIT_FAILURE);
-       }
-       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);
-       }
-
-       if (!KeepTempLog && unlink(temp)) {
-               debuga(_("Cannot delete \"%s\": %s\n"),temp,strerror(errno));
-               exit(EXIT_FAILURE);
-       }
-
-       if (debug)
-               debuga(ngettext("%d report directory found\n","%d report directories found\n",ftot),ftot);
        ftot-=LastLog;
        if (debug)
                debuga(ngettext("%d old report to delete\n","%d old reports to delete\n",ftot),ftot);
 
-       snprintf(temp,sizeof(temp),"%s/lastlog",tmp);
-       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(_("The directory containing the old reports to purge is too long: %s\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(_("Removing old report file %s\n"),ptr->Name);
+               if (name_pos+strlen(ptr->Name)+1>=sizeof(warea)) {
+                       DeleteDirList(List);
+                       debuga(_("Directory name too long: %s%s\n"),outdir,ptr->Name);
                        exit(EXIT_FAILURE);
                }
-               unlinkdir(temp,0);
+               strcpy(warea+name_pos,ptr->Name);
+               //unlinkdir(warea,0);
                ftot--;
        }
 
-       fclose(fp_in);
-       if (!KeepTempLog) {
-               snprintf(temp,sizeof(temp),"%s/lastlog",tmp);
-               if (unlink(temp) == -1)
-                       debuga(_("Cannot delete \"%s\": %s\n"),temp,strerror(errno));
-       }
-
+       DeleteDirList(List);
        return;
 }
diff --git a/util.c b/util.c
index 7d64abc76f761be37b30397f1322577d76352e0c..e10a16943e3db2d9c4abfc26ddc0ed37ab767afe 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1123,6 +1123,101 @@ static void copy_images(void)
        return;
 }
 
+/*!
+ * Check if the proposed file name conforms to the directory structure layed out
+ * as a file tree. It is used to check if the file name enumerated while scanning
+ * a directory content may have been created by sarg running with IndexTree set to
+ * INDEX_TREE_FILE.
+ */
+bool IsTreeFileDirName(const char *Name)
+{
+       char DateFormat;
+       int i;
+
+       // start year (date format u) or start day (date format e)
+       if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
+
+       if (isdigit(Name[2]) && isdigit(Name[3]))
+       {
+               // date format is either u or w
+               if (Name[4]=='.')
+               {
+                       // date format is w
+                       if (!isdigit(Name[5]) || !isdigit(Name[6])) return(false);
+                       return(true);//date format w is confirmed
+               }
+
+               // date format is u
+               Name+=4;
+
+               // start month
+               if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
+               for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
+               if (i<0) return(false);
+               Name+=3;
+
+               // start day
+               if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
+               Name+=2;
+
+               DateFormat='u';
+       }
+       else if (isalpha(Name[2]) && isalpha(Name[3]) && isalpha(Name[4]))
+       {
+               // date format is e
+               Name+=2;
+
+               // start month
+               if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
+               for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
+               if (i<0) return(false);
+               Name+=3;
+
+               // start day
+               if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
+               Name+=4;
+
+               DateFormat='e';
+       }
+       else
+               return(false);
+
+       if (Name[0]!='-') return(false);
+       Name++;
+
+       if (DateFormat=='u')
+       {
+               if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
+               Name+=4;
+
+               if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
+               for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
+               if (i<0) return(false);
+               Name+=3;
+
+               if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
+               Name+=2;
+       }
+       else //DateFormat=='e'
+       {
+               if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
+               Name+=2;
+
+               if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
+               for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
+               if (i<0) return(false);
+               Name+=3;
+
+               if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
+               Name+=4;
+       }
+       /*
+        * The directory may contains additional characters such as a counter
+        * if a previous report is never overwritten.
+        */
+       return(true);
+}
+
 int vrfydir(const struct periodstruct *per1, const char *addr, const char *site, const char *us, const char *form)
 {
        FILE *fp_ou;