Blob


1 /*
2 * Copyright (c) 2020 Ori Bernstein
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include <sys/types.h>
18 #include <sys/queue.h>
20 #include <assert.h>
21 #include <limits.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sha1.h>
28 #include "got_error.h"
29 #include "got_object.h"
31 #include "got_lib_delta.h"
32 #include "got_lib_object.h"
34 struct Dblock {
35 unsigned char *buf;
36 int len;
37 int off;
38 uint64_t hash;
39 };
41 struct Dtab {
42 unsigned char *base;
43 int nbase;
44 struct Dblock *b;
45 int nb;
46 int sz;
47 };
49 struct Delta {
50 int cpy;
51 int off;
52 int len;
53 };
55 enum {
56 Minchunk = 128,
57 Maxchunk = 8192,
58 Splitmask = (1 << 8) - 1,
60 };
62 static uint32_t geartab[] = {
63 0x67ed26b7, 0x32da500c, 0x53d0fee0, 0xce387dc7, 0xcd406d90, 0x2e83a4d4, 0x9fc9a38d, 0xb67259dc,
64 0xca6b1722, 0x6d2ea08c, 0x235cea2e, 0x3149bb5f, 0x1beda787, 0x2a6b77d5, 0x2f22d9ac, 0x91fc0544,
65 0xe413acfa, 0x5a30ff7a, 0xad6fdde0, 0x444fd0f5, 0x7ad87864, 0x58c5ff05, 0x8d2ec336, 0x2371f853,
66 0x550f8572, 0x6aa448dd, 0x7c9ddbcf, 0x95221e14, 0x2a82ec33, 0xcbec5a78, 0xc6795a0d, 0x243995b7,
67 0x1c909a2f, 0x4fded51c, 0x635d334b, 0x0e2b9999, 0x2702968d, 0x856de1d5, 0x3325d60e, 0xeb6a7502,
68 0xec2a9844, 0x0905835a, 0xa1820375, 0xa4be5cab, 0x96a6c058, 0x2c2ccd70, 0xba40fce3, 0xd794c46b,
69 0x8fbae83e, 0xc3aa7899, 0x3d3ff8ed, 0xa0d42b5b, 0x571c0c97, 0xd2811516, 0xf7e7b96c, 0x4fd2fcbd,
70 0xe2fdec94, 0x282cc436, 0x78e8e95c, 0x80a3b613, 0xcfbee20c, 0xd4a32d1c, 0x2a12ff13, 0x6af82936,
71 0xe5630258, 0x8efa6a98, 0x294fb2d1, 0xdeb57086, 0x5f0fddb3, 0xeceda7ce, 0x4c87305f, 0x3a6d3307,
72 0xe22d2942, 0x9d060217, 0x1e42ed02, 0xb6f63b52, 0x4367f39f, 0x055cf262, 0x03a461b2, 0x5ef9e382,
73 0x386bc03a, 0x2a1e79c7, 0xf1a0058b, 0xd4d2dea9, 0x56baf37d, 0x5daff6cc, 0xf03a951d, 0xaef7de45,
74 0xa8f4581e, 0x3960b555, 0xffbfff6d, 0xbe702a23, 0x8f5b6d6f, 0x061739fb, 0x98696f47, 0x3fd596d4,
75 0x151eac6b, 0xa9fcc4f5, 0x69181a12, 0x3ac5a107, 0xb5198fe7, 0x96bcb1da, 0x1b5ddf8e, 0xc757d650,
76 0x65865c3a, 0x8fc0a41a, 0x87435536, 0x99eda6f2, 0x41874794, 0x29cff4e8, 0xb70efd9a, 0x3103f6e7,
77 0x84d2453b, 0x15a450bd, 0x74f49af1, 0x60f664b1, 0xa1c86935, 0xfdafbce1, 0xe36353e3, 0x5d9ba739,
78 0xbc0559ba, 0x708b0054, 0xd41d808c, 0xb2f31723, 0x9027c41f, 0xf136d165, 0xb5374b12, 0x9420a6ac,
79 0x273958b6, 0xe6c2fad0, 0xebdc1f21, 0xfb33af8b, 0xc71c25cd, 0xe9a2d8e5, 0xbeb38a50, 0xbceb7cc2,
80 0x4e4e73f0, 0xcd6c251d, 0xde4c032c, 0x4b04ac30, 0x725b8b21, 0x4eb8c33b, 0x20d07b75, 0x0567aa63,
81 0xb56b2bb7, 0xc1f5fd3a, 0xcafd35ca, 0x470dd4da, 0xfe4f94cd, 0xfb8de424, 0xe8dbcf40, 0xfe50a37a,
82 0x62db5b5d, 0xf32f4ab6, 0x2c4a8a51, 0x18473dc0, 0xfe0cbb6e, 0xfe399efd, 0xdf34ecc9, 0x6ccd5055,
83 0x46097073, 0x139135c2, 0x721c76f6, 0x1c6a94b4, 0x6eee014d, 0x8a508e02, 0x3da538f5, 0x280d394f,
84 0x5248a0c4, 0x3ce94c6c, 0x9a71ad3a, 0x8493dd05, 0xe43f0ab6, 0x18e4ed42, 0x6c5c0e09, 0x42b06ec9,
85 0x8d330343, 0xa45b6f59, 0x2a573c0c, 0xd7fd3de6, 0xeedeab68, 0x5c84dafc, 0xbbd1b1a8, 0xa3ce1ad1,
86 0x85b70bed, 0xb6add07f, 0xa531309c, 0x8f8ab852, 0x564de332, 0xeac9ed0c, 0x73da402c, 0x3ec52761,
87 0x43af2f4d, 0xd6ff45c8, 0x4c367462, 0xd553bd6a, 0x44724855, 0x3b2aa728, 0x56e5eb65, 0xeaf16173,
88 0x33fa42ff, 0xd714bb5d, 0xfbd0a3b9, 0xaf517134, 0x9416c8cd, 0x534cf94f, 0x548947c2, 0x34193569,
89 0x32f4389a, 0xfe7028bc, 0xed73b1ed, 0x9db95770, 0x468e3922, 0x0440c3cd, 0x60059a62, 0x33504562,
90 0x2b229fbd, 0x5174dca5, 0xf7028752, 0xd63c6aa8, 0x31276f38, 0x0646721c, 0xb0191da8, 0xe00e6de0,
91 0x9eac1a6e, 0x9f7628a5, 0xed6c06ea, 0x0bb8af15, 0xf119fb12, 0x38693c1c, 0x732bc0fe, 0x84953275,
92 0xb82ec888, 0x33a4f1b3, 0x3099835e, 0x028a8782, 0x5fdd51d7, 0xc6c717b3, 0xb06caf71, 0x17c8c111,
93 0x61bad754, 0x9fd03061, 0xe09df1af, 0x3bc9eb73, 0x85878413, 0x9889aaf2, 0x3f5a9e46, 0x42c9f01f,
94 0x9984a4f4, 0xd5de43cc, 0xd294daed, 0xbecba2d2, 0xf1f6e72c, 0x5551128a, 0x83af87e2, 0x6f0342ba,
95 };
97 static uint64_t
98 hash(unsigned char *p, int n)
99 {
100 unsigned char buf[SHA1_DIGEST_LENGTH];
101 uint64_t h;
102 SHA1Data(p, n, buf);
103 memcpy(&h, buf, sizeof(h));
104 return be64toh(h);
107 static const struct got_error *
108 addblk(struct Dtab *dt, void *buf, int len, int off, uint64_t h)
110 int i, sz, probe;
111 struct Dblock *db;
113 probe = h % dt->sz;
114 while (dt->b[probe].buf != NULL) {
115 if (len == dt->b[probe].len &&
116 memcmp(buf, dt->b[probe].buf, len) == 0)
117 return NULL;
118 probe = (probe + 1) % dt->sz;
120 assert(dt->b[probe].buf == NULL);
121 dt->b[probe].buf = buf;
122 dt->b[probe].len = len;
123 dt->b[probe].off = off;
124 dt->b[probe].hash = h;
125 dt->nb++;
126 if (dt->sz < 2 * dt->nb) {
127 sz = dt->sz;
128 db = dt->b;
129 dt->sz *= 2;
130 dt->nb = 0;
131 dt->b = calloc(dt->sz, sizeof(struct Dblock));
132 if (dt->b == NULL)
133 return got_error_from_errno("calloc");
134 for (i = 0; i < sz; i++) {
135 if (db[i].buf != NULL)
136 return addblk(dt, db[i].buf, db[i].len,
137 db[i].off, db[i].hash);
139 free(db);
142 return NULL;
145 static struct Dblock *
146 lookup(struct Dtab *dt, unsigned char *p, int n)
148 int probe;
149 uint64_t h;
151 h = hash(p, n);
152 for (probe = h % dt->sz; dt->b[probe].buf != NULL;
153 probe = (probe + 1) % dt->sz) {
154 if (dt->b[probe].hash != h)
155 continue;
156 if (n != dt->b[probe].len)
157 continue;
158 if (memcmp(p, dt->b[probe].buf, n) != 0)
159 continue;
160 return &dt->b[probe];
162 return NULL;
165 static int
166 nextblk(unsigned char *s, unsigned char *e)
168 uint32_t gh;
169 unsigned char *p;
171 if ((e - s) < Minchunk)
172 return e - s;
173 p = s + Minchunk;
174 if ((e - s) > Maxchunk)
175 e = s + Maxchunk;
176 gh = 0;
177 while (p != e) {
178 gh = (gh << 1) + geartab[*p++];
179 if ((gh & Splitmask) == 0)
180 break;
182 return p - s;
185 const struct got_error *
186 dtinit(struct Dtab *dt, struct got_object *obj)
188 unsigned char *s = NULL, *e;
189 uint64_t h;
190 long n, o;
192 o = 0;
193 #ifdef notyet
194 s = (unsigned char *)obj->data;
195 #endif
196 e = s + obj->size;
197 dt->nb = 0;
198 dt->sz = 128;
199 dt->b = calloc(dt->sz, sizeof(struct Dblock));
200 if (dt->b == NULL)
201 return got_error_from_errno("calloc");
202 #ifdef notyet
203 dt->base = (unsigned char *)obj->data;
204 #endif
205 dt->nbase = obj->size;
206 while (s != e) {
207 n = nextblk(s, e);
208 h = hash(s, n);
209 addblk(dt, s, n, o, h);
210 s += n;
211 o += n;
214 return NULL;
217 void
218 dtclear(struct Dtab *dt)
220 free(dt->b);
223 static const struct got_error *
224 emitdelta(struct Delta **pd, int *nd, int cpy, int off, int len)
226 struct Delta *d, *p;
228 *nd += 1;
229 p = reallocarray(*pd, *nd, sizeof(struct Delta));
230 if (p == NULL)
231 return got_error_from_errno("realloc");
232 *pd = p;
233 d = &(*pd)[*nd - 1];
234 d->cpy = cpy;
235 d->off = off;
236 d->len = len;
237 return NULL;
240 static int
241 stretch(struct Dtab *dt, struct Dblock *b, unsigned char *s,
242 unsigned char *e, int n)
244 unsigned char *p, *q, *eb;
246 if (b == NULL)
247 return n;
248 p = s + n;
249 q = dt->base + b->off + n;
250 eb = dt->base + dt->nbase;
251 while (n < (1 << 24)) {
252 if (p == e || q == eb)
253 break;
254 if (*p != *q)
255 break;
256 p++;
257 q++;
258 n++;
260 return n;
263 struct Delta *
264 deltify(struct got_object *obj, struct Dtab *dt, int *pnd)
266 struct Delta *d;
267 struct Dblock *b;
268 unsigned char *s = NULL, *e;
269 long n, o;
271 o = 0;
272 d = NULL;
273 #ifdef notyet
274 s = (unsigned char *)obj->data;
275 #endif
276 e = s + obj->size;
277 *pnd = 0;
278 while (s != e) {
279 n = nextblk(s, e);
280 b = lookup(dt, s, n);
281 n = stretch(dt, b, s, e, n);
282 if (b != NULL)
283 emitdelta(&d, pnd, 1, b->off, n);
284 else
285 emitdelta(&d, pnd, 0, o, n);
286 s += n;
287 o += n;
289 return d;