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 30 Jun 2004 07:27:30 -0000 1.93
8 +++ generator.c 30 Jun 2004 07:43:46 -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,7 +656,8 @@ 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,
248 @@ -584,7 +698,7 @@ void generate_files(int f, struct file_l
251 recv_generator(local_name ? local_name : f_name_to(file, fbuf),
253 + file, i, f, f_nameout);
257 @@ -601,7 +715,7 @@ void generate_files(int f, struct file_l
258 while ((i = get_redo_num()) != -1) {
259 struct file_struct *file = flist->files[i];
260 recv_generator(local_name ? local_name : f_name_to(file, fbuf),
262 + file, i, f, f_nameout);
266 @@ -620,7 +734,7 @@ void generate_files(int f, struct file_l
267 if (!file->basename || !S_ISDIR(file->mode))
269 recv_generator(local_name ? local_name : f_name(file),
275 --- main.c 30 Jun 2004 07:27:30 -0000 1.202
276 +++ main.c 30 Jun 2004 07:43:47 -0000
277 @@ -429,7 +429,7 @@ static int do_recv(int f_in,int f_out,st
282 + int error_pipe[2], name_pipe[2];
284 if (preserve_hard_links)
285 init_hard_links(flist);
286 @@ -441,8 +441,8 @@ static int do_recv(int f_in,int f_out,st
290 - if (fd_pair(error_pipe) < 0) {
291 - rprintf(FERROR,"error pipe failed in do_recv\n");
292 + if (fd_pair(error_pipe) < 0 || fd_pair(name_pipe) < 0) {
293 + rprintf(FERROR, "fd_pair() failed in do_recv\n");
294 exit_cleanup(RERR_SOCKETIO);
297 @@ -450,8 +450,10 @@ static int do_recv(int f_in,int f_out,st
299 if ((pid = do_fork()) == 0) {
300 close(error_pipe[0]);
301 + close(name_pipe[1]);
304 + set_blocking(name_pipe[0]);
306 /* we can't let two processes write to the socket at one time */
307 io_multiplexing_close();
308 @@ -459,7 +461,7 @@ static int do_recv(int f_in,int f_out,st
309 /* set place to send errors */
310 set_msg_fd_out(error_pipe[1]);
312 - recv_files(f_in,flist,local_name);
313 + recv_files(f_in, flist, local_name, name_pipe[0]);
314 io_flush(FULL_FLUSH);
317 @@ -475,14 +477,16 @@ static int do_recv(int f_in,int f_out,st
320 close(error_pipe[1]);
321 + close(name_pipe[0]);
324 + set_blocking(name_pipe[1]);
326 io_start_buffering_out(f_out);
328 set_msg_fd_in(error_pipe[0]);
330 - generate_files(f_out, flist, local_name);
331 + generate_files(f_out, flist, local_name, name_pipe[1]);
333 get_redo_num(); /* Read final MSG_DONE and any prior messages. */
335 --- options.c 20 Jun 2004 19:47:05 -0000 1.157
336 +++ options.c 30 Jun 2004 07:43:47 -0000
337 @@ -94,6 +94,7 @@ int ignore_errors = 0;
338 int modify_window = 0;
339 int blocking_io = -1;
340 int checksum_seed = 0;
342 unsigned int block_size = 0;
345 @@ -270,6 +271,7 @@ void usage(enum logcode F)
346 rprintf(F," -T --temp-dir=DIR create temporary files in directory DIR\n");
347 rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
348 rprintf(F," --link-dest=DIR create hardlinks to DIR for unchanged files\n");
349 + rprintf(F," --fuzzy use similar file as basis if basis doesn't exist\n");
350 rprintf(F," -P equivalent to --partial --progress\n");
351 rprintf(F," -z, --compress compress file data\n");
352 rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n");
353 @@ -368,6 +370,7 @@ static struct poptOption long_options[]
354 {"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
355 {"compare-dest", 0, POPT_ARG_STRING, &compare_dest, 0, 0, 0 },
356 {"link-dest", 0, POPT_ARG_STRING, &compare_dest, OPT_LINK_DEST, 0, 0 },
357 + {"fuzzy", 0, POPT_ARG_NONE, &fuzzy, 0, 0, 0 },
358 /* TODO: Should this take an optional int giving the compression level? */
359 {"compress", 'z', POPT_ARG_NONE, &do_compression, 0, 0, 0 },
360 {"daemon", 0, POPT_ARG_NONE, &daemon_opt, 0, 0, 0 },
361 @@ -989,6 +992,9 @@ void server_options(char **args,int *arg
365 + if (fuzzy && am_sender)
366 + args[ac++] = "--fuzzy";
371 --- receiver.c 30 Jun 2004 07:27:30 -0000 1.84
372 +++ receiver.c 30 Jun 2004 07:43:47 -0000
373 @@ -36,7 +36,6 @@ extern int preserve_perms;
374 extern int cvs_exclude;
377 -extern char *compare_dest;
378 extern int make_backups;
379 extern int do_progress;
380 extern char *backup_dir;
381 @@ -293,14 +292,15 @@ static int receive_data(int f_in,struct
382 * main routine for receiver process.
384 * Receiver process runs on the same host as the generator process. */
385 -int recv_files(int f_in,struct file_list *flist,char *local_name)
386 +int recv_files(int f_in, struct file_list *flist, char *local_name,
391 char *fname, fbuf[MAXPATHLEN];
392 char template[MAXPATHLEN];
393 char fnametmp[MAXPATHLEN];
395 + char *fnamecmp, *cp;
396 char fnamecmpbuf[MAXPATHLEN];
397 struct map_struct *mapbuf;
398 struct file_struct *file;
399 @@ -364,19 +364,19 @@ int recv_files(int f_in,struct file_list
401 rprintf(FINFO,"recv_files(%s)\n",fname);
404 + for (cp = fnamecmpbuf; ; cp++) {
405 + if (read(f_name, cp, 1) <= 0) {
406 + rsyserr(FERROR, errno, "fname-pipe read failed");
407 + exit_cleanup(RERR_PROTOCOL);
412 + fnamecmp = *fnamecmpbuf ? fnamecmpbuf : fname;
415 fd1 = do_open(fnamecmp, O_RDONLY, 0);
417 - if (fd1 == -1 && compare_dest != NULL) {
418 - /* try the file at compare_dest instead */
419 - pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
420 - compare_dest, fname);
421 - fnamecmp = fnamecmpbuf;
422 - fd1 = do_open(fnamecmp, O_RDONLY, 0);
425 if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
426 rsyserr(FERROR, errno, "fstat %s failed",
427 full_fname(fnamecmp));
428 @@ -385,7 +385,7 @@ int recv_files(int f_in,struct file_list
432 - if (fd1 != -1 && S_ISDIR(st.st_mode) && fnamecmp == fname) {
433 + if (fd1 != -1 && S_ISDIR(st.st_mode) && !*fnamecmpbuf) {
434 /* this special handling for directories
435 * wouldn't be necessary if robust_rename()
436 * and the underlying robust_unlink could cope
437 --- rsync.yo 5 Jun 2004 16:16:30 -0000 1.171
438 +++ rsync.yo 30 Jun 2004 07:43:48 -0000
439 @@ -325,6 +325,7 @@ verb(
440 -T --temp-dir=DIR create temporary files in directory DIR
441 --compare-dest=DIR also compare received files relative to DIR
442 --link-dest=DIR create hardlinks to DIR for unchanged files
443 + --fuzzy use similar file as basis if basis is gone
444 -P equivalent to --partial --progress
445 -z, --compress compress file data
446 -C, --cvs-exclude auto ignore files in the same way CVS does