]>
git.ipfire.org Git - thirdparty/sarg.git/blob - index.c
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
6 * please look at http://sarg.sourceforge.net/donations.php
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
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.
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.
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.
27 #include "include/conf.h"
28 #include "include/defs.h"
31 #define MY_LSTAT lstat
37 static void make_date_index ( void );
38 static void make_file_index ( void );
39 static void file_index_to_date_index ( const char * entry
);
40 static void date_index_to_file_index ( const char * entry
);
45 struct dirent
* direntp
;
48 if ( LastLog
> 0 ) mklastlog ( outdir
);
50 if ( Index
== INDEX_NO
) {
51 sprintf ( wdir
, "%s" INDEX_HTML_FILE
, outdir
);
52 if ( access ( wdir
, R_OK
) == 0 ) {
54 debuga ( _ ( "Cannot delete \" %s \" : %s \n " ), wdir
, strerror ( errno
));
62 // TRANSLATORS: The %s is the name of the html index file (index.html).
63 debuga ( _ ( "Making %s \n " ), INDEX_HTML_FILE
);
66 // convert any old report hierarchy
67 if (( dirp
= opendir ( outdir
)) == NULL
) {
68 debuga ( _ ( "Failed to open directory %s - %s \n " ), outdir
, strerror ( errno
));
71 while (( direntp
= readdir ( dirp
)) != NULL
) {
72 if ( isdigit ( direntp
-> d_name
[ 0 ]) && isdigit ( direntp
-> d_name
[ 1 ])) {
73 if ( IndexTree
== INDEX_TREE_DATE
)
74 file_index_to_date_index ( direntp
-> d_name
);
76 date_index_to_file_index ( direntp
-> d_name
);
81 if ( IndexTree
== INDEX_TREE_DATE
) {
89 * Get the effective size of a regular file or directory.
91 * \param statb The structure filled by lstat(2).
93 * \return The size occupied on the disk (more or less).
95 * The actual size occupied on disk by a file or a directory table is not a
96 * trivial computation. It must take into account sparse files, compression,
97 * deduplication and probably many more.
99 * Here, we assume the file takes a whole number of blocks (which is not the
100 * case of ReiserFS); the block size is constant (which is not the case of
101 * ZFS); every data block is stored in one individal block (no deduplication as
102 * is done by btrfs); data are not compressed (unlike ReiserFS and ZFS).
104 * As we are dealing with directories containing mostly text and a few
105 * compressed pictures, we don't worry about sparse files with lot of zeros
106 * that would take less blocks than the actual file size.
108 static long long int get_file_size ( struct stat
* statb
)
110 long long int blocks
;
112 //return(statb->st_size);//the size of the file content
113 //return(statb->st_blocks*512);//what is the purpose of this size?
114 if ( statb
-> st_blksize
== 0 ) return ( statb
-> st_size
);
115 blocks
=( statb
-> st_size
+ statb
-> st_blksize
- 1 )/ statb
-> st_blksize
;
116 return ( blocks
* statb
-> st_blksize
); //how many bytes occupied on disk
120 * Get the size of a directory.
122 * The size is the size of the directory content excluding the directory table.
123 * The "du" tool on Linux returns the content size including the directory
126 * \param path The directory whose size is computed. This is a buffer that must be
127 * big enough to contains the deepest path as directory entries are appended to
128 * the string this buffer contains.
129 * \param path_size The number of bytes available in the \a path buffer.
131 * \return The number of bytes occupied by the directory content.
133 static long long int get_size ( char * path
, int path_size
)
137 struct dirent
* direntp
;
140 long long int total_size
= 0 ;
145 path_len
= strlen ( path
);
146 if ( path_len
+ 2 >= path_size
) {
147 debuga ( _ ( "Directory entry \" %s \" too long \n " ), path
);
150 if (( dirp
= opendir ( path
))== NULL
) {
151 debuga ( _ ( "Cannot open directory %s: %s \n " ), path
, strerror ( errno
));
154 path
[ path_len
++]= '/' ;
155 while (( direntp
= readdir ( dirp
))!= NULL
) {
156 if ( direntp
-> d_name
[ 0 ]== '.' && ( direntp
-> d_name
[ 1 ]== '\0' || ( direntp
-> d_name
[ 1 ]== '.' && direntp
-> d_name
[ 2 ]== '\0' ))) continue ;
157 name_len
= strlen ( direntp
-> d_name
);
158 if ( path_len
+ name_len
+ 1 >= path_size
) {
159 debuga ( _ ( "Directory entry \" %s%s \" too long \n " ), path
, direntp
-> d_name
);
162 strcpy ( path
+ path_len
, direntp
-> d_name
);
163 if ( MY_LSTAT ( path
,& statb
) == - 1 ) {
164 debuga ( _ ( "Failed to get the file statistics of %s: %s \n " ), path
, strerror ( errno
));
167 if ( S_ISDIR ( statb
. st_mode
))
169 if (! dir_list
|| dir_filled
+ name_len
>= dir_allocated
)
171 int size
= 3 *( name_len
+ 1 ); //make room for three file names like this one
172 if ( size
< 256 ) size
= 256 ;
174 dir_list
= realloc ( dir_list
, dir_allocated
);
176 debuga ( _ ( "Not enough memory to recurse into subdirectory \n " ));
180 strcpy ( dir_list
+ dir_filled
, direntp
-> d_name
);
181 dir_filled
+= name_len
+ 1 ;
182 total_size
+= get_file_size (& statb
);
184 else if ( S_ISREG ( statb
. st_mode
))
186 total_size
+= get_file_size (& statb
);
195 while ( start
< dir_filled
)
197 name_len
= strlen ( dir_list
+ start
);
198 strcpy ( path
+ path_len
, dir_list
+ start
);
199 total_size
+= get_size ( path
, path_size
);
205 path
[ path_len
- 1 ]= '\0' ; //restore original string
210 * Rebuild the html index file for a day when the reports are grouped in a date tree.
212 * \param monthdir The buffer containing the path where the html index file must be rebuild.
213 * The buffer must be big enough to contain the deepest path in that directory as the buffer is
214 * used to concatenate the directory entries.
215 * \param monthdir_size The size, in byte, of the \a monthdir buffer.
216 * \param order A postive number to sort the index file in positive order. A negative value sort it
217 * in decreasing order.
218 * \param yearnum The string naming the year in the date tree.
219 * \param monthnum The string naming the month in the date tree.
221 * \return The approximate size occupied by the directory.
223 static long long int make_date_index_day ( char * monthdir
, int monthdir_size
, int order
, const char * yearnum
, const char * monthnum
)
228 struct dirent
* direntp
;
237 long long int total_size
= 0 ;
238 long long int sub_size
;
242 if (( dirp3
= opendir ( monthdir
)) == NULL
) {
243 debuga ( _ ( "Failed to open directory %s - %s \n " ), monthdir
, strerror ( errno
));
246 monthdir_len
= strlen ( monthdir
);
247 if ( monthdir_len
+ strlen ( INDEX_HTML_FILE
)+ 2 >= monthdir_size
) {
248 debuga ( _ ( "Directory path too long: %s/%s \n " ), monthdir
, INDEX_HTML_FILE
);
251 monthdir
[ monthdir_len
++]= '/' ;
252 while (( direntp
= readdir ( dirp3
)) != NULL
) {
253 if ( direntp
-> d_name
[ 0 ]== '.' && ( direntp
-> d_name
[ 1 ]== '\0' || ( direntp
-> d_name
[ 1 ]== '.' && direntp
-> d_name
[ 2 ]== '\0' ))) continue ;
254 name_len
= strlen ( direntp
-> d_name
);
255 if ( monthdir_len
+ name_len
+ 1 >= monthdir_size
) {
256 debuga ( _ ( "Directory entry \" %s%s \" too long \n " ), monthdir
, direntp
-> d_name
);
259 strcpy ( monthdir
+ monthdir_len
, direntp
-> d_name
);
260 if ( MY_LSTAT ( monthdir
,& statb
) == - 1 ) {
261 debuga ( _ ( "Failed to get the file statistics of %s: %s \n " ), monthdir
, strerror ( errno
));
264 if ( S_ISDIR ( statb
. st_mode
))
266 if (! isdigit ( direntp
-> d_name
[ 0 ]) && ! isdigit ( direntp
-> d_name
[ 1 ])) continue ;
268 if ( sscanf ( direntp
-> d_name
, "%d%n" ,& d1
,& i
)!= 1 || d1
< 1 || d1
> 31 || i
< 0 ) continue ;
269 if ( direntp
-> d_name
[ i
]== '-' ) {
270 if ( sscanf ( direntp
-> d_name
+ i
+ 1 , "%d" ,& d2
)!= 1 || d2
< 1 || d2
> 31 ) continue ;
271 } else if ( direntp
-> d_name
[ i
]!= '\0' ) {
276 if ( ndays
>= sizeof ( daysort
)/ sizeof ( daysort
[ 0 ])) {
277 debuga ( _ ( "Too many day directories in %s \n Supernumerary entries are ignored \n " ), monthdir
);
281 for ( i
= ndays
; i
> 0 && day
< daysort
[ i
- 1 ] ; i
--) {
282 daysort
[ i
]= daysort
[ i
- 1 ];
286 total_size
+= get_file_size (& statb
);
288 else if ( S_ISREG ( statb
. st_mode
))
290 total_size
+= get_file_size (& statb
);
295 strcpy ( monthdir
+ monthdir_len
, INDEX_HTML_FILE
);
296 if (( fp_ou
= fopen ( monthdir
, "w" ))== NULL
) {
297 debuga ( _ ( "(index) Cannot open file %s: %s \n " ), monthdir
, strerror ( errno
));
300 snprintf ( title
, sizeof ( title
), ngettext ( "SARG: report for %s/%s" , "SARG: reports for %s/%s" , ndays
), yearnum
, monthnum
);
301 write_html_header ( fp_ou
, 2 , title
, HTML_JS_NONE
);
302 close_html_header ( fp_ou
);
303 fputs ( "<div class= \" index \" ><table cellpadding= \" 1 \" cellspacing= \" 2 \" > \n <tr><td></td><td></td></tr> \n " , fp_ou
);
304 fprintf ( fp_ou
, "<tr><th class= \" header_l \" >%s/%s/%s</th>" , _ ( "YEAR" ), _ ( "MONTH" ), _ ( "DAYS" ));
305 if ( IndexFields
& INDEXFIELDS_DIRSIZE
)
306 fprintf ( fp_ou
, "<th class= \" header_l \" >%s</th>" , _ ( "SIZE" ));
307 fputs ( "</tr> \n " , fp_ou
);
308 for ( d
= 0 ; d
< ndays
; d
++) {
312 day
= daysort
[ ndays
- 1 - d
];
313 d1
=( day
>> 5 ) & 0x1F ;
314 if (( day
& 0x1F ) != 0 ) {
316 sprintf ( daynum
, "%02d-%02d" , d1
, d2
);
318 sprintf ( daynum
, "%02d" , d1
);
320 strcpy ( monthdir
+ monthdir_len
, daynum
);
321 sub_size
= get_size ( monthdir
, monthdir_size
);
323 fprintf ( fp_ou
, "<tr><td class= \" data2 \" ><a href= \" %s/%s \" >%s %s %s</a></td>" , daynum
, INDEX_HTML_FILE
, yearnum
, monthnum
, daynum
);
324 if ( IndexFields
& INDEXFIELDS_DIRSIZE
)
328 strncpy ( size_str
, fixnum ( sub_size
, 1 ), sizeof ( size_str
)- 1 );
329 size_str
[ sizeof ( size_str
)- 1 ]= '\0' ;
330 fprintf ( fp_ou
, "<td class= \" data2 \" >%s</td>" , size_str
);
332 fputs ( "</tr> \n " , fp_ou
);
333 total_size
+= sub_size
;
335 fputs ( "</table></div> \n " , fp_ou
);
336 monthdir
[ monthdir_len
- 1 ]= '\0' ;
337 if ( write_html_trailer ( fp_ou
)< 0 )
338 debuga ( _ ( "Write error in the index %s/%s \n " ), monthdir
, INDEX_HTML_FILE
);
339 if ( fclose ( fp_ou
)== EOF
) {
340 debuga ( _ ( "Write error in %s/%s: %s \n " ), monthdir
, INDEX_HTML_FILE
, strerror ( errno
));
347 * Get the name of a month based on its number.
349 * \param month The month number starting from one.
350 * \param month_name The buffer to store the month name.
351 * \param month_size The size of the \a month_name buffer.
353 static void name_month ( int month
, char * month_name
, int month_size
)
355 const char * m
[ 12 ]={ N_ ( "January" ), N_ ( "February" ), N_ ( "March" ), N_ ( "April" ), N_ ( "May" ), N_ ( "June" ), N_ ( "July" ),
356 N_ ( "August" ), N_ ( "September" ), N_ ( "October" ), N_ ( "November" ), N_ ( "December" )};
358 if ( month
< 1 || month
> 12 ) {
359 debuga ( _ ( "The internal list of month names is invalid. Please report this bug to the translator. \n " ));
362 strncpy ( month_name
, _ ( m
[ month
- 1 ]), month_size
- 1 );
363 month_name
[ month_size
- 1 ]= '\0' ;
367 * Rebuild the html index file for a month when the reports are grouped in a date tree.
369 * \param yeardir The buffer containing the path where the html index file must be rebuild.
370 * The buffer must be big enough to contain the deepest path in that directory as the buffer is
371 * used to concatenate the directory entries.
372 * \param yeardir_size The size, in byte, of the \a yeardir buffer.
373 * \param order A postive number to sort the index file in positive order. A negative value sort it
374 * in decreasing order.
375 * \param yearnum The string naming the year in the date tree.
377 * \return The approximate size occupied by the directory.
379 static long long int make_date_index_month ( char * yeardir
, int yeardir_size
, int order
, const char * yearnum
)
384 struct dirent
* direntp
;
391 char monthname1
[ 9 ], monthname2
[ 9 ];
395 long long int total_size
= 0 ;
396 long long int sub_size
;
400 if (( dirp2
= opendir ( yeardir
)) == NULL
) {
401 debuga ( _ ( "Failed to open directory %s - %s \n " ), yeardir
, strerror ( errno
));
404 yeardir_len
= strlen ( yeardir
);
405 if ( yeardir_len
+ strlen ( INDEX_HTML_FILE
)+ 2 >= yeardir_size
) {
406 debuga ( _ ( "Directory path too long: %s/%s \n " ), yeardir
, INDEX_HTML_FILE
);
409 yeardir
[ yeardir_len
++]= '/' ;
410 while (( direntp
= readdir ( dirp2
)) != NULL
) {
411 if ( direntp
-> d_name
[ 0 ]== '.' && ( direntp
-> d_name
[ 1 ]== '\0' || ( direntp
-> d_name
[ 1 ]== '.' && direntp
-> d_name
[ 2 ]== '\0' ))) continue ;
412 name_len
= strlen ( direntp
-> d_name
);
413 if ( yeardir_len
+ name_len
+ 1 >= yeardir_size
) {
414 debuga ( _ ( "Directory entry \" %s%s \" too long \n " ), yeardir
, direntp
-> d_name
);
417 strcpy ( yeardir
+ yeardir_len
, direntp
-> d_name
);
418 if ( MY_LSTAT ( yeardir
,& statb
) == - 1 ) {
419 debuga ( _ ( "Failed to get the file statistics of %s: %s \n " ), yeardir
, strerror ( errno
));
422 if ( S_ISDIR ( statb
. st_mode
))
424 if (! isdigit ( direntp
-> d_name
[ 0 ]) || ! isdigit ( direntp
-> d_name
[ 1 ])) continue ;
426 if ( sscanf ( direntp
-> d_name
, "%d%n" ,& m1
,& i
)!= 1 || m1
< 1 || m1
> 12 || i
< 0 ) continue ;
427 if ( direntp
-> d_name
[ i
]== '-' ) {
428 if ( sscanf ( direntp
-> d_name
+ i
+ 1 , "%d" ,& m2
)!= 1 || m2
< 1 || m2
> 12 ) continue ;
429 } else if ( direntp
-> d_name
[ i
]!= '\0' ) {
434 if ( nmonths
>= sizeof ( monthsort
)/ sizeof ( monthsort
[ 0 ])) {
435 debuga ( _ ( "Too many month directories in %s \n Supernumerary entries are ignored \n " ), yeardir
);
439 for ( i
= nmonths
; i
> 0 && month
< monthsort
[ i
- 1 ] ; i
--) {
440 monthsort
[ i
]= monthsort
[ i
- 1 ];
444 total_size
+= get_file_size (& statb
);
446 else if ( S_ISREG ( statb
. st_mode
))
448 total_size
+= get_file_size (& statb
);
453 strcpy ( yeardir
+ yeardir_len
, INDEX_HTML_FILE
);
454 if (( fp_ou
= fopen ( yeardir
, "w" ))== NULL
) {
455 debuga ( _ ( "(index) Cannot open file %s: %s \n " ), yeardir
, strerror ( errno
));
458 snprintf ( title
, sizeof ( title
), ngettext ( "SARG: report for %s" , "SARG: reports for %s" , nmonths
), yearnum
);
459 write_html_header ( fp_ou
, 1 , title
, HTML_JS_NONE
);
460 close_html_header ( fp_ou
);
461 fputs ( "<div class= \" index \" ><table cellpadding= \" 1 \" cellspacing= \" 2 \" > \n <tr><td></td><td></td></tr> \n " , fp_ou
);
462 fprintf ( fp_ou
, "<tr><th class= \" header_l \" >%s/%s</th>" , _ ( "YEAR" ), _ ( "MONTH" ));
463 if ( IndexFields
& INDEXFIELDS_DIRSIZE
)
464 fprintf ( fp_ou
, "<th class= \" header_l \" >%s</th>" , _ ( "SIZE" ));
465 fputs ( "</tr> \n " , fp_ou
);
466 for ( m
= 0 ; m
< nmonths
; m
++) {
470 month
= monthsort
[ nmonths
- 1 - m
];
471 m1
=( month
>> 4 ) & 0x0F ;
472 if (( month
& 0x0F ) != 0 ) {
474 sprintf ( monthnum
, "%02d-%02d" , m1
, m2
);
475 name_month ( m1
, monthname1
, sizeof ( monthname1
));
476 name_month ( m2
, monthname2
, sizeof ( monthname2
));
477 sprintf ( nmonth
, "%s-%s" , monthname1
, monthname2
);
479 sprintf ( monthnum
, "%02d" , m1
);
480 name_month ( m1
, nmonth
, sizeof ( nmonth
));
482 if ( yeardir_len
+ strlen ( monthnum
)+ 1 >= yeardir_size
) {
483 yeardir
[ yeardir_len
]= '\0' ;
484 debuga ( _ ( "Directory path too long: %s%s \n " ), yeardir
, monthnum
);
487 strcpy ( yeardir
+ yeardir_len
, monthnum
);
488 sub_size
= make_date_index_day ( yeardir
, yeardir_size
, order
, yearnum
, nmonth
);
490 fprintf ( fp_ou
, "<tr><td class= \" data2 \" ><a href= \" %s/%s \" >%s %s</a></td>" , monthnum
, INDEX_HTML_FILE
, yearnum
, nmonth
);
491 if ( IndexFields
& INDEXFIELDS_DIRSIZE
)
495 strncpy ( size_str
, fixnum ( sub_size
, 1 ), sizeof ( size_str
)- 1 );
496 size_str
[ sizeof ( size_str
)- 1 ]= '\0' ;
497 fprintf ( fp_ou
, "<td class= \" data2 \" >%s</td>" , size_str
);
499 fputs ( "</tr> \n " , fp_ou
);
500 total_size
+= sub_size
;
502 fputs ( "</table></div> \n " , fp_ou
);
503 yeardir
[ yeardir_len
- 1 ]= '\0' ;
504 if ( write_html_trailer ( fp_ou
)< 0 ) {
505 debuga ( _ ( "Write error in the index %s/%s \n " ), yeardir
, INDEX_HTML_FILE
);
507 if ( fclose ( fp_ou
)== EOF
) {
508 debuga ( _ ( "Write error in %s/%s: %s \n " ), yeardir
, INDEX_HTML_FILE
, strerror ( errno
));
515 * Rebuild a date index tree in the output directory.
517 static void make_date_index ( void )
521 struct dirent
* direntp
;
522 char yearindex
[ MAXLEN
];
523 char yeardir
[ MAXLEN
];
531 long long int total_size
;
534 if (( dirp
= opendir ( outdir
)) == NULL
) {
535 debuga ( _ ( "Failed to open directory %s - %s \n " ), outdir
, strerror ( errno
));
538 while (( direntp
= readdir ( dirp
)) != NULL
) {
539 if (! isdigit ( direntp
-> d_name
[ 0 ]) || ! isdigit ( direntp
-> d_name
[ 1 ]) ||
540 ! isdigit ( direntp
-> d_name
[ 2 ]) || ! isdigit ( direntp
-> d_name
[ 3 ])) continue ;
541 year
= atoi ( direntp
-> d_name
) << 10 ;
542 if ( direntp
-> d_name
[ 4 ]== '-' )
544 if (! isdigit ( direntp
-> d_name
[ 5 ]) || ! isdigit ( direntp
-> d_name
[ 6 ]) ||
545 ! isdigit ( direntp
-> d_name
[ 7 ]) || ! isdigit ( direntp
-> d_name
[ 8 ])) continue ;
546 if ( direntp
-> d_name
[ 9 ]) continue ;
547 year
|= atoi ( direntp
-> d_name
+ 5 );
551 if ( direntp
-> d_name
[ 4 ]) continue ;
553 if ( nyears
>= sizeof ( yearsort
)/ sizeof ( yearsort
[ 0 ])) {
555 If too many years are listed in the directory, we ignore the earliest years. The yearsort array
556 is big enough to accomodate the most ambitious use of sarg but this safety is added to prevent
557 a crash should the directory be polluted by other entries.
559 if ( year
> yearsort
[ 0 ]) {
560 for ( i
= 1 ; i
< nyears
&& year
> yearsort
[ i
] ; i
++)
561 yearsort
[ i
- 1 ]= yearsort
[ i
];
565 for ( i
= nyears
; i
> 0 && year
< yearsort
[ i
- 1 ] ; i
--) {
566 yearsort
[ i
]= yearsort
[ i
- 1 ];
574 order
=( strcmp ( IndexSortOrder
, "A" ) == 0 ) ? 1 : - 1 ;
576 if ( snprintf ( yearindex
, sizeof ( yearindex
), "%s" INDEX_HTML_FILE
, outdir
)>= sizeof ( yearindex
)) {
577 debuga ( _ ( "Resulting index file name too long: %s/%s" ), outdir
, INDEX_HTML_FILE
);
580 if (( fp_ou
= fopen ( yearindex
, "w" ))== NULL
) {
581 debuga ( _ ( "(index) Cannot open file %s: %s \n " ), yearindex
, strerror ( errno
));
584 write_html_header ( fp_ou
, 0 , ngettext ( "SARG report" , "SARG reports" , nyears
), HTML_JS_NONE
);
585 close_html_header ( fp_ou
);
586 fputs ( "<div class= \" index \" ><table cellpadding= \" 1 \" cellspacing= \" 2 \" > \n " , fp_ou
);
587 fprintf ( fp_ou
, "<tr><th class= \" header_l \" >%s</th>" , _ ( "YEAR" ));
588 if ( IndexFields
& INDEXFIELDS_DIRSIZE
)
589 fprintf ( fp_ou
, "<th class= \" header_l \" >%s</th>" , _ ( "SIZE" ));
590 fputs ( "</tr> \n " , fp_ou
);
592 yeardirlen
= strlen ( outdir
);
593 if ( yeardirlen
>= sizeof ( yeardir
)) {
594 debuga ( _ ( "Output directory too long: %s" ), outdir
);
597 strcpy ( yeardir
, outdir
);
599 for ( y
= 0 ; y
< nyears
; y
++) {
603 year
= yearsort
[ nyears
- 1 - y
];
604 if (( year
& 0x3FF )== 0 )
605 sprintf ( yearnum
, "%04d" , year
>> 10 );
607 sprintf ( yearnum
, "%04d-%04d" , year
>> 10 , year
& 0x3FF );
608 strcpy ( yeardir
+ yeardirlen
, yearnum
);
609 total_size
= make_date_index_month ( yeardir
, sizeof ( yeardir
), order
, yearnum
);
611 fprintf ( fp_ou
, "<tr><td class= \" data2 \" ><a href= \" %s/%s \" >%s</a></td>" , yearnum
, INDEX_HTML_FILE
, yearnum
);
612 if ( IndexFields
& INDEXFIELDS_DIRSIZE
)
616 strncpy ( size_str
, fixnum ( total_size
, 1 ), sizeof ( size_str
)- 1 );
617 size_str
[ sizeof ( size_str
)- 1 ]= '\0' ;
618 fprintf ( fp_ou
, "<td class= \" data2 \" >%s</td>" , size_str
);
620 fputs ( "</tr> \n " , fp_ou
);
623 fputs ( "</table></div> \n " , fp_ou
);
624 if ( write_html_trailer ( fp_ou
)< 0 )
625 debuga ( _ ( "Write error in the index %s \n " ), yearindex
);
626 if ( fclose ( fp_ou
)== EOF
) {
627 debuga ( _ ( "Write error in %s: %s \n " ), yearindex
, strerror ( errno
));
632 static void make_file_index ( void )
634 #define MAX_CREATION_DATE 15
637 struct dirent
* direntp
;
641 char day
[ 6 ], mon
[ 8 ], year
[ 40 ], hour
[ 10 ];
642 long long int tbytes
;
644 int iyear
, imonth
, iday
, ihour
, iminute
, isecond
, idst
;
650 struct getwordstruct gwarea
;
653 int year
, month
, day
, sortnum
;
654 char creationdate
[ MAX_CREATION_DATE
];
657 } ** sortlist
, * item
, ** tempsort
;
659 sprintf ( wdir
, "%s" INDEX_HTML_FILE
, outdir
);
661 order
=( strcmp ( IndexSortOrder
, "A" ) == 0 ) ? 1 : - 1 ;
663 if (( dirp
= opendir ( outdir
)) == NULL
) {
664 debuga ( _ ( "Failed to open directory %s - %s \n " ), outdir
, strerror ( errno
));
671 while (( direntp
= readdir ( dirp
)) != NULL
) {
672 if ( strchr ( direntp
-> d_name
, '-' ) == 0 ) continue ;
673 if ( obtdate ( outdir
, direntp
-> d_name
, data
)< 0 ) {
674 debuga ( _ ( "The directory \" %s%s \" looks like a report directory but doesn't contain a sarg-date file. You should delete it \n " ), outdir
, direntp
-> d_name
);
677 item
= malloc ( sizeof (* item
));
679 debuga ( _ ( "not enough memory to sort the index \n " ));
683 item
-> year
= atoi ( direntp
-> d_name
);
684 item
-> month
= conv_month ( direntp
-> d_name
+ 4 );
685 item
-> day
= atoi ( direntp
-> d_name
+ 7 );
687 item
-> year
= atoi ( direntp
-> d_name
+ 5 );
688 item
-> month
= conv_month ( direntp
-> d_name
+ 2 );
689 item
-> day
= atoi ( direntp
-> d_name
);
691 item
-> sortnum
=( item
-> year
* 16 + item
-> month
)* 32 + item
-> day
;
692 if ( sscanf ( data
, "%d-%d-%d %d:%d:%d %d" ,& iyear
,& imonth
,& iday
,& ihour
,& iminute
,& isecond
,& idst
)== 7 ) {
693 formatdate ( data
, sizeof ( data
), iyear
, imonth
, iday
, ihour
, iminute
, isecond
, idst
);
694 snprintf ( item
-> creationdate
, sizeof ( item
-> creationdate
), "%04d%02d%02d%02d%02d%02d" , iyear
, imonth
, iday
, ihour
, iminute
, isecond
);
697 Old code to parse a date stored by sarg before 2.2.6.1 in the sarg-date file of each report directory.
699 getword_start (& gwarea
, data
);
700 if ( getword_skip ( 16 ,& gwarea
, ' ' )< 0 ) {
701 debuga ( _ ( "Maybe you have a broken week day in your %s%s/sarg-date file \n " ), outdir
, direntp
-> d_name
);
704 if ( getword_multisep ( mon
, sizeof ( mon
),& gwarea
, ' ' )< 0 ) {
705 debuga ( _ ( "Maybe you have a broken month in your %s%s/sarg-date file \n " ), outdir
, direntp
-> d_name
);
708 if ( getword_multisep ( day
, sizeof ( day
),& gwarea
, ' ' )< 0 ) {
709 debuga ( _ ( "Maybe you have a broken day in your %s%s/sarg-date file \n " ), outdir
, direntp
-> d_name
);
712 if ( getword_multisep ( hour
, sizeof ( hour
),& gwarea
, ' ' )< 0 ) {
713 debuga ( _ ( "Maybe you have a broken time in your %s%s/sarg-date file \n " ), outdir
, direntp
-> d_name
);
717 if ( getword_multisep ( year
, sizeof ( year
),& gwarea
, ' ' )< 0 ) {
718 debuga ( _ ( "Maybe you have a broken year in your %s%s/sarg-date file \n " ), outdir
, direntp
-> d_name
);
721 } while ( year
[ 0 ] && ! isdigit ( year
[ 0 ])); //skip time zone information with spaces until the year is found
722 if ( sscanf ( hour
, "%d:%d:%d" ,& ihour
,& iminute
,& isecond
)!= 3 ) {
723 debuga ( _ ( "Maybe you have a broken time in your %s%s/sarg-date file \n " ), outdir
, direntp
-> d_name
);
726 buildymd ( day
, mon
, year
, ftime
, sizeof ( ftime
));
727 snprintf ( item
-> creationdate
, sizeof ( item
-> creationdate
), "%s%02d%02d%02d" , ftime
, ihour
, iminute
, isecond
);
729 item
-> dirname
= strdup ( direntp
-> d_name
);
730 if (! item
-> dirname
) {
731 debuga ( _ ( "Not enough memory to store the directory name \" %s \" in the index \n " ), direntp
-> d_name
);
734 safe_strcpy ( item
-> date
, data
, sizeof ( item
-> date
));
735 if ( nsort
+ 1 > nallocated
) {
737 tempsort
= realloc ( sortlist
, nallocated
* sizeof (* item
));
739 debuga ( _ ( "not enough memory to sort the index \n " ));
744 for ( i
= nsort
; i
> 0 ; i
--) {
745 if ( item
-> sortnum
> sortlist
[ i
- 1 ]-> sortnum
) break ;
746 if ( item
-> sortnum
== sortlist
[ i
- 1 ]-> sortnum
) {
747 if ( strcmp ( item
-> creationdate
, sortlist
[ i
- 1 ]-> creationdate
)>= 0 ) break ;
749 sortlist
[ i
]= sortlist
[ i
- 1 ];
757 if (( fp_ou
= fopen ( wdir
, "w" ))== NULL
) {
758 debuga ( _ ( "(index) Cannot open file %s: %s \n " ), wdir
, strerror ( errno
));
761 write_html_header ( fp_ou
, 0 , ngettext ( "SARG report" , "SARG reports" , nsort
), HTML_JS_SORTTABLE
);
762 close_html_header ( fp_ou
);
763 fputs ( "<div class= \" index \" ><table cellpadding= \" 1 \" cellspacing= \" 2 \" " , fp_ou
);
764 if ( SortTableJs
[ 0 ]) fputs ( " class= \" sortable \" " , fp_ou
);
766 fprintf ( fp_ou
, "<thead><tr><th class= \" header_l \" >%s</th><th class= \" header_l \" >%s</th><th class= \" header_l \" >%s</th><th class= \" header_l \" >%s</th><th class= \" header_l \" >%s</th></tr></thead> \n " , _ ( "FILE/PERIOD" ), _ ( "CREATION DATE" ), _ ( "USERS" ), _ ( "BYTES" ), _ ( "AVERAGE" ));
767 for ( i
= 0 ; i
< nsort
; i
++) {
771 item
= sortlist
[ nsort
- i
- 1 ];
772 tuser
= obtuser ( outdir
, item
-> dirname
);
773 obttotal ( outdir
, item
-> dirname
, tuser
,& tbytes
,& media
);
774 fputs ( "<tr><td class= \" data2 \" " , fp_ou
);
775 if ( SortTableJs
[ 0 ]) fprintf ( fp_ou
, " sorttable_customkey= \" %d \" " , item
-> sortnum
);
776 fprintf ( fp_ou
, "><a href='%s/%s'>%s</a></td>" , item
-> dirname
, ReplaceIndex
, item
-> dirname
);
777 fputs ( "<td class= \" data2 \" " , fp_ou
);
778 if ( SortTableJs
[ 0 ]) fprintf ( fp_ou
, " sorttable_customkey= \" %s \" " , item
-> creationdate
);
779 fprintf ( fp_ou
, ">%s</td>" , item
-> date
);
780 fprintf ( fp_ou
, "<td class= \" data \" >%d</td>" , tuser
);
781 fputs ( "<td class= \" data \" " , fp_ou
);
782 if ( SortTableJs
[ 0 ]) fprintf ( fp_ou
, " sorttable_customkey= \" %" PRId64
" \" " ,( int64_t ) tbytes
);
783 fprintf ( fp_ou
, ">%s</td>" , fixnum ( tbytes
, 1 ));
784 fputs ( "<td class= \" data \" " , fp_ou
);
785 if ( SortTableJs
[ 0 ]) fprintf ( fp_ou
, " sorttable_customkey= \" %" PRId64
" \" " ,( int64_t ) media
);
786 fprintf ( fp_ou
, ">%s</td></tr> \n " , fixnum ( media
, 1 ));
788 fputs ( "</table></div> \n " , fp_ou
);
789 if ( write_html_trailer ( fp_ou
)< 0 )
790 debuga ( _ ( "Write error in the index %s \n " ), wdir
);
791 if ( fclose ( fp_ou
)== EOF
)
792 debuga ( _ ( "Failed to close the index file %s - %s \n " ), wdir
, strerror ( errno
));
795 for ( i
= 0 ; i
< nsort
; i
++) {
796 free ( sortlist
[ i
]-> dirname
);
803 static void file_index_to_date_index ( const char * entry
)
805 int y1
, y2
, m1
, m2
, d1
, d2
;
810 char olddir
[ MAXLEN
], newdir
[ MAXLEN
];
812 if ( strlen ( entry
) < 19 ) return ;
816 memset ( sm1
, 0 , sizeof ( sm1
));
817 memset ( sm2
, 0 , sizeof ( sm2
));
822 for ( j
= 0 ; entry
[ i
] && isdigit ( entry
[ i
]) ; j
++)
823 y1
= y1
* 10 +( entry
[ i
++]- '0' );
825 for ( j
= 0 ; j
< sizeof ( sm1
)- 1 && entry
[ i
] && isalpha ( entry
[ i
]) ; j
++)
829 for ( j
= 0 ; entry
[ i
] && isdigit ( entry
[ i
]) ; j
++)
830 d1
= d1
* 10 +( entry
[ i
++]- '0' );
833 if ( entry
[ i
++]!= '-' ) return ;
835 for ( j
= 0 ; entry
[ i
] && isdigit ( entry
[ i
]) ; j
++)
836 y2
= y2
* 10 +( entry
[ i
++]- '0' );
838 for ( j
= 0 ; j
< sizeof ( sm2
)- 1 && entry
[ i
] && isalpha ( entry
[ i
]) ; j
++)
842 for ( j
= 0 ; entry
[ i
] && isdigit ( entry
[ i
]) ; j
++)
843 d2
= d2
* 10 +( entry
[ i
++]- '0' );
845 } else if ( df
== 'e' ) {
846 for ( j
= 0 ; entry
[ i
] && isdigit ( entry
[ i
]) ; j
++)
847 d1
= d1
* 10 +( entry
[ i
++]- '0' );
849 for ( j
= 0 ; j
< sizeof ( sm1
)- 1 && entry
[ i
] && isalpha ( entry
[ i
]) ; j
++)
853 for ( j
= 0 ; entry
[ i
] && isdigit ( entry
[ i
]) ; j
++)
854 y1
= y1
* 10 +( entry
[ i
++]- '0' );
857 if ( entry
[ i
++]!= '-' ) return ;
859 for ( j
= 0 ; entry
[ i
] && isdigit ( entry
[ i
]) ; j
++)
860 d2
= d2
* 10 +( entry
[ i
++]- '0' );
862 for ( j
= 0 ; j
< sizeof ( sm2
)- 1 && entry
[ i
] && isalpha ( entry
[ i
]) ; j
++)
866 for ( j
= 0 ; entry
[ i
] && isdigit ( entry
[ i
]) ; j
++)
867 y2
= y2
* 10 +( entry
[ i
++]- '0' );
874 ndirlen
= sprintf ( newdir
, "%s%04d" , outdir
, y1
);
875 if ( access ( newdir
, R_OK
) != 0 ) {
876 if ( mkdir ( newdir
, 0755 )) {
877 debuga ( _ ( "Cannot create directory %s - %s \n " ), newdir
, strerror ( errno
));
881 if ( m1
!= m2
) ndirlen
+= sprintf ( newdir
+ ndirlen
, "/%02d-%02d" , m1
, m2
);
882 else ndirlen
+= sprintf ( newdir
+ ndirlen
, "/%02d" , m1
);
883 if ( access ( newdir
, R_OK
) != 0 ) {
884 if ( mkdir ( newdir
, 0755 )) {
885 debuga ( _ ( "Cannot create directory %s - %s \n " ), newdir
, strerror ( errno
));
890 if ( d1
!= d2
) ndirlen
+= sprintf ( newdir
+ ndirlen
, "/%02d-%02d" , d1
, d2
);
891 else ndirlen
+= sprintf ( newdir
+ ndirlen
, "/%02d" , d1
);
893 sprintf ( olddir
, "%s%s" , outdir
, entry
);
894 if ( rename ( olddir
, newdir
)) {
895 debuga ( _ ( "(index) rename error from \" %s \" to \" %s \" - %s \n " ), olddir
, newdir
, strerror ( errno
));
899 strcpy ( newdir
+ monthlen
, "/images" );
900 if ( access ( newdir
, R_OK
) != 0 ) {
902 char linkdir
[ MAXLEN
];
904 sprintf ( linkdir
, "%simages" , outdir
);
905 if ( symlink ( linkdir
, newdir
)) {
906 debuga ( _ ( "failed to create link \" %s \" to \" %s \" - %s \n " ), linkdir
, newdir
, strerror ( errno
));
913 sprintf ( cmd
, "ln -s \" %simages \" \" %s/images \" " , outdir
, newdir
);
915 if (! WIFEXITED ( cstatus
) || WEXITSTATUS ( cstatus
)) {
916 debuga ( _ ( "command return status %d \n " ), WEXITSTATUS ( cstatus
));
917 debuga ( _ ( "command: %s \n " ), cmd
);
924 static void date_index_to_file_index ( const char * entry
)
932 const char * sm1
, * sm2
;
934 char newdir
[ MAXLEN
], olddir
[ MAXLEN
];
936 struct dirent
* direntp2
;
937 struct dirent
* direntp3
;
939 if ( strlen ( entry
) != 4 ) return ;
942 if ( sscanf ( entry
, "%d%n" ,& y1
,& next
)!= 1 || next
< 0 || entry
[ next
]) return ;
944 val1len
= snprintf ( val1
, sizeof ( val1
), "%s%s" , outdir
, entry
);
945 dirp2
= opendir ( val1
);
947 while (( direntp2
= readdir ( dirp2
)) != NULL
) {
948 if (! isdigit ( direntp2
-> d_name
[ 0 ]) || ! isdigit ( direntp2
-> d_name
[ 1 ])) continue ;
950 str
= direntp2
-> d_name
;
952 for ( j
= 0 ; j
< 2 && str
[ i
] && isdigit ( str
[ i
]) ; j
++)
953 m1
=( m1
* 10 )+( str
[ i
++]- '0' );
955 sm1
= conv_month_name ( m1
);
959 for ( j
= 0 ; j
< 2 && str
[ i
] && isdigit ( str
[ i
]) ; j
++)
960 m2
=( m2
* 10 )+( str
[ i
++]- '0' );
962 sm2
= conv_month_name ( m2
);
963 } else if (! str
[ i
]) {
969 sprintf ( val1
+ val1len
, "/%s" , direntp2
-> d_name
);
970 dirp3
= opendir ( val1
);
971 if (! dirp3
) continue ;
972 while (( direntp3
= readdir ( dirp3
)) != NULL
) {
973 if (! isdigit ( direntp3
-> d_name
[ 0 ]) || ! isdigit ( direntp3
-> d_name
[ 1 ])) continue ;
975 str
= direntp3
-> d_name
;
977 for ( j
= 0 ; str
[ i
] && isdigit ( str
[ i
]) ; j
++)
978 d1
= d1
* 10 +( str
[ i
++]- '0' );
983 for ( j
= 0 ; str
[ i
] && isdigit ( str
[ i
]) ; j
++)
984 d2
= d2
* 10 +( str
[ i
++]- '0' );
986 } else if (! str
[ i
]) {
992 if ( df
== 'u' ) sprintf ( newdir
, "%s%04d%s%02d-%04d%s%02d" , outdir
, y1
, sm1
, d1
, y1
, sm2
, d2
);
993 else if ( df
== 'e' ) sprintf ( newdir
, "%s%02d%s%04d-%02d%s%04d" , outdir
, d1
, sm1
, y1
, d2
, sm2
, y1
);
995 sprintf ( olddir
, "%s%04d/%s/%s" , outdir
, y1
, direntp2
-> d_name
, direntp3
-> d_name
);
996 if ( rename ( olddir
, newdir
)) {
997 debuga ( _ ( "(index) rename error from \" %s \" to \" %s \" - %s \n " ), olddir
, newdir
, strerror ( errno
));
1006 \bug The links to the images in the reports are broken after moving the directories
1007 as the the HTML files are not at the right level for the images any more.