1 This patch adds an option --tr=BAD/GOOD to transliterate filenames. It
2 can be used to remove characters illegal on the destination filesystem.
3 Jeff Weber expressed interest in this:
5 http://lists.samba.org/archive/rsync/2007-October/018996.html
7 This patch is a COMPLETE HACK that covers the most common cases. Others
8 are welcome to improve it.
10 To use this patch, run these commands for a successful build:
12 patch -p1 <patches/transliterate.diff
13 ./configure (optional if already run)
16 diff --git a/flist.c b/flist.c
17 index 09b4fc5..f69167e 100644
20 @@ -87,6 +87,9 @@ extern int filesfrom_convert;
21 extern iconv_t ic_send, ic_recv;
24 +extern char *tr_opt, *tr_left, *tr_right;
25 +extern int tr_right_len;
27 #define PTR_SIZE (sizeof (struct file_struct *))
30 @@ -651,6 +654,24 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
31 stats.total_size += F_LENGTH(file);
34 +static void transliterate(char *thisname)
36 + char *p1, *p2, *pleft;
38 + for (p1 = p2 = thisname; *p1; p1++) {
39 + /* Look up the current character in the left string. */
40 + pleft = strchr(tr_left, *p1);
42 + /* Not found: no change. */
44 + else if (pleft - tr_left < tr_right_len)
45 + /* Store replacement from the right string. */
46 + *p2++ = tr_right[pleft - tr_left];
47 + /* Otherwise delete. */
52 static struct file_struct *recv_file_entry(struct file_list *flist,
55 @@ -719,6 +740,9 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
60 + transliterate(thisname);
63 clean_fname(thisname, 0);
65 diff --git a/options.c b/options.c
66 index e7c6c61..cd0891c 100644
69 @@ -190,6 +190,8 @@ int logfile_format_has_i = 0;
70 int logfile_format_has_o_or_i = 0;
71 int always_checksum = 0;
73 +char *tr_opt = NULL, *tr_left = NULL, *tr_right = NULL;
74 +int tr_right_len = 0;
76 #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */
77 char *batch_name = NULL;
78 @@ -782,6 +784,7 @@ void usage(enum logcode F)
80 rprintf(F," --iconv=CONVERT_SPEC request charset conversion of filenames\n");
82 + rprintf(F," --tr=BAD/GOOD transliterate filenames\n");
83 rprintf(F," -4, --ipv4 prefer IPv4\n");
84 rprintf(F," -6, --ipv6 prefer IPv6\n");
85 rprintf(F," --version print version number\n");
86 @@ -995,6 +998,7 @@ static struct poptOption long_options[] = {
87 {"iconv", 0, POPT_ARG_STRING, &iconv_opt, 0, 0, 0 },
88 {"no-iconv", 0, POPT_ARG_NONE, 0, OPT_NO_ICONV, 0, 0 },
90 + {"tr", 0, POPT_ARG_STRING, &tr_opt, 0, 0, 0 },
91 {"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
92 {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
93 {"8-bit-output", '8', POPT_ARG_VAL, &allow_8bit_chars, 1, 0, 0 },
94 @@ -2195,6 +2199,31 @@ int parse_arguments(int *argc_p, const char ***argv_p)
98 + /* Easiest way to get a local server right is to do this on both sides */
103 + need_unsorted_flist = 1;
104 + /* Our mutation shouldn't interfere with transmission of the
105 + * original option to the server. */
106 + tr_left = strdup(tr_opt);
107 + p = strchr(tr_left, '/');
112 + tr_right_len = strlen(tr_right);
113 + if (strchr(tr_right, '/') != NULL) {
114 + snprintf(err_buf, sizeof err_buf,
115 + "--tr cannot transliterate slashes\n");
126 @@ -2609,6 +2638,12 @@ void server_options(char **args, int *argc_p)
127 else if (remove_source_files)
128 args[ac++] = "--remove-sent-files";
131 + if (asprintf(&arg, "--tr=%s", tr_opt) < 0)
136 if (ac > MAX_SERVER_ARGS) { /* Not possible... */
137 rprintf(FERROR, "argc overflow in server_options().\n");
138 exit_cleanup(RERR_MALLOC);
139 diff --git a/rsync.yo b/rsync.yo
140 index 941f7a5..dda8608 100644
143 @@ -436,6 +436,7 @@ to the detailed description below for a complete description. verb(
144 --read-batch=FILE read a batched update from FILE
145 --protocol=NUM force an older protocol version to be used
146 --iconv=CONVERT_SPEC request charset conversion of filenames
147 + --tr=BAD/GOOD transliterate filenames
148 --checksum-seed=NUM set block/file checksum seed (advanced)
149 -4, --ipv4 prefer IPv4
150 -6, --ipv6 prefer IPv6
151 @@ -2294,6 +2295,22 @@ daemon uses the charset specified in its "charset" configuration parameter
152 regardless of the remote charset you actually pass. Thus, you may feel free to
153 specify just the local charset for a daemon transfer (e.g. bf(--iconv=utf8)).
155 +dit(bf(--tr=BAD/GOOD)) Transliterates filenames on the receiver, after the
156 +iconv conversion (if any). This can be used to remove characters illegal
157 +on the destination filesystem. If you use this option, consider saving a
158 +"find . -ls" listing of the source in the destination to help you determine
159 +the original filenames in case of need.
161 +The argument consists of a string of characters to remove, optionally
162 +followed by a slash and a string of corresponding characters with which to
163 +replace them. The second string may be shorter, in which case any leftover
164 +characters in the first string are simply deleted. For example,
165 +bf(--tr=':\/!') replaces colons with exclamation marks and deletes backslashes.
166 +Slashes cannot be transliterated because it would cause havoc.
168 +If the receiver is invoked over a remote shell, use bf(--protect-args) to
169 +stop the shell from interpreting any nasty characters in the argument.
171 dit(bf(-4, --ipv4) or bf(-6, --ipv6)) Tells rsync to prefer IPv4/IPv6
172 when creating sockets. This only affects sockets that rsync has direct
173 control over, such as the outgoing socket when directly contacting an