home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / rsync221.zip / exclude.c < prev    next >
C/C++ Source or Header  |  1999-03-04  |  8KB  |  345 lines

  1. /* 
  2.    Copyright (C) Andrew Tridgell 1996
  3.    Copyright (C) Paul Mackerras 1996
  4.    
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2 of the License, or
  8.    (at your option) any later version.
  9.    
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.    
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19.  
  20. /* a lot of this stuff was originally derived from GNU tar, although
  21.    it has now changed so much that it is hard to tell :) */
  22.  
  23. #include "rsync.h"
  24.  
  25. extern int verbose;
  26.  
  27. static struct exclude_struct **exclude_list;
  28.  
  29. /*
  30.  * Optimization for special case when all included files are explicitly
  31.  *   listed without wildcards in the "exclude" list followed by a "- *"
  32.  *   to exclude the rest.
  33.  * Contributed by Dave Dykstra <dwd@bell-labs.com>
  34.  */
  35. static int only_included_files = 1;
  36. static struct exclude_struct *exclude_the_rest;
  37.  
  38. int send_included_file_names(int f,struct file_list *flist)
  39. {
  40.     struct exclude_struct *ex, **ex_list;
  41.     int n;
  42.     char *p;
  43.  
  44.     if (!only_included_files || (exclude_the_rest == NULL))
  45.         return 0;
  46.  
  47.     if (verbose > 1) {
  48.         rprintf(FINFO,"(using include-only optimization) ");
  49.     }
  50.  
  51.     /* set exclude_list to NULL temporarily so check_exclude */
  52.     /*   will always return true */
  53.     ex_list = exclude_list;
  54.     exclude_list = NULL;
  55.     for (n=0; (ex = ex_list[n]) != NULL; n++) {
  56.         if (ex == exclude_the_rest)
  57.             break;
  58.         p = ex->pattern;
  59.         while (*p == '/') {
  60.             /* skip the allowed beginning slashes */
  61.             p++;
  62.         }
  63.         send_file_name(f,flist,p,0,0);
  64.     }
  65.     exclude_list = ex_list;
  66.     
  67.     return 1;
  68. }
  69.  
  70. /* build an exclude structure given a exclude pattern */
  71. static struct exclude_struct *make_exclude(char *pattern, int include)
  72. {
  73.     struct exclude_struct *ret;
  74.  
  75.     ret = (struct exclude_struct *)malloc(sizeof(*ret));
  76.     if (!ret) out_of_memory("make_exclude");
  77.  
  78.     memset(ret, 0, sizeof(*ret));
  79.  
  80.     if (strncmp(pattern,"- ",2) == 0) {
  81.         pattern += 2;
  82.     } else if (strncmp(pattern,"+ ",2) == 0) {
  83.         ret->include = 1;
  84.         pattern += 2;
  85.     } else {
  86.         ret->include = include;
  87.     }
  88.  
  89.     ret->pattern = strdup(pattern);
  90.  
  91.     if (!ret->pattern) out_of_memory("make_exclude");
  92.  
  93.     if (strpbrk(pattern, "*[?")) {
  94.         if (!ret->include && (*pattern == '*') && (*(pattern+1) == '\0')) {
  95.             exclude_the_rest = ret;
  96.         } else {
  97.             only_included_files = 0;
  98.         }
  99.         ret->regular_exp = 1;
  100.     } else if (!ret->include) {
  101.         only_included_files = 0;
  102.     }
  103.  
  104.     if (strlen(pattern) > 1 && pattern[strlen(pattern)-1] == '/') {
  105.         ret->pattern[strlen(pattern)-1] = 0;
  106.         ret->directory = 1;
  107.     }
  108.  
  109.     if (!strchr(ret->pattern,'/')) {
  110.         ret->local = 1;
  111.     }
  112.  
  113.     return ret;
  114. }
  115.  
  116. static void free_exclude(struct exclude_struct *ex)
  117. {
  118.     free(ex->pattern);
  119.     memset(ex,0,sizeof(*ex));
  120.     free(ex);
  121. }
  122.  
  123. static int check_one_exclude(char *name,struct exclude_struct *ex,
  124.                  STRUCT_STAT *st)
  125. {
  126.     char *p;
  127.     int match_start=0;
  128.     char *pattern = ex->pattern;
  129.  
  130.     if (ex->local && (p=strrchr(name,'/')))
  131.         name = p+1;
  132.  
  133.     if (!name[0]) return 0;
  134.  
  135.     if (ex->directory && !S_ISDIR(st->st_mode)) return 0;
  136.  
  137.     if (*pattern == '/' && *name != '/') {
  138.         match_start = 1;
  139.         pattern++;
  140.     }
  141.  
  142.     if (ex->regular_exp) {
  143.         if (fnmatch(pattern, name, 0) == 0)
  144.             return 1;
  145.     } else {
  146.         int l1 = strlen(name);
  147.         int l2 = strlen(pattern);
  148.         if (l2 <= l1 && 
  149.             strcmp(name+(l1-l2),pattern) == 0 &&
  150.             (l1==l2 || (!match_start && name[l1-(l2+1)] == '/')))
  151.             return 1;
  152.     }
  153.  
  154.     return 0;
  155. }
  156.  
  157.  
  158. int check_exclude(char *name,struct exclude_struct **local_exclude_list,
  159.           STRUCT_STAT *st)
  160. {
  161.     int n;
  162.  
  163.     if (name && (name[0] == '.') && !name[1])
  164.         /* never exclude '.', even if somebody does --exclude '*' */
  165.         return 0;
  166.  
  167.     if (exclude_list) {
  168.         for (n=0; exclude_list[n]; n++)
  169.             if (check_one_exclude(name,exclude_list[n],st))
  170.                 return !exclude_list[n]->include;
  171.     }
  172.  
  173.     if (local_exclude_list) {
  174.         for (n=0; local_exclude_list[n]; n++)
  175.             if (check_one_exclude(name,local_exclude_list[n],st))
  176.                 return !local_exclude_list[n]->include;
  177.     }
  178.  
  179.     return 0;
  180. }
  181.  
  182.  
  183. void add_exclude_list(char *pattern,struct exclude_struct ***list, int include)
  184. {
  185.     int len=0;
  186.     if (list && *list)
  187.         for (; (*list)[len]; len++) ;
  188.  
  189.     if (strcmp(pattern,"!") == 0) {
  190.         if (verbose > 2)
  191.             rprintf(FINFO,"clearing exclude list\n");
  192.         while ((len)--) {
  193.             free_exclude((*list)[len]);
  194.         }
  195.         free((*list));
  196.         *list = NULL;
  197.         only_included_files = 1;
  198.         exclude_the_rest = NULL;
  199.         return;
  200.     }
  201.  
  202.     *list = (struct exclude_struct **)Realloc(*list,sizeof(struct exclude_struct *)*(len+2));
  203.     
  204.     if (!*list || !((*list)[len] = make_exclude(pattern, include)))
  205.         out_of_memory("add_exclude");
  206.     
  207.     if (verbose > 2)
  208.         rprintf(FINFO,"add_exclude(%s)\n",pattern);
  209.     
  210.     (*list)[len+1] = NULL;
  211. }
  212.  
  213. void add_exclude(char *pattern, int include)
  214. {
  215.     add_exclude_list(pattern,&exclude_list, include);
  216. }
  217.  
  218. struct exclude_struct **make_exclude_list(char *fname,
  219.                       struct exclude_struct **list1,
  220.                       int fatal, int include)
  221. {
  222.     struct exclude_struct **list=list1;
  223.     FILE *f = fopen(fname,"r");
  224.     char line[MAXPATHLEN];
  225.     if (!f) {
  226.         if (fatal) {
  227.             rprintf(FERROR,"%s : %s\n",fname,strerror(errno));
  228.             exit_cleanup(RERR_FILEIO);
  229.         }
  230.         return list;
  231.     }
  232.  
  233.     while (fgets(line,MAXPATHLEN,f)) {
  234.         int l = strlen(line);
  235.         if (l && line[l-1] == '\n') l--;
  236.         line[l] = 0;
  237.         if (line[0]) add_exclude_list(line,&list,include);
  238.     }
  239.     fclose(f);
  240.     return list;
  241. }
  242.  
  243.  
  244. void add_exclude_file(char *fname,int fatal,int include)
  245. {
  246.     if (!fname || !*fname) return;
  247.  
  248.     exclude_list = make_exclude_list(fname,exclude_list,fatal,include);
  249. }
  250.  
  251.  
  252. void send_exclude_list(int f)
  253. {
  254.     int i;
  255.     extern int remote_version;
  256.  
  257.     if (!exclude_list) {
  258.         write_int(f,0);
  259.         return;
  260.     }
  261.  
  262.     for (i=0;exclude_list[i];i++) {
  263.         char *pattern = exclude_list[i]->pattern; 
  264.         int l;
  265.  
  266.         l = strlen(pattern);
  267.         if (l == 0) continue;
  268.         if (exclude_list[i]->include) {
  269.             if (remote_version < 19) {
  270.                 rprintf(FERROR,"remote rsync does not support include syntax - aborting\n");
  271.                 exit_cleanup(RERR_UNSUPPORTED);
  272.             }
  273.             write_int(f,l+2);
  274.             write_buf(f,"+ ",2);
  275.         } else {
  276.             write_int(f,l);
  277.         }
  278.         write_buf(f,pattern,l);
  279.     }    
  280.  
  281.     write_int(f,0);
  282. }
  283.  
  284.  
  285. void recv_exclude_list(int f)
  286. {
  287.     char line[MAXPATHLEN];
  288.     int l;
  289.     while ((l=read_int(f))) {
  290.         if (l >= MAXPATHLEN) overflow("recv_exclude_list");
  291.         read_sbuf(f,line,l);
  292.         add_exclude(line,0);
  293.     }
  294. }
  295.  
  296.  
  297. void add_exclude_line(char *p)
  298. {
  299.     char *tok;
  300.     if (!p || !*p) return;
  301.     p = strdup(p);
  302.     if (!p) out_of_memory("add_exclude_line");
  303.     for (tok=strtok(p," "); tok; tok=strtok(NULL," "))
  304.         add_exclude(tok, 0);
  305.     free(p);
  306. }
  307.  
  308. void add_include_line(char *p)
  309. {
  310.     char *tok;
  311.     if (!p || !*p) return;
  312.     p = strdup(p);
  313.     if (!p) out_of_memory("add_include_line");
  314.     for (tok=strtok(p," "); tok; tok=strtok(NULL," "))
  315.         add_exclude(tok, 1);
  316.     free(p);
  317. }
  318.  
  319.  
  320. static char *cvs_ignore_list[] = {
  321.   "RCS","SCCS","CVS","CVS.adm","RCSLOG","cvslog.*",
  322.   "tags","TAGS",".make.state",".nse_depinfo",
  323.   "*~", "#*", ".#*", ",*", "*.old", "*.bak", "*.BAK", "*.orig",
  324.   "*.rej", ".del-*", "*.a", "*.o", "*.obj", "*.so", "*.Z", "*.elc", "*.ln",
  325.   "core",NULL};
  326.  
  327.  
  328.  
  329. void add_cvs_excludes(void)
  330. {
  331.     char fname[MAXPATHLEN];
  332.     char *p;
  333.     int i;
  334.   
  335.     for (i=0; cvs_ignore_list[i]; i++)
  336.         add_exclude(cvs_ignore_list[i], 0);
  337.  
  338.     if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
  339.         slprintf(fname,sizeof(fname), "%s/.cvsignore",p);
  340.         add_exclude_file(fname,0,0);
  341.     }
  342.  
  343.     add_exclude_line(getenv("CVSIGNORE"));
  344. }
  345.