"Fossies" - the Fresh Open Source Software Archive

Member "sarg-2.4.0/index.c" (24 Dec 2019, 34070 Bytes) of package /linux/privat/sarg-2.4.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "index.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.3.11_vs_2.4.0.

    1 /*
    2  * SARG Squid Analysis Report Generator      http://sarg.sourceforge.net
    3  *                                                            1998, 2015
    4  *
    5  * SARG donations:
    6  *      please look at http://sarg.sourceforge.net/donations.php
    7  * Support:
    8  *     http://sourceforge.net/projects/sarg/forums/forum/363374
    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"
   28 #include "include/defs.h"
   29 
   30 #ifdef HAVE_LSTAT
   31 #define MY_LSTAT lstat
   32 #else
   33 #define MY_LSTAT stat
   34 #endif
   35 
   36 
   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);
   41 
   42 void make_index(void)
   43 {
   44     DIR *dirp;
   45     struct dirent *direntp;
   46     char wdir[MAXLEN];
   47 
   48     if (LastLog > 0) mklastlog(outdir);
   49 
   50     if (Index == INDEX_NO) {
   51         if (snprintf(wdir,sizeof(wdir),"%s"INDEX_HTML_FILE,outdir)>=sizeof(wdir)) {
   52             debuga(__FILE__,__LINE__,_("Path too long: "));
   53             debuga_more("%s"INDEX_HTML_FILE,outdir);
   54             exit(EXIT_FAILURE);
   55         }
   56         if (access(wdir, R_OK) == 0) {
   57             if (unlink(wdir)) {
   58                 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),wdir,strerror(errno));
   59                 exit(EXIT_FAILURE);
   60             }
   61         }
   62         return;
   63     }
   64 
   65     if (debug) {
   66         // TRANSLATORS: The %s is the name of the html index file (index.html).
   67         debuga(__FILE__,__LINE__,_("Making %s\n"),INDEX_HTML_FILE);
   68     }
   69 
   70     // convert any old report hierarchy
   71     if ((dirp = opendir(outdir)) == NULL) {
   72         debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),outdir,strerror(errno));
   73         exit(EXIT_FAILURE);
   74     }
   75     while ((direntp = readdir( dirp )) != NULL) {
   76         if (isdigit(direntp->d_name[0]) && isdigit(direntp->d_name[1])) {
   77             if (IndexTree == INDEX_TREE_DATE)
   78                 file_index_to_date_index(direntp->d_name);
   79             else
   80                 date_index_to_file_index(direntp->d_name);
   81         }
   82     }
   83     closedir(dirp);
   84 
   85     if (IndexTree == INDEX_TREE_DATE) {
   86         make_date_index();
   87     } else {
   88         make_file_index();
   89     }
   90 }
   91 
   92 /*!
   93  * Get the effective size of a regular file or directory.
   94  *
   95  * \param statb The structure filled by lstat(2).
   96  *
   97  * \return The size occupied on the disk (more or less).
   98  *
   99  * The actual size occupied on disk by a file or a directory table is not a
  100  * trivial computation. It must take into account sparse files, compression,
  101  * deduplication and probably many more.
  102  *
  103  * Here, we assume the file takes a whole number of blocks (which is not the
  104  * case of ReiserFS); the block size is constant (which is not the case of
  105  * ZFS); every data block is stored in one individal block (no deduplication as
  106  * is done by btrfs); data are not compressed (unlike ReiserFS and ZFS).
  107  *
  108  * As we are dealing with directories containing mostly text and a few
  109  * compressed pictures, we don't worry about sparse files with lot of zeros
  110  * that would take less blocks than the actual file size.
  111  */
  112 static long long int get_file_size(struct stat *statb)
  113 {
  114 #ifdef __linux__
  115     long long int blocks;
  116 
  117     //return(statb->st_size);//the size of the file content
  118     //return(statb->st_blocks*512);//what is the purpose of this size?
  119     if (statb->st_blksize==0) return(statb->st_size);
  120     blocks=(statb->st_size+statb->st_blksize-1)/statb->st_blksize;
  121     return(blocks*statb->st_blksize);//how many bytes occupied on disk
  122 #else
  123     return(statb->st_size);
  124 #endif
  125 }
  126 
  127 /*!
  128  * Get the size of a directory.
  129  *
  130  * The size is the size of the directory content excluding the directory table.
  131  * The "du" tool on Linux returns the content size including the directory
  132  * table.
  133  *
  134  * \param path The directory whose size is computed. This is a buffer that must be
  135  * big enough to contains the deepest path as directory entries are appended to
  136  * the string this buffer contains.
  137  * \param path_size The number of bytes available in the \a path buffer.
  138  *
  139  * \return The number of bytes occupied by the directory content.
  140  */
  141 static long long int get_size(char *path,int path_size)
  142 {
  143     int path_len;
  144     DIR *dirp;
  145     struct dirent *direntp;
  146     struct stat statb;
  147     int name_len;
  148     long long int total_size=0;
  149     char *dir_list=NULL;
  150     int dir_filled=0;
  151     int dir_allocated=0;
  152 
  153     path_len=strlen(path);
  154     if (path_len+2>=path_size) {
  155         debuga(__FILE__,__LINE__,_("Path too long: "));
  156         debuga_more("%s\n",path);
  157         exit(EXIT_FAILURE);
  158     }
  159     if ((dirp=opendir(path))==NULL) {
  160         debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),path,strerror(errno));
  161         exit(EXIT_FAILURE);
  162     }
  163     path[path_len++]='/';
  164     while ((direntp=readdir(dirp))!=NULL) {
  165         if (direntp->d_name[0]=='.' && (direntp->d_name[1]=='\0' || (direntp->d_name[1]=='.' && direntp->d_name[2]=='\0'))) continue;
  166         name_len=strlen(direntp->d_name);
  167         if (path_len+name_len+1>=path_size) {
  168             debuga(__FILE__,__LINE__,_("Path too long: "));
  169             debuga_more("%s%s\n",path,direntp->d_name);
  170             exit(EXIT_FAILURE);
  171         }
  172         strcpy(path+path_len,direntp->d_name);
  173         if (MY_LSTAT(path,&statb) == -1) {
  174             debuga(__FILE__,__LINE__,_("Failed to get the statistics of file \"%s\": %s\n"),path,strerror(errno));
  175             continue;
  176         }
  177         if (S_ISDIR(statb.st_mode))
  178         {
  179             if (!dir_list || dir_filled+name_len>=dir_allocated)
  180             {
  181                 int size=3*(name_len+1);//make room for three file names like this one
  182                 if (size<256) size=256;
  183                 dir_allocated+=size;
  184                 dir_list=realloc(dir_list,dir_allocated);
  185                 if (!dir_list) {
  186                     debuga(__FILE__,__LINE__,_("Not enough memory to recurse into subdirectory \"%s\"\n"),path);
  187                     exit(EXIT_FAILURE);
  188                 }
  189             }
  190             strcpy(dir_list+dir_filled,direntp->d_name);
  191             dir_filled+=name_len+1;
  192             total_size+=get_file_size(&statb);
  193         }
  194         else if (S_ISREG(statb.st_mode))
  195         {
  196             total_size+=get_file_size(&statb);
  197         }
  198     }
  199     closedir(dirp);
  200 
  201     if (dir_list)
  202     {
  203         int start=0;
  204 
  205         while (start<dir_filled)
  206         {
  207             name_len=strlen(dir_list+start);
  208             strcpy(path+path_len,dir_list+start);
  209             total_size+=get_size(path,path_size);
  210             start+=name_len+1;
  211         }
  212         free(dir_list);
  213     }
  214 
  215     path[path_len-1]='\0';//restore original string
  216     return (total_size);
  217 }
  218 
  219 /*!
  220  * Rebuild the html index file for a day when the reports are grouped in a date tree.
  221  *
  222  * \param monthdir The buffer containing the path where the html index file must be rebuild.
  223  * The buffer must be big enough to contain the deepest path in that directory as the buffer is
  224  * used to concatenate the directory entries.
  225  * \param monthdir_size The size, in byte, of the \a monthdir buffer.
  226  * \param order A postive number to sort the index file in positive order. A negative value sort it
  227  * in decreasing order.
  228  * \param yearnum The string naming the year in the date tree.
  229  * \param monthnum The string naming the month in the date tree.
  230  *
  231  * \return The approximate size occupied by the directory.
  232  */
  233 static long long int make_date_index_day(char *monthdir,int monthdir_size,int order,const char *yearnum,const char *monthnum)
  234 {
  235     int monthdir_len;
  236     int ndays;
  237     DIR *dirp3;
  238     struct dirent *direntp;
  239     struct stat statb;
  240     int i;
  241     int daysort[31*31];
  242     int d1, d2, day;
  243     FILE *fp_ou;
  244     char title[80];
  245     char daynum[10];
  246     int d;
  247     long long int total_size=0;
  248     long long int sub_size;
  249     int name_len;
  250 
  251     ndays=0;
  252     if ((dirp3 = opendir(monthdir)) == NULL) {
  253         debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),monthdir,strerror(errno));
  254         exit(EXIT_FAILURE);
  255     }
  256     monthdir_len=strlen(monthdir);
  257     if (monthdir_len+strlen(INDEX_HTML_FILE)+2>=monthdir_size) {
  258         debuga(__FILE__,__LINE__,_("Path too long: "));
  259         debuga_more("%s/%s\n",monthdir,INDEX_HTML_FILE);
  260         exit(EXIT_FAILURE);
  261     }
  262     monthdir[monthdir_len++]='/';
  263     while ((direntp = readdir( dirp3 )) != NULL) {
  264         if (direntp->d_name[0]=='.' && (direntp->d_name[1]=='\0' || (direntp->d_name[1]=='.' && direntp->d_name[2]=='\0'))) continue;
  265         name_len=strlen(direntp->d_name);
  266         if (monthdir_len+name_len+1>=monthdir_size) {
  267             debuga(__FILE__,__LINE__,_("Path too long: "));
  268             debuga_more("%s%s\n",monthdir,direntp->d_name);
  269             exit(EXIT_FAILURE);
  270         }
  271         strcpy(monthdir+monthdir_len,direntp->d_name);
  272         if (MY_LSTAT(monthdir,&statb) == -1) {
  273             debuga(__FILE__,__LINE__,_("Failed to get the statistics of file \"%s\": %s\n"),monthdir,strerror(errno));
  274             continue;
  275         }
  276         if (S_ISDIR(statb.st_mode))
  277         {
  278             if (!isdigit(direntp->d_name[0]) && !isdigit(direntp->d_name[1])) continue;
  279             i=-1;
  280             if (sscanf(direntp->d_name,"%d%n",&d1,&i)!=1 || d1<1 || d1>31 || i<0) continue;
  281             if (direntp->d_name[i]=='-') {
  282                 if (sscanf(direntp->d_name+i+1,"%d",&d2)!=1 || d2<1 || d2>31) continue;
  283             } else if (direntp->d_name[i]!='\0') {
  284                 continue;
  285             } else {
  286                 d2=0;
  287             }
  288             if (ndays>=sizeof(daysort)/sizeof(daysort[0])) {
  289                 debuga(__FILE__,__LINE__,_("Too many day directories in %s\nSupernumerary entries are ignored\n"),monthdir);
  290                 break;
  291             }
  292             day=(d1 << 5) | d2;
  293             for (i=ndays ; i>0 &&  day<daysort[i-1] ; i--) {
  294                 daysort[i]=daysort[i-1];
  295             }
  296             daysort[i]=day;
  297             ndays++;
  298             total_size+=get_file_size(&statb);
  299         }
  300         else if (S_ISREG(statb.st_mode))
  301         {
  302             total_size+=get_file_size(&statb);
  303         }
  304     }
  305     closedir(dirp3);
  306 
  307     strcpy(monthdir+monthdir_len,INDEX_HTML_FILE);
  308     if ((fp_ou=fopen(monthdir,"w"))==NULL) {
  309         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),monthdir,strerror(errno));
  310         exit(EXIT_FAILURE);
  311     }
  312     snprintf(title,sizeof(title),ngettext("SARG: report for %s/%s","SARG: reports for %s/%s",ndays),yearnum,monthnum);
  313     write_html_header(fp_ou,2,title,HTML_JS_NONE);
  314     close_html_header(fp_ou);
  315     fputs("<div class=\"index\"><table cellpadding=\"1\" cellspacing=\"2\">\n<tr><td></td><td></td></tr>\n",fp_ou);
  316     fprintf(fp_ou,"<tr><th class=\"header_l\">%s/%s/%s</th>",_("YEAR"),_("MONTH"),_("DAYS"));
  317     if (IndexFields & INDEXFIELDS_DIRSIZE)
  318         fprintf(fp_ou,"<th class=\"header_l\">%s</th>",_("SIZE"));
  319     fputs("</tr>\n",fp_ou);
  320     for (d=0 ; d<ndays ; d++) {
  321         if (order>0)
  322             day=daysort[d];
  323         else
  324             day=daysort[ndays-1-d];
  325         d1=(day >> 5) & 0x1F;
  326         if ((day & 0x1F) != 0) {
  327             d2=day & 0x1F;
  328             snprintf(daynum,sizeof(daynum),"%02d-%02d",d1,d2);
  329         } else {
  330             snprintf(daynum,sizeof(daynum),"%02d",d1);
  331         }
  332         strcpy(monthdir+monthdir_len,daynum);
  333         sub_size=get_size(monthdir,monthdir_size);
  334 
  335         fprintf(fp_ou,"<tr><td class=\"data2\"><a href=\"%s/%s\">%s %s %s</a></td>",daynum,INDEX_HTML_FILE,yearnum,monthnum,daynum);
  336         if (IndexFields & INDEXFIELDS_DIRSIZE)
  337         {
  338             char size_str[40];
  339 
  340             strncpy(size_str,fixnum(sub_size,1),sizeof(size_str)-1);
  341             size_str[sizeof(size_str)-1]='\0';
  342             fprintf(fp_ou,"<td class=\"data2\">%s</td>",size_str);
  343         }
  344         fputs("</tr>\n",fp_ou);
  345         total_size+=sub_size;
  346     }
  347     fputs("</table></div>\n",fp_ou);
  348     monthdir[monthdir_len-1]='\0';
  349     write_html_trailer(fp_ou);
  350     if (fclose(fp_ou)==EOF) {
  351         strcpy(monthdir+monthdir_len,INDEX_HTML_FILE);
  352         debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),monthdir,strerror(errno));
  353         exit(EXIT_FAILURE);
  354     }
  355     return(total_size);
  356 }
  357 
  358 /*!
  359  * Get the name of a month based on its number.
  360  *
  361  * \param month The month number starting from one.
  362  * \param month_name The buffer to store the month name.
  363  * \param month_size The size of the \a month_name buffer.
  364  */
  365 static void name_month(int month,char *month_name,int month_size)
  366 {
  367     const char *m[12]={N_("January"),N_("February"),N_("March"),N_("April"),N_("May"),N_("June"),N_("July"),
  368                        N_("August"),N_("September"),N_("October"),N_("November"),N_("December")};
  369 
  370     if (month<1 || month>12) {
  371         debuga(__FILE__,__LINE__,_("The internal list of month names is invalid. Please report this bug to the translator.\n"));
  372         exit(EXIT_FAILURE);
  373     }
  374     strncpy(month_name,_(m[month-1]),month_size-1);
  375     month_name[month_size-1]='\0';
  376 }
  377 
  378 /*!
  379  * Rebuild the html index file for a month when the reports are grouped in a date tree.
  380  *
  381  * \param yeardir The buffer containing the path where the html index file must be rebuild.
  382  * The buffer must be big enough to contain the deepest path in that directory as the buffer is
  383  * used to concatenate the directory entries.
  384  * \param yeardir_size The size, in byte, of the \a yeardir buffer.
  385  * \param order A postive number to sort the index file in positive order. A negative value sort it
  386  * in decreasing order.
  387  * \param yearnum The string naming the year in the date tree.
  388  *
  389  * \return The approximate size occupied by the directory.
  390  */
  391 static long long int make_date_index_month(char *yeardir,int yeardir_size,int order,const char *yearnum)
  392 {
  393     int yeardir_len;
  394     int nmonths;
  395     DIR *dirp2;
  396     struct dirent *direntp;
  397     struct stat statb;
  398     int i;
  399     int monthsort[144];
  400     int m1, m2, month;
  401     FILE *fp_ou;
  402     char title[80];
  403     char monthname1[9], monthname2[9];
  404     char nmonth[30];
  405     char monthnum[10];
  406     int m;
  407     long long int total_size=0;
  408     long long int sub_size;
  409     int name_len;
  410 
  411     nmonths=0;
  412     if ((dirp2 = opendir(yeardir)) == NULL) {
  413         debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),yeardir,strerror(errno));
  414         exit(EXIT_FAILURE);
  415     }
  416     yeardir_len=strlen(yeardir);
  417     if (yeardir_len+strlen(INDEX_HTML_FILE)+2>=yeardir_size) {
  418         debuga(__FILE__,__LINE__,_("Path too long: "));
  419         debuga_more("%s/%s\n",yeardir,INDEX_HTML_FILE);
  420         exit(EXIT_FAILURE);
  421     }
  422     yeardir[yeardir_len++]='/';
  423     while ((direntp = readdir( dirp2 )) != NULL) {
  424         if (direntp->d_name[0]=='.' && (direntp->d_name[1]=='\0' || (direntp->d_name[1]=='.' && direntp->d_name[2]=='\0'))) continue;
  425         name_len=strlen(direntp->d_name);
  426         if (yeardir_len+name_len+1>=yeardir_size) {
  427             debuga(__FILE__,__LINE__,_("Path too long: "));
  428             debuga_more("%s%s\n",yeardir,direntp->d_name);
  429             exit(EXIT_FAILURE);
  430         }
  431         strcpy(yeardir+yeardir_len,direntp->d_name);
  432         if (MY_LSTAT(yeardir,&statb) == -1) {
  433             debuga(__FILE__,__LINE__,_("Failed to get the statistics of file \"%s\": %s\n"),yeardir,strerror(errno));
  434             continue;
  435         }
  436         if (S_ISDIR(statb.st_mode))
  437         {
  438             if (!isdigit(direntp->d_name[0]) || !isdigit(direntp->d_name[1])) continue;
  439             i=-1;
  440             if (sscanf(direntp->d_name,"%d%n",&m1,&i)!=1 || m1<1 || m1>12 || i<0) continue;
  441             if (direntp->d_name[i]=='-') {
  442                 if (sscanf(direntp->d_name+i+1,"%d",&m2)!=1 || m2<1 || m2>12) continue;
  443             } else if (direntp->d_name[i]!='\0') {
  444                 continue;
  445             } else {
  446                 m2=0;
  447             }
  448             if (nmonths>=sizeof(monthsort)/sizeof(monthsort[0])) {
  449                 debuga(__FILE__,__LINE__,_("Too many month directories in %s\nSupernumerary entries are ignored\n"),yeardir);
  450                 break;
  451             }
  452             month=(m1<<4) | m2;
  453             for (i=nmonths ; i>0 &&  month<monthsort[i-1] ; i--) {
  454                 monthsort[i]=monthsort[i-1];
  455             }
  456             monthsort[i]=month;
  457             nmonths++;
  458             total_size+=get_file_size(&statb);
  459         }
  460         else if (S_ISREG(statb.st_mode))
  461         {
  462             total_size+=get_file_size(&statb);
  463         }
  464     }
  465     closedir(dirp2);
  466 
  467     strcpy(yeardir+yeardir_len,INDEX_HTML_FILE);
  468     if ((fp_ou=fopen(yeardir,"w"))==NULL) {
  469         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),yeardir,strerror(errno));
  470         exit(EXIT_FAILURE);
  471     }
  472     snprintf(title,sizeof(title),ngettext("SARG: report for %s","SARG: reports for %s",nmonths),yearnum);
  473     write_html_header(fp_ou,1,title,HTML_JS_NONE);
  474     close_html_header(fp_ou);
  475     fputs("<div class=\"index\"><table cellpadding=\"1\" cellspacing=\"2\">\n<tr><td></td><td></td></tr>\n",fp_ou);
  476     fprintf(fp_ou,"<tr><th class=\"header_l\">%s/%s</th>",_("YEAR"),_("MONTH"));
  477     if (IndexFields & INDEXFIELDS_DIRSIZE)
  478         fprintf(fp_ou,"<th class=\"header_l\">%s</th>",_("SIZE"));
  479     fputs("</tr>\n",fp_ou);
  480     for (m=0 ; m<nmonths ; m++) {
  481         if (order>0)
  482             month=monthsort[m];
  483         else
  484             month=monthsort[nmonths-1-m];
  485         m1=(month >> 4) & 0x0F;
  486         if ((month & 0x0F) != 0) {
  487             m2=month & 0x0F;
  488             snprintf(monthnum,sizeof(monthnum),"%02d-%02d",m1,m2);
  489             name_month(m1,monthname1,sizeof(monthname1));
  490             name_month(m2,monthname2,sizeof(monthname2));
  491             snprintf(nmonth,sizeof(nmonth),"%s-%s",monthname1,monthname2);
  492         } else {
  493             snprintf(monthnum,sizeof(monthnum),"%02d",m1);
  494             name_month(m1,nmonth,sizeof(nmonth));
  495         }
  496         if (yeardir_len+strlen(monthnum)+1>=yeardir_size) {
  497             yeardir[yeardir_len]='\0';
  498             debuga(__FILE__,__LINE__,_("Path too long: "));
  499             debuga_more("%s%s\n",yeardir,monthnum);
  500             exit(EXIT_FAILURE);
  501         }
  502         strcpy(yeardir+yeardir_len,monthnum);
  503         sub_size=make_date_index_day(yeardir,yeardir_size,order,yearnum,nmonth);
  504 
  505         fprintf(fp_ou,"<tr><td class=\"data2\"><a href=\"%s/%s\">%s %s</a></td>",monthnum,INDEX_HTML_FILE,yearnum,nmonth);
  506         if (IndexFields & INDEXFIELDS_DIRSIZE)
  507         {
  508             char size_str[40];
  509 
  510             strncpy(size_str,fixnum(sub_size,1),sizeof(size_str)-1);
  511             size_str[sizeof(size_str)-1]='\0';
  512             fprintf(fp_ou,"<td class=\"data2\">%s</td>",size_str);
  513         }
  514         fputs("</tr>\n",fp_ou);
  515         total_size+=sub_size;
  516     }
  517     fputs("</table></div>\n",fp_ou);
  518     yeardir[yeardir_len-1]='\0';
  519     write_html_trailer(fp_ou);
  520     if (fclose(fp_ou)==EOF) {
  521         strcpy(yeardir+yeardir_len,INDEX_HTML_FILE);
  522         debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),yeardir,strerror(errno));
  523         exit(EXIT_FAILURE);
  524     }
  525     return(total_size);
  526 }
  527 
  528 /*!
  529  * Rebuild a date index tree in the output directory.
  530  */
  531 static void make_date_index(void)
  532 {
  533     FILE *fp_ou;
  534     DIR *dirp;
  535     struct dirent *direntp;
  536     char yearindex[MAXLEN];
  537     char yeardir[MAXLEN];
  538     char yearnum[10];
  539     int yearsort[150];
  540     int nyears;
  541     int year;
  542     int i, y;
  543     int order;
  544     int yeardirlen;
  545     long long int total_size;
  546 
  547     nyears=0;
  548     if ((dirp = opendir(outdir)) == NULL) {
  549         debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),outdir,strerror(errno));
  550         exit(EXIT_FAILURE);
  551     }
  552     while ((direntp = readdir( dirp )) != NULL) {
  553         if (!isdigit(direntp->d_name[0]) || !isdigit(direntp->d_name[1]) ||
  554            !isdigit(direntp->d_name[2]) || !isdigit(direntp->d_name[3])) continue;
  555         year=atoi(direntp->d_name) << 10;
  556         if (direntp->d_name[4]=='-')
  557         {
  558             if (!isdigit(direntp->d_name[5]) || !isdigit(direntp->d_name[6]) ||
  559                !isdigit(direntp->d_name[7]) || !isdigit(direntp->d_name[8])) continue;
  560             if (direntp->d_name[9]) continue;
  561             year|=atoi(direntp->d_name+5);
  562         }
  563         else
  564         {
  565             if (direntp->d_name[4]) continue;
  566         }
  567         if (nyears>=sizeof(yearsort)/sizeof(yearsort[0])) {
  568             /*
  569             If too many years are listed in the directory, we ignore the earliest years. The yearsort array
  570             is big enough to accomodate the most ambitious use of sarg but this safety is added to prevent
  571             a crash should the directory be polluted by other entries.
  572             */
  573             if (year>yearsort[0]) {
  574                 for (i=1 ; i<nyears && year>yearsort[i] ; i++)
  575                     yearsort[i-1]=yearsort[i];
  576                 yearsort[i-1]=year;
  577             }
  578         } else {
  579             for (i=nyears ; i>0 &&  year<yearsort[i-1] ; i--) {
  580                 yearsort[i]=yearsort[i-1];
  581             }
  582             yearsort[i]=year;
  583             nyears++;
  584         }
  585     }
  586     closedir( dirp );
  587 
  588     order=(strcmp(IndexSortOrder,"A") == 0) ? 1 : -1;
  589 
  590     if (snprintf(yearindex,sizeof(yearindex),"%s"INDEX_HTML_FILE,outdir)>=sizeof(yearindex)) {
  591         debuga(__FILE__,__LINE__,_("Resulting index file name too long. File name is \"%s/%s\""),outdir,INDEX_HTML_FILE);
  592         exit(EXIT_FAILURE);
  593     }
  594     if ((fp_ou=fopen(yearindex,"w"))==NULL) {
  595         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),yearindex,strerror(errno));
  596         exit(EXIT_FAILURE);
  597     }
  598     write_html_header(fp_ou,0,ngettext("SARG report","SARG reports",nyears),HTML_JS_NONE);
  599     close_html_header(fp_ou);
  600     fputs("<div class=\"index\"><table cellpadding=\"1\" cellspacing=\"2\">\n",fp_ou);
  601     fprintf(fp_ou,"<tr><th class=\"header_l\">%s</th>",_("YEAR"));
  602     if (IndexFields & INDEXFIELDS_DIRSIZE)
  603         fprintf(fp_ou,"<th class=\"header_l\">%s</th>",_("SIZE"));
  604     fputs("</tr>\n",fp_ou);
  605 
  606     yeardirlen=strlen(outdir);
  607     if (yeardirlen>=sizeof(yeardir)) {
  608         debuga(__FILE__,__LINE__,_("Path too long: "));
  609         debuga_more("%s",outdir);
  610         exit(EXIT_FAILURE);
  611     }
  612     strcpy(yeardir,outdir);
  613 
  614     for (y=0 ; y<nyears ; y++) {
  615         if (order>0)
  616             year=yearsort[y];
  617         else
  618             year=yearsort[nyears-1-y];
  619         if ((year & 0x3FF)==0)
  620             snprintf(yearnum,sizeof(yearnum),"%04d",year>>10);
  621         else
  622             snprintf(yearnum,sizeof(yearnum),"%04d-%04d",year>>10,year & 0x3FF);
  623         strcpy(yeardir+yeardirlen,yearnum);
  624         total_size=make_date_index_month(yeardir,sizeof(yeardir),order,yearnum);
  625 
  626         fprintf(fp_ou,"<tr><td class=\"data2\"><a href=\"%s/%s\">%s</a></td>",yearnum,INDEX_HTML_FILE,yearnum);
  627         if (IndexFields & INDEXFIELDS_DIRSIZE)
  628         {
  629             char size_str[40];
  630 
  631             strncpy(size_str,fixnum(total_size,1),sizeof(size_str)-1);
  632             size_str[sizeof(size_str)-1]='\0';
  633             fprintf(fp_ou,"<td class=\"data2\">%s</td>",size_str);
  634         }
  635         fputs("</tr>\n",fp_ou);
  636     }
  637 
  638     fputs("</table></div>\n",fp_ou);
  639     write_html_trailer(fp_ou);
  640     if (fclose(fp_ou)==EOF) {
  641         debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),yearindex,strerror(errno));
  642         exit(EXIT_FAILURE);
  643     }
  644 }
  645 
  646 static void make_file_index(void)
  647 {
  648     #define MAX_CREATION_DATE 15
  649     FILE *fp_ou;
  650     DIR *dirp;
  651     struct dirent *direntp;
  652     char wdir[MAXLEN];
  653     char data[80];
  654     char ftime[9];
  655     char day[6], mon[8], year[40], hour[10];
  656     long long int tbytes;
  657     long long int media;
  658     int iyear, imonth, iday, ihour, iminute, isecond, idst;
  659     int nsort;
  660     int nallocated;
  661     int order;
  662     int i;
  663     int tuser;
  664     struct getwordstruct gwarea;
  665     struct sortstruct
  666     {
  667         int year, month, day, sortnum;
  668         char creationdate[MAX_CREATION_DATE];
  669         char *dirname;
  670         char date[60];
  671     } **sortlist, *item, **tempsort;
  672 
  673     if (snprintf(wdir,sizeof(wdir),"%s"INDEX_HTML_FILE,outdir)>=sizeof(wdir)) {
  674         debuga(__FILE__,__LINE__,_("Path too long: "));
  675         debuga_more("%s"INDEX_HTML_FILE,outdir);
  676         exit(EXIT_FAILURE);
  677     }
  678 
  679     order=(strcmp(IndexSortOrder,"A") == 0) ? 1 : -1;
  680 
  681     if ((dirp = opendir(outdir)) == NULL) {
  682         debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),outdir,strerror(errno));
  683         exit(EXIT_FAILURE);
  684     }
  685 
  686     nsort=0;
  687     nallocated=0;
  688     sortlist=NULL;
  689     while ((direntp = readdir( dirp )) != NULL) {
  690         if (strchr(direntp->d_name,'-') == 0) continue;
  691         if (obtdate(outdir,direntp->d_name,data)<0) {
  692             debuga(__FILE__,__LINE__,_("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);
  693             continue;
  694         }
  695         item=malloc(sizeof(*item));
  696         if (!item) {
  697             debuga(__FILE__,__LINE__,_("not enough memory to sort the index\n"));
  698             exit(EXIT_FAILURE);
  699         }
  700         if (df=='u') {
  701             item->year=atoi(direntp->d_name);
  702             item->month=conv_month(direntp->d_name+4);
  703             item->day=atoi(direntp->d_name+7);
  704         } else {
  705             item->year=atoi(direntp->d_name+5);
  706             item->month=conv_month(direntp->d_name+2);
  707             item->day=atoi(direntp->d_name);
  708         }
  709         item->sortnum=(item->year*16+item->month)*32+item->day;
  710         if (sscanf(data,"%d-%d-%d %d:%d:%d %d",&iyear,&imonth,&iday,&ihour,&iminute,&isecond,&idst)==7) {
  711             formatdate(data,sizeof(data),iyear,imonth,iday,ihour,iminute,isecond,idst);
  712             snprintf(item->creationdate,sizeof(item->creationdate),"%04d%02d%02d%02d%02d%02d",iyear,imonth,iday,ihour,iminute,isecond);
  713         } else {
  714             /*
  715             Old code to parse a date stored by sarg before 2.2.6.1 in the sarg-date file of each report directory.
  716             */
  717             getword_start(&gwarea,data);
  718             if (getword_skip(16,&gwarea,' ')<0) {
  719                 debuga(__FILE__,__LINE__,_("Invalid date in file \"%s%s/sarg-date\"\n"),outdir,direntp->d_name);
  720                 exit(EXIT_FAILURE);
  721             }
  722             if (getword_multisep(mon,sizeof(mon),&gwarea,' ')<0) {
  723                 debuga(__FILE__,__LINE__,_("Invalid date in file \"%s%s/sarg-date\"\n"),outdir,direntp->d_name);
  724                 exit(EXIT_FAILURE);
  725             }
  726             if (getword_multisep(day,sizeof(day),&gwarea,' ')<0) {
  727                 debuga(__FILE__,__LINE__,_("Invalid date in file \"%s%s/sarg-date\"\n"),outdir,direntp->d_name);
  728                 exit(EXIT_FAILURE);
  729             }
  730             if (getword_multisep(hour,sizeof(hour),&gwarea,' ')<0) {
  731                 debuga(__FILE__,__LINE__,_("Invalid time in file \"%s%s/sarg-date\"\n"),outdir,direntp->d_name);
  732                 exit(EXIT_FAILURE);
  733             }
  734             do {
  735                 if (getword_multisep(year,sizeof(year),&gwarea,' ')<0) {
  736                     debuga(__FILE__,__LINE__,_("Invalid date in file \"%s%s/sarg-date\"\n"),outdir,direntp->d_name);
  737                     exit(EXIT_FAILURE);
  738                 }
  739             } while (year[0] && !isdigit(year[0])); //skip time zone information with spaces until the year is found
  740             if (sscanf(hour,"%d:%d:%d",&ihour,&iminute,&isecond)!=3) {
  741                 debuga(__FILE__,__LINE__,_("Invalid time in file \"%s%s/sarg-date\"\n"),outdir,direntp->d_name);
  742                 exit(EXIT_FAILURE);
  743             }
  744             buildymd(day,mon,year,ftime,sizeof(ftime));
  745             snprintf(item->creationdate,sizeof(item->creationdate),"%s%02d%02d%02d",ftime, ihour, iminute, isecond);
  746         }
  747         item->dirname=strdup(direntp->d_name);
  748         if (!item->dirname) {
  749             debuga(__FILE__,__LINE__,_("Not enough memory to store the directory name \"%s\" in the index\n"),direntp->d_name);
  750             exit(EXIT_FAILURE);
  751         }
  752         safe_strcpy(item->date,data,sizeof(item->date));
  753         if (nsort+1>nallocated) {
  754             nallocated+=10;
  755             tempsort=realloc(sortlist,nallocated*sizeof(*item));
  756             if (!tempsort) {
  757                 debuga(__FILE__,__LINE__,_("not enough memory to sort the index\n"));
  758                 exit(EXIT_FAILURE);
  759             }
  760             sortlist=tempsort;
  761         }
  762         for (i=nsort ; i>0 ; i--) {
  763             if (item->sortnum>sortlist[i-1]->sortnum) break;
  764             if (item->sortnum==sortlist[i-1]->sortnum) {
  765                 if (strcmp(item->creationdate,sortlist[i-1]->creationdate)>=0) break;
  766             }
  767             sortlist[i]=sortlist[i-1];
  768         }
  769         sortlist[i]=item;
  770         nsort++;
  771     }
  772 
  773     closedir( dirp );
  774 
  775     if ((fp_ou=fopen(wdir,"w"))==NULL) {
  776         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),wdir,strerror(errno));
  777         exit(EXIT_FAILURE);
  778     }
  779     write_html_header(fp_ou,0,ngettext("SARG report","SARG reports",nsort),HTML_JS_SORTTABLE);
  780     close_html_header(fp_ou);
  781     fputs("<div class=\"index\"><table cellpadding=\"1\" cellspacing=\"2\"",fp_ou);
  782     if (SortTableJs[0]) fputs(" class=\"sortable\"",fp_ou);
  783     fputs(">\n",fp_ou);
  784     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",
  785             _("FILE/PERIOD"),_("CREATION DATE"),_("USERS"),_("BYTES"),_("AVERAGE"));
  786     for (i=0 ; i<nsort ; i++) {
  787         if (order>0)
  788             item=sortlist[i];
  789         else
  790             item=sortlist[nsort-i-1];
  791         tuser=obtuser(outdir,item->dirname);
  792         obttotal(outdir,item->dirname,tuser,&tbytes,&media);
  793         fputs("<tr><td class=\"data2\"",fp_ou);
  794         if (SortTableJs[0]) fprintf(fp_ou," sorttable_customkey=\"%d\"",item->sortnum);
  795         fprintf(fp_ou,"><a href='%s/%s'>%s</a></td>",item->dirname,ReplaceIndex,item->dirname);
  796         fputs("<td class=\"data2\"",fp_ou);
  797         if (SortTableJs[0]) fprintf(fp_ou," sorttable_customkey=\"%s\"",item->creationdate);
  798         fprintf(fp_ou,">%s</td>",item->date);
  799         fprintf(fp_ou,"<td class=\"data\">%d</td>",tuser);
  800         fputs("<td class=\"data\"",fp_ou);
  801         if (SortTableJs[0]) fprintf(fp_ou," sorttable_customkey=\"%"PRId64"\"",(int64_t)tbytes);
  802         fprintf(fp_ou,">%s</td>",fixnum(tbytes,1));
  803         fputs("<td class=\"data\"",fp_ou);
  804         if (SortTableJs[0]) fprintf(fp_ou," sorttable_customkey=\"%"PRId64"\"",(int64_t)media);
  805         fprintf(fp_ou,">%s</td></tr>\n",fixnum(media,1));
  806     }
  807     fputs("</table></div>\n",fp_ou);
  808     write_html_trailer(fp_ou);
  809     if (fclose(fp_ou)==EOF)
  810         debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),wdir,strerror(errno));
  811 
  812     if (sortlist) {
  813         for (i=0 ; i<nsort ; i++) {
  814             free(sortlist[i]->dirname);
  815             free(sortlist[i]);
  816         }
  817         free(sortlist);
  818     }
  819 }
  820 
  821 static void file_index_to_date_index(const char *entry)
  822 {
  823     int y1, y2, m1, m2, d1, d2;
  824     int i, j;
  825     int ndirlen;
  826     int monthlen;
  827     char sm1[8], sm2[8];
  828     char olddir[MAXLEN], newdir[MAXLEN];
  829 
  830     if (strlen(entry) < 19) return;
  831 
  832     y1=0;
  833     y2=0;
  834     memset(sm1,0,sizeof(sm1));
  835     memset(sm2,0,sizeof(sm2));
  836     d1=0;
  837     d2=0;
  838     i=0;
  839     if (df=='u') {
  840         for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
  841             y1=y1*10+(entry[i++]-'0');
  842         if (j!=4) return;
  843         for (j=0 ; j<sizeof(sm1)-1 && entry[i] && isalpha(entry[i]) ; j++)
  844             sm1[j]=entry[i++];
  845         if (j!=3) return;
  846         sm1[j]='\0';
  847         for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
  848             d1=d1*10+(entry[i++]-'0');
  849         if (j!=2) return;
  850 
  851         if (entry[i++]!='-') return;
  852 
  853         for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
  854             y2=y2*10+(entry[i++]-'0');
  855         if (j!=4) return;
  856         for (j=0 ; j<sizeof(sm2)-1 && entry[i] && isalpha(entry[i]) ; j++)
  857             sm2[j]=entry[i++];
  858         if (j!=3) return;
  859         sm2[j]='\0';
  860         for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
  861             d2=d2*10+(entry[i++]-'0');
  862         if (j!=2) return;
  863     } else if (df=='e') {
  864         for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
  865             d1=d1*10+(entry[i++]-'0');
  866         if (j!=2) return;
  867         for (j=0 ; j<sizeof(sm1)-1 && entry[i] && isalpha(entry[i]) ; j++)
  868             sm1[j]=entry[i++];
  869         if (j!=3) return;
  870         sm1[j]='\0';
  871         for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
  872             y1=y1*10+(entry[i++]-'0');
  873         if (j!=4) return;
  874 
  875         if (entry[i++]!='-') return;
  876 
  877         for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
  878             d2=d2*10+(entry[i++]-'0');
  879         if (j!=2) return;
  880         for (j=0 ; j<sizeof(sm2)-1 && entry[i] && isalpha(entry[i]) ; j++)
  881             sm2[j]=entry[i++];
  882         if (j!=3) return;
  883         sm2[j]='\0';
  884         for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
  885             y2=y2*10+(entry[i++]-'0');
  886         if (j!=4) return;
  887     } else
  888         return;
  889 
  890     m1=conv_month(sm1);
  891     m2=conv_month(sm2);
  892     ndirlen=snprintf(newdir,sizeof(newdir),"%s%04d",outdir,y1);
  893     if (ndirlen>=sizeof(newdir)) {
  894         debuga(__FILE__,__LINE__,_("Path too long: "));
  895         debuga_more("%s%04d",outdir,y1);
  896         exit(EXIT_FAILURE);
  897     }
  898     if (access(newdir, R_OK) != 0) {
  899         if (PortableMkDir(newdir,0755)) {
  900             debuga(__FILE__,__LINE__,_("Cannot create directory \"%s\": %s\n"),newdir,strerror(errno));
  901             exit(EXIT_FAILURE);
  902         }
  903     }
  904     if (m1 != m2) ndirlen+=snprintf(newdir+ndirlen,sizeof(newdir)-ndirlen,"/%02d-%02d",m1,m2);
  905     else ndirlen+=snprintf(newdir+ndirlen,sizeof(newdir)-ndirlen,"/%02d",m1);
  906     if (ndirlen>=sizeof(newdir)) {
  907         debuga(__FILE__,__LINE__,_("Path too long: "));
  908         debuga_more("%s",newdir);
  909         exit(EXIT_FAILURE);
  910     }
  911     if (access(newdir, R_OK) != 0) {
  912         if (PortableMkDir(newdir,0755)) {
  913             debuga(__FILE__,__LINE__,_("Cannot create directory \"%s\": %s\n"),newdir,strerror(errno));
  914             exit(EXIT_FAILURE);
  915         }
  916     }
  917     monthlen=ndirlen;
  918     if (d1!=d2) ndirlen+=snprintf(newdir+ndirlen,sizeof(newdir)-ndirlen,"/%02d-%02d",d1,d2);
  919     else ndirlen+=snprintf(newdir+ndirlen,sizeof(newdir)-ndirlen,"/%02d",d1);
  920     if (ndirlen>=sizeof(newdir)) {
  921         debuga(__FILE__,__LINE__,_("Path too long: "));
  922         debuga_more("%s",newdir);
  923         exit(EXIT_FAILURE);
  924     }
  925 
  926     if (snprintf(olddir,sizeof(olddir),"%s%s",outdir,entry)>=sizeof(olddir)) {
  927         debuga(__FILE__,__LINE__,_("Path too long: "));
  928         debuga_more("%s%s",outdir,entry);
  929         exit(EXIT_FAILURE);
  930     }
  931     if (rename(olddir,newdir)) {
  932         debuga(__FILE__,__LINE__,_("Error renaming \"%s\" to \"%s\": %s\n"),olddir,newdir,strerror(errno));
  933         exit(EXIT_FAILURE);
  934     }
  935 
  936     strcpy(newdir+monthlen,"/images");
  937     if (access(newdir, R_OK) != 0) {
  938 #ifdef HAVE_SYMLINK
  939         char linkdir[MAXLEN];
  940 
  941         format_path(__FILE__, __LINE__, linkdir, sizeof(linkdir), "%simages", outdir);
  942         if (symlink(linkdir,newdir)) {
  943             debuga(__FILE__,__LINE__,_("Failed to create link \"%s\" to \"%s\": %s\n"),linkdir,newdir,strerror(errno));
  944             exit(EXIT_FAILURE);
  945         }
  946 #else
  947         char cmd[MAXLEN];
  948         int cstatus;
  949 
  950         sprintf(cmd,"ln -s \"%simages\" \"%s/images\"",outdir,newdir);
  951         cstatus=system(cmd);
  952         if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
  953             debuga(__FILE__,__LINE__,_("command return status %d\n"),WEXITSTATUS(cstatus));
  954             debuga(__FILE__,__LINE__,_("command: %s\n"),cmd);
  955             exit(EXIT_FAILURE);
  956         }
  957 #endif
  958     }
  959 }
  960 
  961 static void date_index_to_file_index(const char *entry)
  962 {
  963     int y1, next;
  964     int m1, m2;
  965     int d1, d2;
  966     int val1len;
  967     int i, j;
  968     char val1[MAXLEN];
  969     const char *sm1, *sm2;
  970     char *str;
  971     char newdir[MAXLEN], olddir[MAXLEN];
  972     DIR *dirp2, *dirp3;
  973     struct dirent *direntp2;
  974     struct dirent *direntp3;
  975 
  976     if (strlen(entry) != 4) return;
  977 
  978     next=-1;
  979     if (sscanf(entry,"%d%n",&y1,&next)!=1 || next<0 || entry[next]) return;
  980 
  981     val1len=snprintf(val1,sizeof(val1),"%s%s",outdir,entry);
  982     dirp2 = opendir(val1);
  983     if (!dirp2) return;
  984     while ((direntp2 = readdir( dirp2 )) != NULL) {
  985         if (!isdigit(direntp2->d_name[0]) || !isdigit(direntp2->d_name[1])) continue;
  986         i=0;
  987         str=direntp2->d_name;
  988         m1=0;
  989         for (j=0 ; j<2 && str[i] && isdigit(str[i]) ; j++)
  990             m1=(m1*10)+(str[i++]-'0');
  991         if (j>=2) continue;
  992         sm1=conv_month_name(m1);
  993         if (str[i]=='-') {
  994             i++;
  995             m2=0;
  996             for (j=0 ; j<2 && str[i] && isdigit(str[i]) ; j++)
  997                 m2=(m2*10)+(str[i++]-'0');
  998             if (j>=2) continue;
  999             sm2=conv_month_name(m2);
 1000         } else if (!str[i]) {
 1001             sm2=sm1;
 1002         } else {
 1003             continue;
 1004         }
 1005 
 1006         sprintf(val1+val1len,"/%s",direntp2->d_name);
 1007         dirp3 = opendir(val1);
 1008         if (!dirp3) continue;
 1009         while ((direntp3 = readdir( dirp3 )) != NULL) {
 1010             if (!isdigit(direntp3->d_name[0]) || !isdigit(direntp3->d_name[1])) continue;
 1011             i=0;
 1012             str=direntp3->d_name;
 1013             d1=0;
 1014             for (j=0 ; str[i] && isdigit(str[i]) ; j++)
 1015                 d1=d1*10+(str[i++]-'0');
 1016             if (j!=2) continue;
 1017             if (str[i]=='-') {
 1018                 i++;
 1019                 d2=0;
 1020                 for (j=0 ; str[i] && isdigit(str[i]) ; j++)
 1021                     d2=d2*10+(str[i++]-'0');
 1022                 if (j!=2) continue;
 1023             } else if (!str[i]) {
 1024                 d2=d1;
 1025             } else {
 1026                 continue;
 1027             }
 1028 
 1029             if (df=='u') {
 1030                 format_path(__FILE__, __LINE__, newdir, sizeof(newdir), "%s%04d%s%02d-%04d%s%02d", outdir, y1, sm1, d1, y1, sm2, d2);
 1031             } else if (df=='e') {
 1032                 format_path(__FILE__, __LINE__, newdir, sizeof(newdir), "%s%02d%s%04d-%02d%s%04d", outdir, d1, sm1, y1, d2, sm2, y1);
 1033             } else {
 1034                 continue;
 1035             }
 1036             format_path(__FILE__, __LINE__, olddir, sizeof(olddir), "%s%04d/%s/%s", outdir, y1, direntp2->d_name, direntp3->d_name);
 1037             if (rename(olddir,newdir)) {
 1038                 debuga(__FILE__,__LINE__,_("Error renaming \"%s\" to \"%s\": %s\n"),olddir,newdir,strerror(errno));
 1039                 exit(EXIT_FAILURE);
 1040             }
 1041         }
 1042         closedir(dirp3);
 1043     }
 1044     closedir(dirp2);
 1045 
 1046     /*!
 1047     \bug The links to the images in the reports are broken after moving the directories
 1048     as the the HTML files are not at the right level for the images any more.
 1049     */
 1050 }
 1051