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