Fix failing hunks.
[rsync/rsync-patches.git] / fuzzy.diff
CommitLineData
b952a177 1Depends-On-Patch: partial-dir.diff
824abc86 2Depends-On-Patch: g2r-basis-filename.diff
8c5b8235 3
824abc86 4The changes to generator.c were greatly simplified, making the patch
8c5b8235 5easier to maintain and fixing the failing test in the testsuite.
58118c25 6Very lightly tested.
241013b4 7
824abc86
WD
8Be sure to run "make proto" before "make".
9
b952a177
WD
10--- orig/generator.c 2004-07-28 10:14:15
11+++ generator.c 2004-07-28 10:23:12
58118c25
WD
12@@ -41,6 +41,7 @@ extern int ignore_times;
13 extern int size_only;
14 extern int io_timeout;
15 extern int protocol_version;
16+extern int fuzzy;
17 extern int always_checksum;
b952a177 18 extern char *partial_dir;
58118c25 19 extern char *compare_dest;
b952a177 20@@ -249,6 +250,94 @@ static void generate_and_send_sums(int f
58118c25
WD
21 }
22
23
47dd7a31
WD
24+static void split_names(char *fname, char **dirname, char **basename)
25+{
26+ char *slash = strrchr(fname, '/');
27+ if (slash) {
28+ *dirname = fname;
29+ *slash = '\0';
30+ *basename = slash+1;
31+ } else {
32+ *basename = fname;
33+ *dirname = ".";
34+ }
35+}
36+
58118c25 37+
47dd7a31
WD
38+static unsigned int measure_name(const char *name, const char *basename,
39+ const char *ext)
40+{
41+ int namelen = strlen(name);
42+ int extlen = strlen(ext);
43+ unsigned int score = 0;
44+
45+ /* Extensions must match */
46+ if (namelen <= extlen || strcmp(name + namelen - extlen, ext) != 0)
47+ return 0;
48+
49+ /* Now score depends on similarity of prefix */
50+ for (; *name == *basename && *name; name++, basename++)
51+ score++;
52+ return score;
53+}
54+
58118c25
WD
55+
56+static int find_fuzzy(char **fname_ptr, char *buf, STRUCT_STAT *st_ptr)
47dd7a31
WD
57+{
58+ DIR *d;
59+ struct dirent *di;
60+ char *basename, *dirname;
61+ char mangled_name[MAXPATHLEN];
62+ char bestname[MAXPATHLEN];
63+ unsigned int bestscore = 0;
64+ const char *ext;
65+
8c5b8235 66+ strlcpy(mangled_name, *fname_ptr, sizeof mangled_name);
47dd7a31
WD
67+
68+ split_names(mangled_name, &dirname, &basename);
69+ if (!(d = opendir(dirname))) {
70+ rsyserr(FERROR, errno, "recv_generator opendir(%s)", dirname);
71+ return -1;
72+ }
73+
74+ /* Get final extension, eg. .gz; never full basename though. */
75+ ext = strrchr(basename + 1, '.');
76+ if (!ext)
77+ ext = basename + strlen(basename); /* ext = "" */
78+
79+ while ((di = readdir(d)) != NULL) {
80+ const char *dname = d_name(di);
81+ unsigned int score;
82+
83+ if (dname[0] == '.' && (dname[1] == '\0'
84+ || (dname[1] == '.' && dname[2] == '\0')))
85+ continue;
86+
87+ score = measure_name(dname, basename, ext);
88+ if (verbose > 4) {
8c5b8235
WD
89+ rprintf(FINFO, "[%s] fuzzy score for %s = %u\n",
90+ who_am_i(), dname, score);
47dd7a31
WD
91+ }
92+ if (score > bestscore) {
8c5b8235 93+ strlcpy(bestname, dname, sizeof bestname);
47dd7a31
WD
94+ bestscore = score;
95+ }
96+ }
97+ closedir(d);
98+
99+ /* Found a candidate. */
100+ if (bestscore != 0) {
8c5b8235 101+ pathjoin(buf, MAXPATHLEN, dirname, bestname);
47dd7a31 102+ if (verbose > 2) {
8c5b8235
WD
103+ rprintf(FINFO, "[%s] fuzzy match %s->%s\n",
104+ who_am_i(), *fname_ptr, buf);
47dd7a31 105+ }
8c5b8235 106+ *fname_ptr = buf;
58118c25 107+ return link_stat(buf, st_ptr, 0);
47dd7a31
WD
108+ }
109+ return -1;
110+}
58118c25
WD
111+
112
113 /*
114 * Acts on file number @p i from @p flist, whose name is @p fname.
b952a177 115@@ -263,7 +352,7 @@ static void recv_generator(char *fname,
dc3ae351 116 {
495f1899 117 int fd = -1;
f74d2272 118 STRUCT_STAT st;
b952a177
WD
119- int statret, stat_errno;
120+ int statret, stat_errno, fuzzy_file = 0;
8c5b8235
WD
121 char *fnamecmp;
122 char fnamecmpbuf[MAXPATHLEN];
54691942 123
b952a177 124@@ -448,6 +537,14 @@ static void recv_generator(char *fname,
824abc86
WD
125 } else
126 *fnamecmpbuf = '\0';
127
8c5b8235 128+ if (statret == -1 && fuzzy) {
58118c25 129+ statret = find_fuzzy(&fnamecmp, fnamecmpbuf, &st);
8c5b8235
WD
130+ if (!S_ISREG(st.st_mode))
131+ statret = -1;
132+ else
133+ fuzzy_file = 1;
824abc86
WD
134+ }
135+
b952a177
WD
136 if (statret == 0 && !S_ISREG(st.st_mode)) {
137 if (delete_file(fname) != 0)
7628f156 138 return;
b952a177 139@@ -481,7 +578,7 @@ static void recv_generator(char *fname,
241013b4
MP
140 return;
141 }
142
8c5b8235
WD
143- if (skip_file(fname, file, &st)) {
144+ if (!fuzzy_file && skip_file(fname, file, &st)) {
824abc86 145 if (!*fnamecmpbuf)
8c5b8235
WD
146 set_perms(fname, file, &st, PERMS_REPORT);
147 return;
2f5fa77e
WD
148--- orig/main.c 2004-07-22 00:10:43
149+++ main.c 2004-07-22 00:32:31
495f1899
WD
150@@ -47,6 +47,7 @@ extern int keep_dirlinks;
151 extern int preserve_hard_links;
152 extern int protocol_version;
153 extern int recurse;
154+extern int fuzzy;
155 extern int relative_paths;
156 extern int rsync_port;
157 extern int whole_file;
c2530f70 158@@ -458,7 +459,7 @@ static int do_recv(int f_in,int f_out,st
495f1899
WD
159 int pid;
160 int status = 0;
161 int error_pipe[2], name_pipe[2];
c2530f70
WD
162- BOOL need_name_pipe = compare_dest && !dry_run;
163+ BOOL need_name_pipe = (compare_dest || fuzzy) && !dry_run;
495f1899
WD
164
165 if (preserve_hard_links)
166 init_hard_links(flist);
b952a177 167--- orig/options.c 2004-07-26 16:43:48
f6c3b300
WD
168+++ options.c 2004-07-16 20:14:12
169@@ -85,6 +85,7 @@ int safe_symlinks = 0;
170 int copy_unsafe_links = 0;
171 int size_only = 0;
172 int bwlimit = 0;
f74d2272 173+int fuzzy = 0;
f6c3b300
WD
174 size_t bwlimit_writemax = 0;
175 int delete_after = 0;
176 int only_existing = 0;
b952a177 177@@ -279,6 +280,7 @@ void usage(enum logcode F)
c2530f70 178 rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n");
f0533c4c
WD
179 rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
180 rprintf(F," --link-dest=DIR create hardlinks to DIR for unchanged files\n");
181+ rprintf(F," --fuzzy use similar file as basis if basis doesn't exist\n");
182 rprintf(F," -P equivalent to --partial --progress\n");
183 rprintf(F," -z, --compress compress file data\n");
184 rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n");
b952a177 185@@ -378,6 +380,7 @@ static struct poptOption long_options[]
f0533c4c
WD
186 {"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
187 {"compare-dest", 0, POPT_ARG_STRING, &compare_dest, 0, 0, 0 },
188 {"link-dest", 0, POPT_ARG_STRING, &compare_dest, OPT_LINK_DEST, 0, 0 },
f74d2272 189+ {"fuzzy", 0, POPT_ARG_NONE, &fuzzy, 0, 0, 0 },
f0533c4c
WD
190 /* TODO: Should this take an optional int giving the compression level? */
191 {"compress", 'z', POPT_ARG_NONE, &do_compression, 0, 0, 0 },
192 {"daemon", 0, POPT_ARG_NONE, &daemon_opt, 0, 0, 0 },
b952a177 193@@ -1039,6 +1042,9 @@ void server_options(char **args,int *arg
f74d2272 194 }
241013b4 195 }
7b675ff5 196
241013b4
MP
197+ if (fuzzy && am_sender)
198+ args[ac++] = "--fuzzy";
7b675ff5 199+
241013b4 200 *argc = ac;
f74d2272 201 return;
7b675ff5 202
b952a177
WD
203--- orig/receiver.c 2004-07-23 21:59:07
204+++ receiver.c 2004-07-23 22:08:03
205@@ -39,7 +39,6 @@ extern int cvs_exclude;
58118c25
WD
206 extern int io_error;
207 extern char *tmpdir;
b952a177 208 extern char *partial_dir;
58118c25
WD
209-extern char *compare_dest;
210 extern int make_backups;
211 extern int do_progress;
212 extern char *backup_dir;
b952a177 213--- orig/rsync.yo 2004-07-28 02:26:19
824abc86 214+++ rsync.yo 2004-07-03 19:27:25
b952a177 215@@ -327,6 +327,7 @@ verb(
f0533c4c
WD
216 -T --temp-dir=DIR create temporary files in directory DIR
217 --compare-dest=DIR also compare received files relative to DIR
218 --link-dest=DIR create hardlinks to DIR for unchanged files
219+ --fuzzy use similar file as basis if basis is gone
220 -P equivalent to --partial --progress
221 -z, --compress compress file data
222 -C, --cvs-exclude auto ignore files in the same way CVS does