Annotation of embedaddon/rsync/patches/ignore-case.diff, revision 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>