Fixed failing hunks.
[rsync/rsync-patches.git] / transliterate.diff
CommitLineData
b2b87acf
WD
1This patch adds an option --tr=BAD/GOOD to transliterate filenames. It
2can be used to remove characters illegal on the destination filesystem.
3Jeff Weber expressed interest in this:
4
5http://lists.samba.org/archive/rsync/2007-October/018996.html
6
7This patch is a COMPLETE HACK that covers the most common cases. Others
8are welcome to improve it.
9
10To use this patch, run these commands for a successful build:
11
12 patch -p1 <patches/transliterate.diff
13 ./configure (optional if already run)
14 make
15
16--- old/flist.c
17+++ new/flist.c
18@@ -80,6 +80,9 @@ extern int filesfrom_convert;
19 extern iconv_t ic_send, ic_recv;
20 #endif
21
22+extern char *tr_opt, *tr_left, *tr_right;
23+extern int tr_right_len;
24+
25 #define PTR_SIZE (sizeof (struct file_struct *))
26
27 int io_error;
28@@ -600,6 +603,24 @@ static void send_file_entry(int f, struc
29 stats.total_size += F_LENGTH(file);
30 }
31
32+static void transliterate(char *thisname)
33+{
34+ char *p1, *p2, *pleft;
35+
36+ for (p1 = p2 = thisname; *p1; p1++) {
37+ /* Look up the current character in the left string. */
38+ pleft = strchr(tr_left, *p1);
39+ if (!pleft)
40+ /* Not found: no change. */
41+ *p2++ = *p1;
42+ else if (pleft - tr_left < tr_right_len)
43+ /* Store replacement from the right string. */
44+ *p2++ = tr_right[pleft - tr_left];
45+ /* Otherwise delete. */
46+ }
47+ *p2 = '\0';
48+}
49+
50 static struct file_struct *recv_file_entry(struct file_list *flist,
51 int xflags, int f)
52 {
53@@ -668,6 +689,9 @@ static struct file_struct *recv_file_ent
54 }
55 #endif
56
57+ if (tr_opt)
58+ transliterate(thisname);
59+
60 clean_fname(thisname, 0);
61
62 if (sanitize_paths)
63--- old/options.c
64+++ new/options.c
65@@ -181,6 +181,8 @@ int logfile_format_has_i = 0;
66 int logfile_format_has_o_or_i = 0;
67 int always_checksum = 0;
68 int list_only = 0;
69+char *tr_opt = NULL, *tr_left = NULL, *tr_right = NULL;
70+int tr_right_len = 0;
71
72 #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */
73 char *batch_name = NULL;
74@@ -423,6 +425,7 @@ void usage(enum logcode F)
75 #ifdef ICONV_OPTION
76 rprintf(F," --iconv=CONVERT_SPEC request charset conversion of filenames\n");
77 #endif
78+ rprintf(F," --tr=BAD/GOOD transliterate filenames\n");
79 rprintf(F," -4, --ipv4 prefer IPv4\n");
80 rprintf(F," -6, --ipv6 prefer IPv6\n");
81 rprintf(F," --version print version number\n");
82@@ -609,6 +612,7 @@ static struct poptOption long_options[]
83 #ifdef ICONV_OPTION
84 {"iconv", 0, POPT_ARG_STRING, &iconv_opt, 0, 0, 0 },
85 #endif
86+ {"tr", 0, POPT_ARG_STRING, &tr_opt, 0, 0, 0 },
87 {"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
88 {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
89 {"8-bit-output", '8', POPT_ARG_NONE, &allow_8bit_chars, 0, 0, 0 },
90@@ -1620,6 +1624,31 @@ int parse_arguments(int *argc_p, const c
91 }
92 }
93
94+ /* Easiest way to get a local server right is to do this on both sides */
95+ if (tr_opt) {
96+ if (*tr_opt) {
97+ char *p;
98+
99+ need_unsorted_flist = 1;
100+ /* Our mutation shouldn't interfere with transmission of the
101+ * original option to the server. */
102+ tr_left = strdup(tr_opt);
103+ p = strchr(tr_left, '/');
104+ if (p != NULL) {
105+ *p = '\0';
106+ p++;
107+ tr_right = p;
108+ tr_right_len = strlen(tr_right);
109+ if (strchr(tr_right, '/') != NULL) {
110+ snprintf(err_buf, sizeof err_buf,
111+ "--tr cannot transliterate slashes\n");
112+ return 0;
113+ }
114+ }
115+ } else
116+ tr_opt = NULL;
117+ }
118+
119 am_starting_up = 0;
120
121 return 1;
122@@ -1988,6 +2017,12 @@ void server_options(char **args, int *ar
123 else if (remove_source_files)
124 args[ac++] = "--remove-sent-files";
125
126+ if (tr_opt) {
127+ if (asprintf(&arg, "--tr=%s", tr_opt) < 0)
128+ goto oom;
129+ args[ac++] = arg;
130+ }
131+
132 *argc_p = ac;
133 return;
134
135--- old/rsync.yo
136+++ new/rsync.yo
137@@ -422,6 +422,7 @@ to the detailed description below for a
138 --read-batch=FILE read a batched update from FILE
139 --protocol=NUM force an older protocol version to be used
140 --iconv=CONVERT_SPEC request charset conversion of filenames
141+ --tr=BAD/GOOD transliterate filenames
142 --checksum-seed=NUM set block/file checksum seed (advanced)
143 -4, --ipv4 prefer IPv4
144 -6, --ipv6 prefer IPv6
145@@ -2013,6 +2014,22 @@ specifying matching rules that can match
146 For instance, you can specify extra include/exclude rules if there are
147 filename differences on the two sides that need to be accounted for.
148
149+dit(bf(--tr=BAD/GOOD)) Transliterates filenames on the receiver, after the
150+iconv conversion (if any). This can be used to remove characters illegal
151+on the destination filesystem. If you use this option, consider saving a
152+"find . -ls" listing of the source in the destination to help you determine
153+the original filenames in case of need.
154+
155+The argument consists of a string of characters to remove, optionally
156+followed by a slash and a string of corresponding characters with which to
157+replace them. The second string may be shorter, in which case any leftover
158+characters in the first string are simply deleted. For example,
159+bf(--tr=':\/!') replaces colons with exclamation marks and deletes backslashes.
160+Slashes cannot be transliterated because it would cause havoc.
161+
162+If the receiver is invoked over a remote shell, use bf(--protect-args) to
163+stop the shell from interpreting any nasty characters in the argument.
164+
165 dit(bf(-4, --ipv4) or bf(-6, --ipv6)) Tells rsync to prefer IPv4/IPv6
166 when creating sockets. This only affects sockets that rsync has direct
167 control over, such as the outgoing socket when directly contacting an