mirror of
https://github.com/expo/bsdiff.git
synced 2026-11-14 17:49:03 -10:00
bsdiff: convert ebuild to the new eclass format
Portage automatically uses an overlay ebuild of the same name, so it suffices to copy and modify the original ebuild. Review URL: http://codereview.chromium.org/2779016
This commit is contained in:
1 parent
9d4448afbb
commit
339e0eece8
1 file changed
+258
-10
@@ -29,6 +29,9 @@ __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:
|
||||
#endif
|
||||
|
||||
#include <bzlib.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -37,6 +40,235 @@ __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h> // android
|
||||
|
||||
#define JOIN(a, b) __JOIN(a, b)
|
||||
#define __JOIN(a, b) a ## b
|
||||
#define COMPILE_ASSERT(expr, message) \
|
||||
typedef char JOIN(message, JOIN(_, __LINE__)) [(expr) ? 1 : -1]
|
||||
|
||||
COMPILE_ASSERT(sizeof(int64_t) == 8, int64_t_64_bit);
|
||||
|
||||
#define MIN(a, b) \
|
||||
((a) < (b) ? (a) : (b))
|
||||
|
||||
// Reads next int from *ints. The int should be terminated with a comma
|
||||
// or NULL char. *ints will be updated to the space right after the comma
|
||||
// or set to NULL if this was the last number. This assumes the input is
|
||||
// a valid string, as validated with PositionsStringIsValid().
|
||||
// Returns 1 on success.
|
||||
int NextInt64(const char** ints, int64_t *out) {
|
||||
if (!ints[0])
|
||||
return 0;
|
||||
int r = sscanf(*ints, "%" PRIi64, out);
|
||||
if (r == 1) {
|
||||
const char* next_comma = strchr(*ints, ',');
|
||||
const char* next_colon = strchr(*ints, ':');
|
||||
if (!next_comma && !next_colon)
|
||||
*ints = NULL;
|
||||
else if (!next_comma)
|
||||
*ints = next_colon + 1;
|
||||
else if (!next_colon)
|
||||
*ints = next_comma + 1;
|
||||
else
|
||||
*ints = MIN(next_comma, next_colon) + 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
COMPILE_ASSERT(sizeof(intmax_t) == 8, intmax_t_not_64_bit);
|
||||
|
||||
// Returns 1 if str can be converted to int64_t without over/underflowing.
|
||||
// str is assumed to point to an optional negative sign followed by numbers,
|
||||
// optionally followed by non-numeric characters, followed by '\0'.
|
||||
int IsValidInt64(const char* str) {
|
||||
const char* end_ptr;
|
||||
errno = 0;
|
||||
intmax_t result = strtoimax(str, &end_ptr, /* base: */ 10);
|
||||
return errno == 0;
|
||||
}
|
||||
|
||||
// Input validator. Make sure the positions string is well formatted.
|
||||
// All numerical values are checked to make sure they don't over/underflow
|
||||
// int64_t. Returns 1 if valid.
|
||||
int PositionsStringIsValid(const char* positions) {
|
||||
if (positions == NULL)
|
||||
errx(1, "bad string");
|
||||
|
||||
// Special case: empty string is valid
|
||||
if (!positions[0])
|
||||
return 1;
|
||||
|
||||
// Use a state machine to determine if the string is valid.
|
||||
// Key: (s): state, ((s)) valid end state.
|
||||
// n (negative_valid) is a boolean that starts out as true.
|
||||
// If n is true, ':' is the delimiter, otherwise ','.
|
||||
//
|
||||
// .--------------------------.
|
||||
// | | n ? ':' : ',' ; n = !n
|
||||
// V '-'&&n 0-9 |
|
||||
// start->(0)------------->(1)----->((2))---.
|
||||
// `---------------------> <--' 0-9
|
||||
// 0-9
|
||||
int state = 0;
|
||||
int negative_valid = 1;
|
||||
const char* number_start = positions;
|
||||
for (;; positions++) {
|
||||
char c = *positions;
|
||||
switch (state) {
|
||||
case 0:
|
||||
if (c == '-' && negative_valid) {
|
||||
state = 1;
|
||||
continue;
|
||||
}
|
||||
if (isdigit(c)) {
|
||||
state = 2;
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
case 1:
|
||||
if (isdigit(c)) {
|
||||
state = 2;
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
case 2:
|
||||
if (isdigit(c))
|
||||
continue;
|
||||
// number_start must point to a valid number
|
||||
if (!IsValidInt64(number_start)) {
|
||||
return 0;
|
||||
}
|
||||
if ((negative_valid && c == ':') ||
|
||||
(!negative_valid && c == ',')) {
|
||||
state = 0;
|
||||
number_start = positions + 1;
|
||||
negative_valid = !negative_valid;
|
||||
continue;
|
||||
}
|
||||
return (c == '\0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reads into a buffer a series of byte ranges from filename.
|
||||
// Each range is a pair of comma-separated ints from positions.
|
||||
// -1 as an offset means a sparse-hole.
|
||||
// E.g. If positions were "1,5:23,4:-1,8:3,7", then we would return a buffer
|
||||
// consisting of 5 bytes from offset 1 of the file, followed by
|
||||
// 4 bytes from offset 23, then 8 bytes of all zeros, then 7 bytes from
|
||||
// offset 3 in the file.
|
||||
// Returns NULL on error.
|
||||
static char* PositionedRead(const char* filename,
|
||||
const char* positions,
|
||||
ssize_t* old_size) {
|
||||
if (!PositionsStringIsValid(positions)) {
|
||||
errx(1, "invalid positions string for read\n");
|
||||
}
|
||||
|
||||
// Get length
|
||||
const char* p = positions;
|
||||
int64_t length = 0;
|
||||
for (;;) {
|
||||
int64_t value;
|
||||
if (0 == NextInt64(&p, &value)) {
|
||||
break;
|
||||
}
|
||||
int r = NextInt64(&p, &value);
|
||||
if (r == 0) {
|
||||
errx(1, "bad length parse\n");
|
||||
}
|
||||
if (value < 0) {
|
||||
errx(1, "length can't be negative\n");
|
||||
}
|
||||
length += value;
|
||||
}
|
||||
|
||||
// Malloc
|
||||
if (length > 0x40000000) { // 1 GiB; sanity check
|
||||
errx(1, "Read length too long (exceeds 1 GiB)");
|
||||
}
|
||||
// Following bsdiff convention, allocate length + 1 to avoid malloc(0)
|
||||
char* buf = malloc(length + 1);
|
||||
if (buf == NULL) {
|
||||
errx(1, "malloc failed\n");
|
||||
}
|
||||
char* buf_tail = buf;
|
||||
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
errx(1, "open failed for read\n");
|
||||
}
|
||||
|
||||
// Read bytes
|
||||
p = positions;
|
||||
for (;;) {
|
||||
int64_t offset, read_length;
|
||||
if (NextInt64(&p, &offset) == 0) {
|
||||
break;
|
||||
}
|
||||
if (offset < 0) {
|
||||
errx(1, "no support for sparse positions "
|
||||
"yet during read\n");
|
||||
}
|
||||
if (NextInt64(&p, &read_length) == 0) {
|
||||
errx(1, "bad length parse (should never happen)\n");
|
||||
}
|
||||
if (read_length < 0) {
|
||||
errx(1, "length can't be negative "
|
||||
"(should never happen)\n");
|
||||
}
|
||||
ssize_t rc = pread(fd, buf_tail, read_length, offset);
|
||||
if (rc != read_length) {
|
||||
errx(1, "read failed\n");
|
||||
}
|
||||
buf_tail += rc;
|
||||
}
|
||||
close(fd);
|
||||
*old_size = length;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void PositionedWrite(const char* filename,
|
||||
const char* positions,
|
||||
const char* buf,
|
||||
ssize_t new_size) {
|
||||
if (!PositionsStringIsValid(positions)) {
|
||||
errx(1, "invalid positions string for write\n");
|
||||
}
|
||||
int fd = open(filename, O_WRONLY | O_CREAT, 0666);
|
||||
if (fd < 0) {
|
||||
errx(1, "open failed for write\n");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int64_t offset, length;
|
||||
if (NextInt64(&positions, &offset) == 0) {
|
||||
break;
|
||||
}
|
||||
if (NextInt64(&positions, &length) == 0) {
|
||||
errx(1, "bad length parse for write\n");
|
||||
}
|
||||
if (length < 0) {
|
||||
errx(1, "length can't be negative for write\n");
|
||||
}
|
||||
|
||||
if (offset < 0) {
|
||||
// Sparse hole. Skip.
|
||||
} else {
|
||||
ssize_t rc = pwrite(fd, buf, length, offset);
|
||||
if (rc != length) {
|
||||
errx(1, "write failed\n");
|
||||
}
|
||||
}
|
||||
buf += length;
|
||||
new_size -= length;
|
||||
}
|
||||
if (new_size != 0) {
|
||||
errx(1, "output position length doesn't match new size\n");
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static off_t offtin(u_char *buf)
|
||||
{
|
||||
off_t y;
|
||||
@@ -70,7 +302,13 @@ int main(int argc,char * argv[])
|
||||
off_t lenread;
|
||||
off_t i;
|
||||
|
||||
if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);
|
||||
if ((argc != 6) && (argc != 4)) {
|
||||
errx(1,"usage: %s oldfile newfile patchfile \\\n"
|
||||
" [in_offset,in_length,in_offset,in_length,... \\\n"
|
||||
" out_offset,out_length,"
|
||||
"out_offset,out_length,...]\n",argv[0]);
|
||||
}
|
||||
int using_positioning = (argc == 6);
|
||||
|
||||
/* Open patch file */
|
||||
if ((f = fopen(argv[3], "r")) == NULL)
|
||||
@@ -133,12 +371,18 @@ int main(int argc,char * argv[])
|
||||
if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
|
||||
errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);
|
||||
|
||||
if(((fd=open(argv[1],O_RDONLY,0))<0) ||
|
||||
((oldsize=lseek(fd,0,SEEK_END))==-1) ||
|
||||
((old=malloc(oldsize+1))==NULL) ||
|
||||
(lseek(fd,0,SEEK_SET)!=0) ||
|
||||
(read(fd,old,oldsize)!=oldsize) ||
|
||||
(close(fd)==-1)) err(1,"%s",argv[1]);
|
||||
// Read
|
||||
|
||||
if (!using_positioning) {
|
||||
if(((fd=open(argv[1],O_RDONLY,0))<0) ||
|
||||
((oldsize=lseek(fd,0,SEEK_END))==-1) ||
|
||||
((old=malloc(oldsize+1))==NULL) ||
|
||||
(lseek(fd,0,SEEK_SET)!=0) ||
|
||||
(read(fd,old,oldsize)!=oldsize) ||
|
||||
(close(fd)==-1)) err(1,"%s",argv[1]);
|
||||
} else {
|
||||
old = PositionedRead(argv[1], argv[4], &oldsize);
|
||||
}
|
||||
if((new=malloc(newsize+1))==NULL) err(1,NULL);
|
||||
|
||||
oldpos=0;newpos=0;
|
||||
@@ -199,9 +443,13 @@ int main(int argc,char * argv[])
|
||||
err(1, "fclose(%s)", argv[3]);
|
||||
|
||||
/* Write the new file */
|
||||
if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) ||
|
||||
(write(fd,new,newsize)!=newsize) || (close(fd)==-1))
|
||||
err(1,"%s",argv[2]);
|
||||
if (!using_positioning) {
|
||||
if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) ||
|
||||
(write(fd,new,newsize)!=newsize) || (close(fd)==-1))
|
||||
err(1,"%s",argv[2]);
|
||||
} else {
|
||||
PositionedWrite(argv[2], argv[5], new, newsize);
|
||||
}
|
||||
|
||||
free(new);
|
||||
free(old);
|
||||
|
||||
Reference in new issue
Block a user