From: Frederic Marchal Date: Sun, 28 Sep 2014 18:23:28 +0000 (+0200) Subject: Improve old reports deletion X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0971b2d6cc7491724ace6b636e50f57fbf2bcfa9;p=thirdparty%2Fsarg.git Improve old reports deletion 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". --- diff --git a/include/defs.h b/include/defs.h index b59859d..b60ade4 100755 --- a/include/defs.h +++ b/include/defs.h @@ -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); diff --git a/lastlog.c b/lastlog.c index 8334b2c..064cad6 100644 --- a/lastlog.c +++ b/lastlog.c @@ -27,124 +27,162 @@ #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 7d64abc..e10a169 100644 --- 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;