spiralofhope

case-insensitive rsync

2007-07-29
HOWTO, Usability
rsync logo

Software >
rsync >

This adds the --ignore-case option, which makes rsync compare filenames in a case-insensitive manner.

  • samba.anu.edu.au/ftp/unpacked/rsync/patches/ignore-case.diff

    • This was originally a maintained patch, located at but has since disappeared and was not archived.
  • https://bugzilla.samba.org/show_bug.cgi?id=10448




Using the patch ∞

To use this patch, run these commands for a successful build:

patch -p1 <patches/ignore-case.diff
./configure   #  optional if already run
make

--ignore-case rsync patch ∞

Spoiler
--- old/exclude.c
+++ new/exclude.c
@@ -32,6 +32,7 @@ extern int io_error;
 extern int local_server;
 extern int prune_empty_dirs;
 extern int ignore_perishable;
+extern int ignore_case;
 extern int delete_mode;
 extern int delete_excluded;
 extern int cvs_exclude;
@@ -580,16 +581,17 @@ static int rule_matches(char *name, stru
                if (litmatch_array(pattern, strings, slash_handling))
                        return ret_match;
        } else if (anchored_match) {
-               if (strcmp(name, pattern) == 0)
+               if <span class="footnote_referrer" ><a><sup id="footnote_plugin_tooltip_32660_1" class="footnote_plugin_tooltip_text" onclick="footnote_moveToAnchor_32660('footnote_plugin_reference_32660_1');" >[ 1 ]</sup ></a><span id="footnote_plugin_tooltip_text_32660_1" class="footnote_tooltip" >ignore_case ? strcasecmp(name, pattern)
+                                : strcmp(name, pattern</span ></span><script type="text/javascript"> jQuery('#footnote_plugin_tooltip_32660_1').tooltip({ tip: '#footnote_plugin_tooltip_text_32660_1', tipClass: 'footnote_tooltip', effect: 'fade', predelay: 0, fadeInSpeed: 200, delay: 400, fadeOutSpeed: 200, position: 'top center', relative: true, offset: [1, 0], });</script> == 0)
                        return ret_match;
        } else {
                int l1 = strlen(name);
                int l2 = strlen(pattern);
-               if (l2 <= l1 &&
-                   strcmp(name+(l1-l2),pattern) == 0 &&
-                   (l1==l2 || name[l1-(l2+1)] == '/')) {
+               if (l2 <= l1
+                && (ignore_case ? strcasecmp(name + (l1-l2), pattern)
+                                : strcmp(name + (l1-l2), pattern)) == 0
+                && (l1 == l2 || name[l1 - (l2+1)] == '/'))
                        return ret_match;
-               }
        }
 
        return !ret_match;
--- old/flist.c
+++ new/flist.c
@@ -35,6 +35,7 @@ extern int inc_recurse;
 extern int do_progress;
 extern int always_checksum;
 extern int module_id;
+extern int ignore_case;
 extern int ignore_errors;
 extern int numeric_ids;
 extern int recurse;
@@ -2454,7 +2455,7 @@ enum fnc_type { t_PATH, t_ITEM };
 int f_name_cmp(struct file_struct *f1, struct file_struct *f2)
 {
        int dif;
-       const uchar *c1, *c2;
+       const uchar *c1, *c2, ch1, ch2;
        enum fnc_state state1, state2;
        enum fnc_type type1, type2;
        enum fnc_type t_path = protocol_version >= 29 ? t_PATH : t_ITEM;
@@ -2564,7 +2565,15 @@ int f_name_cmp(struct file_struct *f1, s
                        if (type1 != type2)
                                return type1 == t_PATH ? 1 : -1;
                }
-       } while <span class="footnote_referrer" ><a><sup id="footnote_plugin_tooltip_32660_2" class="footnote_plugin_tooltip_text" onclick="footnote_moveToAnchor_32660('footnote_plugin_reference_32660_2');" >[ 2 ]</sup ></a><span id="footnote_plugin_tooltip_text_32660_2" class="footnote_tooltip" >dif = (int)*c1++ - (int)*c2++) == 0);
+               ch1 = CVAL(c1++, 0);
+               ch2 = CVAL(c2++, 0);
+               if (ignore_case) {
+                       if (islower(ch1</span ></span><script type="text/javascript"> jQuery('#footnote_plugin_tooltip_32660_2').tooltip({ tip: '#footnote_plugin_tooltip_text_32660_2', tipClass: 'footnote_tooltip', effect: 'fade', predelay: 0, fadeInSpeed: 200, delay: 400, fadeOutSpeed: 200, position: 'top center', relative: true, offset: [1, 0], });</script>
+                               ch1 = toupper(ch1);
+                       if (islower(ch2))
+                               ch2 = toupper(ch2);
+               }
+       } while <span class="footnote_referrer" ><a><sup id="footnote_plugin_tooltip_32660_3" class="footnote_plugin_tooltip_text" onclick="footnote_moveToAnchor_32660('footnote_plugin_reference_32660_3');" >[ 3 ]</sup ></a><span id="footnote_plugin_tooltip_text_32660_3" class="footnote_tooltip" >dif = ch1 - ch2) == 0);
 
        return dif;
 }
--- old/lib/wildmatch.c
+++ new/lib/wildmatch.c
@@ -53,6 +53,8 @@
 #define ISUPPER(c) (ISASCII(c) && isupper(c</span ></span><script type="text/javascript"> jQuery('#footnote_plugin_tooltip_32660_3').tooltip({ tip: '#footnote_plugin_tooltip_text_32660_3', tipClass: 'footnote_tooltip', effect: 'fade', predelay: 0, fadeInSpeed: 200, delay: 400, fadeOutSpeed: 200, position: 'top center', relative: true, offset: [1, 0], });</script>
 #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
 
+extern int ignore_case;
+
 #ifdef WILD_TEST_ITERATIONS
 int wildmatch_iteration_count;
 #endif
@@ -72,6 +74,8 @@ static int dowild(const uchar *p, const 
     for ( ; (p_ch = *p) != '\0'; text++, p++) {
        int matched, special;
        uchar t_ch, prev_ch;
+       if (ignore_case && ISUPPER(p_ch))
+           p_ch = tolower(p_ch);
        while <span class="footnote_referrer" ><a><sup id="footnote_plugin_tooltip_32660_4" class="footnote_plugin_tooltip_text" onclick="footnote_moveToAnchor_32660('footnote_plugin_reference_32660_4');" >[ 4 ]</sup ></a><span id="footnote_plugin_tooltip_text_32660_4" class="footnote_tooltip" >t_ch = *text) == '\0') {
            if (*a == NULL) {
                if (p_ch != '*')
@@ -237,12 +241,21 @@ static int dowild(const uchar *p, const 
  * of "text" and any strings in array "a". */
 static int doliteral(const uchar *s, const uchar *text, const uchar*const *a)
 {
+    uchar s_ch, t_ch;
     for ( ; *s != '\0'; text++, s++) {
        while (*text == '\0') {
            if <span class="footnote_referrer" ><a><sup id="footnote_plugin_tooltip_32660_5" class="footnote_plugin_tooltip_text" onclick="footnote_moveToAnchor_32660('footnote_plugin_reference_32660_5');" >[ 5 ]</sup ></a><span id="footnote_plugin_tooltip_text_32660_5" class="footnote_tooltip" >text = *a++) == NULL)
                return FALSE;
        }
-       if (*text != *s)
+       s_ch = *s;
+       t_ch = *text;
+       if (ignore_case) {
+           if (ISUPPER(s_ch</span ></span><script type="text/javascript"> jQuery('#footnote_plugin_tooltip_32660_4').tooltip({ tip: '#footnote_plugin_tooltip_text_32660_4', tipClass: 'footnote_tooltip', effect: 'fade', predelay: 0, fadeInSpeed: 200, delay: 400, fadeOutSpeed: 200, position: 'top center', relative: true, offset: [1, 0], });</script>
+               s_ch = tolower(s_ch);
+           if (ISUPPER(t_ch</span ></span><script type="text/javascript"> jQuery('#footnote_plugin_tooltip_32660_5').tooltip({ tip: '#footnote_plugin_tooltip_text_32660_5', tipClass: 'footnote_tooltip', effect: 'fade', predelay: 0, fadeInSpeed: 200, delay: 400, fadeOutSpeed: 200, position: 'top center', relative: true, offset: [1, 0], });</script>
+               t_ch = tolower(t_ch);
+       }
+       if (t_ch != s_ch)
            return FALSE;
     }
 
@@ -288,10 +301,14 @@ static const uchar *trailing_N_elements(
 int wildmatch(const char *pattern, const char *text)
 {
     static const uchar *nomore[1]; /* A NULL pointer. */
+    int ret;
 #ifdef WILD_TEST_ITERATIONS
     wildmatch_iteration_count = 0;
 #endif
-    return dowild<span class="footnote_referrer" ><a><sup id="footnote_plugin_tooltip_32660_6" class="footnote_plugin_tooltip_text" onclick="footnote_moveToAnchor_32660('footnote_plugin_reference_32660_6');" >[ 6 ]</sup ></a><span id="footnote_plugin_tooltip_text_32660_6" class="footnote_tooltip" >const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
+    force_lower_case = ignore_case;
+    ret = dowild<span class="footnote_referrer" ><a><sup id="footnote_plugin_tooltip_32660_7" class="footnote_plugin_tooltip_text" onclick="footnote_moveToAnchor_32660('footnote_plugin_reference_32660_7');" >[ 7 ]</sup ></a><span id="footnote_plugin_tooltip_text_32660_7" class="footnote_tooltip" >const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
+    force_lower_case = 0;
+    return ret;
 }
 
 /* Match the "pattern" against the forced-to-lower-case "text" string. */
@@ -331,12 +348,14 @@ int wildmatch_array(const char *pattern,
     if (!text)
        return FALSE;
 
+    force_lower_case = ignore_case;
+
     if ((matched = dowild(p, text, a</span ></span><script type="text/javascript"> jQuery('#footnote_plugin_tooltip_32660_6').tooltip({ tip: '#footnote_plugin_tooltip_text_32660_6', tipClass: 'footnote_tooltip', effect: 'fade', predelay: 0, fadeInSpeed: 200, delay: 400, fadeOutSpeed: 200, position: 'top center', relative: true, offset: [1, 0], });</script> != TRUE && where < 0
      && matched != ABORT_ALL) {
        while (1) {
            if (*text == '\0') {
                if ((text = (uchar*)*a++) == NULL)
-                   return FALSE;
+                   break;
                continue;
            }
            if (*text++ == '/' && (matched = dowild(p, text, a</span ></span><script type="text/javascript"> jQuery('#footnote_plugin_tooltip_32660_7').tooltip({ tip: '#footnote_plugin_tooltip_text_32660_7', tipClass: 'footnote_tooltip', effect: 'fade', predelay: 0, fadeInSpeed: 200, delay: 400, fadeOutSpeed: 200, position: 'top center', relative: true, offset: [1, 0], });</script> != FALSE
@@ -344,6 +363,9 @@ int wildmatch_array(const char *pattern,
                break;
        }
     }
+
+    force_lower_case = 0;
+
     return matched == TRUE;
 }
 
--- old/options.c
+++ new/options.c
@@ -114,6 +114,7 @@ OFF_T max_size = 0;
 OFF_T min_size = 0;
 int ignore_errors = 0;
 int modify_window = 0;
+int ignore_case = 0;
 int blocking_io = -1;
 int checksum_seed = 0;
 int inplace = 0;
@@ -389,6 +390,7 @@ void usage(enum logcode F)
   rprintf(F,"     --include-from=FILE     read include patterns from FILE\n");
   rprintf(F,"     --files-from=FILE       read list of source-file names from FILE\n");
   rprintf(F," -0, --from0                 all *-from/filter files are delimited by 0s\n");
+  rprintf(F,"     --ignore-case           ignore case when comparing filenames\n");
   rprintf(F,"     --address=ADDRESS       bind address for outgoing socket to daemon\n");
   rprintf(F,"     --port=PORT             specify double-colon alternate port number\n");
   rprintf(F,"     --sockopts=OPTIONS      specify custom TCP options\n");
@@ -577,6 +579,8 @@ static struct poptOption long_options[] 
   {"read-batch",       0,  POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
   {"write-batch",      0,  POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
   {"only-write-batch", 0,  POPT_ARG_STRING, &batch_name, OPT_ONLY_WRITE_BATCH, 0, 0 },
+  {"ignore-case",      0,  POPT_ARG_VAL,    &ignore_case, 1, 0, 0 },
+  {"no-ignore-case",   0,  POPT_ARG_VAL,    &ignore_case, 0, 0, 0 },
   {"files-from",       0,  POPT_ARG_STRING, &files_from, 0, 0, 0 },
   {"from0",           '0', POPT_ARG_VAL,    &eol_nulls, 1, 0, 0},
   {"no-from0",         0,  POPT_ARG_VAL,    &eol_nulls, 0, 0, 0},
@@ -1850,6 +1854,9 @@ void server_options(char **args,int *arg
                args[ac++] = arg;
        }
 
+       if (ignore_case)
+               args[ac++] = "--ignore-case";
+
        if (partial_dir && am_sender) {
                if (partial_dir != tmp_partialdir) {
                        args[ac++] = "--partial-dir";
--- old/wildtest.c
+++ new/wildtest.c
@@ -31,6 +31,7 @@ int fnmatch_errors = 0;
 #endif
 
 int wildmatch_errors = 0;
+int ignore_case = 0;
 
 typedef char bool;

TODO ∞

  • Make this code handle multibyte character encodings, and honor the --iconv setting when converting case.

    • 2017-11-21 — I don’t know where this note came from, but it’s likely not from me.

Footnotes[+]

^ 1 ignore_case ? strcasecmp(name, pattern)
+ : strcmp(name, pattern
^ 2 dif = (int)*c1++ – (int)*c2++) == 0);
+ ch1 = CVAL(c1++, 0);
+ ch2 = CVAL(c2++, 0);
+ if (ignore_case) {
+ if (islower(ch1
^ 3 dif = ch1 – ch2) == 0);

return dif;

}
— old/lib/wildmatch.c
+++ new/lib/wildmatch.c
@@ -53,6 +53,8 @@

#define ISUPPER(c) (ISASCII(c) && isupper(c

^ 4 t_ch = *text) == ‘\0’) {

if (*a == NULL) {
if (p_ch != ‘*’)

@@ -237,12 +241,21 @@ static int dowild(const uchar *p, const

  • of “text” and any strings in array “a”. */

static int doliteral(const uchar *s, const uchar *text, const uchar*const *a)
{
+ uchar s_ch, t_ch;

for ( ; *s != ‘\0’; text++, s++) {
while (*text == ‘\0’) {
if [ 1 ] { footnote_expand_reference_container_32660(); } else { footnote_collapse_reference_container_32660(); } } function footnote_moveToAnchor_32660(p_str_TargetID) { footnote_expand_reference_container_32660(); var l_obj_Target = jQuery('#' + p_str_TargetID); if (l_obj_Target.length) { jQuery('html, body').animate({ scrollTop: l_obj_Target.offset().top - window.innerHeight * 0.20 }, 380);/*duration*/ } }

Footnotes


  1. text = *a++) == NULL)
    return FALSE;
    }

    – if (*text != *s)
    + s_ch = *s;
    + t_ch = *text;
    + if (ignore_case) {
    + if (ISUPPER(s_ch

^ 5 text = *a++) == NULL)

return FALSE;
}

– if (*text != *s)
+ s_ch = *s;
+ t_ch = *text;
+ if (ignore_case) {
+ if (ISUPPER(s_ch
+ s_ch = tolower(s_ch);
+ if (ISUPPER(t_ch

^ 6 const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
+ force_lower_case = ignore_case;
+ ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
+ force_lower_case = 0;
+ return ret;
}

/* Match the “pattern” against the forced-to-lower-case “text” string. */
@@ -331,12 +348,14 @@ int wildmatch_array(const char *pattern,

if (!text)
return FALSE;

+ force_lower_case = ignore_case;
+

if ((matched = dowild(p, text, a

^ 7 const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
+ force_lower_case = 0;
+ return ret;
}

/* Match the “pattern” against the forced-to-lower-case “text” string. */
@@ -331,12 +348,14 @@ int wildmatch_array(const char *pattern,

if (!text)
return FALSE;

+ force_lower_case = ignore_case;
+

if ((matched = dowild(p, text, a != TRUE && where < 0 && matched != ABORT_ALL) { while (1) { if (*text == '\0') { if ((text = (uchar*)*a++) == NULL)

– return FALSE;
+ break;

continue;
}
if (*text++ == ‘/’ && (matched = dowild(p, text, a

    • About – Contact

    • Live
      • projects – entertainment – hardware – software
    • Writing
      • Others’ – My Writing – Misadventures
    • Reviews
      • entertainment – software
    • Glances
      • entertainment – software
    • Loved
      • games – movies – software (Windows – Linux) – television shows
    • Liked
      • games – movies – software (Windows – Linux) – television shows

    configuration: view – edit

  • Search

Proudly powered by WordPress Theme: Parament by Automattic.