Annotation of embedaddon/rsync/patches/ignore-case.diff, revision 1.1.1.1

1.1       misho       1: This adds the --ignore-case option, which makes rsync compare filenames
                      2: in a case-insensitive manner.
                      3: 
                      4: To use this patch, run these commands for a successful build:
                      5: 
                      6:     patch -p1 <patches/ignore-case.diff
                      7:     ./configure                            (optional if already run)
                      8:     make
                      9: 
                     10: TODO:
                     11: 
                     12:  - Make this code handle multibyte character encodings, and honor the
                     13:    --iconv setting when converting case.
                     14: 
                     15: based-on: e94bad1c156fc3910f24e2b3b71a81b0b0bdeb70
                     16: diff --git a/exclude.c b/exclude.c
                     17: --- a/exclude.c
                     18: +++ b/exclude.c
                     19: @@ -683,16 +683,15 @@ static int rule_matches(const char *fname, filter_rule *ex, int name_flags)
                     20:                if (litmatch_array(pattern, strings, slash_handling))
                     21:                        return ret_match;
                     22:        } else if (anchored_match) {
                     23: -              if (strcmp(name, pattern) == 0)
                     24: +              if (ic_strEQ(name, pattern))
                     25:                        return ret_match;
                     26:        } else {
                     27:                int l1 = strlen(name);
                     28:                int l2 = strlen(pattern);
                     29: -              if (l2 <= l1 &&
                     30: -                  strcmp(name+(l1-l2),pattern) == 0 &&
                     31: -                  (l1==l2 || name[l1-(l2+1)] == '/')) {
                     32: +              if (l2 <= l1
                     33: +               && ic_strEQ(name + (l1-l2), pattern)
                     34: +               && (l1 == l2 || name[l1 - (l2+1)] == '/'))
                     35:                        return ret_match;
                     36: -              }
                     37:        }
                     38:  
                     39:        return !ret_match;
                     40: diff --git a/flist.c b/flist.c
                     41: --- a/flist.c
                     42: +++ b/flist.c
                     43: @@ -35,6 +35,7 @@ extern int inc_recurse;
                     44:  extern int always_checksum;
                     45:  extern int checksum_type;
                     46:  extern int module_id;
                     47: +extern int ignore_case;
                     48:  extern int ignore_errors;
                     49:  extern int numeric_ids;
                     50:  extern int quiet;
                     51: @@ -2591,7 +2592,8 @@ struct file_list *recv_file_list(int f, int dir_ndx)
                     52:                                cur_dir++;
                     53:                        if (cur_dir != good_dirname) {
                     54:                                const char *d = dir_ndx >= 0 ? f_name(dir_flist->files[dir_ndx], NULL) : empty_dir;
                     55: -                              if (strcmp(cur_dir, d) != 0) {
                     56: +                              int dir_differs = ignore_case ? strcasecmp(cur_dir, d) : strcmp(cur_dir, d);
                     57: +                              if (dir_differs) {
                     58:                                        rprintf(FERROR,
                     59:                                                "ABORTING due to invalid path from sender: %s/%s\n",
                     60:                                                cur_dir, file->basename);
                     61: @@ -3158,6 +3160,7 @@ int f_name_cmp(const struct file_struct *f1, const struct file_struct *f2)
                     62:  {
                     63:        int dif;
                     64:        const uchar *c1, *c2;
                     65: +      uchar ch1, ch2;
                     66:        enum fnc_state state1, state2;
                     67:        enum fnc_type type1, type2;
                     68:        enum fnc_type t_path = protocol_version >= 29 ? t_PATH : t_ITEM;
                     69: @@ -3268,7 +3271,15 @@ int f_name_cmp(const struct file_struct *f1, const struct file_struct *f2)
                     70:                        if (type1 != type2)
                     71:                                return type1 == t_PATH ? 1 : -1;
                     72:                }
                     73: -      } while ((dif = (int)*c1++ - (int)*c2++) == 0);
                     74: +              ch1 = *c1++;
                     75: +              ch2 = *c2++;
                     76: +              if (ignore_case) {
                     77: +                      if (isupper(ch1))
                     78: +                              ch1 = tolower(ch1);
                     79: +                      if (isupper(ch2))
                     80: +                              ch2 = tolower(ch2);
                     81: +              }
                     82: +      } while ((dif = (int)ch1 - (int)ch2) == 0);
                     83:  
                     84:        return dif;
                     85:  }
                     86: diff --git a/ifuncs.h b/ifuncs.h
                     87: --- a/ifuncs.h
                     88: +++ b/ifuncs.h
                     89: @@ -109,3 +109,38 @@ static inline char *my_strdup(const char *str, const char *file, int line)
                     90:      memcpy(buf, str, len);
                     91:      return buf;
                     92:  }
                     93: +
                     94: +static inline int
                     95: +strEQ(const char *s1, const char *s2)
                     96: +{
                     97: +      return strcmp(s1, s2) == 0;
                     98: +}
                     99: +
                    100: +static inline int
                    101: +strnEQ(const char *s1, const char *s2, size_t n)
                    102: +{
                    103: +      return strncmp(s1, s2, n) == 0;
                    104: +}
                    105: +
                    106: +static inline int
                    107: +ic_strEQ(const char *s1, const char *s2)
                    108: +{
                    109: +      extern int ignore_case;
                    110: +      if (ignore_case)
                    111: +              return strcasecmp(s1, s2) == 0;
                    112: +      return strcmp(s1, s2) == 0;
                    113: +}
                    114: +
                    115: +static inline int
                    116: +ic_strnEQ(const char *s1, const char *s2, size_t n)
                    117: +{
                    118: +      extern int ignore_case;
                    119: +      if (ignore_case)
                    120: +              return strncasecmp(s1, s2, n) == 0;
                    121: +      return strncmp(s1, s2, n) == 0;
                    122: +}
                    123: +
                    124: +#define strNE(s1,s2) (!strEQ(s1,s2))
                    125: +#define strnNE(s1,s2,n) (!strnEQ(s1,s2,n))
                    126: +#define ic_strNE(s1,s2) (!ic_strEQ(s1,s2))
                    127: +#define ic_strnNE(s1,s2) (!ic_strnEQ(s1,s2,n))
                    128: diff --git a/lib/wildmatch.c b/lib/wildmatch.c
                    129: --- a/lib/wildmatch.c
                    130: +++ b/lib/wildmatch.c
                    131: @@ -53,6 +53,8 @@
                    132:  #define ISUPPER(c) (ISASCII(c) && isupper(c))
                    133:  #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
                    134:  
                    135: +extern int ignore_case;
                    136: +
                    137:  #ifdef WILD_TEST_ITERATIONS
                    138:  int wildmatch_iteration_count;
                    139:  #endif
                    140: @@ -72,6 +74,8 @@ static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
                    141:      for ( ; (p_ch = *p) != '\0'; text++, p++) {
                    142:        int matched, special;
                    143:        uchar t_ch, prev_ch;
                    144: +      if (ignore_case && ISUPPER(p_ch))
                    145: +          p_ch = tolower(p_ch);
                    146:        while ((t_ch = *text) == '\0') {
                    147:            if (*a == NULL) {
                    148:                if (p_ch != '*')
                    149: @@ -237,12 +241,21 @@ static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
                    150:   * of "text" and any strings in array "a". */
                    151:  static int doliteral(const uchar *s, const uchar *text, const uchar*const *a)
                    152:  {
                    153: +    uchar s_ch, t_ch;
                    154:      for ( ; *s != '\0'; text++, s++) {
                    155:        while (*text == '\0') {
                    156:            if ((text = *a++) == NULL)
                    157:                return FALSE;
                    158:        }
                    159: -      if (*text != *s)
                    160: +      s_ch = *s;
                    161: +      t_ch = *text;
                    162: +      if (ignore_case) {
                    163: +          if (ISUPPER(s_ch))
                    164: +              s_ch = tolower(s_ch);
                    165: +          if (ISUPPER(t_ch))
                    166: +              t_ch = tolower(t_ch);
                    167: +      }
                    168: +      if (t_ch != s_ch)
                    169:            return FALSE;
                    170:      }
                    171:  
                    172: @@ -288,10 +301,14 @@ static const uchar *trailing_N_elements(const uchar*const **a_ptr, int count)
                    173:  int wildmatch(const char *pattern, const char *text)
                    174:  {
                    175:      static const uchar *nomore[1]; /* A NULL pointer. */
                    176: +    int ret;
                    177:  #ifdef WILD_TEST_ITERATIONS
                    178:      wildmatch_iteration_count = 0;
                    179:  #endif
                    180: -    return dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
                    181: +    force_lower_case = ignore_case;
                    182: +    ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
                    183: +    force_lower_case = 0;
                    184: +    return ret;
                    185:  }
                    186:  
                    187:  /* Match the "pattern" against the forced-to-lower-case "text" string. */
                    188: @@ -331,12 +348,14 @@ int wildmatch_array(const char *pattern, const char*const *texts, int where)
                    189:      if (!text)
                    190:        return FALSE;
                    191:  
                    192: +    force_lower_case = ignore_case;
                    193: +
                    194:      if ((matched = dowild(p, text, a)) != TRUE && where < 0
                    195:       && matched != ABORT_ALL) {
                    196:        while (1) {
                    197:            if (*text == '\0') {
                    198:                if ((text = (uchar*)*a++) == NULL)
                    199: -                  return FALSE;
                    200: +                  break;
                    201:                continue;
                    202:            }
                    203:            if (*text++ == '/' && (matched = dowild(p, text, a)) != FALSE
                    204: @@ -344,6 +363,9 @@ int wildmatch_array(const char *pattern, const char*const *texts, int where)
                    205:                break;
                    206:        }
                    207:      }
                    208: +
                    209: +    force_lower_case = 0;
                    210: +
                    211:      return matched == TRUE;
                    212:  }
                    213:  
                    214: diff --git a/options.c b/options.c
                    215: --- a/options.c
                    216: +++ b/options.c
                    217: @@ -122,6 +122,7 @@ OFF_T max_size = -1;
                    218:  OFF_T min_size = -1;
                    219:  int ignore_errors = 0;
                    220:  int modify_window = 0;
                    221: +int ignore_case = 0;
                    222:  int blocking_io = -1;
                    223:  int checksum_seed = 0;
                    224:  int inplace = 0;
                    225: @@ -774,6 +775,8 @@ static struct poptOption long_options[] = {
                    226:    {"read-batch",       0,  POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
                    227:    {"write-batch",      0,  POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
                    228:    {"only-write-batch", 0,  POPT_ARG_STRING, &batch_name, OPT_ONLY_WRITE_BATCH, 0, 0 },
                    229: +  {"ignore-case",      0,  POPT_ARG_VAL,    &ignore_case, 1, 0, 0 },
                    230: +  {"no-ignore-case",   0,  POPT_ARG_VAL,    &ignore_case, 0, 0, 0 },
                    231:    {"files-from",       0,  POPT_ARG_STRING, &files_from, 0, 0, 0 },
                    232:    {"from0",           '0', POPT_ARG_VAL,    &eol_nulls, 1, 0, 0},
                    233:    {"no-from0",         0,  POPT_ARG_VAL,    &eol_nulls, 0, 0, 0},
                    234: @@ -2795,6 +2798,9 @@ void server_options(char **args, int *argc_p)
                    235:                args[ac++] = arg;
                    236:        }
                    237:  
                    238: +      if (ignore_case)
                    239: +              args[ac++] = "--ignore-case";
                    240: +
                    241:        if (partial_dir && am_sender) {
                    242:                if (partial_dir != tmp_partialdir) {
                    243:                        args[ac++] = "--partial-dir";
                    244: diff --git a/rsync.1.md b/rsync.1.md
                    245: --- a/rsync.1.md
                    246: +++ b/rsync.1.md
                    247: @@ -440,6 +440,7 @@ detailed description below for a complete description.
                    248:  --from0, -0              all *-from/filter files are delimited by 0s
                    249:  --protect-args, -s       no space-splitting; wildcard chars only
                    250:  --copy-as=USER[:GROUP]   specify user & optional group for the copy
                    251: +--ignore-case            ignore case when comparing filenames
                    252:  --address=ADDRESS        bind address for outgoing socket to daemon
                    253:  --port=PORT              specify double-colon alternate port number
                    254:  --sockopts=OPTIONS       specify custom TCP options
                    255: @@ -2195,6 +2196,12 @@ your home directory (remove the '=' for that).
                    256:  
                    257:      >     sudo rsync -aive lsh -M--copy-as=joe src/ lh:dest/
                    258:  
                    259: +0.  `--ignore-case`
                    260: +
                    261: +    This option tells rsync to ignore upper-/lower-case differences when
                    262: +    comparing filenames.  This can avoid problems when sending files to a
                    263: +    filesystem that ignores these differences.
                    264: +
                    265:  0.  `--temp-dir=DIR`, `-T`
                    266:  
                    267:      This option instructs rsync to use DIR as a scratch directory when creating
                    268: diff --git a/t_stub.c b/t_stub.c
                    269: --- a/t_stub.c
                    270: +++ b/t_stub.c
                    271: @@ -33,6 +33,7 @@ int preserve_xattrs = 0;
                    272:  int preserve_perms = 0;
                    273:  int preserve_executability = 0;
                    274:  int open_noatime = 0;
                    275: +int ignore_case = 0;
                    276:  size_t max_alloc = 0; /* max_alloc is needed when combined with util2.o */
                    277:  char *partial_dir;
                    278:  char *module_dir;
                    279: diff --git a/wildtest.c b/wildtest.c
                    280: --- a/wildtest.c
                    281: +++ b/wildtest.c
                    282: @@ -30,6 +30,7 @@
                    283:  int fnmatch_errors = 0;
                    284:  #endif
                    285:  
                    286: +int ignore_case = 0;
                    287:  int wildmatch_errors = 0;
                    288:  
                    289:  typedef char bool;
                    290: diff -Nurp a/rsync.1 b/rsync.1
                    291: --- a/rsync.1
                    292: +++ b/rsync.1
                    293: @@ -516,6 +516,7 @@ detailed description below for a complet
                    294:  --from0, -0              all *-from/filter files are delimited by 0s
                    295:  --protect-args, -s       no space-splitting; wildcard chars only
                    296:  --copy-as=USER[:GROUP]   specify user & optional group for the copy
                    297: +--ignore-case            ignore case when comparing filenames
                    298:  --address=ADDRESS        bind address for outgoing socket to daemon
                    299:  --port=PORT              specify double-colon alternate port number
                    300:  --sockopts=OPTIONS       specify custom TCP options
                    301: @@ -2242,6 +2243,10 @@ The following command does a local copy
                    302:  sudo rsync -aive lsh -M--copy-as=joe src/ lh:dest/
                    303:  .fi
                    304:  .RE
                    305: +.IP "\fB\-\-ignore-case\fP"
                    306: +This option tells rsync to ignore upper-/lower-case differences when
                    307: +comparing filenames.  This can avoid problems when sending files to a
                    308: +filesystem that ignores these differences.
                    309:  .IP "\fB\-\-temp-dir=DIR\fP, \fB\-T\fP"
                    310:  This option instructs rsync to use DIR as a scratch directory when creating
                    311:  temporary copies of the files transferred on the receiving side.  The
                    312: diff -Nurp a/rsync.1.html b/rsync.1.html
                    313: --- a/rsync.1.html
                    314: +++ b/rsync.1.html
                    315: @@ -431,6 +431,7 @@ detailed description below for a complet
                    316:  --from0, -0              all *-from/filter files are delimited by 0s
                    317:  --protect-args, -s       no space-splitting; wildcard chars only
                    318:  --copy-as=USER[:GROUP]   specify user &amp; optional group for the copy
                    319: +--ignore-case            ignore case when comparing filenames
                    320:  --address=ADDRESS        bind address for outgoing socket to daemon
                    321:  --port=PORT              specify double-colon alternate port number
                    322:  --sockopts=OPTIONS       specify custom TCP options
                    323: @@ -2087,6 +2088,12 @@ has no permissions to change.</p>
                    324:  </blockquote>
                    325:  </dd>
                    326:  
                    327: +<dt><code>--ignore-case</code></dt><dd>
                    328: +<p>This option tells rsync to ignore upper-/lower-case differences when
                    329: +comparing filenames.  This can avoid problems when sending files to a
                    330: +filesystem that ignores these differences.</p>
                    331: +</dd>
                    332: +
                    333:  <dt><code>--temp-dir=DIR</code>, <code>-T</code></dt><dd>
                    334:  <p>This option instructs rsync to use DIR as a scratch directory when creating
                    335:  temporary copies of the files transferred on the receiving side.  The

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>