Updated to apply cleanly.
[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 15 May 2004 00:48:11 -0000      1.101
16 +++ Makefile.in 18 Jun 2004 17:32:53 -0000
17 @@ -32,7 +32,7 @@ ZLIBOBJ=zlib/deflate.o zlib/infblock.o z
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 18 Jun 2004 16:30:24 -0000      1.88
27 +++ generator.c 18 Jun 2004 17:32:53 -0000
28 @@ -41,6 +41,7 @@ extern int ignore_times;
29  extern int size_only;
30  extern int io_timeout;
31  extern int protocol_version;
32 +extern int fuzzy;
33  extern int always_checksum;
34  extern char *compare_dest;
35  extern int link_dest;
36 @@ -259,7 +260,61 @@ static void generate_and_send_sums(struc
37         }
38  }
39  
40 +/* Returns -1 for can't open (null file), -2 for skip */
41 +static int open_base_file(struct file_struct *file, char *fname, int statret,
42 +                         STRUCT_STAT *st)
43 +{
44 +       int fd = -1;
45  
46 +       if (statret == 0) {
47 +               if (S_ISREG(st->st_mode)) {
48 +                       if (update_only
49 +                           && cmp_modtime(st->st_mtime, file->modtime) > 0) {
50 +                               if (verbose > 1)
51 +                                       rprintf(FINFO, "%s is newer\n", fname);
52 +                               return -2;
53 +                       }
54 +                       if (skip_file(fname, file, st)) {
55 +                               set_perms(fname, file, st, PERMS_REPORT);
56 +                               return -2;
57 +                       }
58 +                       fd = do_open(fname, O_RDONLY, 0);
59 +                       if (fd == -1) {
60 +                               rsyserr(FERROR, errno, "failed to open %s, continuing",
61 +                                   full_fname(fname));
62 +                               return -1;
63 +                       }
64 +                       return fd;
65 +               } else {
66 +                       /* Try to use symlink contents */
67 +                       if (S_ISLNK(st->st_mode)) {
68 +                               fd = do_open_regular(fname);
69 +                               /* Don't delete yet; receiver will need it */
70 +                       } else {
71 +                               if (delete_file(fname) != 0) {
72 +                                       if (fd != -1)
73 +                                               close(fd);
74 +                                       return -2;
75 +                               }
76 +                       }
77 +               }
78 +       }
79 +
80 +       if (fd == -1 && compare_dest != NULL)
81 +               fd = open_alternate_base_comparedir(fname);
82 +
83 +       if (fd == -1 && fuzzy)
84 +               fd = open_alternate_base_fuzzy(fname);
85 +
86 +       /* Update stat to understand size */
87 +       if (fd != -1) {
88 +               if (do_fstat(fd, st) != 0) {
89 +                       rsyserr(FERROR, errno, "fstat %s", full_fname(fname));
90 +               }
91 +       }
92 +
93 +       return fd;
94 +}
95  
96  /**
97   * Acts on file number @p i from @p flist, whose name is @p fname.
98 @@ -275,8 +330,6 @@ void recv_generator(char *fname, struct 
99         STRUCT_STAT st;
100         struct map_struct *mapbuf;
101         int statret;
102 -       char *fnamecmp;
103 -       char fnamecmpbuf[MAXPATHLEN];
104  
105         if (list_only)
106                 return;
107 @@ -416,109 +469,39 @@ void recv_generator(char *fname, struct 
108         }
109  #endif
110  
111 -       if (preserve_hard_links && hard_link_check(file, HL_CHECK_MASTER))
112 -               return;
113 -
114 -       if (!S_ISREG(file->mode)) {
115 -               rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
116 -               return;
117 -       }
118 -
119 -       fnamecmp = fname;
120 -
121 -       if (statret == -1 && compare_dest != NULL) {
122 -               /* try the file at compare_dest instead */
123 -               int saveerrno = errno;
124 -               pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, compare_dest, fname);
125 -               statret = link_stat(fnamecmpbuf, &st, 0);
126 -               if (!S_ISREG(st.st_mode))
127 -                       statret = -1;
128 -               if (statret == -1)
129 -                       errno = saveerrno;
130 -#if HAVE_LINK
131 -               else if (link_dest && !dry_run) {
132 -                       if (do_link(fnamecmpbuf, fname) != 0) {
133 -                               if (verbose > 0) {
134 -                                       rsyserr(FINFO, errno, "link %s => %s",
135 -                                               fnamecmpbuf, fname);
136 -                               }
137 -                       }
138 -                       fnamecmp = fnamecmpbuf;
139 -               }
140 -#endif
141 -               else
142 -                       fnamecmp = fnamecmpbuf;
143 -       }
144 -
145 -       if (statret == -1) {
146 -               if (preserve_hard_links && hard_link_check(file, HL_SKIP))
147 -                       return;
148 -               if (errno == ENOENT) {
149 -                       write_int(f_out,i);
150 -                       if (!dry_run)
151 -                               write_sum_head(f_out, NULL);
152 -               } else if (verbose > 1) {
153 +       /* Failed to stat for some reason besides "not found". */
154 +       if (statret == -1 && errno != ENOENT) {
155 +               if (verbose > 1) {
156                         rsyserr(FERROR, errno,
157 -                               "recv_generator: failed to open %s",
158 +                               "recv_generator failed to stat %s",
159                                 full_fname(fname));
160                 }
161                 return;
162         }
163  
164 -       if (!S_ISREG(st.st_mode)) {
165 -               if (delete_file(fname) != 0) {
166 -                       return;
167 -               }
168 +       if ((fd = open_base_file(file, fname, statret, &st)) == -2)
169 +               return;
170  
171 -               /* now pretend the file didn't exist */
172 +       if ((disable_deltas_p() || dry_run) && fd != -1) {
173 +               close(fd);
174 +               fd = -1;
175 +       }
176 +
177 +       if (fd == -1) {
178 +               /* the file didn't exist, or we can pretend it doesn't */
179                 if (preserve_hard_links && hard_link_check(file, HL_SKIP))
180                         return;
181 -               write_int(f_out,i);
182 +               write_int(f_out, i);
183                 if (!dry_run)
184                         write_sum_head(f_out, NULL);
185 -               return;
186 -       }
187 -
188 -       if (opt_ignore_existing && fnamecmp == fname) {
189 -               if (verbose > 1)
190 -                       rprintf(FINFO,"%s exists\n",fname);
191 -               return;
192 -       }
193 +               return;
194 +       }
195  
196 -       if (update_only && cmp_modtime(st.st_mtime,file->modtime)>0 && fnamecmp == fname) {
197 -               if (verbose > 1)
198 -                       rprintf(FINFO,"%s is newer\n",fname);
199 -               return;
200 -       }
201 -
202 -       if (skip_file(fname, file, &st)) {
203 -               if (fnamecmp == fname)
204 -                       set_perms(fname, file, &st, PERMS_REPORT);
205 -               return;
206 -       }
207 -
208 -       if (dry_run) {
209 -               write_int(f_out,i);
210 -               return;
211 -       }
212 -
213 -       if (disable_deltas_p()) {
214 -               write_int(f_out,i);
215 -               write_sum_head(f_out, NULL);
216 +       if (preserve_hard_links && hard_link_check(file, HL_CHECK_MASTER))
217                 return;
218 -       }
219  
220 -       /* open the file */
221 -       fd = do_open(fnamecmp, O_RDONLY, 0);
222 -
223 -       if (fd == -1) {
224 -               rsyserr(FERROR, errno, "failed to open %s, continuing",
225 -                       full_fname(fnamecmp));
226 -               /* pretend the file didn't exist */
227 -               if (preserve_hard_links && hard_link_check(file, HL_SKIP))
228 -                       return;
229 -               write_int(f_out,i);
230 -               write_sum_head(f_out, NULL);
231 +       if (!S_ISREG(file->mode)) {
232 +               rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
233                 return;
234         }
235  
236 @@ -528,7 +511,7 @@ void recv_generator(char *fname, struct 
237                 mapbuf = NULL;
238  
239         if (verbose > 3) {
240 -               rprintf(FINFO,"gen mapped %s of size %.0f\n", fnamecmp,
241 +               rprintf(FINFO, "gen mapped %s of size %.0f\n", fname,
242                         (double)st.st_size);
243         }
244  
245 --- options.c   7 Jun 2004 22:05:22 -0000       1.156
246 +++ options.c   18 Jun 2004 17:32:54 -0000
247 @@ -94,6 +94,7 @@ int ignore_errors = 0;
248  int modify_window = 0;
249  int blocking_io = -1;
250  int checksum_seed = 0;
251 +int fuzzy = 0;
252  unsigned int block_size = 0;
253  
254  
255 @@ -270,6 +271,7 @@ void usage(enum logcode F)
256    rprintf(F," -T  --temp-dir=DIR          create temporary files in directory DIR\n");
257    rprintf(F,"     --compare-dest=DIR      also compare destination files relative to DIR\n");
258    rprintf(F,"     --link-dest=DIR         create hardlinks to DIR for unchanged files\n");
259 +  rprintf(F,"     --fuzzy                 use similar file as basis if basis doesn't exist\n");
260    rprintf(F," -P                          equivalent to --partial --progress\n");
261    rprintf(F," -z, --compress              compress file data\n");
262    rprintf(F," -C, --cvs-exclude           auto ignore files in the same way CVS does\n");
263 @@ -368,6 +370,7 @@ static struct poptOption long_options[] 
264    {"temp-dir",        'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
265    {"compare-dest",     0,  POPT_ARG_STRING, &compare_dest, 0, 0, 0 },
266    {"link-dest",        0,  POPT_ARG_STRING, &compare_dest,  OPT_LINK_DEST, 0, 0 },
267 +  {"fuzzy",            0,  POPT_ARG_NONE,   &fuzzy, 0, 0, 0 },
268    /* TODO: Should this take an optional int giving the compression level? */
269    {"compress",        'z', POPT_ARG_NONE,   &do_compression, 0, 0, 0 },
270    {"daemon",           0,  POPT_ARG_NONE,   &daemon_opt, 0, 0, 0 },
271 @@ -989,6 +992,9 @@ void server_options(char **args,int *arg
272                 }
273         }
274  
275 +       if (fuzzy && am_sender)
276 +               args[ac++] = "--fuzzy";
277 +
278         *argc = ac;
279         return;
280  
281 --- receiver.c  14 Jun 2004 15:09:36 -0000      1.82
282 +++ receiver.c  18 Jun 2004 17:32:54 -0000
283 @@ -48,6 +48,7 @@ extern int ignore_errors;
284  extern int orig_umask;
285  extern int keep_partial;
286  extern int checksum_seed;
287 +extern int fuzzy;
288  
289  static void delete_one(char *fn, int is_dir)
290  {
291 @@ -300,8 +301,6 @@ int recv_files(int f_in,struct file_list
292         char *fname, fbuf[MAXPATHLEN];
293         char template[MAXPATHLEN];
294         char fnametmp[MAXPATHLEN];
295 -       char *fnamecmp;
296 -       char fnamecmpbuf[MAXPATHLEN];
297         struct map_struct *mapbuf;
298         struct file_struct *file;
299         struct stats initial_stats;
300 @@ -364,35 +363,31 @@ int recv_files(int f_in,struct file_list
301                 if (verbose > 2)
302                         rprintf(FINFO,"recv_files(%s)\n",fname);
303  
304 -               fnamecmp = fname;
305 -
306                 /* open the file */
307 -               fd1 = do_open(fnamecmp, O_RDONLY, 0);
308 +               fd1 = do_open(fname, O_RDONLY, 0);
309  
310 -               if (fd1 == -1 && compare_dest != NULL) {
311 -                       /* try the file at compare_dest instead */
312 -                       pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
313 -                                compare_dest, fname);
314 -                       fnamecmp = fnamecmpbuf;
315 -                       fd1 = do_open(fnamecmp, O_RDONLY, 0);
316 -               }
317 +               if (fd1 == -1 && compare_dest != NULL)
318 +                       fd1 = open_alternate_base_comparedir(fname);
319 +
320 +               if (fd1 == -1 && fuzzy)
321 +                       fd1 = open_alternate_base_fuzzy(fname);
322  
323                 if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
324                         rsyserr(FERROR, errno, "fstat %s failed",
325 -                               full_fname(fnamecmp));
326 +                               full_fname(fname));
327                         receive_data(f_in,NULL,-1,NULL,file->length);
328                         close(fd1);
329                         continue;
330                 }
331  
332 -               if (fd1 != -1 && S_ISDIR(st.st_mode) && fnamecmp == fname) {
333 +               if (fd1 != -1 && S_ISDIR(st.st_mode)) {
334                         /* this special handling for directories
335                          * wouldn't be necessary if robust_rename()
336                          * and the underlying robust_unlink could cope
337                          * with directories
338                          */
339                         rprintf(FERROR,"recv_files: %s is a directory\n",
340 -                               full_fname(fnamecmp));
341 +                               full_fname(fname));
342                         receive_data(f_in, NULL, -1, NULL, file->length);
343                         close(fd1);
344                         continue;
345 @@ -413,8 +408,10 @@ int recv_files(int f_in,struct file_list
346  
347                 if (fd1 != -1 && st.st_size > 0) {
348                         mapbuf = map_file(fd1,st.st_size);
349 -                       if (verbose > 2)
350 -                               rprintf(FINFO,"recv mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
351 +                       if (verbose > 2) {
352 +                               rprintf(FINFO, "recv mapped %s of size %.0f\n",
353 +                                   fname, (double)st.st_size);
354 +                       }
355                 } else
356                         mapbuf = NULL;
357  
358 --- rsync.yo    5 Jun 2004 16:16:30 -0000       1.171
359 +++ rsync.yo    18 Jun 2004 17:32:54 -0000
360 @@ -325,6 +325,7 @@ verb(
361   -T  --temp-dir=DIR          create temporary files in directory DIR
362       --compare-dest=DIR      also compare received files relative to DIR
363       --link-dest=DIR         create hardlinks to DIR for unchanged files
364 +     --fuzzy                 use similar file as basis if basis is gone
365   -P                          equivalent to --partial --progress
366   -z, --compress              compress file data
367   -C, --cvs-exclude           auto ignore files in the same way CVS does