/* Copyright (C) 2003 John Whitney * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Author: John Whitney */ #include #include #include #include #include #include #include #include #include "linklist.h" #include "file.h" #include #include #include using namespace std; bool force_overwrite = false, verbose = false, remove_intermediate = false, info_mode = false, ensure_md5sum = false, use_bdelta = false; unsigned patch_compression_type = 0; char *patch_compression = "0"; char *tmpdir; unsigned numinputfname = 0; char *inputfname[128]; unsigned numoldrepositories = 0; string oldrepositories[128]; string newrepository; //define recognized filetypes const unsigned UNKNOWN_FMT = 0, BZIP2 = 1, GZIP = 2, ZIP = 3, COMPRESS = 4, TARBALL = 5, DTU = 6, BZIP2_OLD = 7, XDELTA = 8, BDELTA = 9; //openoffice 1.0.2 & 1.0.3 use this format const unsigned MAKEPATCH = 1, PATCHFILE = 2; void showHelp() { printf("deltup version 0.4.2\n"); printf("Bad usage. Try one of:\n"); printf("deltup -m[fvej] [bgz #] [-[dD] ] package1 package2 patchfile #make patch\n"); printf("deltup -p[fvir] [-[dD] ] #apply patches\n"); printf("\n"); printf("Flags: f = force overwrite output files\n"); printf(" v = verbose\n"); printf(" e = ensure md5sum is correct (for bzip2 < v. 1.0.0)\n"); printf(" j = use new bdelta algorithm\n"); printf(" b,g,z = compress package with bzip2, gzip, or internal zlib\n"); printf(" i = don't actually do anything. Just show info\n"); printf(" r = if several patches to one source are given, merge\n"); printf(" patches so they will apply in one step and don't\n"); printf(" create intermediate files\n"); printf(" d = new tarball belongs in \n"); printf(" D = old tarball(s) can be found in \n"); printf("See README in /usr/share/doc/deltup for examples and info\n"); exit(0); } DList tempfiles; char tempname[8] = "/000000"; char *getTmpFilename() { string n = string(tmpdir)+tempname; char *name = new char[n.size()+1]; strcpy(name, n.c_str()); tempfiles.push_back(name); int i; for (i = 6; tempname[i]=='9'; --i) tempname[i]='0'; tempname[i]++; return name; } int invoke_system(string prog, string args); void doneTmpFile(char *c) { invoke_system("rm", string("-f ") + c); tempfiles.erase(tempfiles.find_first(c)); } void cleanup() { if (verbose) printf("cleaning up\n"); while (!tempfiles.empty()) { doneTmpFile(tempfiles.first->obj); } rmdir(tmpdir); } void error(string message) { fprintf(stderr, "error: %s\n", message.c_str()); exit(1); } int invoke_system(string prog, string args) { // printf("%s\n", ret); int ret = system((prog + " " + args).c_str()); if (WIFSIGNALED(ret) && (WTERMSIG(ret) == SIGINT || WTERMSIG(ret) == SIGQUIT)) error("Caught signal"); if (ret==0x7F00) error(string("A required executable, ") + prog + ", was not found"); return ret; } bool endsWith(const char *f, char *end) { return !strcmp(f+strlen(f)-strlen(end), end); } bool compressionTypeSupported(unsigned c) { return (c==UNKNOWN_FMT||c==BZIP2||c==GZIP||c==BZIP2_OLD); } unsigned read_ascii_octal(char *s) { int num = 0; for (char *i = s; i < s+12; ++i) if (*i>='0'&&*i<='7') { num<<=3; num+=*i-'0'; } return num; } bool unzipFileAs(const char *f, unsigned packageformat, char *unzippedfname) { char *command, *extra = "-c "; switch (packageformat) { case UNKNOWN_FMT: command = "cat"; extra=""; break; case BZIP2: command = "bunzip2"; break; case GZIP: command = "gunzip"; break; // case ZIP: // char path[256]; // strcpy(path, tmpdir); // strcat(path, "/ziptemp"); // mkdir(path, 700); // invoke_system(6, "zip // command, f, " > ", unzipdir, "/", unzippedfname); // strcpy(command, "cat "); // break; } return !invoke_system(command, string(extra)+f+" > "+unzippedfname+" 2> /dev/null"); } bool unzipFile(const char *f, char *unzippedfname, unsigned &packageformat) { if (endsWith(f, "bz2")) packageformat = BZIP2; else if (endsWith(f, "gz")) packageformat = GZIP; else if (endsWith(f, "zip")) error("zip files are unzipported (pardon the pun!)"); else if (endsWith(f, "lzw")) error("lzw files are not supported"); else if (endsWith(f, ".Z")) error(".Z compression not supported"); else packageformat = UNKNOWN_FMT; // assume no compression return unzipFileAs(f, packageformat, unzippedfname); } int determine_filetype(char *c) { if (!strncmp(c, "DTU", 3)) return DTU; if (!strncmp(c, "\037\213", 2) || !strncmp(c, "\037\236", 2)) return GZIP; if (!strncmp(c, "BZ", 2)) return BZIP2; if (!strncmp(c, "PK\003\004", 2)) return ZIP; if (!strncmp(c, "%XDZ", 4)) return XDELTA; if (!strncmp(c, "BDT", 3)) return BDELTA; return UNKNOWN_FMT; } int determine_filetype(Injectable_IStream &f) { char c[4]; f.read(c, 4); f.inject(c, 4); int fmt = determine_filetype(c); if (fmt!=UNKNOWN_FMT) return fmt; char tarheader[512]; f.read(tarheader, 512); f.inject(tarheader, 512); if (strncmp(tarheader+257, "ustar", 5)==0) return TARBALL; return UNKNOWN_FMT; } int determine_filetype_fname(const char *fname) { FILE *f = fopen(fname, "rb"); char header[4]; fread(header, 1, 4, f); fclose(f); return determine_filetype(header); } unsigned getLenOfFile(const char *fname) { FILE *f = fopen(fname, "rb"); fseek(f, 0, SEEK_END); unsigned len = ftell(f); fclose(f); return len; } bool fileExists(string fname) { FILE *f = fopen(fname.c_str(), "rb"); bool exists = (f!=NULL); if (exists) fclose(f); return exists; } char *read_filename(IStream &f) { unsigned fnamelen = read_word(f); char *f1 = (char*)malloc(fnamelen+1); f.read(f1, fnamelen); f1[fnamelen] = 0; return f1; } void write_filename(FILE *f, string fname) { unsigned lenName = fname.size(); write_word(f, lenName); fwrite(fname.c_str(), 1, lenName, f); } void read_md5sum(unsigned char *md, string fname) { FILE *f = fopen(fname.c_str(), "rb"); unsigned char buf[4096]; MD5_CTX c; MD5_Init(&c); unsigned numread; do { numread = fread(buf, 1, 4096, f); if (numread) MD5_Update(&c, buf, numread); } while (numread==4096); fclose(f); MD5_Final(md, &c); } bool md5_equal(unsigned char *md1, string fname) { unsigned char md2[16]; read_md5sum(md2, fname); for (int i = 0; i < 16; ++i) if (md1[i]!=md2[i]) return false; return true; } void write_header(FILE *f) { fprintf(f, "DTU"); write_word(f, 4); //FormatVersion } void read_header(IStream &f, unsigned &version, unsigned &numpatches) { char magic[3]; f.read(magic, 3); if (strncmp(magic, "DTU", 3) != 0) error("Invalid patch file"); version = read_word(f); if (version > 4) error("Cannot read package format. Upgrade deltup"); if (version==2) numpatches = read_word(f); else numpatches = 1; } int find_bz2_compression(const char *complete) { // char *complete = combineStrings(2, repository, fname); FILE *f = fopen(complete, "rb"); char header[4]; fread(header, 1, 4, f); fclose(f); return (header[3])-'0'; //assumes ASCII char set } bool old_bzip2_exists() { return !(system("bzip2_old 2> /dev/null")==0x7F00); } bool copy_bytes_to_file(IStream &infile, OStream &outfile, unsigned numleft); void gzip_without_header(string in, string out, char *compression) { /* invoke_system("cat", in + " | gzip -"+compression+ " > " + out); return; */ /* IFStream infile(in.c_str()); OFStream outfile(out.c_str()); unsigned char i_buf[4096]; unsigned char o_buf[4096]; z_stream z; z.zalloc = 0; z.zfree = 0; z.opaque = 0; z.avail_in = 0; deflateInit(&z, *compression-'0'); int b; do { if (!z.avail_in) { z.avail_in = infile.read(i_buf, 4096); z.next_in = i_buf; } z.avail_out = 4096; z.next_out = o_buf; if (!z.avail_in) b = deflate(&z, Z_FINISH); else b = deflate(&z, Z_NO_FLUSH); if (b != Z_OK && b != Z_STREAM_END) { printf("here %i\n", b); error("error during zlib compression"); } outfile.write(o_buf, 4096-z.avail_out); } while (b != Z_STREAM_END); printf("filesize %i\n", getLenOfFile(out.c_str())); */ char *tempfile = getTmpFilename(); invoke_system("cat", in + " | gzip -"+compression+ " > " + tempfile); unsigned filesize = getLenOfFile(tempfile); unsigned numtocrop = 10; char inbuf[12]; IFStream *f = new IFStream(tempfile); char c = f->read(inbuf, 10); char flags = inbuf[3]; if (flags & 2) { f->read(inbuf, 2); numtocrop+=2; } if (flags & 4) { unsigned extrafieldsize = read_word(*f); numtocrop+=2+extrafieldsize; while (extrafieldsize) extrafieldsize -= f->read(inbuf, extrafieldsize<10?extrafieldsize:10); } if (flags & 8) { do { f->read(inbuf, 1); ++numtocrop; } while (inbuf[0]); } if (flags & 16) { do { f->read(inbuf, 1); ++numtocrop; } while (inbuf[0]); } if (flags & 32) { f->read(inbuf, 2); numtocrop += 2; } OFStream o(out.c_str()); copy_bytes_to_file(*f, o, filesize-numtocrop); delete f; doneTmpFile(tempfile); } void createDelta(const char *oldfile, const char *newfile, char *patchfname) { if (numoldrepositories!=1) error("multiple dirs not supported with the -m option"); if (strchr(oldfile, '/') || strchr(newfile, '/')) printf("Warning: don't prefix packages with a path. Use the -d and -D options\n"); string oldrepository=oldrepositories[0]; string file1 = oldrepository+oldfile, file2 = newrepository+newfile; if (!fileExists(file1)) error("cannot access first input file"); if (!fileExists(file2)) error("cannot access second input file"); if (!force_overwrite && fileExists(patchfname)) error("output file already exists"); FILE *testaccess = fopen(patchfname, "wb"); if (!testaccess) error("Access denied to output file"); fclose(testaccess); invoke_system("rm", patchfname); unsigned compression_level, flags = 0; if (verbose) printf("Looking at package contents\n"); char *f1Name = getTmpFilename(), *f2Name = getTmpFilename(), *deltaName = getTmpFilename(), *pristineName = getTmpFilename(); unsigned f1Type, f2Type; if (!unzipFile(file1.c_str(), f1Name, f1Type)) error("Cannot read first input file. Error encountered during decompression"); if (!unzipFile(file2.c_str(), f2Name, f2Type)) error("Cannot read second input file. Error encountered during decompression"); unsigned char md5[16]; read_md5sum(md5, string(f1Name)); if (verbose) printf("Making package delta\n"); // int errorcode = char *zlibCompression = "0"; if (patch_compression_type == 0) { zlibCompression = patch_compression; } if (use_bdelta) invoke_system("bdelta", string(f1Name)+" " + f2Name+" " + deltaName); else invoke_system("xdelta", string("delta -")+zlibCompression+" --pristine "+ f1Name+" "+ f2Name+" "+ deltaName+" 2> /dev/null"); // printf("%i\n", errorcode); doneTmpFile(f1Name); if (verbose) printf("Ensuring MD5sum will be correct\n"); if (f2Type==GZIP) { flags |= 1; char *compression_try = "968712534"; char *gzip_temp = getTmpFilename(); do { compression_level=(*compression_try-'0'); //assumes ASCII char set char compression_str[2] = {0,0}; strncpy(compression_str, compression_try, 1); gzip_without_header(string(f2Name), gzip_temp, compression_str); // invoke_system("cat", string(f2Name)+" | gzip -"+compression_str+ // " > "+gzip_temp); if (use_bdelta) invoke_system("bdelta", string(gzip_temp)+" "+ file2+" "+pristineName); else invoke_system("xdelta", string("delta -")+zlibCompression+" --pristine "+ gzip_temp+" "+ file2+" "+pristineName+" 2> /dev/null"); ++compression_try; } while (*compression_try && getLenOfFile(pristineName)>1024); if (!*compression_try) error("Unknown compression format"); doneTmpFile(gzip_temp); } else if (f2Type==BZIP2) { compression_level=find_bz2_compression(file2.c_str()); if (ensure_md5sum) { char *bzip_temp = getTmpFilename(); char compression_str[4] = " -x"; compression_str[2] = '0' + compression_level; invoke_system("bzip2", string(f2Name)+compression_str+ " -c > "+bzip_temp); if (invoke_system("cmp", string(bzip_temp)+" "+file2+ " > /dev/null")) { f2Type=BZIP2_OLD; if (old_bzip2_exists()) { invoke_system("bzip2_old", string(f2Name)+compression_str+ " -c > "+bzip_temp); if (invoke_system("cmp", string(bzip_temp)+" "+file2+ " > /dev/null")) error("Cannot make correct patch. Please report this to the Deltup maintainer"); if (verbose) printf("marking as old bzip2 format\n"); } else { printf("This package was compressed using a old version of bzip2. Please install a .9 version of bzip2 named bzip2_old in your path to verify md5sum is correct"); } } else if (verbose) printf("bzip2 format is reliable\n"); doneTmpFile(bzip_temp); } } else if (f2Type==UNKNOWN_FMT) {} doneTmpFile(f2Name); if (verbose) printf("Output package to: %s\n", patchfname); char *finalName = getTmpFilename(); FILE *f = fopen(finalName, "wb"); write_header(f); write_filename(f, oldfile); fwrite(md5, 1, 16, f); write_filename(f, newfile); read_md5sum(md5, file2); fwrite(md5, 1, 16, f); write_word(f, f1Type); write_word(f, f2Type); write_dword(f, compression_level); flags|=2; //md5 is after decompression write_dword(f, flags); unsigned len = getLenOfFile(deltaName); write_dword(f, len); fclose(f); invoke_system("cat", string(deltaName)+" >> "+finalName); doneTmpFile(deltaName); if (flags&1) { f = fopen(finalName, "ab"); write_dword(f, getLenOfFile(pristineName)); fclose(f); invoke_system("cat", string(pristineName)+" >> "+finalName); doneTmpFile(pristineName); } char *command; switch (patch_compression_type) { case GZIP: invoke_system("gzip", string("-")+patch_compression+" -c "+finalName+" > "+patchfname); break; case BZIP2: invoke_system("bzip2", string("-")+patch_compression+" -c "+finalName+" > "+patchfname); break; case UNKNOWN_FMT: invoke_system("cat", string(finalName)+" > "+patchfname); break; } doneTmpFile(finalName); if (fileExists(patchfname)) { if (verbose) printf("All done\n"); printf("Patch is %f times smaller.\n", (double)(getLenOfFile(file2.c_str()))/getLenOfFile(patchfname)); } else fprintf(stderr, "Couldn't output patch\n"); } //returns true if all bytes were successfully copied bool copy_bytes_to_file(IStream &infile, OStream &outfile, unsigned numleft) { size_t numread; do { char buf[1024]; numread = infile.read(buf, numleft>1024?1024:numleft); if (outfile.write(buf, numread) != numread) error("Could not write temporary data. Possibly out of space"); numleft-=numread; } while (numleft && !(numread < 1024 && numleft)); return (numleft==0); } struct UncompressedFile { char *fname; char *tmpfname; unsigned type; unsigned compression_level; char *pristineName; bool has_md5; unsigned char md5[16]; }; void finalize_package(UncompressedFile &f) { char *finalName = getTmpFilename(); char *command; switch (f.type) { case BZIP2_OLD: command = "bzip2_old"; break; case BZIP2: command = "bzip2"; break; case GZIP: command = "gzip"; break; case UNKNOWN_FMT: invoke_system("cat", string(f.tmpfname)+" | cat > "+tmpdir+finalName); } if (f.type==BZIP2 || f.type==BZIP2_OLD || f.type==GZIP) { char compress_str[16]; if (f.compression_level) { compress_str[0] = '-'; sprintf(compress_str+1, "%i", f.compression_level); } if (f.type==GZIP) gzip_without_header(string(f.tmpfname), finalName, compress_str+1); // invoke_system("cat", string(f.tmpfname)+" | "+command+" "+compress_str+" -c > "+finalName); else invoke_system(command, string(compress_str)+" "+f.tmpfname+" -c > "+finalName); } if (f.pristineName) { int patchfiletype = determine_filetype_fname(f.pristineName); bool failure; if (patchfiletype == BDELTA) failure = invoke_system("bpatch", string(finalName)+" "+ newrepository+f.fname+" "+ f.pristineName); else if (patchfiletype == XDELTA) { failure = invoke_system("xdelta", string("patch --pristine ")+f.pristineName+" "+ finalName+" "+newrepository+f.fname+" "); } else fprintf(stderr, "Unknown delta format. Try upgrading deltup\n"); if (failure) fprintf(stderr, "permission denied on file: %s%s\n", newrepository.c_str(), f.fname); else if (f.has_md5 && !md5_equal(f.md5, newrepository+f.fname)) fprintf(stderr, "MD5 check failed!!!\n"); } else { invoke_system("mv", string(finalName)+" "+newrepository+f.fname); if (fileExists(finalName)) { fprintf(stderr, "Access denied\n"); doneTmpFile(finalName); //rm PKGfinal only } } if (f.pristineName) { doneTmpFile(finalName); // f.pristineName=0; } doneTmpFile(f.tmpfname); } DList unfinished; void patchPackage(IStream &f) { unsigned version, numpatches; read_header(f, version, numpatches); if (version==1) error("Old patch. Can be read by deltup <= 0.2.1. Support removed before popuralized."); bool check_md5sums = version==4; // if (version<3) error("Old patch. Cannot apply. Try 0.2 series of deltup"); for (unsigned patch = 0; patch < numpatches; ++patch) { UncompressedFile *oldpackage, *newpackage; oldpackage = new UncompressedFile; newpackage = new UncompressedFile; oldpackage->has_md5=newpackage->has_md5=check_md5sums; oldpackage->fname = read_filename(f); //TODO: free later if (check_md5sums) f.read(oldpackage->md5, 16); newpackage->fname = read_filename(f); if (check_md5sums) f.read(newpackage->md5, 16); oldpackage->tmpfname = getTmpFilename(); newpackage->tmpfname = getTmpFilename(); oldpackage->type=read_word(f); newpackage->type=read_word(f); oldpackage->compression_level=9; newpackage->compression_level=read_dword(f)&15; unsigned flags = read_dword(f); oldpackage->pristineName=0; newpackage->pristineName=(flags&1)?getTmpFilename():0; char *deltaName = getTmpFilename(); bool success; { OFStream o(deltaName); unsigned sizeofpatch = read_dword(f); success = sizeofpatch && copy_bytes_to_file(f, o, sizeofpatch); //read numleft and copy bytes } if (flags&1) { OFStream o(newpackage->pristineName); unsigned sizeofpatch = read_dword(f); success = success && sizeofpatch && copy_bytes_to_file(f, o, sizeofpatch); //same as above } if (version<4 && oldpackage->type==GZIP) //3 had a bug with gzip newpackage->pristineName=0; DLink *s; for (s = unfinished.first; s && strcmp(oldpackage->fname, s->obj->fname); s = s->next) ; printf("%s -> %s: ", oldpackage->fname, newpackage->fname); fflush(stdout); if (!success) {printf("patch is truncated\n"); continue;} if (info_mode) {printf("\n"); continue;} string oldrepository=" "; for (int i = 0; i < numoldrepositories; ++i) { if (fileExists((oldrepositories[i]+oldpackage->fname).c_str())) { oldrepository = oldrepositories[i]; } } // if (!fileExists((newrepository+oldpackage->fname).c_str()) && !s) { if (oldrepository==" " && !s) { printf("no source to patch.\n"); continue; } if (!force_overwrite && fileExists((newrepository+newpackage->fname).c_str())) {// && !remove_intermediate) { printf("patch already applied.\n"); continue; } if (!compressionTypeSupported(oldpackage->type)) { printf("Can't uncompress old package. Upgrade deltup.\n"); continue; } else if (!compressionTypeSupported(newpackage->type)) { printf("Can't re-compress package. Upgrade deltup.\n"); continue; } else if (newpackage->type==BZIP2_OLD) { if (!old_bzip2_exists()) { fprintf(stderr, "This package was compressed using a old version of bzip2. Please install a .9 version of bzip2 named bzip2_old in your path"); continue; } } if (s) { delete oldpackage; oldpackage = s->obj; } else { if ((!(flags&2) && oldpackage->has_md5 && !md5_equal(oldpackage->md5, oldrepository+oldpackage->fname)) || !unzipFileAs((oldrepository+oldpackage->fname).c_str(), oldpackage->type, oldpackage->tmpfname)) { printf("previous package is corrupt\n"); continue; } if ((flags&2) && oldpackage->has_md5 && !md5_equal(oldpackage->md5, oldpackage->tmpfname)) { printf("previous package is corrupt\n"); continue; } } int patchfiletype = determine_filetype_fname(deltaName); bool failure; if (patchfiletype == BDELTA) failure = invoke_system("bpatch", string(oldpackage->tmpfname)+" "+ newpackage->tmpfname+" "+ deltaName); else if (patchfiletype == XDELTA) failure = invoke_system("xdelta", string("patch --pristine ")+deltaName+" "+ oldpackage->tmpfname+" "+ newpackage->tmpfname+" 2> /dev/null"); else { fprintf(stderr, "Unknown delta format used. Try upgrading deltup\n"); continue; } if (failure) { printf("Error applying patch\n"); continue; } doneTmpFile(deltaName); doneTmpFile(oldpackage->tmpfname); // if (oldpackage->pristineName) doneTmpFile(oldpackage->pristineName); if (remove_intermediate) { // invoke_system(4, "mv", f2Name, " ", f1Name, " -f"); UncompressedFile *f = newpackage; if (s) { delete s->obj; unfinished.erase(s); } unfinished.push_back(f); } else finalize_package(*newpackage); printf("OK\n"); } } void applyPatchfile(char *fname); void applyPatchfile(IStream &f) { char *fileName = getTmpFilename(); { OFStream o(fileName); copy_bytes_to_file(f, o, unsigned(-1)); } applyPatchfile(fileName); } void applyPatchfile(char *fname) { IStream *f = new IFStream(fname); Injectable_IStream f2(*f); if (((IFStream*)f)->bad()) {fprintf(stderr, "file is missing: %s\n", fname); exit(1);} int type = determine_filetype(f2); delete f; switch (type) { case GZIP: f = new GZ_IFStream(fname); break; case BZIP2: f = new BZ_IFStream(fname); break; case DTU: f = new IFStream(fname); break; case UNKNOWN_FMT: fprintf(stderr, "cannot read file %s\n", fname); exit(1); case TARBALL : f = new IFStream(fname); unsigned zero_count; zero_count = 0; char tarheader[512]; do { f->read(tarheader, 512); if (tarheader[0]==0) ++zero_count; int size = read_ascii_octal(tarheader+124); if (size) { char *fileName = getTmpFilename(); {OFStream o(fileName); copy_bytes_to_file(*f, o, size); } applyPatchfile(fileName); doneTmpFile(fileName); unsigned lastblocksize = size % 512; if (lastblocksize==0) lastblocksize=512; f->read(tarheader, 512 - lastblocksize); } } while (zero_count < 2); return; } Injectable_IStream infile(*f); type = determine_filetype(infile); if (type==DTU) patchPackage(infile); else applyPatchfile(infile); } int parse_args(int argc, char **argv) { unsigned commandtype = 0; bool nextNewRepository=false; bool nextOldRepositories=false; for (int i = 1; i < argc; ++i) { if (argv[i][0]=='-') { for (int j = 1; j < strlen(argv[i]); ++j) { unsigned oldcommandtype = commandtype; switch (argv[i][j]) { case 'm' : commandtype = MAKEPATCH; break; case 'p' : commandtype = PATCHFILE; break; case 'i' : info_mode = true; break; case 'f' : force_overwrite = true; break; case 'v' : verbose = true; break; case 'r' : remove_intermediate = true; break; case 'd' : nextNewRepository=true; break; case 'D' : nextOldRepositories=true; break; case 'z' : patch_compression_type=128; break; case 'g' : patch_compression_type=GZIP; break; case 'b' : patch_compression_type=BZIP2; break; case 'e' : ensure_md5sum=true; break; case 'j' : use_bdelta=true; break; default : printf("unknown option: %c\n", argv[i][j]); exit(1); } if (oldcommandtype&&commandtype!=oldcommandtype) error("cannot specify more than one of -mpc options"); } } else if (patch_compression_type && strcmp(patch_compression, "0")==0) { if (strlen(argv[i]) > 1 || argv[i][0] > '9' || argv[i][0] < '1') error("compression option must precede a digit from 1-9"); patch_compression = argv[i]; if (patch_compression_type==128) patch_compression_type=0; } else if (nextNewRepository) { newrepository = string(argv[i])+"/"; nextNewRepository=false; } else if (nextOldRepositories) { char *list = argv[i]; while (*list) { while (isspace(*list)) ++list; char *p; for (p = list; *p && !isspace(*p); ++p) ; int num = p-list; if (num) { char *oldrepository = (char*)calloc(num+2, 1); strncpy(oldrepository, list, num); strcat(oldrepository, "/"); oldrepositories[numoldrepositories] = oldrepository; ++numoldrepositories; free(oldrepository); list = p; } nextOldRepositories=false; } } else { //assume filename if (numinputfname == 128) error("Maximum of 128 input files allowed in this version"); inputfname[numinputfname] = argv[i]; ++numinputfname; } } if (numoldrepositories==0) { oldrepositories[0]=newrepository; ++numoldrepositories; } if (nextNewRepository) error("must supply directory after -d option"); if (nextOldRepositories) error("must supply directory after -D option"); return commandtype; } int main(int argc, char *argv[]) { char *tmpenv = getenv("TMPDIR"); if (!tmpenv) tmpenv = "/tmp"; char *tmptemplate = new char[strlen(tmpenv)+9]; strcpy(tmptemplate, tmpenv); strcat(tmptemplate, "/.XXXXXX"); tmpdir = mkdtemp(tmptemplate); // free(tmptemplate); // printf("%s\n", tmpdir); atexit(cleanup); int commandtype = parse_args(argc, argv); if (commandtype == MAKEPATCH) { if (numinputfname!=3) showHelp(); else createDelta(inputfname[0], inputfname[1], inputfname[2]); } else if (commandtype == PATCHFILE) { for (int filenum = 0; filenum < numinputfname; ++filenum) applyPatchfile(inputfname[filenum]); while (!unfinished.empty()) { finalize_package(*unfinished.first->obj); unfinished.erase(unfinished.first); } } else showHelp(); }