/* 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 <jjw@linuxmail.org>
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include "linklist.h"
#include "file.h"
#include <ctype.h>
#include <string>
#include <openssl/md5.h>
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] <repository>] package1 package2 patchfile #make patch\n");
printf("deltup -p[fvir] [-[dD] <repository>] <patchfiles> #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 <repository>\n");
printf(" D = old tarball(s) can be found in <repository>\n");
printf("See README in /usr/share/doc/deltup<ver> for examples and info\n");
exit(0);
}
DList<char> 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<UncompressedFile> 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<UncompressedFile> *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();
}
syntax highlighted by Code2HTML, v. 0.9.1