Use "use warnings" rather than -w on the #! line.
[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
cc3e685d
WD
16diff --git a/flist.c b/flist.c
17--- a/flist.c
18+++ b/flist.c
ae306a29 19@@ -84,6 +84,9 @@ extern int filesfrom_convert;
b2b87acf
WD
20 extern iconv_t ic_send, ic_recv;
21 #endif
22
23+extern char *tr_opt, *tr_left, *tr_right;
24+extern int tr_right_len;
25+
26 #define PTR_SIZE (sizeof (struct file_struct *))
27
28 int io_error;
ae306a29 29@@ -619,6 +622,24 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
b2b87acf
WD
30 stats.total_size += F_LENGTH(file);
31 }
32
33+static void transliterate(char *thisname)
34+{
35+ char *p1, *p2, *pleft;
36+
37+ for (p1 = p2 = thisname; *p1; p1++) {
38+ /* Look up the current character in the left string. */
39+ pleft = strchr(tr_left, *p1);
40+ if (!pleft)
41+ /* Not found: no change. */
42+ *p2++ = *p1;
43+ else if (pleft - tr_left < tr_right_len)
44+ /* Store replacement from the right string. */
45+ *p2++ = tr_right[pleft - tr_left];
46+ /* Otherwise delete. */
47+ }
48+ *p2 = '\0';
49+}
50+
51 static struct file_struct *recv_file_entry(struct file_list *flist,
52 int xflags, int f)
53 {
ae306a29 54@@ -687,6 +708,9 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
b2b87acf
WD
55 }
56 #endif
57
58+ if (tr_opt)
59+ transliterate(thisname);
60+
65ecbe35
WD
61 if (*thisname)
62 clean_fname(thisname, 0);
b2b87acf 63
cc3e685d
WD
64diff --git a/options.c b/options.c
65--- a/options.c
66+++ b/options.c
c0c7984e 67@@ -184,6 +184,8 @@ int logfile_format_has_i = 0;
b2b87acf
WD
68 int logfile_format_has_o_or_i = 0;
69 int always_checksum = 0;
70 int list_only = 0;
71+char *tr_opt = NULL, *tr_left = NULL, *tr_right = NULL;
72+int tr_right_len = 0;
73
74 #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */
75 char *batch_name = NULL;
abd3adb8 76@@ -432,6 +434,7 @@ void usage(enum logcode F)
b2b87acf
WD
77 #ifdef ICONV_OPTION
78 rprintf(F," --iconv=CONVERT_SPEC request charset conversion of filenames\n");
79 #endif
80+ rprintf(F," --tr=BAD/GOOD transliterate filenames\n");
81 rprintf(F," -4, --ipv4 prefer IPv4\n");
82 rprintf(F," -6, --ipv6 prefer IPv6\n");
83 rprintf(F," --version print version number\n");
abd3adb8 84@@ -634,6 +637,7 @@ static struct poptOption long_options[] = {
b2b87acf 85 {"iconv", 0, POPT_ARG_STRING, &iconv_opt, 0, 0, 0 },
85096e5e 86 {"no-iconv", 0, POPT_ARG_NONE, 0, OPT_NO_ICONV, 0, 0 },
b2b87acf
WD
87 #endif
88+ {"tr", 0, POPT_ARG_STRING, &tr_opt, 0, 0, 0 },
89 {"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
90 {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
c0c7984e 91 {"8-bit-output", '8', POPT_ARG_VAL, &allow_8bit_chars, 1, 0, 0 },
abd3adb8 92@@ -1681,6 +1685,31 @@ int parse_arguments(int *argc_p, const char ***argv_p)
b2b87acf
WD
93 }
94 }
95
96+ /* Easiest way to get a local server right is to do this on both sides */
97+ if (tr_opt) {
98+ if (*tr_opt) {
99+ char *p;
100+
101+ need_unsorted_flist = 1;
102+ /* Our mutation shouldn't interfere with transmission of the
103+ * original option to the server. */
104+ tr_left = strdup(tr_opt);
105+ p = strchr(tr_left, '/');
106+ if (p != NULL) {
107+ *p = '\0';
108+ p++;
109+ tr_right = p;
110+ tr_right_len = strlen(tr_right);
111+ if (strchr(tr_right, '/') != NULL) {
112+ snprintf(err_buf, sizeof err_buf,
113+ "--tr cannot transliterate slashes\n");
114+ return 0;
115+ }
116+ }
117+ } else
118+ tr_opt = NULL;
119+ }
120+
121 am_starting_up = 0;
122
123 return 1;
abd3adb8 124@@ -2063,6 +2092,12 @@ void server_options(char **args, int *argc_p)
b2b87acf
WD
125 else if (remove_source_files)
126 args[ac++] = "--remove-sent-files";
127
128+ if (tr_opt) {
129+ if (asprintf(&arg, "--tr=%s", tr_opt) < 0)
130+ goto oom;
131+ args[ac++] = arg;
132+ }
133+
ae306a29
WD
134 if (ac > MAX_SERVER_ARGS) { /* Not possible... */
135 rprintf(FERROR, "argc overflow in server_options().\n");
136 exit_cleanup(RERR_MALLOC);
cc3e685d
WD
137diff --git a/rsync.yo b/rsync.yo
138--- a/rsync.yo
139+++ b/rsync.yo
abd3adb8 140@@ -427,6 +427,7 @@ to the detailed description below for a complete description. verb(
b2b87acf
WD
141 --read-batch=FILE read a batched update from FILE
142 --protocol=NUM force an older protocol version to be used
143 --iconv=CONVERT_SPEC request charset conversion of filenames
144+ --tr=BAD/GOOD transliterate filenames
145 --checksum-seed=NUM set block/file checksum seed (advanced)
146 -4, --ipv4 prefer IPv4
147 -6, --ipv6 prefer IPv6
abd3adb8 148@@ -2093,6 +2094,22 @@ daemon uses the charset specified in its "charset" configuration parameter
85096e5e
WD
149 regardless of the remote charset you actually pass. Thus, you may feel free to
150 specify just the local charset for a daemon transfer (e.g. bf(--iconv=utf8)).
b2b87acf
WD
151
152+dit(bf(--tr=BAD/GOOD)) Transliterates filenames on the receiver, after the
153+iconv conversion (if any). This can be used to remove characters illegal
154+on the destination filesystem. If you use this option, consider saving a
155+"find . -ls" listing of the source in the destination to help you determine
156+the original filenames in case of need.
157+
158+The argument consists of a string of characters to remove, optionally
159+followed by a slash and a string of corresponding characters with which to
160+replace them. The second string may be shorter, in which case any leftover
161+characters in the first string are simply deleted. For example,
162+bf(--tr=':\/!') replaces colons with exclamation marks and deletes backslashes.
163+Slashes cannot be transliterated because it would cause havoc.
164+
165+If the receiver is invoked over a remote shell, use bf(--protect-args) to
166+stop the shell from interpreting any nasty characters in the argument.
167+
168 dit(bf(-4, --ipv4) or bf(-6, --ipv6)) Tells rsync to prefer IPv4/IPv6
169 when creating sockets. This only affects sockets that rsync has direct
170 control over, such as the outgoing socket when directly contacting an