"Fossies" - the Fresh Open Source Software Archive

Member "dirsync.c" (11 Apr 2006, 29130 Bytes) of package /linux/privat/old/dirsync-1_11.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 "dirsync.c" see the Fossies "Dox" file reference documentation.

    1 /**
    2  * $Id: dirsync.c,v 1.30 2006/04/11 16:42:01 mviara Exp $
    3  * $Name:  $
    4  * 
    5  * Directories syncronizer. Derived from dirimage.
    6  *
    7    Revision 1.27  2006/02/27 14:54:03  raj
    8    Added mode 3 of copying - don't check mtimes on symlinks (useful when
    9    doing a backward synchronization)
   10  
   11    Revision 1.26  2006/02/26 22:00:27  raj (raj@ap.krakow.pl)
   12    Release 1.11
   13    Changed C++ style comments (// ...) to regular C-style comments to avoid
   14    syntax errors in some compilers (eg. Sun's cc)
   15    Fixed coredump in ArraySearch function when the table was empty
   16    Made the program set access/modify times on directories too (under Unix)
   17    Made the program set the ownership of files/dirs if run by root (Unix)
   18    Made the program duplicate symlinks instead of copy their contents,
   19    unless -L switch is specified (Unix)
   20    Changed mode 2 to show also files with different mtimes, not only with
   21    different sizes
   22  *
   23  * Revision 1.25  2005/11/26 14:59:12  mviara
   24  *
   25  * Tested in linux.
   26  *
   27  * Revision 1.24  2005/11/26 14:39:49  mviara
   28  * Added support for mode 2 and log.
   29  *
   30  * Revision 1.23  2005/11/05 20:54:16  mviara
   31  * Release 1.08
   32  *
   33  * Revision 1.22  2005/11/04 08:06:28  mviara
   34  * Added support for verify copied data.
   35  *
   36  * Revision 1.21  2005/06/04 05:45:51  mviara
   37  *
   38  * Begin version 1.08, added supporto for ignore block devices.
   39  * Fixed bug in linux manual.
   40  *
   41  * Revision 1.20  2004/12/28 15:09:55  mviara
   42  * Added warning when file size change during a copy.
   43  *
   44  * Revision 1.19  2004/12/07 00:15:47  mviara
   45  * Improved statistics.
   46  *
   47  * Revision 1.18  2004/11/30 17:09:43  mviara
   48  * Removed unnecessary printf.
   49  *
   50  * Revision 1.17  2004/11/25 19:17:38  mviara
   51  * Tested in win32 enviroment.
   52  *
   53  * Revision 1.16  2004/11/25 18:58:33  mviara
   54  *
   55  * Added the "Henry Spencer's regular expression library" to support regular
   56  * expression matching in exclude files/directories.
   57  *
   58  * Revision 1.15  2004/11/10 18:14:37  mviara
   59  * Version 1.05 Win32
   60  *
   61  * Revision 1.14  2004/11/05 16:23:44  mviara
   62  *
   63  * Version 1.05
   64  *
   65  * Revision 1.13  2004/10/26 11:22:41  mviara
   66  * Bug fixed on handling root file system.
   67  *
   68  * Revision 1.12  2004/10/25 08:45:58  mviara
   69  * Corrected error on file count.
   70  *
   71  * Revision 1.11  2004/10/18 08:49:48  mviara
   72  * Version 1.03
   73  *
   74  * Revision 1.10  2004/10/16 09:04:53  mviara
   75  * Corrected a bug in source or dest ending in \ or /
   76  *
   77  * Revision 1.9  2004/10/08 18:15:42  mviara
   78  *
   79  * Added option from a text file.
   80  *
   81  * Revision 1.8  2004/10/07 13:59:58  mviara
   82  *
   83  * Improved compatibility (removed <lcms.h>)
   84  *
   85  * Revision 1.7  2004/10/07 13:55:33  mviara
   86  *
   87  * Added install for linux.
   88  * Added #include <unistd.h> to compile in athore linux system.
   89  *
   90  * Revision 1.6  2004/10/07 13:40:40  mviara
   91  * Added support for MSDOS.
   92  *
   93  * Revision 1.5  2004/10/06 03:31:57  mviara
   94  * Version 1.01
   95  *
   96  * Revision 1.4  2004/10/02 04:59:04  mviara
   97  * Improved performance on large directory.
   98  *
   99  * Revision 1.3  2004/09/30 19:32:46  mviara
  100  * Added -r and -m options.
  101  *
  102  * Revision 1.2  2004/09/30 18:05:39  mviara
  103  * Corrected some english error.
  104  *
  105  * Revision 1.1.1.1  2004/09/27 13:12:59  mviara
  106  * First imported version
  107  *
  108  */
  109 static char rcsinfo[] = "$Id: dirsync.c,v 1.30 2006/04/11 16:42:01 mviara Exp $";
  110 
  111 #include <stdio.h>
  112 #include <stdlib.h>
  113 #include <time.h>
  114 #include <sys/stat.h>
  115 #include <string.h>
  116 #include <assert.h>
  117 #include <fcntl.h>
  118 #include <errno.h>
  119 #ifndef __LINUX__
  120 #include <io.h>
  121 #include <sys/utime.h>
  122 #include <limits.h>
  123 #ifdef __WATCOMC__
  124 #include <direct.h>
  125 #else
  126 #include "dirent.h"
  127 #endif
  128 #include "getopt.h"
  129 #endif
  130 
  131 #ifdef __LINUX__
  132 #include <utime.h>
  133 #include <dirent.h>
  134 #include <unistd.h>
  135 #endif
  136 
  137 #include "regex.h"
  138 
  139 #ifdef __LINUX__
  140 #define DIRSEP  '/'
  141 #else
  142 #define DIRSEP  '\\'
  143 #endif
  144 
  145 /**
  146  * MSDOS compatibility
  147  */
  148 #ifndef O_BINARY
  149 #define O_BINARY    0
  150 #endif
  151 
  152 /**
  153  * If not defined define the max path len
  154  */
  155 #ifndef PATH_MAX
  156 #define PATH_MAX    1024
  157 #endif
  158 
  159 
  160 /**
  161  * Structure to hold a link queue
  162  */
  163 typedef struct Link_S
  164 {
  165     struct Link_S * next;
  166 } Link_T;
  167 
  168 
  169 /**
  170  * Directory entry
  171  */
  172 typedef struct Entry_S
  173 {
  174     Link_T  link;
  175     
  176 /*  // Name without path      */
  177     char *      name;
  178     
  179 /*  // Stat buffer            */
  180     struct stat statb;
  181     
  182 } Entry_T;
  183 
  184 /**
  185  * Regular expression entry
  186  */
  187 typedef struct
  188 {
  189     Link_T  link;
  190     regex_t regex;
  191     char *  name;
  192 } RegexEntry_T;
  193 
  194 
  195 typedef struct FileArray_S
  196 {
  197     Link_T  head;
  198     long    count;
  199     Entry_T **entry;
  200 } FileArray_T;
  201 
  202 typedef struct Directory_S
  203 {
  204     FileArray_T files;
  205     FileArray_T dirs;
  206 } Directory_T;
  207 
  208 #ifdef __MSDOS__
  209 #define DEFAULT_BUFFER_SIZE (1024*64)
  210 #else
  211 #define DEFAULT_BUFFER_SIZE (1024*1024)
  212 #endif
  213 
  214 #define DEFAULT_VERBOSE 2
  215 
  216 static long filesCopied = 0;
  217 static long filesDeleted = 0;
  218 static long filesChecked = 0;
  219 static long errors = 0;
  220 static long kbCopied = 0;
  221 static int  mode = 0;
  222 static int  dontRemove = 0;
  223 static int  fileVerify = 0;
  224 static Link_T   excludedDirs;
  225 static Link_T   excludedFiles;
  226 static Link_T   excludedRegex;
  227 static FILE *   log = 0;
  228 static char * buffer,* buffer1;
  229 static int  bufferSize = DEFAULT_BUFFER_SIZE;
  230 static int  verbose = DEFAULT_VERBOSE;
  231 /* (JR) add */
  232 static int  followSymlinks = 0;
  233 
  234 #define MSG_PATH(msg) if (*msg) \
  235                       printf(msg);\
  236                       *msg=0;
  237 
  238 
  239 static void QueueInit(Link_T * link)
  240 {
  241     link->next = link;
  242 }
  243 
  244 static void QueueAdd(Link_T * head,Link_T * link)
  245 {
  246     link->next = head->next;
  247     head->next = link;
  248 }
  249 
  250 static char dateTimeFormat[128] = "%d/%m/%Y %H:%M:%S";
  251 
  252 static char * GetDateAndTime()
  253 {
  254     time_t t;
  255     static char  buffer[32];
  256     struct tm * tmp;
  257     
  258     time(&t);
  259     tmp =localtime(&t);
  260     
  261     strftime(buffer,sizeof(buffer),dateTimeFormat,tmp);
  262 
  263     return buffer;
  264 }
  265 
  266 static char dateFormat[128] = "%d-%m-%Y";
  267 
  268 static char * GetDate()
  269 {
  270     time_t t;
  271     static char  buffer[32];
  272     struct tm * tmp;
  273 
  274     time(&t);
  275     tmp =localtime(&t);
  276 
  277     strftime(buffer,sizeof(buffer),dateFormat,tmp);
  278 
  279     return buffer;
  280 }
  281 
  282 
  283 static void LogDateAndTime()
  284 {
  285     fprintf(log,"%s ",GetDateAndTime());
  286 }
  287 
  288 static void PrintError(char *cmd,char *obj)
  289 {
  290     int code = errno;
  291     char *msg = strerror(code);
  292     if (code == 0)
  293         msg = "";
  294     fprintf(stderr,"\ndirsync: %s (%s) %s (%d)\n",cmd,obj,msg,code);
  295     errors++;
  296 
  297     if (log)
  298     {
  299         LogDateAndTime();
  300         fprintf(log,"%s (%s) %s (%d)\n",cmd,obj,msg,code);
  301     }
  302 }
  303 
  304 static char * FilePath(char * dest,char * dir,char * file)
  305 {
  306     int len;
  307 
  308     len = strlen(dir);
  309 
  310     if (dir[len - 1] != DIRSEP)
  311         sprintf(dest,"%s%c%s",dir,DIRSEP,file);
  312     else
  313         sprintf(dest,"%s%s",dir,file);
  314     
  315     return dest;
  316 }
  317 
  318 
  319 static void CopyAttribute(char *path,struct stat * statb)
  320 {
  321     struct utimbuf time;
  322 
  323 /* (JR) mod - set attributes on directories too! */
  324 #ifndef __LINUX__
  325     if ((statb->st_mode & S_IFMT) == S_IFREG)
  326 #endif
  327     {
  328         time.actime = statb->st_atime;
  329         time.modtime = statb->st_mtime;
  330         if (utime(path,&time))
  331         {
  332             PrintError("utime",path);
  333         }
  334     }
  335 
  336 #ifdef __LINUX__
  337     /* (JR) if run as root, set ownership too */
  338     if (geteuid() == 0) {
  339       if (chown(path,statb->st_uid,statb->st_gid))
  340         PrintError("chown",path);
  341     }
  342 #endif
  343 
  344     if (chmod(path,statb->st_mode))
  345     {
  346         PrintError("chmod",path);
  347     }
  348 
  349 }
  350 
  351 static void FileUnlink(char * path)
  352 {
  353     
  354     if (unlink(path))
  355     {
  356 #ifdef UNSECURE
  357         chmod(path,0777);
  358         if (unlink(path))
  359 #endif
  360             PrintError("unlink",path);
  361     }
  362 
  363 }
  364 
  365 static int FileVerify(char * msg,char *source,char * dest,Entry_T *e)
  366 {
  367     int fds,fdd;
  368     int nread;
  369     int result;
  370     size_t count = 0;
  371     char sourcePath[PATH_MAX+1];
  372     char destPath[PATH_MAX+1];
  373     size_t perc,oldPerc=101;
  374 
  375     FilePath(sourcePath,source,e->name);
  376     FilePath(destPath,dest,e->name);
  377 
  378 
  379     fds = open(sourcePath,O_RDONLY|O_BINARY);
  380 
  381     if (fds < 0)
  382     {
  383         PrintError("open",sourcePath);
  384         return 1;
  385     }
  386 
  387     fdd = open(destPath,O_RDONLY|O_BINARY);
  388 
  389 
  390     if (fdd < 0)
  391     {
  392         PrintError("open",destPath);
  393         close(fds);
  394         return 1;
  395     }
  396 
  397 
  398     if (verbose > 1)
  399     {
  400         MSG_PATH(msg);
  401         printf("\rVERIFY %-50.50s %10ld Byte ",e->name,e->statb.st_size);
  402         fflush(stdout);
  403     }
  404 
  405     if (log)
  406     {
  407         LogDateAndTime();
  408         fprintf(log,"VERIFY %s %10lu Bytes\n",e->name,e->statb.st_size);
  409     }
  410     
  411 
  412     result = 0;
  413     
  414     for (;;)
  415     {
  416         nread = read(fds,buffer,bufferSize);
  417         
  418         if (nread < 0)
  419         {
  420             PrintError("read",sourcePath);
  421             result = 1;
  422             break;
  423         }
  424 
  425         if (nread == 0)
  426             break;
  427 
  428         if (read(fdd,buffer1,nread) != nread)
  429         {
  430             PrintError("read",destPath);
  431             result = 1;
  432             break;
  433         }
  434 
  435         if (memcmp(buffer,buffer1,nread))
  436         {
  437             errno = 0;
  438             PrintError("Verify",destPath);
  439             result = 1;
  440         }
  441 
  442         count += nread;
  443 
  444         if (verbose > 1)
  445         {
  446             if (count == e->statb.st_size)
  447                 perc = 100;
  448             else
  449                 perc = (size_t)(((double)count * 100.0) / (double)e->statb.st_size);
  450 
  451             if (perc > 100)
  452                 perc = 100;
  453 
  454             if (perc != oldPerc)
  455             {
  456                 printf("%%%03lu\010\010\010\010",perc);
  457                 fflush(stdout);
  458                 oldPerc = perc;
  459             }
  460         }
  461     }
  462 
  463     close(fdd);
  464     close(fds);
  465 
  466     printf("\r                                                                              \r");
  467     
  468     return result;
  469 
  470 }
  471 
  472 
  473 static void FileCopy(char * msg,char *source,char * dest,Entry_T *e)
  474 {
  475     int fds,fdd;
  476     char sourcePath[PATH_MAX+1];
  477     char destPath[PATH_MAX+1];
  478 #ifdef __LINUX__
  479     char symlinkPath[PATH_MAX+1];
  480     int dd;
  481 #endif
  482     int nread;
  483     size_t count = 0;
  484     size_t perc,oldPerc=101;
  485     
  486 
  487     if (log)
  488     {
  489         LogDateAndTime();
  490         fprintf(log,"COPY   %s %10lu Bytes\n",e->name,e->statb.st_size);
  491     }
  492     
  493     if (verbose > 1)
  494     {
  495         MSG_PATH(msg);
  496         printf("COPY   %-50.50s %10lu Byte ",e->name,e->statb.st_size);
  497         fflush(stdout);
  498     }
  499     
  500     FilePath(sourcePath,source,e->name);
  501     FilePath(destPath,dest,e->name);
  502     
  503 #ifdef __LINUX__
  504         /* (JR) - duplicate symlinks instead of following them */
  505     if ((e->statb.st_mode & S_IFMT) == S_IFLNK && !followSymlinks) {
  506       count=readlink(sourcePath,symlinkPath,PATH_MAX);
  507       if (count<0) {
  508         PrintError("symlink read",sourcePath);
  509         return;
  510       }
  511       /* add null byte */
  512       symlinkPath[count]=0;
  513       if (dd = symlink(symlinkPath,destPath) < 0) {
  514         if (errno==EEXIST) {
  515           FileUnlink(destPath);
  516           dd = symlink(symlinkPath,destPath);
  517         }
  518       }
  519       if (dd < 0) {
  520         PrintError("symlink create",destPath);
  521         return;
  522       }
  523       /* set ownership; can't set times nor permissions on a symlink */
  524       if (geteuid() == 0) {
  525         if (lchown(destPath,e->statb.st_uid,e->statb.st_gid))
  526         PrintError("chown",destPath);
  527       }
  528     } else {
  529 #endif
  530     
  531     fds = open(sourcePath,O_RDONLY|O_BINARY);
  532 
  533     if (fds < 0)
  534     {
  535         PrintError("open",sourcePath);
  536         return;
  537     }
  538     
  539     fdd = open(destPath,O_WRONLY|O_BINARY|O_CREAT|O_TRUNC,0777);
  540 
  541     
  542     if (fdd < 0)
  543     {
  544         FileUnlink(destPath);
  545         fdd = open(destPath,O_WRONLY|O_BINARY|O_CREAT|O_TRUNC,0777);
  546         if (fdd < 0)
  547         {
  548             PrintError("open",destPath);
  549             close(fds);
  550             return;
  551         }
  552     }
  553 
  554     for (;;)
  555     {
  556         nread = read(fds,buffer,bufferSize);
  557         if (nread < 0)
  558         {
  559             PrintError("read",sourcePath);
  560             break;
  561         }
  562 
  563         if (nread == 0)
  564             break;
  565 
  566         
  567         if (write(fdd,buffer,nread) != nread)
  568         {
  569             PrintError("write",destPath);
  570             break;
  571             
  572         }
  573 
  574         count += nread;
  575 
  576         if (verbose > 1)
  577         {
  578             if (count == e->statb.st_size)
  579                 perc = 100;
  580             else
  581                 perc = (size_t)(((double)count * 100.0) / (double)e->statb.st_size);
  582             
  583             if (perc > 100)
  584                 perc = 100;
  585             
  586             if (perc != oldPerc)
  587             {
  588                 printf("%%%03lu\010\010\010\010",perc);
  589                 fflush(stdout);
  590                 oldPerc = perc;
  591             }
  592         }
  593     }
  594 
  595     if (close(fdd))
  596     {
  597         PrintError("close",destPath);
  598     }
  599 
  600     if (close(fds))
  601     {
  602         PrintError("close",sourcePath);
  603     }
  604 
  605     if (fileVerify)
  606         FileVerify(msg,source,dest,e);
  607     
  608 
  609 
  610     CopyAttribute(destPath,&e->statb);
  611     
  612 #ifdef __LINUX__
  613     }   /* (JR) end of symlink if ... */
  614 #endif
  615 
  616     if (verbose > 1)
  617         printf("\r");
  618 
  619     filesCopied++;
  620 
  621     if (count !=  e->statb.st_size)
  622     {
  623         fprintf(stderr,"dirsync: Size of %s changed, expected %lu copied %lu\n",
  624               sourcePath,e->statb.st_size,count);
  625     }
  626     
  627     count /= 1024;
  628     kbCopied += count;
  629 
  630     
  631 }
  632 
  633 
  634 static void FileRemove(char * msg,char *dir,char *file)
  635 {
  636     char  path[PATH_MAX+1];
  637     filesDeleted ++;
  638     
  639     FilePath(path,dir,file);
  640 
  641     if (log)
  642     {
  643         LogDateAndTime();
  644         fprintf(log,"RM     %s\n",path);
  645     }
  646     
  647     if (verbose > 0)
  648     {
  649         MSG_PATH(msg);
  650         printf("RM     %s\n",path);
  651     }
  652     
  653     FileUnlink(path);
  654 }
  655 
  656 
  657 static void * CheckedAlloc(int size)
  658 {
  659     void *p;
  660 
  661     
  662     if (!size)
  663         return 0;
  664     
  665     p = malloc(size);
  666 
  667     if (p == 0)
  668     {
  669         fprintf(stderr,"\ndirsync: Out of memory\n");
  670         exit(1);
  671     }
  672 
  673     return p;
  674 }
  675 
  676 static int RegexSearch(Link_T * head,char *name)
  677 {
  678     Link_T * link;
  679     RegexEntry_T * e;
  680 
  681     
  682     for (link = head->next ; link != head ; link=link->next)
  683     {
  684         e = (RegexEntry_T *)link;
  685 /*      //printf("regsearch %s with %s\n",e->name,name);   */
  686 
  687         if (regexec(&e->regex,name,0,NULL,0) == 0)
  688         {
  689 /*          //printf("%s matched by %s \n",name,e->name);   */
  690 
  691             return 1;
  692 
  693         }
  694         
  695     }
  696 
  697     return 0;
  698 }
  699 
  700 static Entry_T * EntrySearch(Link_T * head,char *name)
  701 {
  702     Link_T * link;
  703     Entry_T * e;
  704 
  705     
  706     
  707     for (link = head->next ; link != head ; link=link->next)
  708     {
  709         e = (Entry_T *)link;
  710         if (!strcmp(name,e->name))
  711         {
  712             return e;
  713         }
  714     }
  715 
  716     return 0;
  717 }
  718 
  719 static void EntryAdd(Link_T * queue,char *name,struct stat * statb)
  720 {
  721     int len = strlen(name)+1;
  722     Entry_T * entry;
  723 
  724     entry = CheckedAlloc(sizeof(Entry_T));
  725     entry->name = (char *)CheckedAlloc(len);
  726     memcpy(entry->name,name,len);
  727     if (statb != NULL)
  728         entry->statb = * statb;
  729 
  730     QueueAdd(queue,&entry->link);
  731 }
  732 
  733 static void RegexAdd(Link_T * queue,char *name)
  734 {
  735     int len = strlen(name)+1;
  736     RegexEntry_T * entry;
  737 
  738     entry = CheckedAlloc(sizeof(RegexEntry_T));
  739     entry->name = (char *)CheckedAlloc(len);
  740     memcpy(entry->name,name,len);
  741     if (regcomp(&entry->regex,name,REG_NOSUB) != 0)
  742     {
  743         PrintError("regex",name);
  744     }
  745     else
  746         QueueAdd(queue,&entry->link);
  747 }
  748 
  749 static int ArrayCompare(const void *v1,const void *v2)
  750 {
  751     Entry_T * e1 = *( Entry_T **)v1;
  752     Entry_T * e2 = *( Entry_T **)v2;
  753 
  754     return strcmp(e1->name,e2->name);
  755 }
  756 
  757 static Entry_T *  ArraySearch(FileArray_T *a,Entry_T *e)
  758 {
  759     Entry_T ** result;
  760     if (a->count > 0) {      /* dumps core if empty table! - (JR) */
  761       result =  (Entry_T **)bsearch(&e,a->entry,a->count,sizeof(Entry_T *),ArrayCompare);
  762       if (!result)
  763         return 0;
  764       return *result;
  765     } else
  766       return 0;
  767 }
  768 
  769 
  770 static Entry_T **  ArrayCreate(FileArray_T * a)
  771 {
  772     long i;
  773     Link_T * link;
  774     Entry_T * e;
  775 
  776     
  777     for (a->count = 0,link = a->head.next ; link != &a->head ; link=link->next)
  778         a->count++;
  779 
  780     a->entry = CheckedAlloc(a->count*sizeof(Entry_T *));
  781 
  782     for (i = 0,link = a->head.next ; link != &a->head ; link=link->next)
  783     {
  784         e = (Entry_T *)link;
  785         a->entry[i++] = e;
  786     }
  787 
  788     qsort(a->entry,a->count,sizeof(Entry_T *),ArrayCompare);
  789     
  790     return 0;
  791 }
  792 
  793 static int ScanDir(char *dirname,Directory_T * queue,struct stat * statb)
  794 {
  795     struct dirent * d;
  796     DIR * dir;
  797     long dirCount,fileCount;
  798     char path[PATH_MAX+1];
  799     struct stat s;
  800     
  801     fileCount = dirCount = 0;
  802     
  803     QueueInit(&queue->files.head);
  804     QueueInit(&queue->dirs.head);
  805     
  806     if (stat(dirname,statb))
  807     {
  808         PrintError("stat",dirname);
  809         return 1;
  810     }
  811 
  812     if ((statb->st_mode & S_IFMT) != S_IFDIR)
  813     {
  814         fprintf(stderr,"\ndirsync: %s is not a directory\n",dirname);
  815         errors++;
  816         return 1;
  817     }
  818 
  819     if (verbose > 0)
  820     {
  821         printf("SCAN   %-60.60s  ",dirname);
  822         
  823         fflush(stdout);
  824     }
  825     
  826     dir = opendir(dirname);
  827 
  828     if (dir == 0)
  829     {
  830         PrintError("opendir",dirname);
  831         return 1;
  832     }
  833 
  834     while ((d = readdir(dir)) != 0)
  835     {
  836         FilePath(path,dirname,d->d_name);
  837 /*test  printf("%s\n",d->d_name);  */
  838 
  839         if (RegexSearch(&excludedRegex,path))
  840             continue;
  841         
  842 #ifdef __LINUX__
  843         if (followSymlinks ? stat(path,&s) : lstat(path,&s))
  844 #else
  845         if (stat(path,&s))
  846 #endif
  847         {
  848             PrintError("stat",path);
  849             continue;
  850         }
  851 
  852 /*      //printf("%s\n",d->d_name);   */
  853         switch (s.st_mode & S_IFMT)
  854         {
  855             case    S_IFDIR:
  856                     if (EntrySearch(&excludedDirs,d->d_name) == NULL)
  857                     {
  858                         EntryAdd(&queue->dirs.head,d->d_name,&s);
  859                         dirCount++;
  860                     }
  861                     break;
  862                     
  863             case    S_IFREG:
  864 #ifdef S_IFLNK
  865             case    S_IFLNK:
  866 #endif          
  867                     if (EntrySearch(&excludedFiles,d->d_name) == NULL)
  868                     {
  869                         EntryAdd(&queue->files.head,d->d_name,&s);
  870                         fileCount++;
  871                     }
  872                     break;
  873 
  874 #ifdef S_IFBLK
  875             case    S_IFBLK:
  876                     fprintf(stderr,"\ndirsync: Ignored block device %s in %s\n",
  877                             d->d_name,dirname);
  878                     break;
  879 #endif
  880                     
  881 #ifdef S_IFCHR
  882             case    S_IFCHR:
  883                     fprintf(stderr,"\ndirsync: Ignored char device %s in %s\n",
  884                             d->d_name,dirname);
  885                     break;
  886 #endif
  887                     
  888 #ifdef  S_IFFIFO
  889             case    S_IFFIFO:
  890                     fprintf(stderr,"\ndirsync: Ignored fifo %s in %s\n",
  891                         d->d_name,dirname);
  892                     break;
  893 #endif
  894             default:
  895                     fprintf(stderr,"\ndirsync: Ignored unknown  %s in directory %s\n",
  896                             d->d_name,dirname);
  897                     break;
  898 
  899         }
  900 
  901     }
  902 
  903     closedir(dir);
  904 
  905     
  906     if (verbose > 0)
  907     {
  908         printf("*");
  909         fflush(stdout);
  910     }
  911 
  912     /**
  913      * Now create one sorted array for files and directory
  914      */
  915     ArrayCreate(&queue->files);
  916     ArrayCreate(&queue->dirs);
  917     
  918     if (verbose > 0)
  919     {
  920         printf("\010 \010\r");
  921         fflush(stdout);
  922     }
  923     
  924     return 0;
  925 }
  926 
  927 static void Mkdir(char * msg,char * path)
  928 {
  929     if (verbose > 1)
  930     {
  931         MSG_PATH(msg);
  932         printf("MKDIR  %s\n",path);
  933     }
  934     
  935 #ifdef __LINUX__
  936     if (mkdir(path,0777))
  937 #else
  938     if (mkdir(path))
  939 #endif
  940     {
  941         PrintError("mkdir",path);
  942     }
  943 
  944 }
  945 
  946 static void Rmdir(char * msg,char *dirname,char *file)
  947 {
  948     char  path[PATH_MAX+1];
  949 
  950     FilePath(path,dirname,file);
  951 
  952     if (log)
  953     {
  954         LogDateAndTime();
  955         fprintf(log,"RMDIR  %s\n",path);
  956         
  957     }
  958     
  959     if (verbose > 0)
  960     {
  961         MSG_PATH(msg);
  962         printf("RMDIR  %s\n",path);
  963     }
  964 
  965     if (rmdir(path))
  966     {
  967 #ifdef UNSECURE
  968         chmod(path,0777);
  969         if (rmdir(path))
  970 #endif
  971         {
  972             PrintError("rmdir",path);
  973         }
  974     }
  975 }
  976 
  977 static void FreeArray(FileArray_T * a)
  978 {
  979     long i;
  980     Entry_T * e;
  981 
  982     for (i = 0 ; i < a->count ; i++)
  983     {
  984         e = a->entry[i];
  985         free(e->name);
  986         free(e);
  987     }
  988 
  989     if (a->entry)
  990         free(a->entry);
  991 }
  992 
  993 static void FreeDirectory(Directory_T * dir)
  994 {
  995     FreeArray(&dir->files);
  996     FreeArray(&dir->dirs);
  997 }
  998     
  999 static void RmdirAll(char *msg,char *dirname,char *file)
 1000 {
 1001     char path[PATH_MAX+1];
 1002     struct stat statb;
 1003     Directory_T dir;
 1004     Entry_T * e;
 1005     long i;
 1006     
 1007     FilePath(path,dirname,file);        
 1008     
 1009     if (ScanDir(path,&dir,&statb))
 1010         return;
 1011     
 1012 /*  // Step 1. Remove all file       */
 1013     for (i = 0 ; i  < dir.files.count ; i++)
 1014     {
 1015         e = dir.files.entry[i];
 1016 
 1017         FileRemove(msg,path,e->name);
 1018     }
 1019 
 1020 /*  // Step 2. Remove all dir        */
 1021     for (i = 0 ; i < dir.dirs.count ; i++)
 1022     {
 1023         e = dir.dirs.entry[i];
 1024 
 1025         RmdirAll(msg,path,e->name);
 1026     }
 1027 
 1028 /*  // Step 3. Remove dir            */
 1029 
 1030     Rmdir(msg,dirname,file);
 1031 
 1032     FreeDirectory(&dir);
 1033 }
 1034 
 1035 static int dirsync(char *source,char *dest)
 1036 {
 1037     char sourcePath[PATH_MAX+1],destPath[PATH_MAX+1];
 1038     char msg[80*2+5];
 1039     Directory_T dirSource,dirDest;
 1040     Entry_T * se , *de;
 1041     int needCopy;
 1042     struct stat statSource,statDest;
 1043     int firstTime = 1;
 1044     long i;
 1045 /* (JR) add */
 1046     int isLink = 0;
 1047     
 1048     sprintf(msg,"FROM   %-70.70s\nTO     %-70.70s\n",source,dest);
 1049 
 1050     if (log)
 1051     {
 1052         LogDateAndTime();
 1053         fprintf(log,"FROM   %s\n",source);
 1054         LogDateAndTime();
 1055         fprintf(log,"TO     %s\n",dest);
 1056     }
 1057     
 1058     if (ScanDir(source,&dirSource,&statSource))
 1059         return 1;
 1060 
 1061     if (ScanDir(dest,&dirDest,&statDest))
 1062     {
 1063         FreeDirectory(&dirSource);
 1064         return 1;
 1065     }
 1066     
 1067 /*  // Step 1. Delete all file not present in the source dir    */
 1068     for (i = 0 ; i < dirDest.files.count ; i++)
 1069     {
 1070         de = dirDest.files.entry[i];
 1071         se = ArraySearch(&dirSource.files,de);
 1072 
 1073         if (se == NULL)
 1074         {
 1075             if (!dontRemove)
 1076             {
 1077                 if (mode == 2)
 1078                 {
 1079                     MSG_PATH(msg);
 1080                     printf("\t5 %s\n",de->name);
 1081                     if (log)
 1082                     {
 1083                         LogDateAndTime();
 1084                         fprintf(log,"ERROR  %s - File not present in the source\n",de->name);
 1085                     }
 1086                 }
 1087                 else
 1088                 {
 1089                     if (firstTime)
 1090                     {
 1091                         firstTime = 0;
 1092 #ifdef UNSECURE
 1093                         chmod(dest,0777);
 1094 #endif
 1095                     }
 1096                     FileRemove(msg,dest,de->name);
 1097                 }
 1098             }
 1099         }
 1100     }
 1101 
 1102 /*  // Step 2. Delete all directories not present in the source    */
 1103     for (i = 0 ; i < dirDest.dirs.count; i++)
 1104     {
 1105         de = dirDest.dirs.entry[i];
 1106         se = ArraySearch(&dirSource.dirs,de);
 1107 
 1108         if (se == NULL)
 1109         {
 1110             if (!dontRemove)
 1111             {
 1112                 if (mode == 2)
 1113                 {
 1114                     MSG_PATH(msg);
 1115 /*                  printf("\t0%s\n",de->name); */
 1116                     printf("\t0 %s\n",de->name);
 1117                     if (log)
 1118                     {
 1119                         LogDateAndTime();
 1120                         fprintf(log,"ERROR  %s - Directory not present in the source\n",de->name);
 1121                     }
 1122                     
 1123                 }
 1124                 else
 1125                 {
 1126                     if (firstTime)
 1127                     {
 1128                         firstTime = 0;
 1129 #ifdef UNSECURE
 1130                         chmod(dest,0777);
 1131 #endif
 1132                     }                   
 1133                     RmdirAll(msg,dest,de->name);
 1134                 }
 1135             }
 1136         }
 1137     }
 1138     
 1139 /*  // Step 3. Copy all file changed form source to dest    */
 1140     for (i = 0 ; i < dirSource.files.count ; i++)
 1141     {
 1142         se = dirSource.files.entry[i];
 1143         de = ArraySearch(&dirDest.files,se);
 1144 /* (JR) add */
 1145 #ifdef S_IFLNK
 1146         isLink = ((se->statb.st_mode & S_IFMT) == S_IFLNK);
 1147 #endif
 1148 /* (JR) end */
 1149 
 1150         needCopy = 0;
 1151         filesChecked++;
 1152         
 1153 /*      // File not present in the destination          */
 1154         if (de == NULL)
 1155             needCopy = 1;
 1156         else switch (mode)
 1157         {
 1158             case    0:
 1159                     if (se->statb.st_size != de->statb.st_size ||
 1160 /*                    se->statb.st_mtime != de->statb.st_mtime)  */
 1161 /* (JR) mod */
 1162                       isLink ? (se->statb.st_mtime > de->statb.st_mtime)
 1163                          : (se->statb.st_mtime != de->statb.st_mtime))
 1164                         needCopy = 1;
 1165                     break;
 1166             case    1:
 1167                     if (se->statb.st_mtime > de->statb.st_mtime)
 1168                         needCopy = 1;
 1169                     break;
 1170             case    2:
 1171 /*                  if (se->statb.st_size != de->statb.st_size)  */
 1172 /* (JR) mod */
 1173                     if (se->statb.st_size != de->statb.st_size ||
 1174                       isLink ? (se->statb.st_mtime > de->statb.st_mtime)
 1175                          : (se->statb.st_mtime != de->statb.st_mtime))
 1176                         needCopy = 1;
 1177                     break;
 1178 /* (JR) add */
 1179             case    3:
 1180                     if (se->statb.st_size != de->statb.st_size ||
 1181                       (!isLink && se->statb.st_mtime != de->statb.st_mtime))
 1182                         needCopy = 1;
 1183                     break;
 1184                     
 1185         }
 1186                             
 1187         if (needCopy)
 1188         {
 1189             if (mode == 2)
 1190             {
 1191                 MSG_PATH(msg);
 1192                 printf("\t2 %s\n",se->name);
 1193                 if (log)
 1194                 {
 1195                     LogDateAndTime();
 1196                     fprintf(log,"ERROR  %s - Need to be copied\n",se->name);
 1197                 }
 1198                 
 1199             }
 1200             else
 1201             {
 1202 /*              FileCopy(msg,source,dest,se);  */
 1203                 if (firstTime)
 1204                 {
 1205                     firstTime = 0;
 1206 #ifdef UNSECURE
 1207                     chmod(dest,0777);
 1208 #endif
 1209                 }
 1210                 /* this rather should be here? - (JR) */
 1211                 FileCopy(msg,source,dest,se);
 1212                 
 1213             }
 1214         }
 1215         else
 1216         {
 1217             if (mode == 2)
 1218                 if (FileVerify(msg,source,dest,se))
 1219                 {
 1220                     MSG_PATH(msg);
 1221                     printf("\t4 %s\n",se->name);
 1222                     if (log)
 1223                     {
 1224                         LogDateAndTime();
 1225                         fprintf(log,"ERROR  %s - Verify error\n",se->name);
 1226                     }
 1227                     
 1228                 }
 1229         }
 1230             
 1231     }
 1232 
 1233 /*  // Step 4. Call dirsync in all directory        */
 1234     for (i = 0 ; i < dirSource.dirs.count ; i++)
 1235     {
 1236 
 1237         se = dirSource.dirs.entry[i];
 1238         de = ArraySearch(&dirDest.dirs,se);
 1239         FilePath(destPath,dest,se->name);
 1240         FilePath(sourcePath,source,se->name);
 1241 
 1242         if (de == NULL)
 1243         {
 1244             if (mode == 2)
 1245             {
 1246                 MSG_PATH(msg);
 1247                 printf("\t1 %s\n",se->name);
 1248                 if (log)
 1249                 {
 1250                     LogDateAndTime();
 1251                     fprintf(log,"ERROR  %s - Directory not present in destinatio\n",se->name);
 1252                 }
 1253                 
 1254             }
 1255             else
 1256                 /* (JR) add */
 1257                 if (firstTime)
 1258                 {
 1259                     firstTime = 0;
 1260 #ifdef UNSECURE
 1261                     chmod(dest,0777);
 1262 #endif
 1263                 }
 1264                 /* (JR) end */
 1265                 Mkdir(msg,destPath);
 1266                 /* another (JR) add, in case of an empty dir */
 1267                 CopyAttribute(destPath,&se->statb);
 1268         }
 1269 
 1270         if (de != NULL || mode != 2)
 1271             dirsync(sourcePath,destPath);
 1272     }
 1273 
 1274     /* Set destination directory attributes */
 1275     if (firstTime == 0 && mode != 2)
 1276         CopyAttribute(dest,&statSource);
 1277 
 1278     FreeDirectory(&dirDest);
 1279     FreeDirectory(&dirSource);
 1280     
 1281     return 0;
 1282 }
 1283 
 1284 
 1285 static void Usage()
 1286 {
 1287     printf("usage : dirsync [option(s)] source dest\n");
 1288     printf("\tsource\tsoure directory (must exist)\n");
 1289     printf("\tdest\tdestination directory (must exist)\n");
 1290     printf("\t-h\tDisplay this message\n");
 1291     printf("\t-v lvl\tset verbose level (default %d,min 0,max 9)\n",DEFAULT_VERBOSE);
 1292     printf("\t-q\tQuiet mode (same result of -v 0)\n");
 1293     printf("\t-V\tVerify copied data\n");
 1294     printf("\t-X name\tExclude directory name (1) from scanning (default . ..)\n");
 1295     printf("\t-x name\tExclude file name (1) from scanning\n");
 1296     printf("\t-e name\tExclude regular expression name (1) from scanning\n");
 1297     printf("\t-b size\tSet the read/write buffer size (default %d)\n",DEFAULT_BUFFER_SIZE);
 1298     printf("\t-m mode\tSet copy file mode,always missing file are copied\n");
 1299     printf("\t\t0 - Copy file if have different size or date (default)\n");
 1300     printf("\t\t1 - Copy file if the destination is older than source\n");
 1301     printf("\t\t2 - Do not copy any file only show the difference \n");
 1302     printf("\t\t    with this code :  0 Directory not present in source\n");
 1303     printf("\t\t                   :  1 Directory nont present in destination\n");
 1304     printf("\t\t                      2 Different size, 4 Not equal\n");
 1305     printf("\t\t3 - Like mode 0 but do not check size/time in symbolics link\n");
 1306 /* (JR) add */
 1307     printf("\t\t3 - Like mode 0, but don't check date on symlinks\n");
 1308 /* (JR) end */
 1309     printf("\t-T fmt\tSet date and time format, default %s\n",dateTimeFormat);
 1310     printf("\t-D fmt\tSet date format, default %s\n",dateFormat);
 1311     printf("\t-l file\tLog operation in file, if - use date format .log (see -D)\n");
 1312     printf("\t-r\tDon't remove file/directory missed in the source\n");
 1313 /* (JR) add */
 1314     printf("\t-L\tFollow symlinks (copy contents instead of duplicating link)\n");
 1315 /* (JR) end */
 1316     printf("\n\t\t(1) If name begin with @ for example @list the names will be\n");
 1317     printf("\t\tread from a text file named list.\n");
 1318     
 1319 }
 1320 
 1321 static void AddRegexOption(Link_T * queue,char *name)
 1322 {
 1323     FILE * fd;
 1324     char buffer[PATH_MAX+1];
 1325 
 1326     if (*name != '@')
 1327     {
 1328         RegexAdd(queue,name);
 1329         return;
 1330     }
 1331     name++;
 1332 
 1333     if ((fd = fopen(name,"rt")) == NULL)
 1334     {
 1335         PrintError("fopen",name);
 1336         exit(1);
 1337     }
 1338 
 1339     while (fscanf(fd,"%s",buffer) == 1)
 1340     {
 1341         RegexAdd(queue,name);
 1342     }
 1343 
 1344     fclose(fd);
 1345 
 1346 
 1347 }
 1348 
 1349 static void AddEntryOption(Link_T * queue,char *name)
 1350 {
 1351     FILE * fd;
 1352     char buffer[PATH_MAX+1];
 1353     
 1354     if (*name != '@')
 1355     {
 1356         EntryAdd(queue,name,NULL);
 1357         return;
 1358     }
 1359     name++;
 1360 
 1361     if ((fd = fopen(name,"rt")) == NULL)
 1362     {
 1363         PrintError("fopen",name);
 1364         exit(1);
 1365     }
 1366 
 1367     while (fscanf(fd,"%s",buffer) == 1)
 1368     {
 1369         EntryAdd(queue,name,NULL);
 1370     }
 1371 
 1372     fclose(fd);
 1373     
 1374 }
 1375 
 1376 
 1377 static void RemoveDirsep(char * path)
 1378 {
 1379     int len;
 1380     len = strlen(path);
 1381     
 1382 #ifdef __LINUX__
 1383     if (len > 1 && path[len - 1] == DIRSEP)
 1384         path[len - 1] = '\0';
 1385 #else
 1386     if (len > 1 && path[len - 1] == DIRSEP && path[len - 2] != ':')
 1387         path[len - 1] = '\0';
 1388 #endif
 1389 }
 1390 
 1391 int main(int argc,char **argv)
 1392 {
 1393     time_t start,end;
 1394     long kbSec;
 1395     int o;
 1396     char logfile[PATH_MAX];
 1397     char * version = "DirSync 1.11 author mario@viara.cn, mod by (JR)";
 1398 
 1399     printf("%s\n\n",version);
 1400     
 1401     QueueInit(&excludedDirs);
 1402     QueueInit(&excludedFiles);
 1403     QueueInit(&excludedRegex);
 1404     
 1405 /*  // Add default excluded dir        */
 1406     EntryAdd(&excludedDirs,".",NULL);
 1407     EntryAdd(&excludedDirs,"..",NULL);
 1408 
 1409 
 1410 
 1411 /*  while (( o = getopt(argc,argv,"T:D:l:Vqhv:x:X:b:m:re:")) != -1) */
 1412 /* (JR) mod */
 1413     while (( o = getopt(argc,argv,"T:D:l:Vqhv:x:X:b:m:re:L")) != -1)
 1414     {
 1415         switch (o)
 1416         {
 1417             case    'T':
 1418                     strcpy(dateTimeFormat,optarg);
 1419                     break;
 1420             case    'D':
 1421                     strcpy(dateFormat,optarg);
 1422                     break;
 1423             case    'l':
 1424                     if (strcmp(optarg,"-"))
 1425                         strcpy(logfile,optarg);
 1426                     else
 1427                         sprintf(logfile,"%s.log",GetDate());
 1428                     log = fopen(logfile,"w");
 1429                     if (log == NULL)
 1430                     {
 1431                         PrintError("fopen",logfile);
 1432                         exit(1);
 1433                     }
 1434                     else
 1435                     {
 1436                         LogDateAndTime();
 1437                         fprintf(log,"%s\n",version);
 1438                     }
 1439                     
 1440                     if (verbose)
 1441                         printf("Log operation in %s\n",logfile);
 1442                     break;
 1443             case    'V':
 1444                     fileVerify = 1;
 1445                     break;
 1446             case    'r':
 1447                     dontRemove = 1;
 1448                     break;
 1449                     
 1450             case    'm':
 1451                     mode = atoi(optarg);
 1452                     if (mode < 0 || mode > 3)
 1453                     {
 1454                         printf("dirsync: invalid -m %d\n",mode);
 1455                         Usage();
 1456                         return 2;
 1457                     }
 1458                     break;
 1459             case    'b':
 1460                     bufferSize = atoi(optarg);
 1461                     break;
 1462 
 1463             case    'e':
 1464                     AddRegexOption(&excludedRegex,optarg);
 1465                     break;
 1466             case    'x':
 1467                     AddEntryOption(&excludedFiles,optarg);
 1468 /*                  //EntryAdd(&excludedFiles,optarg,NULL);  */
 1469                     break;
 1470                     
 1471             case    'X':
 1472                     AddEntryOption(&excludedDirs,optarg);
 1473 /*                  //EntryAdd(&excludedDirs,optarg,NULL);   */
 1474                     break;
 1475             case    'q':
 1476                     verbose = 0;
 1477                     break;
 1478             case    'v':
 1479                     verbose = atoi(optarg);
 1480                     break;
 1481             case    '?':
 1482             case    'h':
 1483                     Usage();
 1484                     return 2;
 1485             /* (JR) add */
 1486             case    'L':
 1487                     followSymlinks = 1;
 1488                     break;
 1489         }
 1490     }
 1491 
 1492     if (optind + 2 != argc)
 1493     {
 1494         printf("dirsync: source and destination not specified\nplease try dirsync -h for usage\n");
 1495         exit(1);
 1496     }
 1497 
 1498     /**
 1499      * Allocated buffer 1 to read and 2 to verify
 1500      */
 1501     buffer  = (char *)CheckedAlloc(bufferSize);
 1502     buffer1 = (char *)CheckedAlloc(bufferSize);
 1503     
 1504     time(&start);
 1505 
 1506     RemoveDirsep(argv[optind]);
 1507     RemoveDirsep(argv[optind+1]);
 1508 
 1509     if (log)
 1510     {
 1511         LogDateAndTime();
 1512         fprintf(log,"ARGS[%d]   %s %s\n",mode,argv[optind],argv[optind+1]);
 1513     }
 1514     
 1515     dirsync(argv[optind],argv[optind+1]);
 1516     time(&end);
 1517 
 1518     if (verbose)
 1519     {
 1520         if (end - start > 0)
 1521             kbSec = kbCopied / (end -start);
 1522         else
 1523             kbSec = 0;
 1524         printf("\r                                                                              \r");
 1525                   
 1526         printf("%ld files, %ld copied %lu KB %ld KB/s, %ld deleted, %ld s",
 1527                filesChecked,filesCopied,kbCopied,kbSec,filesDeleted,end -start);
 1528         if (errors)
 1529             printf(",%ld error(s)",errors);
 1530         printf("\n");
 1531     }
 1532 
 1533     if (log)
 1534     {
 1535         LogDateAndTime();
 1536         fprintf(log,"       %ld files, %ld copied (%lu KB, %ld KB/s), %10ld deleted, %10ld second(s)",
 1537                filesChecked,filesCopied,kbCopied,kbSec,filesDeleted,end -start);
 1538         if (errors)
 1539             fprintf(log,",%ld error(s)",errors);
 1540         fprintf(log,"\n");
 1541         fclose(log);
 1542     }
 1543 
 1544     return errors == 0 ? 0 : 2;
 1545 }