bsdiff-portable

A more portable version of Colin Percival's bsdiff
git clone git://git.sgregoratto.me/bsdiff-portable
Log | Files | Refs | README | LICENSE

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 }