]> git.ipfire.org Git - thirdparty/sarg.git/blame - lastlog.c
Add support to decompress xz files
[thirdparty/sarg.git] / lastlog.c
CommitLineData
25697a35 1/*
94ff9470 2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
110ce984 3 * 1998, 2015
25697a35
GS
4 *
5 * SARG donations:
6 * please look at http://sarg.sourceforge.net/donations.php
1164c474
FM
7 * Support:
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
25697a35
GS
9 * ---------------------------------------------------------------------
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
24 *
25 */
26
27#include "include/conf.h"
5f3cfd1d 28#include "include/defs.h"
25697a35 29
0971b2d6
FM
30struct DirEntry
31{
32 struct DirEntry *Next;
33 time_t Time;
34 char *Name;
35};
36
37static void DeleteDirList(struct DirEntry *List)
38{
39 struct DirEntry *Next;
40
41 while (List)
42 {
43 Next=List->Next;
44 if (List->Name) free(List->Name);
45 free(List);
46 List=Next;
47 }
48}
49
50static struct DirEntry *AppendDirEntry(struct DirEntry *List,time_t CreationTime,const char *Name,int NameLen)
51{
52 struct DirEntry *entry;
53 struct DirEntry *prev;
54 struct DirEntry *ptr;
55
56 entry=malloc(sizeof(*entry));
57 if (!entry) {
af961877 58 debuga(__FILE__,__LINE__,_("Not enough memory to store a report to purge\n"));
0971b2d6
FM
59 DeleteDirList(List);
60 return(NULL);
61 }
62 entry->Name=malloc((NameLen+1)*sizeof(char));
63 if (!entry->Name) {
64 free(entry);
af961877 65 debuga(__FILE__,__LINE__,_("Not enough memory to store a report to purge\n"));
0971b2d6
FM
66 DeleteDirList(List);
67 return(NULL);
68 }
69 entry->Time=CreationTime;
70 strcpy(entry->Name,Name);
71
72 // store most recent file first
73 prev=NULL;
74 for (ptr=List ; ptr ; ptr=ptr->Next)
75 {
76 if (ptr->Time>CreationTime) break;
77 prev=ptr;
78 }
79 entry->Next=ptr;
80 if (prev)
81 prev->Next=entry;
82 else
83 List=entry;
84
85 return(List);
86}
87
16c12388
FM
88static struct DirEntry *BuildDirDateList(struct DirEntry *List,char *Path,int PathSize,int RootPos,int Length,int Level)
89{
90 DIR *dirp;
91 struct dirent *direntp;
92 struct stat statb;
93 int name_len;
94
95 if ((dirp = opendir(Path)) == NULL) {
af961877 96 debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),Path,strerror(errno));
16c12388
FM
97 exit(EXIT_FAILURE);
98 }
99 while ((direntp = readdir( dirp )) != NULL )
100 {
101 name_len=strlen(direntp->d_name);
102 if (RootPos+name_len+1>=PathSize) {
af961877 103 debuga(__FILE__,__LINE__,_("Directory entry \"%s%s\" too long to purge the old reports\n"),Path,direntp->d_name);
16c12388
FM
104 exit(EXIT_FAILURE);
105 }
106 strcpy(Path+Length,direntp->d_name);
107 if (stat(Path,&statb) == -1) {
af961877 108 debuga(__FILE__,__LINE__,_("Failed to get the statistics of file \"%s\": %s\n"),Path,strerror(errno));
16c12388
FM
109 continue;
110 }
111 if (!S_ISDIR(statb.st_mode)) continue;
112 if (Level==0)
113 {
114 if (IsTreeMonthFileName(direntp->d_name))
115 {
116 Path[Length+name_len]='/';
117 Path[Length+name_len+1]='\0';
118 List=BuildDirDateList(List,Path,PathSize,RootPos,Length+name_len+1,1);
119 if (!List)
120 {
af961877 121 debuga(__FILE__,__LINE__,_("Old reports deletion not undertaken due to previous error\n"));
16c12388
FM
122 break;
123 }
124 }
125 }
126 else if (Level==1)
127 {
128 if (IsTreeDayFileName(direntp->d_name))
129 {
130 List=AppendDirEntry(List,statb.st_mtime,Path+RootPos,Length-RootPos+name_len);
131 if (!List)
132 {
af961877 133 debuga(__FILE__,__LINE__,_("Old reports deletion not undertaken due to previous error\n"));
16c12388
FM
134 break;
135 }
136 }
137 }
138 }
139
140 closedir(dirp);
141 return(List);
142}
143
0971b2d6 144static struct DirEntry *BuildDirList(const char *Path)
25697a35 145{
9bd92830
FM
146 DIR *dirp;
147 struct dirent *direntp;
9bd92830 148 struct stat statb;
0971b2d6
FM
149 char warea[MAXLEN];
150 int name_pos;
151 int name_len;
152 struct DirEntry *List=NULL;
9bd92830 153
0971b2d6
FM
154 name_pos=strlen(Path);
155 if (name_pos>=sizeof(warea)) {
af961877 156 debuga(__FILE__,__LINE__,_("The directory name \"%s\" containing the old reports to purge is too long\n"),Path);
007905af 157 exit(EXIT_FAILURE);
9bd92830 158 }
0971b2d6 159 strcpy(warea,Path);
9bd92830 160 if ((dirp = opendir(outdir)) == NULL) {
af961877 161 debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),outdir,strerror(errno));
9bd92830
FM
162 exit(EXIT_FAILURE);
163 }
0971b2d6
FM
164 while ((direntp = readdir( dirp )) != NULL )
165 {
0971b2d6
FM
166 name_len=strlen(direntp->d_name);
167 if (name_pos+name_len+1>=sizeof(warea)) {
af961877 168 debuga(__FILE__,__LINE__,_("Directory entry \"%s%s\" too long to purge the old reports\n"),Path,direntp->d_name);
0971b2d6
FM
169 exit(EXIT_FAILURE);
170 }
171 strcpy(warea+name_pos,direntp->d_name);
9bd92830 172 if (stat(warea,&statb) == -1) {
af961877 173 debuga(__FILE__,__LINE__,_("Failed to get the statistics of file \"%s\": %s\n"),warea,strerror(errno));
9bd92830
FM
174 continue;
175 }
16c12388
FM
176 if (!S_ISDIR(statb.st_mode)) continue;
177 if (IsTreeFileDirName(direntp->d_name))
0971b2d6 178 {
16c12388
FM
179 List=AppendDirEntry(List,statb.st_mtime,direntp->d_name,name_len);
180 if (!List)
181 {
af961877 182 debuga(__FILE__,__LINE__,_("Old reports deletion not undertaken due to previous error\n"));
16c12388
FM
183 break;
184 }
185 }
186 else if (IsTreeYearFileName(direntp->d_name))
187 {
188 warea[name_pos+name_len]='/';
189 warea[name_pos+name_len+1]='\0';
190 List=BuildDirDateList(List,warea,sizeof(warea),name_pos,name_pos+name_len+1,0);
191 if (!List)
192 {
af961877 193 debuga(__FILE__,__LINE__,_("Old reports deletion not undertaken due to previous error\n"));
16c12388
FM
194 break;
195 }
0971b2d6 196 }
9bd92830
FM
197 }
198
0971b2d6
FM
199 closedir(dirp);
200 return(List);
201}
202
16c12388
FM
203static void DeleteEmptyDirs(char *Path,int PathSize,int BasePos)
204{
205 char *Dir;
206 DIR *dirp;
207 struct dirent *direntp;
208 bool index;
209
210 while ((Dir=strrchr(Path,'/'))!=NULL)
211 {
212 if (Dir-Path<=BasePos) break;
213 *Dir='\0';
214 if ((dirp = opendir(Path)) == NULL) {
af961877 215 debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),Path,strerror(errno));
16c12388
FM
216 return;
217 }
218 index=false;
219 while ((direntp = readdir( dirp )) != NULL )
220 {
221 if (direntp->d_name[0]=='.' && (direntp->d_name[1]=='\0' || (direntp->d_name[1]=='.' && direntp->d_name[2]=='\0'))) continue;
222 if (!strcmp(direntp->d_name,INDEX_HTML_FILE))
223 {
224 index=true;
225 continue;
226 }
227 break;
228 }
229 closedir(dirp);
230 if (direntp!=NULL) {
231 // at least one file exists in the directory, don't delete the directory
232 break;
233 }
234 if (debug)
af961877 235 debuga(__FILE__,__LINE__,_("Deleting empty directory \"%s\"\n"),Path);
16c12388
FM
236 if (index) {
237 if (strlen(Path)+strlen(INDEX_HTML_FILE)+2>=PathSize) {
af961877 238 debuga(__FILE__,__LINE__,_("Buffer too small to delete index file \"%s/%s\""),Path,INDEX_HTML_FILE);
16c12388
FM
239 exit(EXIT_FAILURE);
240 }
241 strcat(Path,"/"INDEX_HTML_FILE);
242 if (unlink(Path)==-1) {
af961877 243 debuga(__FILE__,__LINE__,_("Failed to delete \"%s\": %s\n"),Path,strerror(errno));
16c12388
FM
244 exit(EXIT_FAILURE);
245 }
246 *Dir='\0';
247 }
248 if (rmdir(Path)) {
af961877 249 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),Path,strerror(errno));
16c12388
FM
250 exit(EXIT_FAILURE);
251 }
252 }
253 //! \todo Rebuild the surviving index file
254}
255
0971b2d6
FM
256void mklastlog(const char *outdir)
257{
258 char warea[MAXLEN];
259 int name_pos;
260 int ftot=0;
261 struct DirEntry *List;
262 struct DirEntry *ptr;
263
264 if(LastLog <= 0)
265 return;
266
267 List=BuildDirList(outdir);
268 if (!List) return;
269
270 for (ptr=List ; ptr ; ptr=ptr->Next) ftot++;
271 if (debug)
af961877 272 debuga(__FILE__,__LINE__,ngettext("%d report directory found\n","%d report directories found\n",ftot),ftot);
9bd92830 273
0428e5fd 274 if(ftot<=LastLog) {
0971b2d6 275 DeleteDirList(List);
0428e5fd 276 if (debug) {
af961877 277 debuga(__FILE__,__LINE__,ngettext("No old reports to delete as only %d report currently exists\n",
0428e5fd
FM
278 "No old reports to delete as only %d reports currently exist\n",ftot),ftot);
279 }
0428e5fd
FM
280 return;
281 }
282
9bd92830 283 ftot-=LastLog;
0428e5fd 284 if (debug)
af961877 285 debuga(__FILE__,__LINE__,ngettext("%d old report to delete\n","%d old reports to delete\n",ftot),ftot);
9bd92830 286
0971b2d6
FM
287 name_pos=strlen(outdir);
288 if (name_pos>=sizeof(warea)) {
289 DeleteDirList(List);
af961877 290 debuga(__FILE__,__LINE__,_("The directory name \"%s\" containing the old reports to purge is too long\n"),outdir);
007905af 291 exit(EXIT_FAILURE);
9bd92830 292 }
0971b2d6
FM
293 strcpy(warea,outdir);
294 for (ptr=List ; ptr && ftot>0 ; ptr=ptr->Next)
295 {
9bd92830 296 if(debug)
af961877 297 debuga(__FILE__,__LINE__,_("Removing old report file %s\n"),ptr->Name);
0971b2d6
FM
298 if (name_pos+strlen(ptr->Name)+1>=sizeof(warea)) {
299 DeleteDirList(List);
af961877 300 debuga(__FILE__,__LINE__,_("Path too long: "));
041018b6 301 debuga_more("%s%s\n",outdir,ptr->Name);
9bd92830
FM
302 exit(EXIT_FAILURE);
303 }
0971b2d6 304 strcpy(warea+name_pos,ptr->Name);
1ed866e0 305 unlinkdir(warea,0);
16c12388 306 DeleteEmptyDirs(warea,sizeof(warea),name_pos);
9bd92830
FM
307 ftot--;
308 }
309
0971b2d6 310 DeleteDirList(List);
9bd92830 311 return;
25697a35 312}