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; }
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; }
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; }
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; }
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; }
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; }
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; }