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