mirror of
https://github.com/clearlinux/bsdiff.git
synced 2026-09-04 12:51:29 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb522b1dc9 | ||
|
|
53ce8b6d66 | ||
|
|
02b6820a3d | ||
|
|
f563c9a475 | ||
|
|
72a6259228 | ||
|
|
5c2c4c76ac | ||
|
|
b45ff19ee4 | ||
|
|
fcd3298583 | ||
|
|
0d3d976fe4 | ||
|
|
f192356812 | ||
|
|
f81fb5a612 | ||
|
|
0322f0839c | ||
|
|
4807cb41f5 | ||
|
|
dd93df7347 | ||
|
|
0d1a46ed6c | ||
|
|
a1c17f3e9d | ||
|
|
9807f60b46 | ||
|
|
e27563e653 | ||
|
|
e0e8bcda58 | ||
|
|
2e5b80929c | ||
|
|
6127bd6095 | ||
|
|
85b1c5345b | ||
|
|
d039492824 | ||
|
|
43a817a2e5 | ||
|
|
4e868b4772 | ||
|
|
71b9d7e78a | ||
|
|
b46a4e2c0f |
+8
-2
@@ -1,4 +1,8 @@
|
||||
*~
|
||||
*.swp
|
||||
*.o
|
||||
*.i
|
||||
*.s
|
||||
.libs/
|
||||
*.lo
|
||||
*.pc
|
||||
@@ -19,13 +23,15 @@ install-sh
|
||||
libbsdiff.la
|
||||
libtool
|
||||
ltmain.sh
|
||||
m4/
|
||||
m4/*
|
||||
!m4/.gitignore
|
||||
missing
|
||||
src/.dirstamp
|
||||
src/*.gcda
|
||||
src/*.gcno
|
||||
stamp-h1
|
||||
bsdiff-*.tar.xz
|
||||
/bsdiff-*.tar.xz
|
||||
/bsdiff-*/
|
||||
test/*.diff
|
||||
test/*.out
|
||||
test/*.log
|
||||
|
||||
+32
-3
@@ -67,7 +67,8 @@ lib_LTLIBRARIES = \
|
||||
|
||||
libbsdiff_la_SOURCES = \
|
||||
src/diff.c \
|
||||
src/patch.c
|
||||
src/patch.c \
|
||||
src/sufsort.c
|
||||
|
||||
libbsdiff_la_LIBADD = \
|
||||
$(zlib_LIBS)
|
||||
@@ -96,11 +97,18 @@ libbsdiff_la_LDFLAGS = \
|
||||
-version-info $(LIBBSDIFF_CURRENT):$(LIBBSDIFF_REVISION):$(LIBBSDIFF_AGE) \
|
||||
-Wl,--version-script=$(top_srcdir)/src/bsdiff.sym
|
||||
|
||||
mostlyclean-local:
|
||||
-rm -f *.i
|
||||
-rm -f *.s
|
||||
|
||||
distclean-local:
|
||||
rm -rf aclocal.m4 ar-lib autom4te.cache config.guess config.h.in config.h.in~ config.sub configure depcomp install-sh ltmain.sh m4 Makefile.in missing compile
|
||||
-rm -f config.guess~
|
||||
-rm -f config.h.in~
|
||||
-rm -f config.sub~
|
||||
-rm -f configure~
|
||||
|
||||
install-exec-hook:
|
||||
perl findstatic.pl */*.o | grep -v Checking ||:
|
||||
perl $(top_srcdir)/findstatic.pl $(top_builddir)/src/*.o | grep -v Checking || :
|
||||
|
||||
TEST_EXTENSIONS = .sh
|
||||
|
||||
@@ -146,6 +154,27 @@ dist_check_SCRIPTS = \
|
||||
test/run.sh
|
||||
endif
|
||||
|
||||
compliant:
|
||||
@git diff --quiet --exit-code include src; ret=$$?; \
|
||||
if [ $$ret -eq 1 ]; then \
|
||||
echo "Error: can only check code style when include/ and src/ are clean."; \
|
||||
echo "Stash or commit your changes and try again."; \
|
||||
exit $$ret; \
|
||||
elif [ $$ret -gt 1 ]; then \
|
||||
exit $$ret; \
|
||||
fi; \
|
||||
clang-format -i -style=file include/*.h src/*.c; ret=$$?; \
|
||||
if [ $$ret -ne 0 ]; then \
|
||||
exit $$ret; \
|
||||
fi; \
|
||||
git diff --quiet --exit-code include src; ret=$$?; \
|
||||
if [ $$ret -eq 1 ]; then \
|
||||
echo "Code style issues found. Run 'git diff' to view issues."; \
|
||||
elif [ $$ret -eq 0 ]; then \
|
||||
echo "No code style issues found."; \
|
||||
fi; \
|
||||
exit $$ret
|
||||
|
||||
release:
|
||||
@git rev-parse v$(PACKAGE_VERSION) &> /dev/null; \
|
||||
if [ "$$?" -eq 0 ]; then \
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
## DISCONTINUATION OF PROJECT.
|
||||
|
||||
This project will no longer be maintained by Intel.
|
||||
|
||||
Intel will not provide or guarantee development of or support for this project, including but not limited to, maintenance, bug fixes, new releases or updates. Patches to this project are no longer accepted by Intel. If you have an ongoing need to use this project, are interested in independently developing it, or would like to maintain patches for the community, please create your own fork of the project.
|
||||
|
||||
Contact: webadmin@linux.intel.com
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
AC_PREREQ([2.66])
|
||||
AC_INIT([bsdiff], [1.0.2], [patrick.mccarty@intel.com])
|
||||
AC_INIT([bsdiff],[1.0.4],[patrick.mccarty@intel.com])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_STDC
|
||||
AC_LANG(C)
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_PREFIX_DEFAULT(/usr/local)
|
||||
|
||||
+4
-1
@@ -2,6 +2,7 @@
|
||||
#define __INCLUDE_GUARD_BSHEADER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h> // for u_char
|
||||
|
||||
#include "bsdiff.h"
|
||||
|
||||
@@ -58,7 +59,7 @@ struct header_v20 {
|
||||
uint64_t extra_length;
|
||||
uint64_t old_file_length;
|
||||
uint64_t new_file_length;
|
||||
uint64_t mtime; /* unused */
|
||||
uint64_t mtime; /* unused */
|
||||
uint32_t file_mode;
|
||||
uint32_t file_owner;
|
||||
uint32_t file_group;
|
||||
@@ -177,4 +178,6 @@ static inline int eblock_get_enc(enc_flags_t enc)
|
||||
}
|
||||
}
|
||||
|
||||
int qsufsort(int64_t *, int64_t *, u_char *, int64_t);
|
||||
|
||||
#endif
|
||||
|
||||
+236
-321
@@ -3,7 +3,7 @@
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
@@ -32,8 +32,6 @@ __FBSDID
|
||||
#define _GNU_SOURCE
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef BSDIFF_WITH_BZIP2
|
||||
#include <bzlib.h>
|
||||
#endif
|
||||
@@ -45,20 +43,20 @@ __FBSDID
|
||||
#include <lzma.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <endian.h>
|
||||
#include <grp.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <zlib.h>
|
||||
#include <endian.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "bsheader.h"
|
||||
|
||||
@@ -76,178 +74,12 @@ static int bsdiff_fulldl;
|
||||
#undef MIN
|
||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
/* NOTES:
|
||||
* I and V are chunks of memory (arrays) with length = (oldfile size +1) * sizeof(int64_t).
|
||||
* Additionally, we pass in arraylen now. The parent function qsufsort receives it, so it
|
||||
* should be available here as well for error checking.
|
||||
* start: is actually the point in the array sent in during the suffix sort, which sorts by
|
||||
* small blocks/chunks.
|
||||
* len: refers to the length of the current chunk being processed - NOT the array length(s).
|
||||
* h: will never be more than 8, and increases by *2 during suffix sort (h += h) */
|
||||
static void split(int64_t *I, int64_t *V, int64_t arraylen, int64_t start, int64_t len,
|
||||
int64_t h)
|
||||
{
|
||||
int64_t i, j, k, x, tmp, jj, kk;
|
||||
|
||||
if (len < 16) {
|
||||
for (k = start; k < start + len; k += j) {
|
||||
j = 1;
|
||||
x = V[I[k] + h];
|
||||
for (i = 1; k + i < start + len; i++) {
|
||||
if (V[I[k + i] + h] < x) {
|
||||
x = V[I[k + i] + h];
|
||||
j = 0;
|
||||
}
|
||||
if (V[I[k + i] + h] == x) {
|
||||
tmp = I[k + j];
|
||||
I[k + j] = I[k + i];
|
||||
I[k + i] = tmp;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < j; i++) {
|
||||
V[I[k + i]] = k + j - 1;
|
||||
}
|
||||
if (j == 1) {
|
||||
I[k] = -1;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
x = V[I[start + len / 2] + h];
|
||||
jj = 0;
|
||||
kk = 0;
|
||||
for (i = start; i < start + len; i++) {
|
||||
if (V[I[i] + h] < x) {
|
||||
jj++;
|
||||
}
|
||||
if (V[I[i] + h] == x) {
|
||||
kk++;
|
||||
}
|
||||
}
|
||||
jj += start;
|
||||
kk += jj;
|
||||
|
||||
i = start;
|
||||
j = 0;
|
||||
k = 0;
|
||||
while (i < jj) {
|
||||
if (V[I[i] + h] < x) {
|
||||
i++;
|
||||
} else if (V[I[i] + h] == x) {
|
||||
tmp = I[i];
|
||||
I[i] = I[jj + j];
|
||||
I[jj + j] = tmp;
|
||||
j++;
|
||||
} else {
|
||||
tmp = I[i];
|
||||
I[i] = I[kk + k];
|
||||
I[kk + k] = tmp;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
while (jj + j < kk) {
|
||||
if (V[I[jj + j] + h] == x) {
|
||||
j++;
|
||||
} else {
|
||||
tmp = I[jj + j];
|
||||
I[jj + j] = I[kk + k];
|
||||
I[kk + k] = tmp;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
if (jj > start) {
|
||||
split(I, V, arraylen, start, jj - start, h);
|
||||
}
|
||||
|
||||
for (i = 0; i < kk - jj; i++) {
|
||||
V[I[jj + i]] = kk - 1;
|
||||
}
|
||||
if (jj == kk - 1) {
|
||||
I[jj] = -1;
|
||||
}
|
||||
|
||||
if (start + len > kk) {
|
||||
split(I, V, arraylen, kk, start + len - kk, h);
|
||||
}
|
||||
}
|
||||
|
||||
/* The old_data (previous file data) is passed into this suffix sort and sorted
|
||||
* accordingly using the I and V arrays, which are both of length oldsize +1. */
|
||||
static int qsufsort(int64_t *I, int64_t *V, u_char *old, int64_t oldsize)
|
||||
{
|
||||
int64_t buckets[QSUF_BUCKET_SIZE];
|
||||
int64_t i, h, len;
|
||||
|
||||
for (i = 0; i < QSUF_BUCKET_SIZE; i++) {
|
||||
buckets[i] = 0;
|
||||
}
|
||||
for (i = 0; i < oldsize; i++) {
|
||||
buckets[old[i]]++;
|
||||
}
|
||||
for (i = 1; i < QSUF_BUCKET_SIZE; i++) {
|
||||
buckets[i] += buckets[i - 1];
|
||||
}
|
||||
for (i = QSUF_BUCKET_SIZE - 1; i > 0; i--) {
|
||||
buckets[i] = buckets[i - 1];
|
||||
}
|
||||
buckets[0] = 0;
|
||||
|
||||
for (i = 0; i < oldsize; i++) {
|
||||
if (buckets[old[i]] > oldsize + 1) {
|
||||
return -1;
|
||||
}
|
||||
I[++buckets[old[i]]] = i;
|
||||
}
|
||||
|
||||
for (i = 0; i < oldsize; i++) {
|
||||
V[i] = buckets[old[i]];
|
||||
}
|
||||
V[oldsize] = 0;
|
||||
for (i = 1; i < QSUF_BUCKET_SIZE; i++) {
|
||||
if (buckets[i] == buckets[i - 1] + 1) {
|
||||
I[buckets[i]] = -1;
|
||||
}
|
||||
}
|
||||
I[0] = -1;
|
||||
|
||||
for (h = 1; I[0] != -(oldsize + 1); h += h) {
|
||||
len = 0;
|
||||
for (i = 0; i < oldsize + 1;) {
|
||||
if (I[i] < 0) {
|
||||
len -= I[i];
|
||||
i -= I[i];
|
||||
} else {
|
||||
if (len) {
|
||||
I[i - len] = -len;
|
||||
}
|
||||
len = V[I[i]] + 1 - i;
|
||||
split(I, V, oldsize, i, len, h);
|
||||
i += len;
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
if (len) {
|
||||
I[i - len] = -len;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < oldsize + 1; i++) {
|
||||
I[V[i]] = i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int64_t matchlen(u_char *old, int64_t oldsize, u_char *new,
|
||||
int64_t newsize)
|
||||
static int64_t matchlen(u_char *old, int64_t old_size, u_char *new,
|
||||
int64_t new_size)
|
||||
{
|
||||
int64_t i;
|
||||
|
||||
for (i = 0; (i < oldsize) && (i < newsize); i++) {
|
||||
for (i = 0; (i < old_size) && (i < new_size); i++) {
|
||||
if (old[i] != new[i]) {
|
||||
break;
|
||||
}
|
||||
@@ -256,30 +88,60 @@ static int64_t matchlen(u_char *old, int64_t oldsize, u_char *new,
|
||||
return i;
|
||||
}
|
||||
|
||||
static int64_t search(int64_t *I, u_char *old, int64_t oldsize,
|
||||
u_char *new, int64_t newsize, int64_t st, int64_t en,
|
||||
int64_t *pos)
|
||||
/**
|
||||
* Finds the longest matching array of bytes between the OLD and NEW file. The
|
||||
* old file is suffix-sorted; the suffix-sorted array is stored at I, and
|
||||
* indices to search between are indicated by ST (start) and EN (end). The
|
||||
* function does not return a value, but once a match is determined, OLD_POS is
|
||||
* updated to the position of the match within OLD, and MAX_LEN is set to the
|
||||
* match length.
|
||||
*/
|
||||
static void search(int64_t *I, u_char *old, int64_t old_size,
|
||||
u_char *new, int64_t new_size, int64_t st, int64_t en,
|
||||
int64_t *old_pos, int64_t *max_len)
|
||||
{
|
||||
int64_t x, y;
|
||||
|
||||
if (en - st < 2) {
|
||||
x = matchlen(old + I[st], oldsize - I[st], new, newsize);
|
||||
y = matchlen(old + I[en], oldsize - I[en], new, newsize);
|
||||
/* Initialize max_len for the binary search */
|
||||
if (st == 0 && en == old_size) {
|
||||
*max_len = matchlen(old, old_size, new, new_size);
|
||||
*old_pos = I[st];
|
||||
}
|
||||
|
||||
if (x > y) {
|
||||
*pos = I[st];
|
||||
return x;
|
||||
} else {
|
||||
*pos = I[en];
|
||||
return y;
|
||||
/* The binary search terminates here when "en" and "st" are adjacent
|
||||
* indices in the suffix-sorted array. */
|
||||
if (en - st < 2) {
|
||||
x = matchlen(old + I[st], old_size - I[st], new, new_size);
|
||||
if (x > *max_len) {
|
||||
*max_len = x;
|
||||
*old_pos = I[st];
|
||||
}
|
||||
y = matchlen(old + I[en], old_size - I[en], new, new_size);
|
||||
if (y > *max_len) {
|
||||
*max_len = y;
|
||||
*old_pos = I[en];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
x = st + (en - st) / 2;
|
||||
if (memcmp(old + I[x], new, MIN(oldsize - I[x], newsize)) < 0) {
|
||||
return search(I, old, oldsize, new, newsize, x, en, pos);
|
||||
|
||||
int64_t length = MIN(old_size - I[x], new_size);
|
||||
u_char *oldoffset = old + I[x];
|
||||
|
||||
/* This match *could* be the longest one, so check for that here */
|
||||
int64_t tmp = matchlen(oldoffset, length, new, length);
|
||||
if (tmp > *max_len) {
|
||||
*max_len = tmp;
|
||||
*old_pos = I[x];
|
||||
}
|
||||
|
||||
/* Determine how to continue the binary search */
|
||||
if (memcmp(oldoffset, new, length) < 0) {
|
||||
return search(I, old, old_size, new, new_size, x, en, old_pos, max_len);
|
||||
} else {
|
||||
return search(I, old, oldsize, new, newsize, st, x, pos);
|
||||
return search(I, old, old_size, new, new_size, st, x, old_pos, max_len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,16 +386,8 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
{
|
||||
int fd, efd;
|
||||
u_char *old_data, *new_data;
|
||||
int64_t oldsize, newsize;
|
||||
int64_t old_size, new_size;
|
||||
int64_t *I, *V;
|
||||
int64_t scan;
|
||||
int64_t pos = 0;
|
||||
int64_t len;
|
||||
int64_t lastscan, lastpos, lastoffset;
|
||||
int64_t oldscore, scsc;
|
||||
int64_t s, Sf, lenf, Sb, lenb;
|
||||
int64_t overlap, Ss, lens;
|
||||
int64_t i;
|
||||
uint64_t cblen, dblen, eblen;
|
||||
u_char *cb, *db, *eb;
|
||||
struct stat new_stat;
|
||||
@@ -542,9 +396,12 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
off_t first_block;
|
||||
int c_enc, d_enc, e_enc;
|
||||
enc_flags_t encodings;
|
||||
char delta_filename_unique[2 * PATH_MAX];
|
||||
|
||||
struct header_v20 large_header;
|
||||
struct header_v21 small_header;
|
||||
|
||||
sprintf(delta_filename_unique, "%s.%i", delta_filename, getpid());
|
||||
FILE *pf;
|
||||
|
||||
ret = lstat(old_filename, &old_stat);
|
||||
@@ -557,6 +414,8 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
if (S_ISDIR(new_stat.st_mode) || S_ISDIR(old_stat.st_mode)) {
|
||||
/* no delta on symlinks ! */
|
||||
return -1;
|
||||
@@ -577,16 +436,16 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
return -1;
|
||||
}
|
||||
|
||||
oldsize = old_stat.st_size;
|
||||
old_size = old_stat.st_size;
|
||||
|
||||
/* We may start with an empty file, if so, just mark it for full download
|
||||
* to throw into the pack. In the case that newfile is <200, it will quit
|
||||
* and ask for fulldownload, so we only need to check oldsize */
|
||||
if (oldsize == 0) {
|
||||
* and ask for fulldownload, so we only need to check old_size */
|
||||
if (old_size == 0) {
|
||||
memset(&small_header, 0, sizeof(struct header_v21));
|
||||
memcpy(&small_header.magic, BSDIFF_HDR_FULLDL, 8);
|
||||
|
||||
efd = open(delta_filename, O_CREAT | O_EXCL | O_WRONLY, 00644);
|
||||
efd = open(delta_filename_unique, O_CREAT | O_EXCL | O_WRONLY, 00644);
|
||||
if (efd < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
@@ -603,15 +462,16 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
}
|
||||
fclose(pf);
|
||||
close(fd);
|
||||
rename(delta_filename_unique, delta_filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* TODO: investigate why this needs to be +1 to not overrun; coverity complains
|
||||
* that we overrun old_data when we calculate differences otherwise. Tenatively,
|
||||
* since this is used in qsufsort, it may need to be +1 like I and V because of
|
||||
* a sentinel byte when sorting. However, newsize does not cause any overruns
|
||||
* a sentinel byte when sorting. However, new_size does not cause any overruns
|
||||
* when created with the regular file size */
|
||||
old_data = mmap(NULL, oldsize + 1, PROT_READ, MAP_SHARED, fd, 0);
|
||||
old_data = mmap(NULL, old_size + 1, PROT_READ, MAP_SHARED, fd, 0);
|
||||
close(fd);
|
||||
|
||||
if (old_data == MAP_FAILED) {
|
||||
@@ -621,19 +481,19 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
|
||||
/* These arrays are size + 1 because suffix sort needs space for the
|
||||
* data + 1 sentinel element to actually do the sorting. Not because
|
||||
* oldsize might be 0. */
|
||||
if ((I = malloc((oldsize + 1) * sizeof(int64_t))) == NULL) {
|
||||
munmap(old_data, oldsize);
|
||||
* old_size might be 0. */
|
||||
if ((I = malloc((old_size + 1) * sizeof(int64_t))) == NULL) {
|
||||
munmap(old_data, old_size);
|
||||
return -1;
|
||||
}
|
||||
if ((V = malloc((oldsize + 1) * sizeof(int64_t))) == NULL) {
|
||||
munmap(old_data, oldsize);
|
||||
if ((V = malloc((old_size + 1) * sizeof(int64_t))) == NULL) {
|
||||
munmap(old_data, old_size);
|
||||
free(I);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qsufsort(I, V, old_data, oldsize) != 0) {
|
||||
munmap(old_data, oldsize);
|
||||
if (qsufsort(I, V, old_data, old_size) != 0) {
|
||||
munmap(old_data, old_size);
|
||||
free(I);
|
||||
free(V);
|
||||
return -1;
|
||||
@@ -642,19 +502,19 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
free(V);
|
||||
|
||||
if ((fd = open(new_filename, O_RDONLY, 0)) < 0) {
|
||||
munmap(old_data, oldsize);
|
||||
munmap(old_data, old_size);
|
||||
free(I);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fstat(fd, &new_stat) != 0) {
|
||||
munmap(old_data, oldsize);
|
||||
munmap(old_data, old_size);
|
||||
free(I);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
newsize = new_stat.st_size;
|
||||
new_size = new_stat.st_size;
|
||||
|
||||
/* Note: testing this to see how diffs between small files affect
|
||||
* updates. Small files seem to cause some problems between certain
|
||||
@@ -664,76 +524,77 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
* the "is bsdiff < 90% of newfile size" check that would otherwise
|
||||
* be performed later on.
|
||||
*/
|
||||
if (newsize < 200) {
|
||||
if (new_size < 200) {
|
||||
memset(&small_header, 0, sizeof(struct header_v21));
|
||||
memcpy(&small_header.magic, BSDIFF_HDR_FULLDL, 8);
|
||||
|
||||
efd = open(delta_filename, O_CREAT | O_EXCL | O_WRONLY, 00644);
|
||||
efd = open(delta_filename_unique, O_CREAT | O_EXCL | O_WRONLY, 00644);
|
||||
if (efd < 0) {
|
||||
close(fd);
|
||||
munmap(old_data, oldsize);
|
||||
munmap(old_data, old_size);
|
||||
free(I);
|
||||
return -1;
|
||||
}
|
||||
if ((pf = fdopen(efd, "w")) == NULL) {
|
||||
close(efd);
|
||||
close(fd);
|
||||
munmap(old_data, oldsize);
|
||||
munmap(old_data, old_size);
|
||||
free(I);
|
||||
return -1;
|
||||
}
|
||||
if (fwrite(&small_header, 8, 1, pf) != 1) {
|
||||
fclose(pf);
|
||||
close(fd);
|
||||
munmap(old_data, oldsize);
|
||||
munmap(old_data, old_size);
|
||||
|
||||
free(I);
|
||||
return -1;
|
||||
}
|
||||
fclose(pf);
|
||||
close(fd);
|
||||
munmap(old_data, oldsize);
|
||||
munmap(old_data, old_size);
|
||||
free(I);
|
||||
rename(delta_filename_unique, delta_filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((new_data = malloc(newsize)) == NULL) {
|
||||
if ((new_data = malloc(new_size)) == NULL) {
|
||||
close(fd);
|
||||
munmap(old_data, oldsize);
|
||||
munmap(old_data, old_size);
|
||||
free(I);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pread(fd, new_data, newsize, 0) != newsize) {
|
||||
if (pread(fd, new_data, new_size, 0) != new_size) {
|
||||
close(fd);
|
||||
munmap(old_data, oldsize);
|
||||
munmap(old_data, old_size);
|
||||
free(new_data);
|
||||
free(I);
|
||||
return -1;
|
||||
}
|
||||
if (close(fd) == -1) {
|
||||
munmap(old_data, oldsize);
|
||||
munmap(old_data, old_size);
|
||||
free(new_data);
|
||||
free(I);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we can write 3 8 byte tupples extra, so allocate some headroom */
|
||||
if ((cb = malloc(newsize + 25)) == NULL) {
|
||||
munmap(old_data, oldsize);
|
||||
if ((cb = malloc(new_size + 25)) == NULL) {
|
||||
munmap(old_data, old_size);
|
||||
free(new_data);
|
||||
free(I);
|
||||
return -1;
|
||||
}
|
||||
if ((db = malloc(newsize + 25)) == NULL) {
|
||||
munmap(old_data, oldsize);
|
||||
if ((db = malloc(new_size + 25)) == NULL) {
|
||||
munmap(old_data, old_size);
|
||||
free(new_data);
|
||||
free(cb);
|
||||
free(I);
|
||||
return -1;
|
||||
}
|
||||
if ((eb = malloc(newsize + 25)) == NULL) {
|
||||
munmap(old_data, oldsize);
|
||||
if ((eb = malloc(new_size + 25)) == NULL) {
|
||||
munmap(old_data, old_size);
|
||||
free(new_data);
|
||||
free(cb);
|
||||
free(db);
|
||||
@@ -745,109 +606,152 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
eblen = 0;
|
||||
|
||||
/* Compute the differences */
|
||||
scan = 0;
|
||||
len = 0;
|
||||
lastscan = 0;
|
||||
lastpos = 0;
|
||||
lastoffset = 0;
|
||||
while (scan < newsize) {
|
||||
oldscore = 0;
|
||||
int64_t new_pos = 0;
|
||||
int64_t old_pos = 0;
|
||||
int64_t match_len = 0;
|
||||
int64_t last_new_pos = 0;
|
||||
int64_t last_old_pos = 0;
|
||||
int64_t last_offset = 0;
|
||||
while (new_pos < new_size) {
|
||||
// Find an exact match between old and new files, and require
|
||||
// that more than 8 of the matching bytes "mismatch" from the
|
||||
// previous exact match. A score (old_score) is used to track
|
||||
// how many bytes match starting from new_pos in new, and from
|
||||
// old_pos in the previous iteration.
|
||||
// NOTE: the magic value 8 is a heuristic; further testing is
|
||||
// needed to prove whether this is the best number, or if the
|
||||
// number should vary according to other factors, etc.
|
||||
int64_t old_score = 0;
|
||||
int64_t new_peek;
|
||||
for (new_peek = new_pos += match_len; new_pos < new_size; new_pos++) {
|
||||
search(I, old_data, old_size, new_data + new_pos, new_size - new_pos,
|
||||
0, old_size, &old_pos, &match_len);
|
||||
|
||||
for (scsc = scan += len; scan < newsize; scan++) {
|
||||
len =
|
||||
search(I, old_data, oldsize, new_data + scan, newsize - scan,
|
||||
0, oldsize, &pos);
|
||||
|
||||
for (; scsc < scan + len; scsc++) {
|
||||
if ((scsc + lastoffset < oldsize) &&
|
||||
(old_data[scsc + lastoffset] == new_data[scsc])) {
|
||||
oldscore++;
|
||||
for (; new_peek < new_pos + match_len; new_peek++) {
|
||||
if ((new_peek + last_offset < old_size) &&
|
||||
(old_data[new_peek + last_offset] == new_data[new_peek])) {
|
||||
old_score++;
|
||||
}
|
||||
}
|
||||
|
||||
if (((len == oldscore) && (len != 0)) ||
|
||||
(len > oldscore + 8)) {
|
||||
if (((match_len == old_score) && (match_len != 0)) ||
|
||||
(match_len > old_score + 8)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((scan + lastoffset < oldsize) &&
|
||||
(old_data[scan + lastoffset] == new_data[scan])) {
|
||||
oldscore--;
|
||||
// Before beginning the next loop iteration, decrement
|
||||
// old_score if needed, since new_pos will be
|
||||
// incremented.
|
||||
if ((new_pos + last_offset < old_size) &&
|
||||
(old_data[new_pos + last_offset] == new_data[new_pos])) {
|
||||
old_score--;
|
||||
}
|
||||
}
|
||||
|
||||
if ((len != oldscore) || (scan == newsize)) {
|
||||
s = 0;
|
||||
Sf = 0;
|
||||
lenf = 0;
|
||||
for (i = 0;
|
||||
(lastscan + i < scan) && (lastpos + i < oldsize);) {
|
||||
if (old_data[lastpos + i] == new_data[lastscan + i]) {
|
||||
s++;
|
||||
if ((match_len != old_score) || (new_pos == new_size)) {
|
||||
int64_t bytes = 0, max = 0;
|
||||
// Compute the length of a fuzzy match starting from
|
||||
// the beginning of the fuzzy match recorded at the end
|
||||
// of the previous iteration (i.e. len_fuzzybackward
|
||||
// less than the previous match positions). At least
|
||||
// half of the bytes match between old and new. This
|
||||
// fuzzy match will be used to construct a diff string
|
||||
// in the diff block.
|
||||
// NOTE: "at least half matching bytes" is a heuristic
|
||||
// for both fuzzy regions being constructed below;
|
||||
// further testing is needed to prove whether this is
|
||||
// the best percentage, or if the percentage should
|
||||
// vary according to other factors, etc.
|
||||
int64_t len_fuzzyforward = 0;
|
||||
for (int64_t i = 0;
|
||||
(last_new_pos + i < new_pos) && (last_old_pos + i < old_size);) {
|
||||
if (old_data[last_old_pos + i] == new_data[last_new_pos + i]) {
|
||||
bytes++;
|
||||
}
|
||||
i++;
|
||||
if (s * 2 - i > Sf * 2 - lenf) {
|
||||
Sf = s;
|
||||
lenf = i;
|
||||
if (bytes * 2 - i > max * 2 - len_fuzzyforward) {
|
||||
max = bytes;
|
||||
len_fuzzyforward = i;
|
||||
}
|
||||
}
|
||||
|
||||
lenb = 0;
|
||||
if (scan < newsize) {
|
||||
s = 0;
|
||||
Sb = 0;
|
||||
for (i = 1;
|
||||
(scan >= lastscan + i) && (pos >= i);
|
||||
// Compute the length of a fuzzy match ending at the
|
||||
// current positions in old and new files (old_pos and
|
||||
// new_pos). At least half of the bytes match between
|
||||
// old and new. This fuzzy match will be used for the
|
||||
// next iteration.
|
||||
int64_t len_fuzzybackward = 0;
|
||||
if (new_pos < new_size) {
|
||||
bytes = 0;
|
||||
max = 0;
|
||||
for (int64_t i = 1;
|
||||
(new_pos >= last_new_pos + i) && (old_pos >= i);
|
||||
i++) {
|
||||
if (old_data[pos - i] == new_data[scan - i]) {
|
||||
s++;
|
||||
if (old_data[old_pos - i] == new_data[new_pos - i]) {
|
||||
bytes++;
|
||||
}
|
||||
if (s * 2 - i > Sb * 2 - lenb) {
|
||||
Sb = s;
|
||||
lenb = i;
|
||||
if (bytes * 2 - i > max * 2 - len_fuzzybackward) {
|
||||
max = bytes;
|
||||
len_fuzzybackward = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lastscan + lenf > scan - lenb) {
|
||||
overlap = (lastscan + lenf) - (scan - lenb);
|
||||
s = 0;
|
||||
Ss = 0;
|
||||
lens = 0;
|
||||
for (i = 0; i < overlap; i++) {
|
||||
if (new_data[lastscan + lenf - overlap + i] ==
|
||||
old_data[lastpos + lenf - overlap + i]) {
|
||||
s++;
|
||||
// If there is an overlap between len_fuzzyforward and
|
||||
// len_fuzzybackward in the new file, that overlap must
|
||||
// be eliminated.
|
||||
if (last_new_pos + len_fuzzyforward > new_pos - len_fuzzybackward) {
|
||||
bytes = 0;
|
||||
max = 0;
|
||||
int64_t overlap = (last_new_pos + len_fuzzyforward) - (new_pos - len_fuzzybackward);
|
||||
int64_t len_fuzzyshift = 0;
|
||||
// Scan the overlap area for differences
|
||||
// between old and new. If any mismatching
|
||||
// bytes are found, extend len_fuzzyforward to
|
||||
// cover those bytes, because we want them
|
||||
// included in the diff block.
|
||||
for (int64_t i = 0; i < overlap; i++) {
|
||||
if (new_data[last_new_pos + len_fuzzyforward - overlap + i] ==
|
||||
old_data[last_old_pos + len_fuzzyforward - overlap + i]) {
|
||||
bytes++;
|
||||
}
|
||||
if (new_data[scan - lenb + i] ==
|
||||
old_data[pos - lenb + i]) {
|
||||
s--;
|
||||
if (new_data[new_pos - len_fuzzybackward + i] ==
|
||||
old_data[old_pos - len_fuzzybackward + i]) {
|
||||
bytes--;
|
||||
}
|
||||
if (s > Ss) {
|
||||
Ss = s;
|
||||
lens = i + 1;
|
||||
if (bytes > max) {
|
||||
max = bytes;
|
||||
len_fuzzyshift = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
lenf += lens - overlap;
|
||||
lenb -= lens;
|
||||
len_fuzzyforward += len_fuzzyshift - overlap;
|
||||
len_fuzzybackward -= len_fuzzyshift;
|
||||
}
|
||||
|
||||
for (i = 0; i < lenf; i++) {
|
||||
// Set the diff string in the diff block. For each byte
|
||||
// in the fuzzy forward region, the byte from old is
|
||||
// subtracted from new. When applying the delta (with
|
||||
// bspatch) this operation is reversed, by performing
|
||||
// additions.
|
||||
for (int64_t i = 0; i < len_fuzzyforward; i++) {
|
||||
db[dblen + i] =
|
||||
new_data[lastscan + i] - old_data[lastpos + i];
|
||||
new_data[last_new_pos + i] - old_data[last_old_pos + i];
|
||||
}
|
||||
for (i = 0; i < (scan - lenb) - (lastscan + lenf); i++) {
|
||||
eb[eblen + i] = new_data[lastscan + lenf + i];
|
||||
// Set the extra string in the extra block. The
|
||||
// contents are the bytes in new file between the fuzzy
|
||||
// forward and fuzzy backward regions.
|
||||
for (int64_t i = 0; i < (new_pos - len_fuzzybackward) - (last_new_pos + len_fuzzyforward); i++) {
|
||||
eb[eblen + i] = new_data[last_new_pos + len_fuzzyforward + i];
|
||||
}
|
||||
|
||||
dblen += lenf;
|
||||
eblen += (scan - lenb) - (lastscan + lenf);
|
||||
dblen += len_fuzzyforward;
|
||||
eblen += (new_pos - len_fuzzybackward) - (last_new_pos + len_fuzzyforward);
|
||||
|
||||
/* checking for control block overflow...
|
||||
* See regression test #15 for an example */
|
||||
if ((int64_t)(cblen + 24) > (newsize + 25)) {
|
||||
munmap(old_data, oldsize);
|
||||
if ((int64_t)(cblen + 24) > (new_size + 25)) {
|
||||
munmap(old_data, old_size);
|
||||
free(new_data);
|
||||
free(cb);
|
||||
free(db);
|
||||
@@ -856,18 +760,28 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
return -1;
|
||||
}
|
||||
|
||||
offtout(lenf, cb + cblen);
|
||||
// Set three values in the control block:
|
||||
// 1. ADD instruction (value: length of the diff
|
||||
// string). It uses the offset of the third control
|
||||
// block value from the previous iteration.
|
||||
// 2. INSERT instruction (value: length of the extra
|
||||
// string)
|
||||
// 3. offset in old file for the next ADD instruction
|
||||
offtout(len_fuzzyforward, cb + cblen);
|
||||
cblen += 8;
|
||||
|
||||
offtout((scan - lenb) - (lastscan + lenf), cb + cblen);
|
||||
offtout((new_pos - len_fuzzybackward) - (last_new_pos + len_fuzzyforward), cb + cblen);
|
||||
cblen += 8;
|
||||
|
||||
offtout((pos - lenb) - (lastpos + lenf), cb + cblen);
|
||||
offtout((old_pos - len_fuzzybackward) - (last_old_pos + len_fuzzyforward), cb + cblen);
|
||||
cblen += 8;
|
||||
|
||||
lastscan = scan - lenb;
|
||||
lastpos = pos - lenb;
|
||||
lastoffset = pos - scan;
|
||||
// Save old/new file positions to the beginning of the
|
||||
// fuzzy backward region, since the next fuzzy forward
|
||||
// region will be calculated from that point.
|
||||
last_new_pos = new_pos - len_fuzzybackward;
|
||||
last_old_pos = old_pos - len_fuzzybackward;
|
||||
last_offset = old_pos - new_pos;
|
||||
}
|
||||
}
|
||||
free(I);
|
||||
@@ -883,7 +797,7 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
|
||||
/* Create the patch file */
|
||||
|
||||
efd = open(delta_filename, O_CREAT | O_EXCL | O_WRONLY, 00644);
|
||||
efd = open(delta_filename_unique, O_CREAT | O_EXCL | O_WRONLY, 00644);
|
||||
if (efd < 0) {
|
||||
ret = -1;
|
||||
goto fulldl_free;
|
||||
@@ -905,8 +819,8 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
small_header.control_length = cblen;
|
||||
small_header.diff_length = dblen;
|
||||
small_header.extra_length = eblen;
|
||||
small_header.old_file_length = oldsize;
|
||||
small_header.new_file_length = newsize;
|
||||
small_header.old_file_length = old_size;
|
||||
small_header.new_file_length = new_size;
|
||||
small_header.file_mode = new_stat.st_mode;
|
||||
small_header.file_owner = new_stat.st_uid;
|
||||
small_header.file_group = new_stat.st_gid;
|
||||
@@ -916,7 +830,7 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
eblock_set_enc(&small_header.encoding, e_enc);
|
||||
encodings = small_header.encoding;
|
||||
|
||||
if ((first_block + cblen + dblen + eblen > 0.90 * newsize) && (enc != BSDIFF_ENC_NONE)) { /* tune */
|
||||
if ((first_block + cblen + dblen + eblen > 0.90 * new_size) && (enc != BSDIFF_ENC_NONE)) { /* tune */
|
||||
memcpy(&small_header.magic, BSDIFF_HDR_FULLDL, 8);
|
||||
ret = 1;
|
||||
if (fwrite(&small_header, 8, 1, pf) != 1) {
|
||||
@@ -944,8 +858,8 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
large_header.control_length = cblen;
|
||||
large_header.diff_length = dblen;
|
||||
large_header.extra_length = eblen;
|
||||
large_header.old_file_length = oldsize;
|
||||
large_header.new_file_length = newsize;
|
||||
large_header.old_file_length = old_size;
|
||||
large_header.new_file_length = new_size;
|
||||
large_header.file_mode = new_stat.st_mode;
|
||||
large_header.file_owner = new_stat.st_uid;
|
||||
large_header.file_group = new_stat.st_gid;
|
||||
@@ -955,7 +869,7 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
eblock_set_enc(&large_header.encoding, e_enc);
|
||||
encodings = large_header.encoding;
|
||||
|
||||
if ((first_block + cblen + dblen + eblen > 0.90 * newsize) && (enc != BSDIFF_ENC_NONE)) { /* tune */
|
||||
if ((first_block + cblen + dblen + eblen > 0.90 * new_size) && (enc != BSDIFF_ENC_NONE)) { /* tune */
|
||||
memcpy(&large_header.magic, BSDIFF_HDR_FULLDL, 8);
|
||||
ret = 1;
|
||||
if (fwrite(&large_header, 8, 1, pf) != 1) {
|
||||
@@ -986,7 +900,7 @@ int make_bsdiff_delta(char *old_filename, char *new_filename, char *delta_filena
|
||||
}
|
||||
|
||||
bsdiff_files++;
|
||||
bsdiff_newbytes += newsize;
|
||||
bsdiff_newbytes += new_size;
|
||||
bsdiff_outputbytes += first_block + cblen + dblen + eblen;
|
||||
|
||||
if (cblock_get_enc(encodings) == BSDIFF_ENC_NONE) {
|
||||
@@ -1038,9 +952,10 @@ fulldl_close_free:
|
||||
if (fclose(pf)) {
|
||||
ret = -1;
|
||||
}
|
||||
rename(delta_filename_unique, delta_filename);
|
||||
fulldl_free:
|
||||
/* Free the memory we used */
|
||||
munmap(old_data, oldsize);
|
||||
munmap(old_data, old_size);
|
||||
free(new_data);
|
||||
free(cb);
|
||||
free(db);
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
* Copyright © 2012-2016 Intel Corporation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
|
||||
+4
-4
@@ -4,7 +4,7 @@
|
||||
* Copyright © 2012-2016 Intel Corporation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
@@ -30,12 +30,12 @@
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "bsdiff.h"
|
||||
#include "bsheader.h"
|
||||
@@ -110,7 +110,7 @@ static void print_v20_header(struct header_v20 *h, FILE *f)
|
||||
if (h->mtime == 0) {
|
||||
printf("Mtime:\t(not set, as expected)\n");
|
||||
} else {
|
||||
printf("Mtime:\t%s (probably means there is a bug)\n", ctime((const time_t*)&h->mtime));
|
||||
printf("Mtime:\t%s (probably means there is a bug)\n", ctime((const time_t *)&h->mtime));
|
||||
}
|
||||
printf("Mode:\t%4o\n", h->file_mode);
|
||||
printf("Uid:\t%d\n", h->file_owner);
|
||||
|
||||
+48
-48
@@ -3,7 +3,7 @@
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
@@ -44,23 +44,23 @@ __FBSDID
|
||||
#include <lzma.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <zlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <linux/fs.h>
|
||||
#include <assert.h>
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <limits.h>
|
||||
#include <linux/fs.h>
|
||||
#include <pwd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "bsheader.h"
|
||||
|
||||
@@ -254,12 +254,12 @@ static size_t xzread(xzfile *xzf, u_char *buf, size_t len, lzma_ret *err)
|
||||
|
||||
typedef struct {
|
||||
FILE *f; /* method = NONE, BZIP2, ZEROS */
|
||||
int fd; /* method = BZIP2 */
|
||||
int fd; /* method = BZIP2 */
|
||||
union {
|
||||
#ifdef BSDIFF_WITH_BZIP2
|
||||
BZFILE *bz2; /* method = BZIP2 */
|
||||
#endif
|
||||
gzFile gz; /* method = GZIP */
|
||||
gzFile gz; /* method = GZIP */
|
||||
#ifdef BSDIFF_WITH_LZMA
|
||||
xzfile *xz; /* method = XZ */
|
||||
#endif
|
||||
@@ -539,12 +539,12 @@ static int apply_delta_v2(int subver, FILE *f,
|
||||
cfile cf, df, ef;
|
||||
unsigned char *old_data = NULL, *new_data;
|
||||
unsigned char buf[8];
|
||||
off_t oldpos, newpos;
|
||||
off_t old_pos, new_pos;
|
||||
int64_t ctrl[3];
|
||||
int i, ret, fd;
|
||||
off_t data_offset;
|
||||
off_t ctrllen, difflen, extralen;
|
||||
off_t oldsize, newsize;
|
||||
off_t old_size, new_size;
|
||||
mode_t mode;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
@@ -561,8 +561,8 @@ static int apply_delta_v2(int subver, FILE *f,
|
||||
ctrllen = header.control_length;
|
||||
difflen = header.diff_length;
|
||||
extralen = header.extra_length;
|
||||
oldsize = header.old_file_length;
|
||||
newsize = header.new_file_length;
|
||||
old_size = header.old_file_length;
|
||||
new_size = header.new_file_length;
|
||||
mode = header.file_mode;
|
||||
uid = header.file_owner;
|
||||
gid = header.file_group;
|
||||
@@ -576,8 +576,8 @@ static int apply_delta_v2(int subver, FILE *f,
|
||||
ctrllen = header.control_length;
|
||||
difflen = header.diff_length;
|
||||
extralen = header.extra_length;
|
||||
oldsize = header.old_file_length;
|
||||
newsize = header.new_file_length;
|
||||
old_size = header.old_file_length;
|
||||
new_size = header.new_file_length;
|
||||
mode = header.file_mode;
|
||||
uid = header.file_owner;
|
||||
gid = header.file_group;
|
||||
@@ -588,7 +588,7 @@ static int apply_delta_v2(int subver, FILE *f,
|
||||
|
||||
if ((ret = check_header(f, encoding,
|
||||
ctrllen, difflen, extralen,
|
||||
oldsize, newsize, data_offset)) < 0) {
|
||||
old_size, new_size, data_offset)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -597,29 +597,29 @@ static int apply_delta_v2(int subver, FILE *f,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = read_file(old_filename, &old_data, oldsize);
|
||||
ret = read_file(old_filename, &old_data, old_size);
|
||||
if (ret < 0) {
|
||||
goto preperror;
|
||||
}
|
||||
|
||||
if (newsize > BSDIFF_MAX_FILESZ) {
|
||||
munmap(old_data, oldsize);
|
||||
if (new_size > BSDIFF_MAX_FILESZ) {
|
||||
munmap(old_data, old_size);
|
||||
ret = -1;
|
||||
goto preperror;
|
||||
}
|
||||
|
||||
/* Allocate newsize+1 bytes instead of newsize bytes to ensure
|
||||
/* Allocate new_size+1 bytes instead of new_size bytes to ensure
|
||||
that we never try to malloc(0) and get a NULL pointer */
|
||||
if ((new_data = malloc(newsize + 1)) == NULL) {
|
||||
munmap(old_data, oldsize);
|
||||
if ((new_data = malloc(new_size + 1)) == NULL) {
|
||||
munmap(old_data, old_size);
|
||||
ret = -1;
|
||||
goto preperror;
|
||||
}
|
||||
memset(new_data, 0, newsize + 1);
|
||||
memset(new_data, 0, new_size + 1);
|
||||
|
||||
oldpos = 0;
|
||||
newpos = 0;
|
||||
while (newpos < newsize) {
|
||||
old_pos = 0;
|
||||
new_pos = 0;
|
||||
while (new_pos < new_size) {
|
||||
/* Read control data:
|
||||
* ctrl[0] == offset into diff block
|
||||
* ctrl[1] == offset into extra block
|
||||
@@ -628,7 +628,7 @@ static int apply_delta_v2(int subver, FILE *f,
|
||||
* The three control block words manage reads of the diff,
|
||||
* extra and old_data so that those three sources can be
|
||||
* combined into new_data. ctrl[2] in particular may cause
|
||||
* oldpos to jump forward AND backward in order to allow
|
||||
* old_pos to jump forward AND backward in order to allow
|
||||
* copies of the original file content rather than using
|
||||
* diff or extra content.
|
||||
*/
|
||||
@@ -641,47 +641,47 @@ static int apply_delta_v2(int subver, FILE *f,
|
||||
}
|
||||
|
||||
/* Sanity-check */
|
||||
if (newpos + ctrl[0] > newsize || ctrl[0] < 0 || newpos + ctrl[0] < 0) {
|
||||
if (new_pos + ctrl[0] > new_size || ctrl[0] < 0 || new_pos + ctrl[0] < 0) {
|
||||
ret = -1;
|
||||
goto readerror;
|
||||
}
|
||||
|
||||
/* Read diff string */
|
||||
ret = cfread(&df, new_data + newpos, ctrl[0], BSDIFF_BLOCK_DIFF, &d_zeros);
|
||||
ret = cfread(&df, new_data + new_pos, ctrl[0], BSDIFF_BLOCK_DIFF, &d_zeros);
|
||||
if (ret < 0) {
|
||||
goto readerror;
|
||||
}
|
||||
|
||||
/* Add old data to diff string */
|
||||
for (i = 0; i < ctrl[0]; i++) {
|
||||
if ((oldpos + i >= 0) && (oldpos + i < oldsize)) {
|
||||
new_data[newpos + i] += old_data[oldpos + i];
|
||||
if ((old_pos + i >= 0) && (old_pos + i < old_size)) {
|
||||
new_data[new_pos + i] += old_data[old_pos + i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust pointers */
|
||||
newpos += ctrl[0];
|
||||
oldpos += ctrl[0];
|
||||
new_pos += ctrl[0];
|
||||
old_pos += ctrl[0];
|
||||
|
||||
/* Sanity-check */
|
||||
if (newpos + ctrl[1] > newsize || ctrl[1] < 0 || newpos + ctrl[1] < 0) {
|
||||
if (new_pos + ctrl[1] > new_size || ctrl[1] < 0 || new_pos + ctrl[1] < 0) {
|
||||
ret = -1;
|
||||
goto readerror;
|
||||
}
|
||||
if (oldpos + ctrl[2] > oldsize || oldpos + ctrl[2] < 0) {
|
||||
if (old_pos + ctrl[2] > old_size || old_pos + ctrl[2] < 0) {
|
||||
ret = -1;
|
||||
goto readerror;
|
||||
}
|
||||
|
||||
/* Read extra string */
|
||||
ret = cfread(&ef, new_data + newpos, ctrl[1], BSDIFF_BLOCK_EXTRA, &e_zeros);
|
||||
ret = cfread(&ef, new_data + new_pos, ctrl[1], BSDIFF_BLOCK_EXTRA, &e_zeros);
|
||||
if (ret < 0) {
|
||||
goto readerror;
|
||||
}
|
||||
|
||||
/* Adjust pointers */
|
||||
newpos += ctrl[1];
|
||||
oldpos += ctrl[2];
|
||||
new_pos += ctrl[1];
|
||||
old_pos += ctrl[2];
|
||||
}
|
||||
|
||||
/* Clean up the readers */
|
||||
@@ -696,7 +696,7 @@ static int apply_delta_v2(int subver, FILE *f,
|
||||
goto writeerror;
|
||||
}
|
||||
|
||||
if (write(fd, new_data, newsize) != newsize) {
|
||||
if (write(fd, new_data, new_size) != new_size) {
|
||||
unlink(new_filename);
|
||||
close(fd);
|
||||
ret = -1;
|
||||
@@ -719,12 +719,12 @@ static int apply_delta_v2(int subver, FILE *f,
|
||||
|
||||
writeerror:
|
||||
free(new_data);
|
||||
munmap(old_data, oldsize);
|
||||
munmap(old_data, old_size);
|
||||
return ret;
|
||||
|
||||
readerror:
|
||||
free(new_data);
|
||||
munmap(old_data, oldsize);
|
||||
munmap(old_data, old_size);
|
||||
preperror:
|
||||
cfclose(&cf);
|
||||
cfclose(&df);
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
* Copyright © 2012-2016 Intel Corporation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
/*-
|
||||
* Copyright 2003-2005 Colin Percival
|
||||
* All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted providing that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "bsheader.h"
|
||||
|
||||
/* NOTES:
|
||||
* I and V are chunks of memory (arrays) with length = (oldfile size +1) * sizeof(int64_t).
|
||||
* Additionally, we pass in arraylen now. The parent function qsufsort receives it, so it
|
||||
* should be available here as well for error checking.
|
||||
* start: is actually the point in the array sent in during the suffix sort, which sorts by
|
||||
* small blocks/chunks.
|
||||
* len: refers to the length of the current chunk being processed - NOT the array length(s).
|
||||
* h: will never be more than 8, and increases by *2 during suffix sort (h += h) */
|
||||
static void split(int64_t *I, int64_t *V, int64_t arraylen, int64_t start, int64_t len,
|
||||
int64_t h)
|
||||
{
|
||||
int64_t i, j, k, x, tmp, jj, kk;
|
||||
|
||||
if (len < 16) {
|
||||
for (k = start; k < start + len; k += j) {
|
||||
j = 1;
|
||||
x = V[I[k] + h];
|
||||
for (i = 1; k + i < start + len; i++) {
|
||||
if (V[I[k + i] + h] < x) {
|
||||
x = V[I[k + i] + h];
|
||||
j = 0;
|
||||
}
|
||||
if (V[I[k + i] + h] == x) {
|
||||
tmp = I[k + j];
|
||||
I[k + j] = I[k + i];
|
||||
I[k + i] = tmp;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < j; i++) {
|
||||
V[I[k + i]] = k + j - 1;
|
||||
}
|
||||
if (j == 1) {
|
||||
I[k] = -1;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
x = V[I[start + len / 2] + h];
|
||||
jj = 0;
|
||||
kk = 0;
|
||||
for (i = start; i < start + len; i++) {
|
||||
if (V[I[i] + h] < x) {
|
||||
jj++;
|
||||
}
|
||||
if (V[I[i] + h] == x) {
|
||||
kk++;
|
||||
}
|
||||
}
|
||||
jj += start;
|
||||
kk += jj;
|
||||
|
||||
i = start;
|
||||
j = 0;
|
||||
k = 0;
|
||||
while (i < jj) {
|
||||
if (V[I[i] + h] < x) {
|
||||
i++;
|
||||
} else if (V[I[i] + h] == x) {
|
||||
tmp = I[i];
|
||||
I[i] = I[jj + j];
|
||||
I[jj + j] = tmp;
|
||||
j++;
|
||||
} else {
|
||||
tmp = I[i];
|
||||
I[i] = I[kk + k];
|
||||
I[kk + k] = tmp;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
while (jj + j < kk) {
|
||||
if (V[I[jj + j] + h] == x) {
|
||||
j++;
|
||||
} else {
|
||||
tmp = I[jj + j];
|
||||
I[jj + j] = I[kk + k];
|
||||
I[kk + k] = tmp;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
if (jj > start) {
|
||||
split(I, V, arraylen, start, jj - start, h);
|
||||
}
|
||||
|
||||
for (i = 0; i < kk - jj; i++) {
|
||||
V[I[jj + i]] = kk - 1;
|
||||
}
|
||||
if (jj == kk - 1) {
|
||||
I[jj] = -1;
|
||||
}
|
||||
|
||||
if (start + len > kk) {
|
||||
split(I, V, arraylen, kk, start + len - kk, h);
|
||||
}
|
||||
}
|
||||
|
||||
/* The old_data (previous file data) is passed into this suffix sort and sorted
|
||||
* accordingly using the I and V arrays, which are both of length old_size +1. */
|
||||
int qsufsort(int64_t *I, int64_t *V, u_char *old, int64_t old_size)
|
||||
{
|
||||
int64_t buckets[QSUF_BUCKET_SIZE];
|
||||
int64_t i, h, len;
|
||||
|
||||
for (i = 0; i < QSUF_BUCKET_SIZE; i++) {
|
||||
buckets[i] = 0;
|
||||
}
|
||||
for (i = 0; i < old_size; i++) {
|
||||
buckets[old[i]]++;
|
||||
}
|
||||
for (i = 1; i < QSUF_BUCKET_SIZE; i++) {
|
||||
buckets[i] += buckets[i - 1];
|
||||
}
|
||||
for (i = QSUF_BUCKET_SIZE - 1; i > 0; i--) {
|
||||
buckets[i] = buckets[i - 1];
|
||||
}
|
||||
buckets[0] = 0;
|
||||
|
||||
for (i = 0; i < old_size; i++) {
|
||||
if (buckets[old[i]] > old_size + 1) {
|
||||
return -1;
|
||||
}
|
||||
I[++buckets[old[i]]] = i;
|
||||
}
|
||||
|
||||
for (i = 0; i < old_size; i++) {
|
||||
V[i] = buckets[old[i]];
|
||||
}
|
||||
V[old_size] = 0;
|
||||
for (i = 1; i < QSUF_BUCKET_SIZE; i++) {
|
||||
if (buckets[i] == buckets[i - 1] + 1) {
|
||||
I[buckets[i]] = -1;
|
||||
}
|
||||
}
|
||||
I[0] = -1;
|
||||
|
||||
for (h = 1; I[0] != -(old_size + 1); h += h) {
|
||||
len = 0;
|
||||
for (i = 0; i < old_size + 1;) {
|
||||
if (I[i] < 0) {
|
||||
len -= I[i];
|
||||
i -= I[i];
|
||||
} else {
|
||||
if (len) {
|
||||
I[i - len] = -len;
|
||||
}
|
||||
len = V[I[i]] + 1 - i;
|
||||
split(I, V, old_size, i, len, h);
|
||||
i += len;
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
if (len) {
|
||||
I[i - len] = -len;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < old_size + 1; i++) {
|
||||
I[V[i]] = i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+7
-2
@@ -8,10 +8,15 @@ testnum=0
|
||||
|
||||
sudo rm -f *.diff *.out
|
||||
|
||||
VALGRIND="valgrind -q"
|
||||
if [ -n "$SKIP_VALGRIND" ]; then
|
||||
VALGRIND=""
|
||||
fi
|
||||
|
||||
libdir="$abs_builddir/.libs"
|
||||
ldpath="LD_LIBRARY_PATH=$libdir"
|
||||
BSDIFF="sudo $ldpath valgrind -q $libdir/bsdiff"
|
||||
BSPATCH="sudo $ldpath valgrind -q $libdir/bspatch"
|
||||
BSDIFF="sudo $ldpath $VALGRIND $libdir/bsdiff"
|
||||
BSPATCH="sudo $ldpath $VALGRIND $libdir/bspatch"
|
||||
|
||||
# If exit status is 0, the test succeeded. Else it failed.
|
||||
check_success() {
|
||||
|
||||
Reference in New Issue
Block a user