1 /*-
2  * Copyright (c) 2002-2005 MAEKAWA Masahide <maekawa@cvsync.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/types.h>
31 
32 #include <stdlib.h>
33 
34 #include <errno.h>
35 #include <limits.h>
36 #include <pthread.h>
37 #include <string.h>
38 
39 #include "compat_stdbool.h"
40 #include "compat_stdint.h"
41 #include "compat_inttypes.h"
42 #include "compat_limits.h"
43 #include "basedef.h"
44 
45 #include "cvsync.h"
46 #include "cvsync_attr.h"
47 #include "filetypes.h"
48 #include "hash.h"
49 #include "mux.h"
50 #include "rdiff.h"
51 
52 #include "filecmp.h"
53 #include "updater.h"
54 
55 bool
filecmp_rdiff_update(struct filecmp_args * fca,struct cvsync_file * cfp)56 filecmp_rdiff_update(struct filecmp_args *fca, struct cvsync_file *cfp)
57 {
58 	static const uint8_t _cmds[3] = { 0x00, 0x01, UPDATER_UPDATE_RDIFF };
59 	static const uint8_t _cmde[3] = { 0x00, 0x01, UPDATER_UPDATE_END };
60 	const struct hash_args *hashops = fca->fca_hash_ops;
61 	struct cvsync_attr *cap = &fca->fca_attr;
62 	uint64_t fsize, offset = 0;
63 	uint32_t bsize, length = 0, weak;
64 	uint8_t *cmd = fca->fca_cmd, *sp, *bp, *sv_sp;
65 	size_t rsize, len, n, i;
66 
67 	if ((cap->ca_type != FILETYPE_FILE) &&
68 	    (cap->ca_type != FILETYPE_RCS) &&
69 	    (cap->ca_type != FILETYPE_RCS_ATTIC)) {
70 		return (false);
71 	}
72 
73 	if (!mux_recv(fca->fca_mux, MUX_FILECMP_IN, cmd, 12))
74 		return (false);
75 	fsize = GetDDWord(cmd);
76 	bsize = GetDWord(&cmd[8]);
77 	n = (size_t)(fsize / bsize);
78 	if ((rsize = (size_t)(fsize % bsize)) != 0)
79 		n++;
80 	else
81 		rsize = bsize;
82 
83 	if (!mux_send(fca->fca_mux, MUX_UPDATER, _cmds, sizeof(_cmds)))
84 		return (false);
85 
86 	sp = cfp->cf_addr;
87 	bp = sp + (size_t)cfp->cf_size;
88 
89 	for (i = 0 ; i < n ; i++) {
90 		if (!mux_recv(fca->fca_mux, MUX_FILECMP_IN, cmd, 4))
91 			return (false);
92 		weak = GetDWord(cmd);
93 		if (!mux_recv(fca->fca_mux, MUX_FILECMP_IN, fca->fca_hash,
94 			      hashops->length)) {
95 			return (false);
96 		}
97 		if (sp >= bp)
98 			continue;
99 
100 		if (i != n - 1)
101 			len = bsize;
102 		else
103 			len = rsize;
104 
105 		sv_sp = sp;
106 		if ((sp = rdiff_search(sp, bp, bsize, len, weak, fca->fca_hash,
107 				       hashops)) == NULL) {
108 			sp = sv_sp;
109 			continue;
110 		}
111 
112 		if ((len = sp - sv_sp) > 0) {
113 			if (length > 0) {
114 				if (!rdiff_copy(fca->fca_mux, MUX_UPDATER,
115 						(off_t)offset, length)) {
116 					return (false);
117 				}
118 				length = 0;
119 			}
120 			if (!rdiff_data(fca->fca_mux, MUX_UPDATER, sv_sp, len))
121 				return (false);
122 		}
123 
124 		if ((len = (size_t)(fsize - i * bsize)) > bsize)
125 			len = bsize;
126 
127 		sp += len;
128 
129 		if (length == 0) {
130 			offset = i * bsize;
131 			length = len;
132 			continue;
133 		}
134 		if (offset + length == i * bsize) {
135 			length += len;
136 			continue;
137 		}
138 
139 		if (!rdiff_copy(fca->fca_mux, MUX_UPDATER, (off_t)offset,
140 				length)) {
141 			return (false);
142 		}
143 		if (!rdiff_copy(fca->fca_mux, MUX_UPDATER, (off_t)(i * bsize),
144 				len)) {
145 			return (false);
146 		}
147 
148 		length = 0;
149 	}
150 	if ((length > 0) && ((uint64_t)length < fsize)) {
151 		if (!rdiff_copy(fca->fca_mux, MUX_UPDATER, (off_t)offset,
152 				length)) {
153 			return (false);
154 		}
155 		length = 0;
156 	}
157 	if (sp < bp) {
158 		if (length > 0) {
159 			if (!rdiff_copy(fca->fca_mux, MUX_UPDATER,
160 					(off_t)offset, length)) {
161 				return (false);
162 			}
163 		}
164 		if (!rdiff_data(fca->fca_mux, MUX_UPDATER, sp,
165 				(size_t)(bp - sp))) {
166 			return (false);
167 		}
168 	}
169 	if (!rdiff_eof(fca->fca_mux, MUX_UPDATER))
170 		return (false);
171 
172 	if (!(*hashops->init)(&fca->fca_hash_ctx))
173 		return (false);
174 	(*hashops->update)(fca->fca_hash_ctx, cfp->cf_addr,
175 			   (size_t)cfp->cf_size);
176 	(*hashops->final)(fca->fca_hash_ctx, cmd);
177 
178 	if (!mux_send(fca->fca_mux, MUX_UPDATER, cmd, hashops->length))
179 		return (false);
180 
181 	if (!mux_send(fca->fca_mux, MUX_UPDATER, _cmde, sizeof(_cmde)))
182 		return (false);
183 
184 	return (true);
185 }
186 
187 bool
filecmp_rdiff_ignore(struct filecmp_args * fca)188 filecmp_rdiff_ignore(struct filecmp_args *fca)
189 {
190 	const struct hash_args *hashops = fca->fca_hash_ops;
191 	struct cvsync_attr *cap = &fca->fca_attr;
192 	uint64_t fsize;
193 	uint32_t bsize;
194 	uint8_t *cmd = fca->fca_cmd;
195 	size_t n, i;
196 
197 	if ((cap->ca_type != FILETYPE_FILE) &&
198 	    (cap->ca_type != FILETYPE_RCS) &&
199 	    (cap->ca_type != FILETYPE_RCS_ATTIC)) {
200 		return (false);
201 	}
202 
203 	if (!mux_recv(fca->fca_mux, MUX_FILECMP_IN, cmd, 12))
204 		return (false);
205 	fsize = GetDDWord(cmd);
206 	bsize = GetDWord(&cmd[8]);
207 	n = (size_t)(fsize / bsize);
208 	if ((fsize % bsize) != 0)
209 		n++;
210 
211 	for (i = 0 ; i < n ; i++) {
212 		if (!mux_recv(fca->fca_mux, MUX_FILECMP_IN, cmd,
213 			      hashops->length + 4)) {
214 			return (false);
215 		}
216 	}
217 
218 	return (true);
219 }
220 
221 bool
filecmp_rdiff_ischanged(struct filecmp_args * fca,struct cvsync_file * cfp)222 filecmp_rdiff_ischanged(struct filecmp_args *fca, struct cvsync_file *cfp)
223 {
224 	const struct hash_args *hashops = fca->fca_hash_ops;
225 	uint64_t fsize;
226 	uint32_t bsize, weak;
227 	uint8_t *cmd = fca->fca_cmd, *sp, *bp;
228 	size_t len, n, i = 0;
229 
230 	if (!mux_recv(fca->fca_mux, MUX_FILECMP_IN, cmd, 12))
231 		return (false);
232 	fsize = GetDDWord(cmd);
233 	bsize = GetDWord(&cmd[8]);
234 
235 	n = (size_t)(fsize / bsize);
236 	if ((fsize % bsize) != 0)
237 		n++;
238 
239 	sp = cfp->cf_addr;
240 	bp = sp + (size_t)fsize;
241 
242 	if ((uint64_t)cfp->cf_size == fsize) {
243 		while (i < n) {
244 			if (!mux_recv(fca->fca_mux, MUX_FILECMP_IN, cmd, 4))
245 				return (false);
246 			weak = GetDWord(cmd);
247 			if (!mux_recv(fca->fca_mux, MUX_FILECMP_IN, cmd,
248 				      hashops->length)) {
249 				return (false);
250 			}
251 			i++;
252 
253 			if ((len = bp - sp) > bsize)
254 				len = bsize;
255 			if (rdiff_weak(sp, len) != weak)
256 				break;
257 
258 			if (!(*hashops->init)(&fca->fca_hash_ctx))
259 				return (false);
260 			(*hashops->update)(fca->fca_hash_ctx, sp, len);
261 			(*hashops->final)(fca->fca_hash_ctx, fca->fca_hash);
262 
263 			if (memcmp(fca->fca_hash, cmd, hashops->length) != 0)
264 				break;
265 
266 			sp += len;
267 		}
268 		if (i == n)
269 			return (true);
270 	}
271 
272 	len = (n - i) * (hashops->length + 4);
273 
274 	while (len > 0) {
275 		if (len > fca->fca_cmdmax)
276 			n = fca->fca_cmdmax;
277 		else
278 			n = len;
279 		mux_recv(fca->fca_mux, MUX_FILECMP_IN, cmd, n);
280 		len -= n;
281 	}
282 
283 	return (false);
284 }
285