From 3106f55ad9b6d5ca9d427fcdd6ac6fe95459ac78 Mon Sep 17 00:00:00 2001 From: "egbert.liu" Date: Wed, 23 Oct 2019 20:38:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=9C=A8buffer?= =?UTF-8?q?=E4=B8=AD=E8=BF=9B=E8=A1=8Cdiff=E7=9A=84=E7=89=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bsdiff/bsdiff.c | 118 +++++++++++++++++++++++++++----------------- src/bsdiff/bsdiff.h | 1 + src/main.cc | 28 +++++++++++ 3 files changed, 103 insertions(+), 44 deletions(-) diff --git a/src/bsdiff/bsdiff.c b/src/bsdiff/bsdiff.c index 398aa26..a5bec24 100644 --- a/src/bsdiff/bsdiff.c +++ b/src/bsdiff/bsdiff.c @@ -195,36 +195,22 @@ static void offtout(off_t x,u_char *buf) if(x<0) buf[7]|=0x80; } -int bsdiff(const char* error, const char* oldfile, const char* newfile, const char* patchfile) { - int fd; - u_char *old,*new; - off_t oldsize,newsize; +int bsdiff_buf(const char* error, const char *old, size_t oldsize, char *new, size_t newsize, char **patch_buf) { off_t *I,*V; + u_char *db,*eb; off_t scan,pos,len; - off_t lastscan,lastpos,lastoffset; + u_char header[32]; off_t oldscore,scsc; off_t s,Sf,lenf,Sb,lenb; - off_t overlap,Ss,lens; + off_t lastscan,lastpos,lastoffset; off_t i; - off_t dblen,eblen; - u_char *db,*eb; u_char buf[8]; - u_char header[32]; - FILE * pf; - BZFILE * pfbz2; + off_t overlap,Ss,lens; + off_t dblen,eblen; int bz2err; - - /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure - that we never try to malloc(0) and get a NULL pointer */ - if(((fd=open(oldfile,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)) { - sprintf((char*)error, "\"%s\" %s", oldfile, strerror(errno)); - return -1; - } + BZFILE * pfbz2; + FILE * pf; + size_t patch_len; if(((I=malloc((oldsize+1)*sizeof(off_t)))==NULL) || ((V=malloc((oldsize+1)*sizeof(off_t)))==NULL)) { @@ -236,28 +222,16 @@ int bsdiff(const char* error, const char* oldfile, const char* newfile, const ch free(V); - /* Allocate newsize+1 bytes instead of newsize bytes to ensure - that we never try to malloc(0) and get a NULL pointer */ - if(((fd=open(newfile,O_RDONLY,0))<0) || - ((newsize=lseek(fd,0,SEEK_END))==-1) || - ((new=malloc(newsize+1))==NULL) || - (lseek(fd,0,SEEK_SET)!=0) || - (read(fd,new,newsize)!=newsize) || - (close(fd)==-1)) { - sprintf((char*)error, "\"%s\" %s", newfile, strerror(errno)); - return -1; - } - if(((db=malloc(newsize+1))==NULL) || ((eb=malloc(newsize+1))==NULL)) err(1,NULL); dblen=0; eblen=0; - - /* Create the patch file */ - if ((pf = fopen(patchfile, "w")) == NULL) { - sprintf((char*)error, "\"%s\" %s", patchfile, strerror(errno)); + + if ((pf = open_memstream(patch_buf, &patch_len)) == NULL) { + sprintf((char*)error, "open patch_buf failed: %s", strerror(errno)); return -1; - } + } + /* Header is 0 8 "BSDIFF40" @@ -273,10 +247,12 @@ int bsdiff(const char* error, const char* oldfile, const char* newfile, const ch offtout(0, header + 8); offtout(0, header + 16); offtout(newsize, header + 24); + if (fwrite(header, 32, 1, pf) != 1) { - sprintf((char*)error, "\"%s\" %s", patchfile, strerror(errno)); + sprintf((char*)error, "write header for patch failed: %s", strerror(errno)); return -1; - } + } + /* Compute the differences, writing ctrl as we go */ if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL) { @@ -372,6 +348,8 @@ int bsdiff(const char* error, const char* oldfile, const char* newfile, const ch lastoffset=pos-scan; }; }; + + BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL); if (bz2err != BZ_OK) { sprintf((char*)error, "BZ2_bzWriteClose, bz2err = %d", bz2err); @@ -403,6 +381,7 @@ int bsdiff(const char* error, const char* oldfile, const char* newfile, const ch return -1; } + /* Compute size of compressed diff data */ if ((newsize = ftello(pf)) == -1) { sprintf((char*)error, "\"ftello\" %s", strerror(errno)); @@ -428,15 +407,18 @@ int bsdiff(const char* error, const char* oldfile, const char* newfile, const ch return -1; } + // 只有在这里才能去到正确的长度,否则之后的代码会把pos设置为0 + size_t real_len = ftello(pf); /* Seek to the beginning, write the header, and close the file */ if (fseeko(pf, 0, SEEK_SET)) { sprintf((char*)error, "\"fseeko\" %s", strerror(errno)); return -1; } if (fwrite(header, 32, 1, pf) != 1) { - sprintf((char*)error, "\"%s\" %s", patchfile, strerror(errno)); + sprintf((char*)error, "write header for patch failed: %s", strerror(errno)); return -1; - } + } + if (fclose(pf)) { sprintf((char*)error, "\"fclose\" %s", strerror(errno)); return -1; @@ -446,6 +428,54 @@ int bsdiff(const char* error, const char* oldfile, const char* newfile, const ch free(db); free(eb); free(I); + return real_len; +} + +int bsdiff(const char* error, const char* oldfile, const char* newfile, const char* patchfile) { + int fd; + u_char *old,*new; + off_t oldsize,newsize; + FILE * pf; + char *patch_buf; + off_t patch_size; + + /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure + that we never try to malloc(0) and get a NULL pointer */ + if(((fd=open(oldfile,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)) { + sprintf((char*)error, "\"%s\" %s", oldfile, strerror(errno)); + return -1; + } + + /* Allocate newsize+1 bytes instead of newsize bytes to ensure + that we never try to malloc(0) and get a NULL pointer */ + if(((fd=open(newfile,O_RDONLY,0))<0) || + ((newsize=lseek(fd,0,SEEK_END))==-1) || + ((new=malloc(newsize+1))==NULL) || + (lseek(fd,0,SEEK_SET)!=0) || + (read(fd,new,newsize)!=newsize) || + (close(fd)==-1)) { + sprintf((char*)error, "\"%s\" %s", newfile, strerror(errno)); + return -1; + } + + + if ((pf = fopen(patchfile, "w")) == NULL) { + sprintf((char*)error, "\"%s\" %s", patchfile, strerror(errno)); + return -1; + } + + patch_size = bsdiff_buf(error, old, oldsize, new, newsize, &patch_buf); + fwrite(patch_buf, sizeof(char), patch_size, pf); + free(patch_buf); + if (fclose(pf)) { + sprintf((char*)error, "\"fclose\" %s", strerror(errno)); + return -1; + } free(old); free(new); diff --git a/src/bsdiff/bsdiff.h b/src/bsdiff/bsdiff.h index 652bac4..28eb09d 100644 --- a/src/bsdiff/bsdiff.h +++ b/src/bsdiff/bsdiff.h @@ -30,5 +30,6 @@ #include int bsdiff(const char* error, const char* oldfile, const char* newfile, const char* patchfile); +int bsdiff_buf(const char* error, const char *old_buf, size_t oldsize, char *new_buf, size_t newsize, char **patch_buf); #endif \ No newline at end of file diff --git a/src/main.cc b/src/main.cc index 6790f47..034f8b5 100644 --- a/src/main.cc +++ b/src/main.cc @@ -35,6 +35,33 @@ namespace bsdpNode { } } + void diff_buf(const FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + HandleScope scope(isolate); + + if (!node::Buffer::HasInstance(args[0]) || !node::Buffer::HasInstance(args[1])) { + isolate->ThrowException(Exception::Error( + String::NewFromUtf8(isolate, "Invalid arguments."))); + return; + } + + char* old_buf = node::Buffer::Data(args[0]); + size_t old_len = node::Buffer::Length(args[0]); + char* new_buf = node::Buffer::Data(args[1]); + size_t new_len = node::Buffer::Length(args[1]); + char error[1024]; + + char *patch_buf; + int ret = bsdiff_buf(error, old_buf, old_len, new_buf, new_len, &patch_buf); + if(ret < 0) { + isolate->ThrowException(Exception::Error( + String::NewFromUtf8(isolate, error))); + } + Local buf; + node::Buffer::New(isolate, patch_buf, ret).ToLocal(&buf); + args.GetReturnValue().Set(buf); + } + void patch(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); HandleScope scope(isolate); @@ -60,6 +87,7 @@ namespace bsdpNode { void init(Local exports) { NODE_SET_METHOD(exports, "diff", diff); NODE_SET_METHOD(exports, "patch", patch); + NODE_SET_METHOD(exports, "diff_buf", diff_buf); } NODE_MODULE(bsdp, init)