]>
Commit | Line | Data |
---|---|---|
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 |
30 | struct DirEntry |
31 | { | |
32 | struct DirEntry *Next; | |
33 | time_t Time; | |
34 | char *Name; | |
35 | }; | |
36 | ||
37 | static 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 | ||
50 | static 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 |
88 | static 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 | 144 | static 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 |
203 | static 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 |
256 | void 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 | } |