3 I greatly simplified the changes to generator.c, making the patch
4 easier to maintain and fixing the failing test in the testsuite.
7 --- generator.c 29 Jun 2004 19:19:00 -0000 1.92
8 +++ generator.c 30 Jun 2004 07:35:56 -0000
9 @@ -41,6 +41,7 @@ extern int ignore_times;
11 extern int io_timeout;
12 extern int protocol_version;
14 extern int always_checksum;
15 extern char *compare_dest;
17 @@ -257,6 +258,94 @@ static void generate_and_send_sums(struc
21 +static void split_names(char *fname, char **dirname, char **basename)
23 + char *slash = strrchr(fname, '/');
27 + *basename = slash+1;
35 +static unsigned int measure_name(const char *name, const char *basename,
38 + int namelen = strlen(name);
39 + int extlen = strlen(ext);
40 + unsigned int score = 0;
42 + /* Extensions must match */
43 + if (namelen <= extlen || strcmp(name + namelen - extlen, ext) != 0)
46 + /* Now score depends on similarity of prefix */
47 + for (; *name == *basename && *name; name++, basename++)
53 +static int find_fuzzy(char **fname_ptr, char *buf, STRUCT_STAT *st_ptr)
57 + char *basename, *dirname;
58 + char mangled_name[MAXPATHLEN];
59 + char bestname[MAXPATHLEN];
60 + unsigned int bestscore = 0;
63 + strlcpy(mangled_name, *fname_ptr, sizeof mangled_name);
65 + split_names(mangled_name, &dirname, &basename);
66 + if (!(d = opendir(dirname))) {
67 + rsyserr(FERROR, errno, "recv_generator opendir(%s)", dirname);
71 + /* Get final extension, eg. .gz; never full basename though. */
72 + ext = strrchr(basename + 1, '.');
74 + ext = basename + strlen(basename); /* ext = "" */
76 + while ((di = readdir(d)) != NULL) {
77 + const char *dname = d_name(di);
80 + if (dname[0] == '.' && (dname[1] == '\0'
81 + || (dname[1] == '.' && dname[2] == '\0')))
84 + score = measure_name(dname, basename, ext);
86 + rprintf(FINFO, "[%s] fuzzy score for %s = %u\n",
87 + who_am_i(), dname, score);
89 + if (score > bestscore) {
90 + strlcpy(bestname, dname, sizeof bestname);
96 + /* Found a candidate. */
97 + if (bestscore != 0) {
98 + pathjoin(buf, MAXPATHLEN, dirname, bestname);
100 + rprintf(FINFO, "[%s] fuzzy match %s->%s\n",
101 + who_am_i(), *fname_ptr, buf);
104 + return link_stat(buf, st_ptr, 0);
111 * Acts on file number @p i from @p flist, whose name is @p fname.
112 @@ -267,12 +356,12 @@ static void generate_and_send_sums(struc
113 * out. It might be wrong.
115 static void recv_generator(char *fname, struct file_struct *file, int i,
117 + int f_out, int f_nameout)
121 struct map_struct *mapbuf;
123 + int statret, fuzzy_file = 0;
125 char fnamecmpbuf[MAXPATHLEN];
127 @@ -431,8 +520,10 @@ static void recv_generator(char *fname,
128 statret = link_stat(fnamecmpbuf, &st, 0);
129 if (!S_ISREG(st.st_mode))
134 + *fnamecmpbuf = '\0';
137 else if (link_dest && !dry_run) {
138 if (do_link(fnamecmpbuf, fname) != 0) {
139 @@ -440,18 +531,30 @@ static void recv_generator(char *fname,
140 rsyserr(FINFO, errno, "link %s => %s",
144 - fnamecmp = fnamecmpbuf;
145 + fnamecmp = fnamecmpbuf;
147 + *fnamecmpbuf = '\0';
151 fnamecmp = fnamecmpbuf;
153 + *fnamecmpbuf = '\0';
155 + if (statret == -1 && fuzzy) {
156 + statret = find_fuzzy(&fnamecmp, fnamecmpbuf, &st);
157 + if (!S_ISREG(st.st_mode))
164 if (preserve_hard_links && hard_link_check(file, HL_SKIP))
166 if (errno == ENOENT) {
167 + if (f_nameout >= 0)
168 + write(f_nameout, "", 1);
171 write_sum_head(f_out, NULL);
172 @@ -471,37 +574,43 @@ static void recv_generator(char *fname,
173 /* now pretend the file didn't exist */
174 if (preserve_hard_links && hard_link_check(file, HL_SKIP))
176 + if (f_nameout >= 0)
177 + write(f_nameout, "", 1);
180 write_sum_head(f_out, NULL);
184 - if (opt_ignore_existing && fnamecmp == fname) {
185 + if (opt_ignore_existing && !*fnamecmpbuf) {
187 rprintf(FINFO,"%s exists\n",fname);
191 - if (update_only && fnamecmp == fname
192 + if (update_only && !*fnamecmpbuf
193 && cmp_modtime(st.st_mtime, file->modtime) > 0) {
195 rprintf(FINFO,"%s is newer\n",fname);
199 - if (skip_file(fname, file, &st)) {
200 - if (fnamecmp == fname)
201 + if (!fuzzy_file && skip_file(fname, file, &st)) {
203 set_perms(fname, file, &st, PERMS_REPORT);
208 + if (f_nameout >= 0)
209 + write(f_nameout, "", 1);
214 if (disable_deltas_p()) {
215 + if (f_nameout >= 0)
216 + write(f_nameout, "", 1);
218 write_sum_head(f_out, NULL);
220 @@ -516,6 +625,8 @@ static void recv_generator(char *fname,
221 /* pretend the file didn't exist */
222 if (preserve_hard_links && hard_link_check(file, HL_SKIP))
224 + if (f_nameout >= 0)
225 + write(f_nameout, "", 1);
227 write_sum_head(f_out, NULL);
229 @@ -534,6 +645,8 @@ static void recv_generator(char *fname,
231 rprintf(FINFO, "generating and sending sums for %d\n", i);
233 + if (f_nameout >= 0)
234 + write(f_nameout, fnamecmpbuf, strlen(fnamecmpbuf) + 1);
236 generate_and_send_sums(mapbuf, st.st_size, f_out);
238 @@ -543,10 +656,11 @@ static void recv_generator(char *fname,
242 -void generate_files(int f, struct file_list *flist, char *local_name)
243 +void generate_files(int f, struct file_list *flist, char *local_name,
249 char fbuf[MAXPATHLEN];
252 @@ -584,7 +698,7 @@ void generate_files(int f, struct file_l
255 recv_generator(local_name ? local_name : f_name_to(file, fbuf),
257 + file, i, f, f_nameout);
261 @@ -601,7 +715,7 @@ void generate_files(int f, struct file_l
262 while ((i = get_redo_num()) != -1) {
263 struct file_struct *file = flist->files[i];
264 recv_generator(local_name ? local_name : f_name_to(file, fbuf),
266 + file, i, f, f_nameout);
270 @@ -620,7 +734,7 @@ void generate_files(int f, struct file_l
271 if (!file->basename || !S_ISDIR(file->mode))
273 recv_generator(local_name ? local_name : f_name(file),
279 --- main.c 28 Jun 2004 17:45:40 -0000 1.201
280 +++ main.c 30 Jun 2004 07:35:57 -0000
281 @@ -428,8 +428,8 @@ static void do_server_sender(int f_in, i
282 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
288 + int error_pipe[2], name_pipe[2];
290 if (preserve_hard_links)
291 init_hard_links(flist);
292 @@ -441,17 +441,19 @@ static int do_recv(int f_in,int f_out,st
296 - if (fd_pair(error_pipe) < 0) {
297 - rprintf(FERROR,"error pipe failed in do_recv\n");
298 + if (fd_pair(error_pipe) < 0 || fd_pair(name_pipe) < 0) {
299 + rprintf(FERROR, "fd_pair() failed in do_recv\n");
300 exit_cleanup(RERR_SOCKETIO);
303 io_flush(NORMAL_FLUSH);
305 - if ((pid=do_fork()) == 0) {
306 + if ((pid = do_fork()) == 0) {
307 close(error_pipe[0]);
308 + close(name_pipe[1]);
311 + set_blocking(name_pipe[0]);
313 /* we can't let two processes write to the socket at one time */
314 io_multiplexing_close();
315 @@ -459,7 +461,7 @@ static int do_recv(int f_in,int f_out,st
316 /* set place to send errors */
317 set_msg_fd_out(error_pipe[1]);
319 - recv_files(f_in,flist,local_name);
320 + recv_files(f_in, flist, local_name, name_pipe[0]);
321 io_flush(FULL_FLUSH);
324 @@ -475,14 +477,16 @@ static int do_recv(int f_in,int f_out,st
327 close(error_pipe[1]);
328 + close(name_pipe[0]);
331 + set_blocking(name_pipe[1]);
333 io_start_buffering_out(f_out);
335 set_msg_fd_in(error_pipe[0]);
337 - generate_files(f_out, flist, local_name);
338 + generate_files(f_out, flist, local_name, name_pipe[1]);
340 get_redo_num(); /* Read final MSG_DONE and any prior messages. */
342 --- options.c 20 Jun 2004 19:47:05 -0000 1.157
343 +++ options.c 30 Jun 2004 07:35:57 -0000
344 @@ -94,6 +94,7 @@ int ignore_errors = 0;
345 int modify_window = 0;
346 int blocking_io = -1;
347 int checksum_seed = 0;
349 unsigned int block_size = 0;
352 @@ -270,6 +271,7 @@ void usage(enum logcode F)
353 rprintf(F," -T --temp-dir=DIR create temporary files in directory DIR\n");
354 rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
355 rprintf(F," --link-dest=DIR create hardlinks to DIR for unchanged files\n");
356 + rprintf(F," --fuzzy use similar file as basis if basis doesn't exist\n");
357 rprintf(F," -P equivalent to --partial --progress\n");
358 rprintf(F," -z, --compress compress file data\n");
359 rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n");
360 @@ -368,6 +370,7 @@ static struct poptOption long_options[]
361 {"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
362 {"compare-dest", 0, POPT_ARG_STRING, &compare_dest, 0, 0, 0 },
363 {"link-dest", 0, POPT_ARG_STRING, &compare_dest, OPT_LINK_DEST, 0, 0 },
364 + {"fuzzy", 0, POPT_ARG_NONE, &fuzzy, 0, 0, 0 },
365 /* TODO: Should this take an optional int giving the compression level? */
366 {"compress", 'z', POPT_ARG_NONE, &do_compression, 0, 0, 0 },
367 {"daemon", 0, POPT_ARG_NONE, &daemon_opt, 0, 0, 0 },
368 @@ -989,6 +992,9 @@ void server_options(char **args,int *arg
372 + if (fuzzy && am_sender)
373 + args[ac++] = "--fuzzy";
378 --- receiver.c 29 Jun 2004 15:12:01 -0000 1.83
379 +++ receiver.c 30 Jun 2004 07:35:57 -0000
380 @@ -36,7 +36,6 @@ extern int preserve_perms;
381 extern int cvs_exclude;
384 -extern char *compare_dest;
385 extern int make_backups;
386 extern int do_progress;
387 extern char *backup_dir;
388 @@ -293,14 +292,15 @@ static int receive_data(int f_in,struct
389 * main routine for receiver process.
391 * Receiver process runs on the same host as the generator process. */
392 -int recv_files(int f_in,struct file_list *flist,char *local_name)
393 +int recv_files(int f_in, struct file_list *flist, char *local_name,
398 char *fname, fbuf[MAXPATHLEN];
399 char template[MAXPATHLEN];
400 char fnametmp[MAXPATHLEN];
402 + char *fnamecmp, *cp;
403 char fnamecmpbuf[MAXPATHLEN];
404 struct map_struct *mapbuf;
405 struct file_struct *file;
406 @@ -364,19 +364,19 @@ int recv_files(int f_in,struct file_list
408 rprintf(FINFO,"recv_files(%s)\n",fname);
411 + for (cp = fnamecmpbuf; ; cp++) {
412 + if (read(f_name, cp, 1) <= 0) {
413 + rsyserr(FERROR, errno, "fname-pipe read failed");
414 + exit_cleanup(RERR_PROTOCOL);
419 + fnamecmp = *fnamecmpbuf ? fnamecmpbuf : fname;
422 fd1 = do_open(fnamecmp, O_RDONLY, 0);
424 - if (fd1 == -1 && compare_dest != NULL) {
425 - /* try the file at compare_dest instead */
426 - pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
427 - compare_dest, fname);
428 - fnamecmp = fnamecmpbuf;
429 - fd1 = do_open(fnamecmp, O_RDONLY, 0);
432 if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
433 rsyserr(FERROR, errno, "fstat %s failed",
434 full_fname(fnamecmp));
435 @@ -385,7 +385,7 @@ int recv_files(int f_in,struct file_list
439 - if (fd1 != -1 && S_ISDIR(st.st_mode) && fnamecmp == fname) {
440 + if (fd1 != -1 && S_ISDIR(st.st_mode) && !*fnamecmpbuf) {
441 /* this special handling for directories
442 * wouldn't be necessary if robust_rename()
443 * and the underlying robust_unlink could cope
444 --- rsync.yo 5 Jun 2004 16:16:30 -0000 1.171
445 +++ rsync.yo 30 Jun 2004 07:35:58 -0000
446 @@ -325,6 +325,7 @@ verb(
447 -T --temp-dir=DIR create temporary files in directory DIR
448 --compare-dest=DIR also compare received files relative to DIR
449 --link-dest=DIR create hardlinks to DIR for unchanged files
450 + --fuzzy use similar file as basis if basis is gone
451 -P equivalent to --partial --progress
452 -z, --compress compress file data
453 -C, --cvs-exclude auto ignore files in the same way CVS does