/* xPK.c -- General XPK file-to-file packer/unpacker * Copyright (C) 1996-1999 Dirk Stöcker * This file is part of the xpk package. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ /* Written by Dirk Stöcker * UNIX version by Vesa Halttunen */ #include #include #include #include #include #include #include #define NAME "xPK" #define DISTRIBUTION "(Freeware) " #define REVISION "4" unsigned int chunkfunc(struct XpkProgress *); char *tempname(char *); char *basename(char *); void doarg(char *); char *dofile(char *); void end(char *); int isexecutable(char *); struct Hook chunkhook = {{0}, (unsigned int (*) ()) chunkfunc}; void *XpkBase=0; char errbuf[2048], *err=0, namebuf[2048], PrevName[2048], strbuf[2048]; struct stat *fib=0; unsigned char usage[] = "Usage: XPK [-efrsux] [-m method] [-p password] files\n" " -e = extract files (same as -u)\n" " -f = force packing of already packed files\n" " -m = four letter packing method name\n" " -p = encrypt/decrypt using password\n" " -r = recursively (un)pack files in dir\n" " -s = add suffix and don't delete original\n" " -x = pack executables only\n"; unsigned char suffix=0, force=0, unpack=0, recurse=0, depth=0, executables=0; char *password=0, *method=0; int main(int argc, char **argv) { char *c; int i=1; if(!(fib=(void *)malloc(sizeof(struct stat)))) end("Not enough memory\n"); if(strcasecmp(basename(argv[0]), "XPK")) method = basename(argv[0]); else if(argc < 2 || !strcmp (argv[1], "?")) end(usage); for(; *argv[i] == '-'; i++) for(c = argv[i] + 1; *c; c++) { switch (*c) { case 'p': password = argv[++i]; break; case 'm': method = argv[++i]; break; case 's': suffix = 1; break; case 'f': force = 1; break; case 'e': case 'u': unpack = 1; break; case 'r': recurse = 1; break; case 'x': executables = 1; break; default: end(usage); } if(i >= argc) end(usage); } if(!method && !unpack) end("Need a packing method, use -m\n"); if(i == argc) end(usage); for(; i < argc && !err; i++) doarg(argv[i]); end(err); } void iprint(char * s) { int i; for(i = depth; i; --i) fwrite(" ", 1, 2, stdout); fwrite(s, 1, strlen(s), stdout); } void doarg(char *name) { unsigned int lock; if(*name==-1) return; if((stat(name, fib))<0) { sprintf(err = errbuf, "Error %ld reading %s\n", errno, name); return; } if(!(S_ISDIR(fib->st_mode))) { dofile(name); } #ifdef perse else if(recurse) { unsigned int prev; sprintf(strbuf, "Directory %s\n", name); iprint(strbuf); prev = CurrentDir(lock); *PrevName=-1; while(ExNext(lock, fib) && !err) { if(SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) err = " *** Break"; else { char * thisname; unsigned int i = strlen(fib->fib_FileName) + 1; if(!(thisname = (char *) AllocMem(i, MEMF_ANY))) { Write(Output(), "Not enough memory\n", 18); break; } CopyMem(fib->fib_FileName, thisname, i); depth++; doarg(PrevName); depth--; strcpy(PrevName, thisname); FreeMem(thisname, i); } } depth++; doarg(PrevName); depth--; *PrevName = 0xFF; } #endif } char *dofile(char *filename) { struct XpkFib xfib = {0}; char buf[100]; int len; if(!force || unpack) { if(XpkExamineTags(&xfib, XPK_InName, (unsigned int) filename, TAG_DONE)) { sprintf(buf, "Error examining %s\n", filename); iprint(buf); return 0; } } tempname(filename); if(!unpack) { if(!force && xfib.xf_Type != XPKTYPE_UNPACKED) { sprintf(buf, "Skipping (already packed) %s\n", filename); iprint(buf); return 0; } if(executables && !isexecutable(filename)) return 0; if(suffix) sprintf(namebuf, "%s.xpk", filename); if(XpkPackTags( XPK_InName, (unsigned int) filename, XPK_OutName, (unsigned int) namebuf, XPK_ChunkHook, (unsigned int) &chunkhook, XPK_GetError, (unsigned int) errbuf, XPK_PackMethod, (unsigned int) method, XPK_Password, (unsigned int) password, XPK_NoClobber, 1, TAG_DONE)) { unsigned int i = strlen(errbuf); errbuf[i] = '\n'; errbuf[i+1] = '\0'; return err = errbuf; } } /* Unpack */ else { if(xfib.xf_Type != XPKTYPE_PACKED) { sprintf(buf, "Skipping (already unpacked) %s\n", filename); iprint(buf); return 0; } len = strlen(filename); suffix = 0; if(len > 4 && !strcasecmp(filename + len - 5, ".xpk")) { strcpy(namebuf, filename); namebuf[len - 5] = 0; suffix = 1; } if(XpkUnpackTags( XPK_InName, (unsigned int) filename, XPK_FileName, (unsigned int) filename, XPK_OutName, (unsigned int) namebuf, XPK_ChunkHook, (unsigned int) &chunkhook, XPK_Password, (unsigned int) password, XPK_GetError, (unsigned int) errbuf, XPK_NoClobber, 1, TAG_DONE)) { unsigned int i = strlen(errbuf); errbuf[i] = '\n'; errbuf[i+1] = '\0'; return err = errbuf; } } if(!suffix) { if(unlink(filename)<0) return err = "Cannot delete input file\n"; if(rename(namebuf, filename)<0) return err = "Cannot rename tempfile\n"; } } unsigned int chunkfunc(struct XpkProgress *prog) { unsigned char buf[180]; if(prog->xp_Type == XPKPROG_START) fwrite("\033[0 p", 1, 5, stdout); if(prog->xp_Type != XPKPROG_END) sprintf(buf, "%4s: %-8s (%3ld%% done, %2ld%% CF, %6ld cps) %s\033[K\r", prog->xp_PackerName, prog->xp_Activity, prog->xp_Done, prog->xp_CF, prog->xp_Speed, prog->xp_FileName); else sprintf(buf, "%4s: %-8s (%3ldK, %2ld%% CF, %6ld cps) %s\033[K\n", prog->xp_PackerName, prog->xp_Activity, prog->xp_ULen / 1024, prog->xp_CF, prog->xp_Speed, prog->xp_FileName); iprint(buf); if(prog->xp_Type == XPKPROG_END) fwrite("\033[1 p", 1, 5, stdout); return 0; } char *tempname(char *name) { sprintf(namebuf, ".tmp%s", basename(name)); return namebuf; } int isexecutable(char *name) { struct stat testfib; if((stat(name, &testfib))<0) return 0; if((testfib.st_mode & S_IXUSR)) return 1; return 0; } void end(char * text) { if(text) fwrite(text, 1, strlen(text), stdout); if(fib) free(fib); exit(text ? 10 : 0); } char *basename(char *path) { char *ptr; if(path) { while((ptr=(char *)strpbrk(path, "/"))) path=ptr+1; return path; } else return 0; }