27 Commits
Author SHA1 Message Date
Robert Dower eb522b1dc9 archive repository 2025-08-07 13:27:50 -07:00
Patrick McCarty 53ce8b6d66 Remove trailing whitespace
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2022-08-30 17:56:16 +00:00
Arjan van de Ven 02b6820a3d deal with two error cases 2022-08-30 14:30:34 +00:00
Patrick McCarty f563c9a475 Fix style issues detected with clang-format v14
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2022-08-30 02:53:29 +00:00
Arjan van de Ven 72a6259228 write to a unique-ish file and then rename at the end to avoid clashes 2022-08-29 18:20:53 -07:00
Patrick McCarty 5c2c4c76ac gitignore: ignore incomplete or extracted dist tarballs
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2021-01-03 21:56:51 +00:00
Patrick McCarty b45ff19ee4 gitignore: ignore more editor swap files 2021-01-03 21:54:05 +00:00
Patrick McCarty fcd3298583 mostlyclean: also remove .i and .s files
These files will be generated by `make` if CFLAGS contains `-save-temps`
or related flags.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2021-01-03 21:53:36 +00:00
Patrick McCarty 0d3d976fe4 distclean: more closely follow automake's guidelines
According to the documentation, `distclean` should delete files that
`configure` built. Since many of the files we have been declaring for
`distclean-local` are generated by `autoreconf`, avoid deleting several
of those files.

Also, note that the `autom4te.cache` directory is deleted by
`maintainer-clean` already. Most of the others are required for a clean
`configure` run.

To restore the tree to a pristine state, use `git clean -xffd`.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2021-01-03 21:43:36 +00:00
Patrick McCarty f192356812 distcheck: fix findstatic.pl runs for vpath build
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2021-01-03 21:42:50 +00:00
Patrick McCarty f81fb5a612 build: add placeholder m4 directory to avoid aclocal warning
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2020-12-30 04:02:54 +00:00
Patrick McCarty 0322f0839c configure: incorporate one more change from autoupdate
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2020-12-30 03:56:29 +00:00
Patrick McCarty 4807cb41f5 configure: address new warning from latest autoreconf
autoreconf from autoconf 2.70 warns that AC_PROG_CC_STDC is obsolete,
recommending to use AC_PROG_CC instead. We already call the latter
macro, and the behavior change appears to have been introduced in
autoconf 2.54 (released 2002-09-13), which is older than our minimum
supported version of 2.66.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2020-12-30 03:46:48 +00:00
Patrick McCarty dd93df7347 Ignore editor swap files
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2020-12-30 03:35:13 +00:00
Patrick McCarty 0d1a46ed6c Fix a code style issue raised by clang-format
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2020-04-10 10:53:44 -07:00
Patrick McCarty a1c17f3e9d Add additional code comments about some magic numbers
These values originate from Colin's paper directly, but I think more
data-driven testing and analysis is needed to determine whether the
values are generally optimal.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2018-10-09 21:43:32 -07:00
Patrick McCarty 9807f60b46 Rename several more variables and add code comments
The goal with these variables renamings is twofold: to clarify meaning
of the values being used, and to be consistently named for ease of
readability.

For example, the "scan" variable stored the position in the new file
where a match is searched for, and "pos" stored the position in the old
file where a match is found. These variables are now named "new_pos" and
"old_pos" to reflect that they both store position information,
referencing the new and old files, respectively.

Also, declare the renamed variables closer to where they are used, since
the function is quite lengthy already, and we build the code with
-std=gnu99, so this syntax is supported.

Finally, add some (hopefully) helpful code comments to clarify the diff
creation algorithm. The bspatch code in src/patch.c is better documented
than the diff code, so I am starting with the diff code documentation.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2018-10-09 21:30:45 -07:00
Patrick McCarty e27563e653 Rename oldsize->old_size and newsize->new_size
To align better with variable renamings in the forthcoming commit,
rename the two variables indicating size of the old and new files first.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2018-10-09 21:30:45 -07:00
Patrick McCarty e0e8bcda58 Release v1.0.4
This release fixes an issue with libbsdiff thread safety. This was a
regression introduced in v1.0.3.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2018-06-14 14:50:54 -07:00
Patrick McCarty 2e5b80929c Make revised search algorithm thread safe
In commit 85b1c5345b, I introduced a new "max_len" variable, used by the
search() function to store the maximum match length found in course of
the binary search.

However, I overlooked the fact that the search() function then lost
thread safety, as "max_len" would be shared by all threads of a process
using libbsdiff.

Fix the issue by not using a global variable, instead updating "max_len"
via another pointer, just like the "pos" variable is handled already.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2018-06-14 14:46:52 -07:00
Patrick McCarty 6127bd6095 Release v1.0.3
This release fixes a bug that results in significantly improved diff
creation times in certain cases.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2018-02-22 18:04:24 -08:00
Patrick McCarty 85b1c5345b Find the longest match in the suffix-sorted array
Fixes #2

The current implementation performs a binary search through the
suffix-sorted array to find byte sequence matches between old and new
files. However, the algorithm is not optimal when it repeatedly matches
very short strings, leading to performance issues as reported in issue
 #2.

This commit changes the algorithm to consider *all* matches encountered
during the binary search and choose the longest of these matches.

The overall performance impact is yet to be determined, but it appears
to yield a small percentage increase in diff creation time (expected)
and a large percentage *decrease* for the case of diffing the files from
issue #2. In my testing, the creation time there decreases from approx
64 minutes to 4.5 seconds.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2018-02-22 18:01:17 -08:00
Patrick McCarty d039492824 Fix code style
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-06-12 11:33:09 -07:00
Patrick McCarty 43a817a2e5 build: add 'compliant' makefile target for fixing code style
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-06-12 11:32:33 -07:00
Patrick McCarty 4e868b4772 Split suffix sort code into a separate source file
To prepare for the possibility of testing other suffix sort algorithms
in the future, split this code into a separate source file for clarity.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-06-12 11:24:09 -07:00
Patrick McCarty 71b9d7e78a Allow for skipping valgrind use in tests
In case the system valgrind is not functioning properly, allow the test
suite to run without using the tool by setting SKIP_VALGRIND=1 for `make
check`.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2016-12-13 10:07:22 -08:00
Patrick McCarty b46a4e2c0f Run clang-format to fix code style
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2016-12-13 09:49:33 -08:00
13 changed files with 542 additions and 385 deletions
+8 -2
View File
@@ -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
View File
@@ -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 \
+7
View File
@@ -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
View File
@@ -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)
View File
+4 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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() {