Example #1
0
File: nile.c Project: Gottox/nile
int
nilePatch(FILE *oldfile, FILE *patch, FILE *output, enum Options options) {
	int rv = 0;
	char difference[3*8], header[8], buf[BUFSIZ];
	char oldmd5[MD5_DIGEST_LENGTH] = { 0 }, newmd5[MD5_DIGEST_LENGTH] = { 0 };
	int size;

	off_t skip, oldsize, newsize;

	if(fread(header, sizeof(header), 1, patch) != 1 ||
			memcmp(header, MAGIC, sizeof(header)) != 0) {
		fprintf(stderr, "patchfile: invalid magic\n");
		goto patch_cleanup;
	}

	if(fread(header, sizeof(header), 1, patch) != 1) {
		fprintf(stderr, "patchfile: invalid header\n");
		goto patch_cleanup;
	}

	if(fread(oldmd5, sizeof(oldmd5), 1, patch) != 1) {
		fprintf(stderr, "patchfile: invalid header\n");
		goto patch_cleanup;
	}
	if(fread(newmd5, sizeof(newmd5), 1, patch) != 1) {
		fprintf(stderr, "patchfile: invalid header\n");
		goto patch_cleanup;
	}

	while((size = fread(difference, sizeof(difference), 1, patch)) == 1) {
		skip = offtin(difference);
		oldsize = offtin(difference+8);
		newsize = offtin(difference+16);
		fprintf(stderr, "skip %li oldsize: %li newsize: %li\n", skip, oldsize,
				newsize);

		while((size = fread(buf, 1, MIN(sizeof(buf), skip), oldfile)) > 0) {
			fwrite(buf, size, 1, output);
			skip -= size;
		}

		fseek(oldfile, oldsize, SEEK_CUR);

		while((size = fread(buf, 1, MIN(sizeof(buf), newsize), patch)) > 0) {
			fwrite(buf, size, 1, output);
			newsize -= size;
		}
	}
	if(size < 0) {
		perror("patchfile");
		rv = 1;
	}
	else if(size != 0) {
		fprintf(stderr, "patchfile: premature end of file %i\n", size);
		rv = 1;
	}
patch_cleanup:
	return rv;
}
JNIEXPORT jbyteArray JNICALL Java_cn_reactnative_modules_update_DownloadTask_bsdiffPatch
        (JNIEnv *env, jobject self, jbyteArray origin, jbyteArray patch){
    jclass newExcCls;
    jbyte* outPtr;
    struct bspatch_stream stream;
    bz_stream zip;

    jbyte* originPtr = (*env)->GetByteArrayElements(env, origin, NULL);
    size_t originLength = (*env)->GetArrayLength(env, origin);
    jbyte* patchPtr = (*env)->GetByteArrayElements(env, patch, NULL);
    size_t patchLength = (*env)->GetArrayLength(env, patch);
    jbyteArray ret = NULL;

    if (patchLength < 32) {
        newExcCls = (*env)->FindClass(env,"java/lang/Error");
        if (newExcCls != NULL) /* Unable to find the new exception class, give up. */
            (*env)->ThrowNew(env,newExcCls, "Corrupt patch");
        (*env)->ReleaseByteArrayElements(env, origin, originPtr, JNI_ABORT);
        (*env)->ReleaseByteArrayElements(env, patch, patchPtr, JNI_ABORT);
        return NULL;
    }
    int64_t newsize=offtin((uint8_t*)patchPtr + 16);
    if (memcmp(patchPtr, "ENDSLEY/BSDIFF43", 16) != 0 || newsize<0) {
        newExcCls = (*env)->FindClass(env, "java/lang/Error");
        if (newExcCls != NULL) /* Unable to find the new exception class, give up. */
            (*env)->ThrowNew(env, newExcCls, "Corrupt patch");
        (*env)->ReleaseByteArrayElements(env, origin, originPtr, JNI_ABORT);
        (*env)->ReleaseByteArrayElements(env, patch, patchPtr, JNI_ABORT);
        return NULL;
    }
    ret = (*env)->NewByteArray(env, newsize);
    if (ret == NULL) {
        return NULL; //  out of memory error thrown
    }
    outPtr = (*env)->GetByteArrayElements(env, ret, NULL);

    zip.bzalloc = NULL;
    zip.bzfree = NULL;
    zip.opaque = NULL;
    BZ2_bzDecompressInit(&zip, 0, 1);

    zip.next_in = (char*)patchPtr + 32;
    zip.avail_in = patchLength - 32;

    stream.read = bz2_read;
    stream.opaque = &zip;
    if (bspatch((const uint8_t*)originPtr, originLength, (uint8_t*)outPtr, newsize, &stream)) {
        newExcCls = (*env)->FindClass(env, "java/lang/Error");
        if (newExcCls != NULL) /* Unable to find the new exception class, give up. */
            (*env)->ThrowNew(env, newExcCls, "bspatch");
    }

    BZ2_bzDecompressEnd(&zip);

    (*env)->ReleaseByteArrayElements(env, ret, outPtr, 0);
    (*env)->ReleaseByteArrayElements(env, origin, originPtr, JNI_ABORT);
    (*env)->ReleaseByteArrayElements(env, patch, patchPtr, JNI_ABORT);
    return ret;
}
Example #3
0
int bspatch(const uint8_t* olddata, int64_t oldsize, uint8_t* newdata, int64_t newsize, struct bspatch_stream* stream)
{
	uint8_t buf[8];
	int64_t oldpos,newpos;
	int64_t ctrl[3];
	int64_t i;

	oldpos=0;newpos=0;
	while(newpos<newsize) {
		/* Read control data */
		for(i=0;i<=2;i++) {
			if (stream->read(stream, buf, 8))
				return -1;
			ctrl[i]=offtin(buf);
		};

		/* Sanity-check */
		if(newpos+ctrl[0]>newsize)
			return -1;

		/* Read diff string */
		if (stream->read(stream, newdata + newpos, ctrl[0]))
			return -1;

		/* Add olddata data to diff string */
		for(i=0;i<ctrl[0];i++)
			if((oldpos+i>=0) && (oldpos+i<oldsize))
				newdata[newpos+i]+=olddata[oldpos+i];

		/* Adjust pointers */
		newpos+=ctrl[0];
		oldpos+=ctrl[0];

		/* Sanity-check */
		if(newpos+ctrl[1]>newsize)
			return -1;

		/* Read extra string */
		if (stream->read(stream, newdata + newpos, ctrl[1]))
			return -1;

		/* Adjust pointers */
		newpos+=ctrl[1];
		oldpos+=ctrl[2];
	};

	return 0;
}
Example #4
0
bool makeNewfile(const unsigned char*oldfilebuff,unsigned int oldfileSize,const char*p_newfile,const char* p_patchfile)
{
	FILE * f, * cpf, * dpf, * epf;
	BZFILE * cpfbz2, * dpfbz2, * epfbz2;
	int cbz2err, dbz2err, ebz2err;
	int fd;
	ssize_t oldsize,newsize;
	ssize_t bzctrllen,bzdatalen;
	unsigned char header[32],buf[8];
	unsigned char *old, *newfile;
	off_t oldpos,newpos;
	off_t ctrl[3];
	off_t lenread;
	off_t i;
    
    
	/* Open patch file */
	if ((f = fopen(p_patchfile, "r")) == NULL)
    {
		err(1, "fopen(%s)", p_patchfile);
        return false;
    }
    
	/*
     File format:
     0	8	"BSDIFF40"
     8	8	X
     16	8	Y
     24	8	sizeof(newfile)
     32	X	bzip2(control block)
     32+X	Y	bzip2(diff block)
     32+X+Y	???	bzip2(extra block)
     with control block a set of triples (x,y,z) meaning "add x bytes
     from oldfile to x bytes from the diff block; copy y bytes from the
     extra block; seek forwards in oldfile by z bytes".
     */
    
	/* Read header */
	if (fread(header, 1, 32, f) < 32) {
		if (feof(f))
        {
			errx(1, "Corrupt patch\n");
            return false;
        }
		err(1, "fread(%s)", p_patchfile);
        return false;
	}
    
	/* Check for appropriate magic */
	if (memcmp(header, "BSDIFF40", 8) != 0)
    {
		errx(1, "Corrupt patch\n");
        return false;
    }
    
	/* Read lengths from header */
	bzctrllen=offtin(header+8);
	bzdatalen=offtin(header+16);
	newsize=offtin(header+24);
	if((bzctrllen<0) || (bzdatalen<0) || (newsize<0))
    {
		errx(1,"Corrupt patch\n");
        return false;
    }
    
	/* Close patch file and re-open it via libbzip2 at the right places */
	if (fclose(f))
    {
		err(1, "fclose(%s)", p_patchfile);
        return false;
    }
	if ((cpf = fopen(p_patchfile, "r")) == NULL)
    {
		err(1, "fopen(%s)", p_patchfile);
        return false;
    }
	if (fseeko(cpf, 32, SEEK_SET))
    {
		err(1, "fseeko(%s, %lld)", p_patchfile,
		    (long long)32);
        return false;
    }
	if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
    {
		errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);
        return false;
    }
	if ((dpf = fopen(p_patchfile, "r")) == NULL)
    {
		err(1, "fopen(%s)", p_patchfile);
        return false;
    }
	if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))
    {
		err(1, "fseeko(%s, %lld)", p_patchfile,
		    (long long)(32 + bzctrllen));
        return false;
    }
	if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
    {
		errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);
        return false;
    }
	if ((epf = fopen(p_patchfile, "r")) == NULL)
    {
		err(1, "fopen(%s)", p_patchfile);
        return false;
    }
	if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
    {
		err(1, "fseeko(%s, %lld)", p_patchfile,
		    (long long)(32 + bzctrllen + bzdatalen));
        return false;
    }
	if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
    {
		errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);
        return false;
    }
//	if(((fd=open(p_oldfile,O_RDONLY,0))<0) ||
//       ((oldsize=lseek(fd,0,SEEK_END))==-1) ||
//       ((old=(unsigned char *)malloc(oldsize+1))==NULL) ||
//       (lseek(fd,0,SEEK_SET)!=0) ||
//       (read(fd,old,oldsize)!=oldsize) ||
//       (close(fd)==-1))
    old=(unsigned char*)oldfilebuff;
    oldsize=oldfileSize;


	if((newfile=(unsigned char *)malloc(newsize+1))==NULL)
    {
        err(1,NULL);
        return false;
    }
	oldpos=0;newpos=0;
	while(newpos<newsize) {
		/* Read control data */
		for(i=0;i<=2;i++) {
			lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
			if ((lenread < 8) || ((cbz2err != BZ_OK) &&
                                  (cbz2err != BZ_STREAM_END)))
            {
				errx(1, "Corrupt patch\n");
                return false;
            }
			ctrl[i]=offtin(buf);
		};
        
		/* Sanity-check */
		if(newpos+ctrl[0]>newsize)
        {
			errx(1,"Corrupt patch\n");
            return false;
        }
        
		/* Read diff string */
		lenread = BZ2_bzRead(&dbz2err, dpfbz2, newfile + newpos, ctrl[0]);
		if ((lenread < ctrl[0]) ||
		    ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
        {
			errx(1, "Corrupt patch\n");
            return false;
        }
		/* Add old data to diff string */
		for(i=0;i<ctrl[0];i++)
			if((oldpos+i>=0) && (oldpos+i<oldsize))
				newfile[newpos+i]+=old[oldpos+i];
        
		/* Adjust pointers */
		newpos+=ctrl[0];
		oldpos+=ctrl[0];
        
		/* Sanity-check */
		if(newpos+ctrl[1]>newsize)
        {
			errx(1,"Corrupt patch\n");
            return false;
        }
		/* Read extra string */
		lenread = BZ2_bzRead(&ebz2err, epfbz2, newfile + newpos, ctrl[1]);
		if ((lenread < ctrl[1]) ||
		    ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
        {
			errx(1, "Corrupt patch\n");
            return false;
        }
		/* Adjust pointers */
		newpos+=ctrl[1];
		oldpos+=ctrl[2];
	};
    
	/* Clean up the bzip2 reads */
	BZ2_bzReadClose(&cbz2err, cpfbz2);
	BZ2_bzReadClose(&dbz2err, dpfbz2);
	BZ2_bzReadClose(&ebz2err, epfbz2);
	if (fclose(cpf) || fclose(dpf) || fclose(epf))
    {
		err(1, "fclose(%s)", p_patchfile);
        return false;
    }
	/* Write the new file */
	if(((fd=open(p_newfile,O_CREAT|O_TRUNC|O_WRONLY,0666))<0) ||
       (write(fd,newfile,newsize)!=newsize) || (close(fd)==-1))
    {
		err(1,"%s",p_newfile);
        return false;
    }
	free(newfile);

	return true;
}
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
                        const Value* patch, ssize_t patch_offset,
                        unsigned char** new_data, ssize_t* new_size) {
    // Patch data format:
    //   0       8       "BSDIFF40"
    //   8       8       X
    //   16      8       Y
    //   24      8       sizeof(newfile)
    //   32      X       bzip2(control block)
    //   32+X    Y       bzip2(diff block)
    //   32+X+Y  ???     bzip2(extra block)
    // with control block a set of triples (x,y,z) meaning "add x bytes
    // from oldfile to x bytes from the diff block; copy y bytes from the
    // extra block; seek forwards in oldfile by z bytes".

    unsigned char* header = (unsigned char*) patch->data + patch_offset;
    if (memcmp(header, "BSDIFF40", 8) != 0) {
        printf("corrupt bsdiff patch file header (magic number)\n");
        return 1;
    }

    ssize_t ctrl_len, data_len;
    ctrl_len = offtin(header+8);
    data_len = offtin(header+16);
    *new_size = offtin(header+24);

    if (ctrl_len < 0 || data_len < 0 || *new_size < 0) {
        printf("corrupt patch file header (data lengths)\n");
        return 1;
    }

    int bzerr;

    bz_stream cstream;
    cstream.next_in = patch->data + patch_offset + 32;
    cstream.avail_in = ctrl_len;
    cstream.bzalloc = NULL;
    cstream.bzfree = NULL;
    cstream.opaque = NULL;
    if ((bzerr = BZ2_bzDecompressInit(&cstream, 0, 0)) != BZ_OK) {
        printf("failed to bzinit control stream (%d)\n", bzerr);
    }

    bz_stream dstream;
    dstream.next_in = patch->data + patch_offset + 32 + ctrl_len;
    dstream.avail_in = data_len;
    dstream.bzalloc = NULL;
    dstream.bzfree = NULL;
    dstream.opaque = NULL;
    if ((bzerr = BZ2_bzDecompressInit(&dstream, 0, 0)) != BZ_OK) {
        printf("failed to bzinit diff stream (%d)\n", bzerr);
    }

    bz_stream estream;
    estream.next_in = patch->data + patch_offset + 32 + ctrl_len + data_len;
    estream.avail_in = patch->size - (patch_offset + 32 + ctrl_len + data_len);
    estream.bzalloc = NULL;
    estream.bzfree = NULL;
    estream.opaque = NULL;
    if ((bzerr = BZ2_bzDecompressInit(&estream, 0, 0)) != BZ_OK) {
        printf("failed to bzinit extra stream (%d)\n", bzerr);
    }

    *new_data = malloc(*new_size);
    if (*new_data == NULL) {
        printf("failed to allocate %ld bytes of memory for output file\n",
               (long)*new_size);
        return 1;
    }

    off_t oldpos = 0, newpos = 0;
    off_t ctrl[3];
    off_t len_read;
    int i;
    unsigned char buf[24];
    while (newpos < *new_size) {
        // Read control data
        if (FillBuffer(buf, 24, &cstream) != 0) {
            printf("error while reading control stream\n");
            return 1;
        }
        ctrl[0] = offtin(buf);
        ctrl[1] = offtin(buf+8);
        ctrl[2] = offtin(buf+16);

        if (ctrl[0] < 0 || ctrl[1] < 0) {
            printf("corrupt patch (negative byte counts)\n");
            return 1;
        }

        // Sanity check
        if (newpos + ctrl[0] > *new_size) {
            printf("corrupt patch (new file overrun)\n");
            return 1;
        }

        // Read diff string
        if (FillBuffer(*new_data + newpos, ctrl[0], &dstream) != 0) {
            printf("error while reading diff stream\n");
            return 1;
        }

        // Add old data to diff string
        for (i = 0; i < ctrl[0]; ++i) {
            if ((oldpos+i >= 0) && (oldpos+i < old_size)) {
                (*new_data)[newpos+i] += old_data[oldpos+i];
            }
        }

        // Adjust pointers
        newpos += ctrl[0];
        oldpos += ctrl[0];

        // Sanity check
        if (newpos + ctrl[1] > *new_size) {
            printf("corrupt patch (new file overrun)\n");
            return 1;
        }

        // Read extra string
        if (FillBuffer(*new_data + newpos, ctrl[1], &estream) != 0) {
            printf("error while reading extra stream\n");
            return 1;
        }

        // Adjust pointers
        newpos += ctrl[1];
        oldpos += ctrl[2];
    }

    BZ2_bzDecompressEnd(&cstream);
    BZ2_bzDecompressEnd(&dstream);
    BZ2_bzDecompressEnd(&estream);
    return 0;
}
Example #6
0
int patch(AbstractFile* in, AbstractFile* out, AbstractFile* patch) {
	unsigned char header[32], buf[8];
	off_t oldsize, newsize;
	off_t bzctrllen, bzdatalen;
	off_t oldpos, newpos;
	int i;
	int cbz2err, dbz2err, ebz2err;
	off_t ctrl[3];
	size_t lenread;
	
	BZStream* cpfbz2;
	BZStream* dpfbz2;
	BZStream* epfbz2;
	
	/* Read header */
	if (patch->read(patch, header, 32) < 32) {
		return -1;
	}
	
	/* Check for appropriate magic */
	if (memcmp(header, "BSDIFF40", 8) != 0)
		return -2;
		
	/* Read lengths from header */
	bzctrllen = offtin(header + 8);
	bzdatalen = offtin(header + 16);
	newsize = offtin(header + 24);

	if((bzctrllen < 0) || (bzdatalen < 0) || (newsize < 0))
		return -3;
		
	cpfbz2 = openBZStream(patch, 32, 1024);
	dpfbz2 = openBZStream(patch, 32 + bzctrllen, 1024);
	epfbz2 = openBZStream(patch, 32 + bzctrllen + bzdatalen, 1024);
	
	oldsize = in->getLength(in);
	
	oldpos = 0;
	newpos = 0;
	unsigned char* writeBuffer = (unsigned char*) malloc(BUFFERSIZE);
	unsigned char* readBuffer = (unsigned char*) malloc(BUFFERSIZE);

	while(newpos < newsize) {
		/* Read control data */
		for(i=0;i<=2;i++) {
			lenread = bzRead(&cbz2err, cpfbz2, buf, 8);
			if ((lenread < 8) || ((cbz2err != BZ_OK) &&
			    (cbz2err != BZ_STREAM_END)))
				return -4;
			ctrl[i] = offtin(buf);
		};
			
		/* Sanity-check */
		if((newpos + ctrl[0]) > newsize)
			return -5;

		/* Read diff string */
		unsigned int toRead;
		unsigned int total = ctrl[0];
		while(total > 0) {
			if(total > BUFFERSIZE)
				toRead = BUFFERSIZE;
			else
				toRead = total;

			memset(writeBuffer, 0, toRead);
			lenread = bzRead(&dbz2err, dpfbz2, writeBuffer, toRead);
			if ((lenread < toRead) ||
			    ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
				return -6;

			/* Add old data to diff string */
			in->seek(in, oldpos);
			unsigned int maxRead;
			if((oldpos + toRead) > oldsize)
				maxRead = oldsize - oldpos;
			else
				maxRead = toRead;

			in->read(in, readBuffer, maxRead);
			for(i = 0; i < maxRead; i++) {
				writeBuffer[i] += readBuffer[i];
			}

			out->seek(out, newpos);
			out->write(out, writeBuffer, toRead);

			/* Adjust pointers */
			newpos += toRead;
			oldpos += toRead;
			total -= toRead;
		}

		/* Sanity-check */
		if((newpos + ctrl[1]) > newsize)
			return -7;

		total = ctrl[1];

		while(total > 0){ 
			if(total > BUFFERSIZE)
				toRead = BUFFERSIZE;
			else
				toRead = total;

			/* Read extra string */
			lenread = bzRead(&ebz2err, epfbz2, writeBuffer, toRead);
			if ((lenread < toRead) ||
			    ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
				return -8;

			out->seek(out, newpos);
			out->write(out, writeBuffer, toRead);
			
			/* Adjust pointers */
			newpos += toRead;
			total -= toRead;
		}

		oldpos += ctrl[2];
	};
	
	free(writeBuffer);
	free(readBuffer);

	closeBZStream(cpfbz2);
	closeBZStream(dpfbz2);
	closeBZStream(epfbz2);

	out->close(out);
	in->close(in);

	patch->close(patch);
	return 0;
}
// This function modifies the main() function included in bspatch.c of bsdiff-4.3 found at http://www.daemonology.net/bsdiff/
// It is changed to be a standalone function, to work entirely in memory, and to use my class MemoryDecompressor as an interface to BZip
// Up to the caller to deallocate new
bool ApplyPatch(char *old, unsigned int oldsize, char **_new, unsigned int *newsize, char *patch, unsigned int patchsize )
{
//	FILE * f, * cpf, * dpf, * epf;
//	BZFILE * cpfbz2, * dpfbz2, * epfbz2;
//	int cbz2err, dbz2err, ebz2err;
//	int fd;
//	ssize_t oldsize,newsize;
	ssize_t bzctrllen,bzdatalen;
	//u_char header[32];
	u_char buf[8];
//	u_char *old, *_new;
	off_t oldpos,newpos;
	off_t ctrl[3];
//	off_t lenread;
	off_t i;
	MemoryDecompressor decompress;
	unsigned int coff, doff, eoff;

//	if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);

	/* Open patch file */
//	if ((f = fopen(argv[3], "rb")) == NULL)
//		err(1, "fopen(%s)", argv[3]);

	/*
	File format:
	0	8	"BSDIFF40"
	8	8	X
	16	8	Y
	24	8	sizeof(newfile)
	32	X	bzip2(control block)
	32+X	Y	bzip2(diff block)
	32+X+Y	???	bzip2(extra block)
	with control block a set of triples (x,y,z) meaning "add x bytes
	from oldfile to x bytes from the diff block; copy y bytes from the
	extra block; seek forwards in oldfile by z bytes".
	*/

	/* Read header */
//	if (fread(header, 1, 32, f) < 32) {
//		if (feof(f))
//			errx(1, "Corrupt patch\n",0);
//		err(1, "fread(%s)", argv[3]);
//	}

//	memcpy(header, patch, 32);

	/* Check for appropriate magic */
	if (memcmp(patch, "BSDIFF40", 8) != 0)
	//	errx(1, "Corrupt patch\n",0);
		return false;

	/* Read lengths from header */
	bzctrllen=offtin((u_char*)patch+8);
	bzdatalen=offtin((u_char*)patch+16);
	*newsize=offtin((u_char*)patch+24);
	if((bzctrllen<0) || (bzdatalen<0) || (*newsize<0))
	//	errx(1,"Corrupt patch\n",0);
		return false;

	/* Close patch file and re-open it via libbzip2 at the right places */
//	if (fclose(f))
//		err(1, "fclose(%s)", argv[3]);
//	if ((cpf = fopen(argv[3], "rb")) == NULL)
//		err(1, "fopen(%s)", argv[3]);
//	if (fseeko(cpf, 32, SEEK_SET))
//		err(1, "fseeko(%s, %lld)", argv[3],
//		(long long)32);
//	if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
//		errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);
//	if ((dpf = fopen(argv[3], "rb")) == NULL)
//		err(1, "fopen(%s)", argv[3]);
//	if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))
//		err(1, "fseeko(%s, %lld)", argv[3],
//		(long long)(32 + bzctrllen));
//	if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
//		errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);
//	if ((epf = fopen(argv[3], "rb")) == NULL)
//		err(1, "fopen(%s)", argv[3]);
//	if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
//		err(1, "fseeko(%s, %lld)", argv[3],
//		(long long)(32 + bzctrllen + bzdatalen));
//	if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
//		errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);
	
	// decompress.Decompress((char*)patch+32, patchsize-32, true);

	coff=0;
	if (decompress.Decompress((char*)patch+32, bzctrllen, false)==false)
		return false;
	doff=decompress.GetTotalOutputSize();
	if (decompress.Decompress((char*)patch+32+bzctrllen, bzdatalen, false)==false)
		return false;
	eoff=decompress.GetTotalOutputSize();
	if (decompress.Decompress((char*)patch+32+bzctrllen+bzdatalen, patchsize-(32+bzctrllen+bzdatalen), true)==false)
		return false;

//	if(((fd=open(argv[1],O_RDONLY | _O_BINARY,0))<0) ||
//		((oldsize=lseek(fd,0,SEEK_END))==-1) ||
//		((old=(u_char*)malloc(oldsize+1))==NULL) ||
//		(lseek(fd,0,SEEK_SET)!=0) ||
//		(read(fd,old,oldsize)!=oldsize) ||
//		(close(fd)==-1)) err(1,"%s",argv[1]);
//	if((_new=(u_char*)malloc(newsize+1))==NULL) err(1,NULL);
	*_new = new char[*newsize+1];

	oldpos=0;newpos=0;
	while(newpos<(off_t)*newsize) {
		/* Read control data */
		for(i=0;i<=2;i++) {
		//	lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
		//	if ((lenread < 8) || ((cbz2err != BZ_OK) &&
		//		(cbz2err != BZ_STREAM_END)))
		//		errx(1, "Corrupt patch\n");
			memcpy(buf, decompress.GetOutput()+coff, 8);
			coff+=8;
		
			ctrl[i]=offtin(buf);
		};

		/* Sanity-check */
		if(newpos+ctrl[0]>(off_t)*newsize)
		{
			delete [] (*_new);
			return false;
		}

		/* Read diff string */
		//lenread = BZ2_bzRead(&dbz2err, dpfbz2, _new + newpos, ctrl[0]);
		//if ((lenread < ctrl[0]) ||
		//	((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
		//	errx(1, "Corrupt patch\n");
		memcpy(*_new + newpos, decompress.GetOutput()+doff, ctrl[0]);
		doff+=ctrl[0];

		/* Add old data to diff string */
		for(i=0;i<ctrl[0];i++)
			if((oldpos+i>=0) && (oldpos+i<(off_t)oldsize))
				(*_new)[newpos+i]+=old[oldpos+i];

		/* Adjust pointers */
		newpos+=ctrl[0];
		oldpos+=ctrl[0];

		/* Sanity-check */
		if(newpos+ctrl[1]>(off_t)*newsize)
		{
			delete [] (*_new);
			return false;
		}

		/* Read extra string */
		//lenread = BZ2_bzRead(&ebz2err, epfbz2, _new + newpos, ctrl[1]);
		//if ((lenread < ctrl[1]) ||
		//	((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
		//	errx(1, "Corrupt patch\n");
		memcpy(*_new + newpos, decompress.GetOutput()+eoff, ctrl[1]);
		eoff+=ctrl[1];

		/* Adjust pointers */
		newpos+=ctrl[1];
		oldpos+=ctrl[2];
	};

	/* Clean up the bzip2 reads */
//	BZ2_bzReadClose(&cbz2err, cpfbz2);
//	BZ2_bzReadClose(&dbz2err, dpfbz2);
//	BZ2_bzReadClose(&ebz2err, epfbz2);
//	if (fclose(cpf) || fclose(dpf) || fclose(epf))
//		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]);

//	free(_new);
//	free(old);

	return true;
}
int PATCH_main(int argc,char * argv[])
{
	FILE * f, * cpf, * dpf, * epf;
	BZFILE * cpfbz2, * dpfbz2, * epfbz2;
	int cbz2err, dbz2err, ebz2err;
	int fd;
	ssize_t oldsize,newsize;
	ssize_t bzctrllen,bzdatalen;
	u_char header[32],buf[8];
	u_char *old, *_new;
	off_t oldpos,newpos;
	off_t ctrl[3];
	off_t lenread;
	off_t i;

	unsigned bytesRead=0;

	if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);

	/* Open patch file */
	if ((f = fopen(argv[3], "rb")) == NULL)
		err(1, "fopen(%s)", argv[3]);

	/*
	File format:
	0	8	"BSDIFF40"
	8	8	X
	16	8	Y
	24	8	sizeof(newfile)
	32	X	bzip2(control block)
	32+X	Y	bzip2(diff block)
	32+X+Y	???	bzip2(extra block)
	with control block a set of triples (x,y,z) meaning "add x bytes
	from oldfile to x bytes from the diff block; copy y bytes from the
	extra block; seek forwards in oldfile by z bytes".
	*/

	/* Read header */
	if (fread(header, 1, 32, f) < 32) {
		if (feof(f))
			errx(1, "Corrupt patch\n");
		err(1, "fread(%s)", argv[3]);
	}

	/* Check for appropriate magic */
	if (memcmp(header, "BSDIFF40", 8) != 0)
		errx(1, "Corrupt patch\n");

	/* Read lengths from header */
	bzctrllen=offtin(header+8);
	bzdatalen=offtin(header+16);
	newsize=offtin(header+24);
	if((bzctrllen<0) || (bzdatalen<0) || (newsize<0))
		errx(1,"Corrupt patch\n");

	/* Close patch file and re-open it via libbzip2 at the right places */
	if (fclose(f))
		err(1, "fclose(%s)", argv[3]);
	if ((cpf = fopen(argv[3], "rb")) == NULL)
		err(1, "fopen(%s)", argv[3]);
	if (fseeko(cpf, 32, SEEK_SET))
		err(1, "fseeko(%s, %lld)", argv[3],
		(long long)32);
	if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
		errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);
	if ((dpf = fopen(argv[3], "rb")) == NULL)
		err(1, "fopen(%s)", argv[3]);
	if (fseeko(dpf, 32 + bzctrllen, SEEK_SET))
		err(1, "fseeko(%s, %lld)", argv[3],
		(long long)(32 + bzctrllen));
	if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
		errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);
	if ((epf = fopen(argv[3], "rb")) == NULL)
		err(1, "fopen(%s)", argv[3]);
	if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
		err(1, "fseeko(%s, %lld)", argv[3],
		(long long)(32 + bzctrllen + bzdatalen));
	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|O_BINARY,0))<0) ||
		((oldsize=lseek(fd,0,SEEK_END))==-1) ||
		((old=(u_char*)malloc(oldsize+1))==NULL) ||
		(lseek(fd,0,SEEK_SET)!=0) ||
		(read(fd,old,oldsize)!=oldsize) ||
		(close(fd)==-1)) err(1,"%s",argv[1]);
	if((_new=(u_char*)malloc(newsize+1))==NULL) err(1,NULL);

	oldpos=0;newpos=0;
	while(newpos<newsize) {
		/* Read control data */
		for(i=0;i<=2;i++) {
			lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
			if ((lenread < 8) || ((cbz2err != BZ_OK) &&
				(cbz2err != BZ_STREAM_END)))
				errx(1, "Corrupt patch\n");
			bytesRead+=8;
			//printf("cbz2err cpfbz2 %i %i\n", 8, bytesRead);
			ctrl[i]=offtin(buf);
		};

		/* Sanity-check */
		if(newpos+ctrl[0]>newsize)
			errx(1,"Corrupt patch\n");

		/* Read diff string */
		lenread = BZ2_bzRead(&dbz2err, dpfbz2, _new + newpos, ctrl[0]);
		bytesRead+=8;
//		printf("dbz2err dpfbz2 %i %i\n", ctrl[0], bytesRead);
		if ((lenread < ctrl[0]) ||
			((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
			errx(1, "Corrupt patch\n");

		/* Add old data to diff string */
		for(i=0;i<ctrl[0];i++)
			if((oldpos+i>=0) && (oldpos+i<oldsize))
				_new[newpos+i]+=old[oldpos+i];

		/* Adjust pointers */
		newpos+=ctrl[0];
		oldpos+=ctrl[0];

		/* Sanity-check */
		if(newpos+ctrl[1]>newsize)
			errx(1,"Corrupt patch\n");

		/* Read extra string */
		lenread = BZ2_bzRead(&ebz2err, epfbz2, _new + newpos, ctrl[1]);
		bytesRead+=8;
//		printf("ebz2err epfbz2 %i %i\n", ctrl[1], bytesRead);
		if ((lenread < ctrl[1]) ||
			((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
			errx(1, "Corrupt patch\n");

		/* Adjust pointers */
		newpos+=ctrl[1];
		oldpos+=ctrl[2];
	};

	/* Clean up the bzip2 reads */
	BZ2_bzReadClose(&cbz2err, cpfbz2);
	BZ2_bzReadClose(&dbz2err, dpfbz2);
	BZ2_bzReadClose(&ebz2err, epfbz2);
	if (fclose(cpf) || fclose(dpf) || fclose(epf))
		err(1, "fclose(%s)", argv[3]);

	/* Write the new file */
	if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666))<0) ||
		(write(fd,_new,newsize)!=newsize) || (close(fd)==-1))
		err(1,"%s",argv[2]);

	free(_new);
	free(old);

	return 0;
}
Example #9
0
int patch(AbstractFile* in, AbstractFile* out, AbstractFile* patch) {
	unsigned char header[32], buf[8];
	off_t oldsize, newsize;
	off_t bzctrllen, bzdatalen;
	off_t oldpos, newpos;
	unsigned char *old, *newBuffer;
	int i;
	int cbz2err, dbz2err, ebz2err;
	off_t ctrl[3];
	size_t lenread;
	
	BZStream* cpfbz2;
	BZStream* dpfbz2;
	BZStream* epfbz2;
	
	/* Read header */
	if (patch->read(patch, header, 32) < 32) {
		return -1;
	}
	
	/* Check for appropriate magic */
	if (memcmp(header, "BSDIFF40", 8) != 0)
		return -2;
		
	/* Read lengths from header */
	bzctrllen = offtin(header + 8);
	bzdatalen = offtin(header + 16);
	newsize = offtin(header + 24);

	if((bzctrllen < 0) || (bzdatalen < 0) || (newsize < 0))
		return -3;
		
	cpfbz2 = openBZStream(patch, 32, 1024);
	dpfbz2 = openBZStream(patch, 32 + bzctrllen, 1024);
	epfbz2 = openBZStream(patch, 32 + bzctrllen + bzdatalen, 1024);
	
	oldsize = in->getLength(in);
	old = malloc(oldsize + 1);
	in->seek(in, 0);
	in->read(in, old, oldsize);
	in->close(in);
	
	newBuffer = malloc(newsize + 1);
	
	oldpos = 0;
	newpos = 0;
	while(newpos < newsize) {
		/* Read control data */
		for(i=0;i<=2;i++) {
			lenread = bzRead(&cbz2err, cpfbz2, buf, 8);
			if ((lenread < 8) || ((cbz2err != BZ_OK) &&
			    (cbz2err != BZ_STREAM_END)))
				return -4;
			ctrl[i] = offtin(buf);
		};
			
		/* Sanity-check */
		if((newpos + ctrl[0]) > newsize)
			return -5;

		/* Read diff string */
		memset(newBuffer + newpos, 0, ctrl[0]);
		lenread = bzRead(&dbz2err, dpfbz2, newBuffer + newpos, ctrl[0]);
		if ((lenread < ctrl[0]) ||
		    ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
			return -6;

		/* Add old data to diff string */
		for(i = 0; i < ctrl[0]; i++) {
			if(((oldpos + i)>=0) && ((oldpos + i)<oldsize)) {
				newBuffer[newpos + i] += old[oldpos + i];
			}
		}
				
		/* Adjust pointers */
		newpos += ctrl[0];
		oldpos += ctrl[0];

		/* Sanity-check */
		if((newpos + ctrl[1]) > newsize)
			return -7;

		/* Read extra string */
		lenread = bzRead(&ebz2err, epfbz2, newBuffer + newpos, ctrl[1]);
		if ((lenread < ctrl[1]) ||
		    ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
			return -8;
			
		/* Adjust pointers */
		newpos += ctrl[1];
		oldpos += ctrl[2];
	};
	
	closeBZStream(cpfbz2);
	closeBZStream(dpfbz2);
	closeBZStream(epfbz2);
	out->seek(out, 0);

	if(out->write(out, newBuffer, newsize) != newsize)
		return -9;
	out->close(out);
	free(newBuffer);
	free(old);

	patch->close(patch);
	return 0;
}
Example #10
0
int bspatch(u_char* old, off_t oldsize, FILE* f, u_char** new_out, off_t* newsize_out)
{
	size_t offset;
	BZFILE * cpfbz2=NULL, * dpfbz2=NULL, * epfbz2=NULL;
	int cbz2err, dbz2err, ebz2err;
	u_char* newp=NULL;
	off_t newsize;
	off_t bzctrllen,bzdatalen;
	u_char header[32],buf[8];
	off_t oldpos,newpos;
	off_t ctrl[3];
	off_t lenread;
	off_t i;

	offset = ftell(f);

	/*
	File format:
		0	8	"BSDIFF40"
		8	8	X
		16	8	Y
		24	8	sizeof(newfile)
		32	X	bzip2(control block)
		32+X	Y	bzip2(diff block)
		32+X+Y	???	bzip2(extra block)
	with control block a set of triples (x,y,z) meaning "add x bytes
	from oldfile to x bytes from the diff block; copy y bytes from the
	extra block; seek forwards in oldfile by z bytes".
	*/

	/* Read header */
	if (fread(header, 1, 32, f) < 32) {
		if (feof(f)) {
			printf("Corrupt patch\n");
		} else {
			printf("fread(%s)", "patch_file");
		}
		goto error;
	}

	/* Read lengths from header */
	if(memcmp(header, "BSDIFFXX", 8)!=0) {
		printf("Corrupt patch\n");
		goto error;
	}
	bzctrllen=offtin(header+8);
	bzdatalen=offtin(header+16);
	newsize=offtin(header+24);
	if((bzctrllen<0) || (bzdatalen<0) || (newsize<0)) {
		printf("Corrupt patch\n");
		goto error;
	}

	newp = malloc(newsize);
	if(!newp) goto error;

	if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, f, 0, 0, NULL, 0)) == NULL) {
		printf("BZ2_bzReadOpen, bz2err = %d", cbz2err);
		goto error;
	}
	if (fseek(f, (long)(offset + 32 + bzctrllen), SEEK_SET)) {
		printf("fseeko(%s, %lld)", "patch_file", (long long)(offset + 32 + bzctrllen));
		goto error;
	}
	if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, f, 0, 0, NULL, 0)) == NULL) {
		printf("BZ2_bzReadOpen, bz2err = %d", dbz2err);
		goto error;
	}
	if (fseek(f, (long)(offset + 32 + bzctrllen + bzdatalen), SEEK_SET)) {
		printf("fseeko(%s, %lld)", "patch_file", (long long)(32 + bzctrllen + bzdatalen));
		goto error;
	}
	if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, f, 0, 0, NULL, 0)) == NULL) {
		printf("BZ2_bzReadOpen, bz2err = %d", ebz2err);
		goto error;
	}

	oldpos=0;newpos=0;
	while(newpos<newsize) {
		/* Read control data */
		for(i=0;i<=2;i++) {
			lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
			if ((lenread < 8) || ((cbz2err != BZ_OK) &&
			    (cbz2err != BZ_STREAM_END))) {
				printf("Corrupt patch\n");
				goto error;
			}
			ctrl[i]=offtin(buf);
		};

		/* Sanity-check */
		if(newpos+ctrl[0]>newsize) {
			printf("Corrupt patch\n");
			goto error;
		}

		/* Read diff string */
		lenread = BZ2_bzRead(&dbz2err, dpfbz2, newp + newpos, ctrl[0]);
		if ((lenread < ctrl[0]) ||
		    ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END))) {
			printf("Corrupt patch\n");
			goto error;
		}

		/* Add old data to diff string */
		for(i=0;i<ctrl[0];i++)
			if((oldpos+i>=0) && (oldpos+i<oldsize))
				newp[newpos+i]+=old[oldpos+i];

		/* Adjust pointers */
		newpos+=ctrl[0];
		oldpos+=ctrl[0];

		/* Sanity-check */
		if(newpos+ctrl[1]>newsize) {
			printf("Corrupt patch\n");
			goto error;
		}

		/* Read extra string */
		lenread = BZ2_bzRead(&ebz2err, epfbz2, newp + newpos, ctrl[1]);
		if ((lenread < ctrl[1]) ||
		    ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END))) {
			printf("Corrupt patch\n");
			goto error;
		}

		/* Adjust pointers */
		newpos+=ctrl[1];
		oldpos+=ctrl[2];
	};

	/* Clean up the bzip2 reads */
	BZ2_bzReadClose(&cbz2err, cpfbz2);
	BZ2_bzReadClose(&dbz2err, dpfbz2);
	BZ2_bzReadClose(&ebz2err, epfbz2);

	*new_out = newp;
	*newsize_out = newsize;
	return 0;

error:
	if(cpfbz2) BZ2_bzReadClose(&cbz2err, cpfbz2);
	if(dpfbz2) BZ2_bzReadClose(&dbz2err, dpfbz2);
	if(epfbz2) BZ2_bzReadClose(&ebz2err, epfbz2);
	if(newp) free(newp);
	return -1;
}
Example #11
0
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
                        const char* patch_filename, ssize_t patch_offset,
                        unsigned char** new_data, ssize_t* new_size) {

  FILE* f;
  if ((f = fopen(patch_filename, "rb")) == NULL) {
    fprintf(stderr, "failed to open patch file\n");
    return 1;
  }

  // File format:
  //   0       8       "BSDIFF40"
  //   8       8       X
  //   16      8       Y
  //   24      8       sizeof(newfile)
  //   32      X       bzip2(control block)
  //   32+X    Y       bzip2(diff block)
  //   32+X+Y  ???     bzip2(extra block)
  // with control block a set of triples (x,y,z) meaning "add x bytes
  // from oldfile to x bytes from the diff block; copy y bytes from the
  // extra block; seek forwards in oldfile by z bytes".

  fseek(f, patch_offset, SEEK_SET);

  unsigned char header[32];
  if (fread(header, 1, 32, f) < 32) {
    fprintf(stderr, "failed to read patch file header\n");
    return 1;
  }

  if (memcmp(header, "BSDIFF40", 8) != 0) {
    fprintf(stderr, "corrupt bsdiff patch file header (magic number)\n");
    return 1;
  }

  ssize_t ctrl_len, data_len;
  ctrl_len = offtin(header+8);
  data_len = offtin(header+16);
  *new_size = offtin(header+24);

  if (ctrl_len < 0 || data_len < 0 || *new_size < 0) {
    fprintf(stderr, "corrupt patch file header (data lengths)\n");
    return 1;
  }

  fclose(f);

  int bzerr;

#define OPEN_AT(f, bzf, offset)                                          \
  FILE* f;                                                               \
  BZFILE* bzf;                                                           \
  if ((f = fopen(patch_filename, "rb")) == NULL) {                       \
    fprintf(stderr, "failed to open patch file\n");                      \
    return 1;                                                            \
  }                                                                      \
  if (fseeko(f, offset+patch_offset, SEEK_SET)) {                        \
    fprintf(stderr, "failed to seek in patch file\n");                   \
    return 1;                                                            \
  }                                                                      \
  if ((bzf = BZ2_bzReadOpen(&bzerr, f, 0, 0, NULL, 0)) == NULL) {        \
    fprintf(stderr, "failed to bzReadOpen in patch file (%d)\n", bzerr); \
    return 1;                                                            \
  }

  OPEN_AT(cpf, cpfbz2, 32);
  OPEN_AT(dpf, dpfbz2, 32+ctrl_len);
  OPEN_AT(epf, epfbz2, 32+ctrl_len+data_len);

#undef OPEN_AT

  *new_data = malloc(*new_size);
  if (*new_data == NULL) {
    fprintf(stderr, "failed to allocate %d bytes of memory for output file\n",
            (int)*new_size);
    return 1;
  }

  off_t oldpos = 0, newpos = 0;
  off_t ctrl[3];
  off_t len_read;
  int i;
  unsigned char buf[8];
  while (newpos < *new_size) {
    // Read control data
    for (i = 0; i < 3; ++i) {
      len_read = BZ2_bzRead(&bzerr, cpfbz2, buf, 8);
      if (len_read < 8 || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) {
        fprintf(stderr, "corrupt patch (read control)\n");
        return 1;
      }
      ctrl[i] = offtin(buf);
    }

    // Sanity check
    if (newpos + ctrl[0] > *new_size) {
      fprintf(stderr, "corrupt patch (new file overrun)\n");
      return 1;
    }

    // Read diff string
    len_read = BZ2_bzRead(&bzerr, dpfbz2, *new_data + newpos, ctrl[0]);
    if (len_read < ctrl[0] || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) {
      fprintf(stderr, "corrupt patch (read diff)\n");
      return 1;
    }

    // Add old data to diff string
    for (i = 0; i < ctrl[0]; ++i) {
      if ((oldpos+i >= 0) && (oldpos+i < old_size)) {
        (*new_data)[newpos+i] += old_data[oldpos+i];
      }
    }

    // Adjust pointers
    newpos += ctrl[0];
    oldpos += ctrl[0];

    // Sanity check
    if (newpos + ctrl[1] > *new_size) {
      fprintf(stderr, "corrupt patch (new file overrun)\n");
      return 1;
    }

    // Read extra string
    len_read = BZ2_bzRead(&bzerr, epfbz2, *new_data + newpos, ctrl[1]);
    if (len_read < ctrl[1] || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) {
      fprintf(stderr, "corrupt patch (read extra)\n");
      return 1;
    }

    // Adjust pointers
    newpos += ctrl[1];
    oldpos += ctrl[2];
  }

  BZ2_bzReadClose(&bzerr, cpfbz2);
  BZ2_bzReadClose(&bzerr, dpfbz2);
  BZ2_bzReadClose(&bzerr, epfbz2);
  fclose(cpf);
  fclose(dpf);
  fclose(epf);

  return 0;
}