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 <pthread.h>
33 #include <string.h>
34 
35 #include "compat_stdbool.h"
36 #include "compat_stdint.h"
37 #include "compat_inttypes.h"
38 #include "basedef.h"
39 
40 #include "hash.h"
41 #include "logmsg.h"
42 #include "mux.h"
43 #include "rdiff.h"
44 
45 uint32_t
rdiff_weak(const uint8_t * addr,size_t size)46 rdiff_weak(const uint8_t *addr, size_t size)
47 {
48 	uint16_t l_rv = 0, h_rv = 0;
49 	size_t i;
50 
51 	for (i = 0 ; i < size ; i++) {
52 		l_rv += addr[i];
53 		h_rv += l_rv;
54 	}
55 
56 	return ((h_rv << 16) | l_rv);
57 }
58 
59 uint8_t *
rdiff_search(uint8_t * sp,uint8_t * bp,uint32_t bsize,size_t length,uint32_t weak,uint8_t * strong,const struct hash_args * hashops)60 rdiff_search(uint8_t *sp, uint8_t *bp, uint32_t bsize, size_t length,
61 	     uint32_t weak, uint8_t *strong, const struct hash_args *hashops)
62 {
63 	uint32_t w;
64 	uint16_t wl, wh, rwl, rwh;
65 	uint8_t hash[HASH_MAXLEN];
66 	void *ctx;
67 	size_t len;
68 
69 	if ((len = bp - sp) < length)
70 		return (NULL);
71 	if (len > bsize)
72 		len = bsize;
73 	if ((w = rdiff_weak(sp, len)) == weak) {
74 		if (!(*hashops->init)(&ctx)) {
75 			logmsg_err("rdiff error: hash init");
76 			return (NULL);
77 		}
78 		(*hashops->update)(ctx, sp, len);
79 		(*hashops->final)(ctx, hash);
80 
81 		if (memcmp(hash, strong, hashops->length) == 0)
82 			return (sp);
83 	}
84 	rwl = RDIFF_WEAK_LOW(weak);
85 	rwh = RDIFF_WEAK_HIGH(weak);
86 
87 	wl = RDIFF_WEAK_LOW(w);
88 	wh = RDIFF_WEAK_HIGH(w);
89 
90 	while (sp < bp) {
91 		if ((len = bp - sp) < length)
92 			return (NULL);
93 
94 		if (len > bsize) {
95 			wl = wl - sp[0] + sp[bsize];
96 			wh = wh - bsize * sp[0] + wl;
97 			len = bsize;
98 		} else {
99 			wl = wl - sp[0];
100 			wh = wh - len-- * sp[0];
101 		}
102 
103 		if ((rwl == wl) && (rwh == wh)) {
104 			if (!(*hashops->init)(&ctx)) {
105 				logmsg_err("rdiff error: hash init");
106 				return (NULL);
107 			}
108 			(*hashops->update)(ctx, sp + 1, len);
109 			(*hashops->final)(ctx, hash);
110 
111 			if (memcmp(hash, strong, hashops->length) == 0)
112 				return (sp + 1);
113 		}
114 
115 		sp++;
116 	}
117 
118 	return (NULL);
119 }
120 
121 bool
rdiff_copy(struct mux * mx,uint8_t chnum,off_t position,size_t length)122 rdiff_copy(struct mux *mx, uint8_t chnum, off_t position, size_t length)
123 {
124 	uint8_t cmd[RDIFF_MAXCMDLEN];
125 
126 	cmd[0] = RDIFF_CMD_COPY;
127 	SetDDWord(&cmd[1], position);
128 	SetDWord(&cmd[9], length);
129 
130 	if (!mux_send(mx, chnum, cmd, 13)) {
131 		logmsg_err("rdiff(COPY) error: send");
132 		return (false);
133 	}
134 
135 	return (true);
136 }
137 
138 bool
rdiff_data(struct mux * mx,uint8_t chnum,const void * buffer,size_t bufsize)139 rdiff_data(struct mux *mx, uint8_t chnum, const void *buffer, size_t bufsize)
140 {
141 	uint8_t cmd[RDIFF_MAXCMDLEN];
142 
143 	cmd[0] = RDIFF_CMD_DATA;
144 	SetDWord(&cmd[1], bufsize);
145 
146 	if (!mux_send(mx, chnum, cmd, 5)) {
147 		logmsg_err("rdiff(DATA) error: send");
148 		return (false);
149 	}
150 	if (!mux_send(mx, chnum, buffer, bufsize)) {
151 		logmsg_err("rdiff(DATA) error: send");
152 		return (false);
153 	}
154 
155 	return (true);
156 }
157 
158 bool
rdiff_eof(struct mux * mx,uint8_t chnum)159 rdiff_eof(struct mux *mx, uint8_t chnum)
160 {
161 	uint8_t cmd[RDIFF_MAXCMDLEN];
162 
163 	cmd[0] = RDIFF_CMD_EOF;
164 
165 	if (!mux_send(mx, chnum, cmd, 1)) {
166 		logmsg_err("rdiff(EOF) error: send");
167 		return (false);
168 	}
169 
170 	return (true);
171 }
172