Updated rsync.yo hunk.
[rsync/rsync-patches.git] / fuzzy.diff
1 From: Rusty Russell <rusty@rustcorp.com.au>
2 Date: Wed, 03 Apr 2002 17:08:57 +1000
3
4 Found old patch on google, and updated it for 2.5.4 (I know, but that's what
5 apt-get source gave me).
6
7 Compiles, otherwise untested.
8 Rusty.
9
10 [Updated for current CVS version by Wayne Davison.  Passes *MOST* of the
11 test suite, but otherwise UNTESTED.]
12 --
13   Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
14
15 --- Makefile.in 10 Feb 2004 17:06:11 -0000      1.98
16 +++ Makefile.in 27 Feb 2004 08:57:09 -0000
17 @@ -32,7 +32,7 @@
18         zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \
19         zlib/zutil.o zlib/adler32.o
20  OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o \
21 -       main.o checksum.o match.o syscall.o log.o backup.o
22 +       main.o checksum.o match.o syscall.o log.o backup.o alternate.o
23  OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \
24         fileio.o batch.o clientname.o
25  OBJS3=progress.o pipe.o
26 --- generator.c 27 Feb 2004 08:03:49 -0000      1.76
27 +++ generator.c 27 Feb 2004 08:57:09 -0000
28 @@ -43,10 +43,12 @@
29  extern int always_checksum;
30  extern char *compare_dest;
31  extern int link_dest;
32 +extern int fuzzy;
33  
34  
35  /* choose whether to skip a particular file */
36 -static int skip_file(char *fname, struct file_struct *file, STRUCT_STAT *st)
37 +static int skip_file(char *fname, struct file_struct *file,
38 +                    const STRUCT_STAT *st)
39  {
40         if (st->st_size != file->length) {
41                 return 0;
42 @@ -252,7 +254,62 @@
43         }
44  }
45  
46 +/* Returns -1 for can't open (null file), -2 for skip */
47 +static int open_base_file(struct file_struct *file, char *fname, int statret,
48 +                         STRUCT_STAT *st)
49 +{
50 +       int fd = -1;
51  
52 +       if (statret == 0) {
53 +               if (S_ISREG(st->st_mode)) {
54 +                       if (update_only
55 +                           && cmp_modtime(st->st_mtime, file->modtime) > 0) {
56 +                               if (verbose > 1)
57 +                                       rprintf(FINFO, "%s is newer\n", fname);
58 +                               return -2;
59 +                       }
60 +                       if (skip_file(fname, file, st)) {
61 +                               set_perms(fname, file, st, 1);
62 +                               return -2;
63 +                       }
64 +                       fd = do_open(fname, O_RDONLY, 0);
65 +                       if (fd == -1) {
66 +                               rprintf(FERROR, "failed to open %s, continuing : %s\n",
67 +                                   full_fname(fname), strerror(errno));
68 +                               return -1;
69 +                       }
70 +                       return fd;
71 +               } else {
72 +                       /* Try to use symlink contents */
73 +                       if (S_ISLNK(st->st_mode)) {
74 +                               fd = do_open_regular(fname);
75 +                               /* Don't delete yet; receiver will need it */
76 +                       } else {
77 +                               if (delete_file(fname) != 0) {
78 +                                       if (fd != -1)
79 +                                               close(fd);
80 +                                       return -2;
81 +                               }
82 +                       }
83 +               }
84 +       }
85 +
86 +       if (fd == -1 && compare_dest != NULL)
87 +               fd = open_alternate_base_comparedir(fname);
88 +
89 +       if (fd == -1 && fuzzy)
90 +               fd = open_alternate_base_fuzzy(fname);
91 +
92 +       /* Update stat to understand size */
93 +       if (fd != -1) {
94 +               if (do_fstat(fd, st) != 0) {
95 +                       rprintf(FERROR, "fstat %s : %s\n",
96 +                           full_fname(fname), strerror(errno));
97 +               }
98 +       }
99 +
100 +       return fd;
101 +}
102  
103  /**
104   * Acts on file number @p i from @p flist, whose name is @p fname.
105 @@ -268,9 +325,6 @@ void recv_generator(char *fname, struct 
106         STRUCT_STAT st;
107         struct map_struct *mapbuf;
108         int statret;
109 -       char *fnamecmp;
110 -       char fnamecmpbuf[MAXPATHLEN];
111 -       extern char *compare_dest;
112         extern int list_only;
113         extern int only_existing;
114         extern int orig_umask;
115 @@ -397,108 +451,38 @@ void recv_generator(char *fname, struct 
116         }
117  #endif
118  
119 -       if (preserve_hard_links && hard_link_check(file, HL_CHECK_MASTER))
120 -               return;
121 -
122 -       if (!S_ISREG(file->mode)) {
123 -               rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
124 -               return;
125 -       }
126 -
127 -       fnamecmp = fname;
128 -
129 -       if (statret == -1 && compare_dest != NULL) {
130 -               /* try the file at compare_dest instead */
131 -               int saveerrno = errno;
132 -               pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, compare_dest, fname);
133 -               statret = link_stat(fnamecmpbuf,&st);
134 -               if (!S_ISREG(st.st_mode))
135 -                       statret = -1;
136 -               if (statret == -1)
137 -                       errno = saveerrno;
138 -#if HAVE_LINK
139 -               else if (link_dest && !dry_run) {
140 -                       if (do_link(fnamecmpbuf, fname) != 0) {
141 -                               if (verbose > 0) {
142 -                                       rprintf(FINFO,"link %s => %s : %s\n",
143 -                                               fnamecmpbuf, fname,
144 -                                               strerror(errno));
145 -                               }
146 -                       }
147 -                       fnamecmp = fnamecmpbuf;
148 -               }
149 -#endif
150 -               else
151 -                       fnamecmp = fnamecmpbuf;
152 -       }
153 -
154 -       if (statret == -1) {
155 -               if (preserve_hard_links && hard_link_check(file, HL_SKIP))
156 -                       return;
157 -               if (errno == ENOENT) {
158 -                       write_int(f_out,i);
159 -                       if (!dry_run) write_sum_head(f_out, NULL);
160 -               } else if (verbose > 1) {
161 +       /* Failed to stat for some reason besides "not found". */
162 +       if (statret == -1 && errno != ENOENT) {
163 +               if (verbose > 1)
164                         rprintf(FERROR,
165 -                               "recv_generator: failed to open %s: %s\n",
166 +                               "recv_generator failed to stat %s: %s\n",
167                                 full_fname(fname), strerror(errno));
168 -               }
169                 return;
170         }
171  
172 -       if (!S_ISREG(st.st_mode)) {
173 -               if (delete_file(fname) != 0) {
174 -                       return;
175 -               }
176 -
177 -               /* now pretend the file didn't exist */
178 -               if (preserve_hard_links && hard_link_check(file, HL_SKIP))
179 -                       return;
180 -               write_int(f_out,i);
181 -               if (!dry_run) write_sum_head(f_out, NULL);
182 +       if ((fd = open_base_file(file, fname, statret, &st)) == -2)
183                 return;
184 -       }
185 -
186 -       if (opt_ignore_existing && fnamecmp == fname) {
187 -               if (verbose > 1)
188 -                       rprintf(FINFO,"%s exists\n",fname);
189 -               return;
190 -       }
191  
192 -       if (update_only && cmp_modtime(st.st_mtime,file->modtime)>0 && fnamecmp == fname) {
193 -               if (verbose > 1)
194 -                       rprintf(FINFO,"%s is newer\n",fname);
195 -               return;
196 +       if ((disable_deltas_p() || dry_run) && fd != -1) {
197 +               close(fd);
198 +               fd = -1;
199         }
200  
201 -       if (skip_file(fname, file, &st)) {
202 -               if (fnamecmp == fname)
203 -                       set_perms(fname,file,&st,1);
204 -               return;
205 -       }
206 -
207 -       if (dry_run) {
208 -               write_int(f_out,i);
209 -               return;
210 -       }
211 -
212 -       if (disable_deltas_p()) {
213 -               write_int(f_out,i);
214 -               write_sum_head(f_out, NULL);
215 -               return;
216 -       }
217 -
218 -       /* open the file */
219 -       fd = do_open(fnamecmp, O_RDONLY, 0);
220 -
221         if (fd == -1) {
222 -               rprintf(FERROR, "failed to open %s, continuing: %s\n",
223 -                       full_fname(fnamecmp), strerror(errno));
224 -               /* pretend the file didn't exist */
225 +               /* the file didn't exist, or we can pretend it doesn't */
226                 if (preserve_hard_links && hard_link_check(file, HL_SKIP))
227                         return;
228 -               write_int(f_out,i);
229 -               write_sum_head(f_out, NULL);
230 +               write_int(f_out, i);
231 +               if (!dry_run)
232 +                       write_sum_head(f_out, NULL);
233 +               return;
234 +       }
235 +
236 +       if (preserve_hard_links && hard_link_check(file, HL_CHECK_MASTER))
237 +               return;
238 +
239 +       if (!S_ISREG(file->mode)) {
240 +               rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
241                 return;
242         }
243  
244 @@ -508,7 +492,7 @@ void recv_generator(char *fname, struct 
245                 mapbuf = NULL;
246  
247         if (verbose > 3) {
248 -               rprintf(FINFO,"gen mapped %s of size %.0f\n", fnamecmp,
249 +               rprintf(FINFO, "gen mapped %s of size %.0f\n", fname,
250                         (double)st.st_size);
251         }
252  
253 --- options.c   22 Feb 2004 08:56:43 -0000      1.139
254 +++ options.c   27 Feb 2004 08:57:10 -0000
255 @@ -89,6 +89,7 @@
256  int modify_window = 0;
257  int blocking_io = -1;
258  int checksum_seed = 0;
259 +int fuzzy = 0;
260  unsigned int block_size = 0;
261  
262  
263 @@ -288,6 +289,7 @@ void usage(enum logcode F)
264    rprintf(F,"     --bwlimit=KBPS          limit I/O bandwidth, KBytes per second\n");
265    rprintf(F,"     --write-batch=PREFIX    write batch fileset starting with PREFIX\n");
266    rprintf(F,"     --read-batch=PREFIX     read batch fileset starting with PREFIX\n");
267 +  rprintf(F,"     --fuzzy                 use similar file as basis if it does't exist\n");
268    rprintf(F," -h, --help                  show this help screen\n");
269  #ifdef INET6
270    rprintf(F," -4                          prefer IPv4\n");
271 @@ -383,6 +385,7 @@ static struct poptOption long_options[] 
272    {"files-from",       0,  POPT_ARG_STRING, &files_from, 0, 0, 0 },
273    {"from0",           '0', POPT_ARG_NONE,   &eol_nulls, 0, 0, 0},
274    {"no-implied-dirs",  0,  POPT_ARG_VAL,    &implied_dirs, 0, 0, 0 },
275 +  {"fuzzy",            0,  POPT_ARG_NONE,   &fuzzy, 0, 0, 0 },
276    {"protocol",         0,  POPT_ARG_INT,    &protocol_version, 0, 0, 0 },
277  #ifdef INET6
278    {0,                '4', POPT_ARG_VAL,    &default_af_hint, AF_INET, 0, 0 },
279 @@ -945,6 +948,9 @@ void server_options(char **args,int *arg
280                         args[ac++] = "--from0";
281                 }
282         }
283 +
284 +       if (fuzzy && am_sender)
285 +               args[ac++] = "--fuzzy";
286  
287         *argc = ac;
288         return;
289 --- proto.h     17 Feb 2004 23:13:06 -0000      1.184
290 +++ proto.h     27 Feb 2004 08:57:10 -0000
291 @@ -1,6 +1,9 @@
292  /* This file is automatically generated with "make proto". DO NOT EDIT */
293  
294  int allow_access(char *addr, char *host, char *allow_list, char *deny_list);
295 +int do_open_regular(char *fname);
296 +int open_alternate_base_fuzzy(const char *fname);
297 +int open_alternate_base_comparedir(const char *fname);
298  void base64_encode(char *buf, int len, char *out);
299  char *auth_server(int f_in, int f_out, int module, char *addr, char *leader);
300  void auth_client(int fd, char *user, char *challenge);
301 --- receiver.c  27 Feb 2004 08:03:49 -0000      1.73
302 +++ receiver.c  27 Feb 2004 08:57:10 -0000
303 @@ -39,6 +39,7 @@
304  extern char *backup_suffix;
305  extern int backup_suffix_len;
306  extern int cleanup_got_literal;
307 +extern int fuzzy;
308  
309  static void delete_one(char *fn, int is_dir)
310  {
311 @@ -288,8 +289,6 @@ int recv_files(int f_in,struct file_list
312         char *fname, fbuf[MAXPATHLEN];
313         char template[MAXPATHLEN];
314         char fnametmp[MAXPATHLEN];
315 -       char *fnamecmp;
316 -       char fnamecmpbuf[MAXPATHLEN];
317         struct map_struct *mapbuf;
318         int i;
319         struct file_struct *file;
320 @@ -356,35 +355,31 @@ int recv_files(int f_in,struct file_list
321                 if (verbose > 2)
322                         rprintf(FINFO,"recv_files(%s)\n",fname);
323  
324 -               fnamecmp = fname;
325 -
326                 /* open the file */
327 -               fd1 = do_open(fnamecmp, O_RDONLY, 0);
328 +               fd1 = do_open(fname, O_RDONLY, 0);
329  
330 -               if (fd1 == -1 && compare_dest != NULL) {
331 -                       /* try the file at compare_dest instead */
332 -                       pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
333 -                                compare_dest, fname);
334 -                       fnamecmp = fnamecmpbuf;
335 -                       fd1 = do_open(fnamecmp, O_RDONLY, 0);
336 -               }
337 +               if (fd1 == -1 && compare_dest != NULL)
338 +                       fd1 = open_alternate_base_comparedir(fname);
339 +
340 +               if (fd1 == -1 && fuzzy)
341 +                       fd1 = open_alternate_base_fuzzy(fname);
342  
343                 if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
344                         rprintf(FERROR, "fstat %s failed: %s\n",
345 -                               full_fname(fnamecmp), strerror(errno));
346 +                               full_fname(fname), strerror(errno));
347                         receive_data(f_in,NULL,-1,NULL,file->length);
348                         close(fd1);
349                         continue;
350                 }
351  
352 -               if (fd1 != -1 && S_ISDIR(st.st_mode) && fnamecmp == fname) {
353 +               if (fd1 != -1 && S_ISDIR(st.st_mode)) {
354                         /* this special handling for directories
355                          * wouldn't be necessary if robust_rename()
356                          * and the underlying robust_unlink could cope
357                          * with directories
358                          */
359                         rprintf(FERROR,"recv_files: %s is a directory\n",
360 -                               full_fname(fnamecmp));
361 +                               full_fname(fname));
362                         receive_data(f_in, NULL, -1, NULL, file->length);
363                         close(fd1);
364                         continue;
365 @@ -405,8 +400,10 @@ int recv_files(int f_in,struct file_list
366  
367                 if (fd1 != -1 && st.st_size > 0) {
368                         mapbuf = map_file(fd1,st.st_size);
369 -                       if (verbose > 2)
370 -                               rprintf(FINFO,"recv mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
371 +                       if (verbose > 2) {
372 +                               rprintf(FINFO, "recv mapped %s of size %.0f\n",
373 +                                   fname, (double)st.st_size);
374 +                       }
375                 } else
376                         mapbuf = NULL;
377