util.c (5924B)
1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright 2003-2005 Colin Percival 5 * Copyright 2011-2012 Thieu Le 6 * Copyright 2012 Matthew Endsley 7 * Copyright 2020 Stephen Gregoratto 8 * All rights reserved 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted providing that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 28 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "config.h" 33 #include <sys/stat.h> 34 35 #if HAVE_ERR 36 #include <err.h> 37 #endif 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include "bsdiff.h" 45 46 void 47 split(off_t *I, off_t *V, off_t start, off_t len, off_t h) 48 { 49 off_t i, j, k, x, tmp, jj, kk; 50 51 if (len < 16) { 52 for (k = start; k < start + len; k += j) { 53 j = 1; 54 x = V[I[k] + h]; 55 for (i = 1; k + i < start + len; i++) { 56 if (V[I[k + i] + h] < x) { 57 x = V[I[k + i] + h]; 58 j = 0; 59 } 60 if (V[I[k + i] + h] == x) { 61 tmp = I[k + j]; 62 I[k + j] = I[k + i]; 63 I[k + i] = tmp; 64 j++; 65 } 66 } 67 for (i = 0; i < j; i++) 68 V[I[k + i]] = k + j - 1; 69 if (j == 1) 70 I[k] = -1; 71 } 72 return; 73 } 74 75 x = V[I[start + len / 2] + h]; 76 jj = kk = 0; 77 for (i = start; i < start + len; i++) { 78 if (V[I[i] + h] < x) 79 jj++; 80 if (V[I[i] + h] == x) 81 kk++; 82 } 83 jj += start; 84 kk += jj; 85 86 i = start; 87 j = k = 0; 88 while (i < jj) { 89 if (V[I[i] + h] < x) { 90 i++; 91 } else if (V[I[i] + h] == x) { 92 tmp = I[i]; 93 I[i] = I[jj + j]; 94 I[jj + j] = tmp; 95 j++; 96 } else { 97 tmp = I[i]; 98 I[i] = I[kk + k]; 99 I[kk + k] = tmp; 100 k++; 101 } 102 } 103 104 while (jj + j < kk) { 105 if (V[I[jj + j] + h] == x) { 106 j++; 107 } else { 108 tmp = I[jj + j]; 109 I[jj + j] = I[kk + k]; 110 I[kk + k] = tmp; 111 k++; 112 } 113 } 114 115 if (jj > start) 116 split(I, V, start, jj - start, h); 117 118 for (i = 0; i < kk - jj; i++) 119 V[I[jj + i]] = kk - 1; 120 if (jj == kk - 1) 121 I[jj] = -1; 122 123 if (start + len > kk) 124 split(I, V, kk, start + len - kk, h); 125 } 126 127 void 128 qsufsort(off_t *I, off_t *V, uint8_t *old, off_t oldsize) 129 { 130 off_t buckets[256]; 131 off_t i, h, len; 132 133 for (i = 0; i < 256; i++) 134 buckets[i] = 0; 135 for (i = 0; i < oldsize; i++) 136 buckets[old[i]]++; 137 for (i = 1; i < 256; i++) 138 buckets[i] += buckets[i - 1]; 139 for (i = 255; i > 0; i--) 140 buckets[i] = buckets[i - 1]; 141 buckets[0] = 0; 142 143 for (i = 0; i < oldsize; i++) 144 I[++buckets[old[i]]] = i; 145 I[0] = oldsize; 146 for (i = 0; i < oldsize; i++) 147 V[i] = buckets[old[i]]; 148 V[oldsize] = 0; 149 for (i = 1; i < 256; i++) 150 if (buckets[i] == buckets[i - 1] + 1) 151 I[buckets[i]] = -1; 152 I[0] = -1; 153 154 for (h = 1; I[0] != -(oldsize + 1); h += h) { 155 len = 0; 156 for (i = 0; i < oldsize + 1;) { 157 if (I[i] < 0) { 158 len -= I[i]; 159 i -= I[i]; 160 } else { 161 if (len) 162 I[i - len] = -len; 163 len = V[I[i]] + 1 - i; 164 split(I, V, i, len, h); 165 i += len; 166 len = 0; 167 } 168 } 169 if (len) 170 I[i - len] = -len; 171 } 172 173 for (i = 0; i < oldsize + 1; i++) 174 I[V[i]] = i; 175 } 176 177 off_t 178 matchlen(uint8_t *old, off_t oldsize, uint8_t *new, off_t newsize) 179 { 180 off_t i; 181 182 for (i = 0; (i < oldsize) && (i < newsize); i++) 183 if (old[i] != new[i]) 184 break; 185 186 return i; 187 } 188 189 off_t 190 search(off_t *I, uint8_t *old, off_t oldsize, uint8_t *new, off_t newsize, 191 off_t st, off_t en, off_t *pos) 192 { 193 off_t x, y; 194 195 if (en - st < 2) { 196 x = matchlen(old + I[st], oldsize - I[st], new, newsize); 197 y = matchlen(old + I[en], oldsize - I[en], new, newsize); 198 199 if (x > y) { 200 *pos = I[st]; 201 return x; 202 } else { 203 *pos = I[en]; 204 return y; 205 } 206 } 207 208 x = st + (en - st) / 2; 209 if (memcmp(old + I[x], new, MIN(oldsize - I[x], newsize)) <= 0) 210 return search(I, old, oldsize, new, newsize, x, en, pos); 211 else 212 return search(I, old, oldsize, new, newsize, st, x, pos); 213 } 214 215 void 216 offtout(off_t x, uint8_t *buf) 217 { 218 off_t y; 219 220 y = x < 0 ? -x : x; 221 222 for (size_t i = 0; i <= 6; i++) { 223 buf[i] = y % 256; 224 y -= buf[i]; 225 y /= 256; 226 } 227 buf[7] = y % 256; 228 229 if (x < 0) 230 buf[7] |= 0x80; 231 } 232 233 off_t 234 offtin(uint8_t *buf) 235 { 236 off_t y; 237 238 y = buf[7] & 0x7F; 239 for (int i = 6; i >= 0; i--) { 240 y *= 256; 241 y += buf[i]; 242 } 243 244 if (buf[7] & 0x80) 245 y = -y; 246 247 return y; 248 } 249 250 void 251 usage(void) 252 { 253 fprintf(stderr, "usage: %s oldfile newfile patchfile\n", getprogname()); 254 255 exit(1); 256 } 257 258 uint8_t * 259 readfile(char *path, off_t *size, struct stat *st) 260 { 261 uint8_t *buf = NULL; 262 int fd; 263 264 if ((path == NULL || *path == '\0') || 265 size == NULL || st == NULL) 266 errx(1, "readfile: bad args"); 267 268 if ((fd = open(path, O_RDONLY, 0)) == -1) 269 err(1, "%s: open", path); 270 if (fstat(fd, st) == -1) 271 err(1, "%s: fstat", path); 272 /* 273 * Allocate size + 1 bytes to ensure that we never 274 * try to malloc(0) and get a NULL pointer. 275 */ 276 *size = st->st_size; 277 if ((buf = reallocarray(NULL, *size + 1, 1)) == NULL) 278 err(1, "%s: reallocarray", path); 279 280 if (read(fd, buf, *size) == -1) 281 err(1, "%s: read", path); 282 if (close(fd) == -1) 283 err(1, "%s: close", path); 284 285 return buf; 286 }