/*********************************************************************** This file is part of HA, a general purpose file archiver. Copyright (C) 1995 Harri Hirvola 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., 675 Mass Ave, Cambridge, MA 02139, USA. ************************************************************************ HA main program ***********************************************************************/ #include #include #include #include #include #include #include "error.h" #include "ha.h" #include "archive.h" #include "haio.h" #include "cpy.h" #include "asc.h" #include "hsc.h" /*********************************************************************** Commands */ #define ADD 'a' #define EXTRACT 'e' #define PEXTRACT 'x' #define FRESHEN 'f' #define UPDATE 'u' #define LIST 'l' #define DELETE 'd' #define TEST 't' #define INFO 'h' char *myname; int quiet=0,useattr=0,special=0; static unsigned ilen=0; static int fulllist=0,usepath=1,yes=0,touch=0,recurse=0,savedir=0,move=0; static char *defpat[]={ALLFILES}; static int metqueue[M_UNK+1]={M_UNK}; static int (*addthis)(char*, char*); static void dummy(void) { /* Do nothing */ } struct { char *name; void (*encode)(void); void (*decode)(void); void (*cleanup)(void); } method[]= { {"CPY",cpy,cpy,dummy}, {"ASC",asc_pack,asc_unpack,asc_cleanup}, {"HSC",hsc_pack,hsc_unpack,hsc_cleanup}, {"3"},{"4"},{"5"},{"6"},{"7"},{"8"},{"9"},{"10"},{"11"},{"12"},{"13"}, {"DIR"}, {"SPC"} }; static void banner(void) { fprintf(stderr,BANNER); fflush(stderr); } static unsigned getinfo(unsigned char *buf, unsigned blen) { static unsigned char *idat=infodat; unsigned i; for (i=0;i archive [files]" EXAMPLE "\n" "\n commands :" "\n a[sdqemr012] - Add files d[q] - Delete files" "\n e[aqty] - Extract files f[sdqemr012] - Freshen files" "\n l[f] - List files t[q] - Test files" "\n u[sdqemr012] - Update files x[aqty] -" " eXtract files with pathnames" "\n" "\n switches :" "\n 0,1,2 - try method (0-CPY,1-ASC,2-HSC)" "\n t - Touch files r - Recurse subdirs" "\n f - Full listing y -" " assume Yes on all questions" "\n m - Move files a -" " set system specific file Attributes" "\n e - Exclude pathnames s - find Special files" "\n q - Quiet operation d -" " make Directory entries" "\n" "\nType \"ha h | more\" to get more information about HA." "\n" ); fflush(stderr); if (ex) { cu_do(NULL); exit(ex); } } static int yesno(char *format, char *string) { int rep; if (yes || quiet) return 1; printf(format,string); fflush(stdout); for (rep=0;!rep;) { switch (rep=getchar()) { case 'Y' : case 'y' : case 'N' : case 'n' : case 'A' : case 'a' : break; default : rep=0; break; } } if (rep=='Y'||rep=='y') rep=1; else if (rep=='A'||rep=='a') rep=yes=1; else rep=0; return rep; } static void backstep(int len) { while (--len) putchar(0x08); } static void do_list(void) { U32B tcs,tos; unsigned files; Fheader *hd; arc_reset(); if ((hd=arc_seek())==NULL) error(1,ERR_NOFILES); printf("\n filename original compressed" " rate date time m"); if (fulllist) { printf("\n CRC-32 path"); md_listhdr(); } printf("\n=================================" "=========================================="); tcs=tos=files=0; for(;;) { if (hd->type==0xff) continue; if (fulllist && files) { printf("\n-------------------------" "--------------------------------------------------"); } printf("\n %-15s %-11" F_32B " %-11" F_32B " %3d.%d %% %s %s", hd->name,hd->olen,hd->clen, (hd->olen==0?100:(int)(100*hd->clen/hd->olen)), (hd->olen==0?0:(int)((1000*hd->clen/hd->olen)%10)), md_timestring(hd->time),method[hd->type].name); if (fulllist) { printf("\n %08" FX_32B " %s",hd->crc, *hd->path==0?"(none)":md_tomdpath(hd->path)); md_listdat(); } tcs+=hd->clen; tos+=hd->olen; ++files; if ((hd=arc_seek())==NULL) break; } printf("\n=============================" "=============================================="); printf("\n %-4d %-11" F_32B " %-11" F_32B " %3d.%d %%\n", files,tos,tcs,(tos==0?100:(int)(100*tcs/tos)), (tos==0?0:(int)((1000*tcs/tos)%10))); } static void do_extract(void) { Fheader *hd; char *ofname; unsigned char *sdata; int of,newdir; void *cumark; arc_reset(); if ((hd=arc_seek())==NULL) error(1,ERR_NOFILES); do { if (usepath) { makepath(hd->path); ofname=md_tomdpath(fullpath(hd->path,hd->name)); } else ofname=md_tomdpath(hd->name); switch(hd->type) { case M_SPECIAL: if (!access(ofname,F_OK)) { if (!yesno("\nOverwrite special file %s ? (y/n/a) ",ofname)) break; } if (!quiet) { printf("\nMaking SPC %s",ofname); backstep(strlen(ofname)+8); } if (hd->clen) { if ((sdata=malloc(hd->clen))==NULL) error(1,ERR_MEM,"do_extract()"); if (read(arcfile,sdata,hd->clen)!=hd->clen) error(1,ERR_READ,arcname); } else sdata=NULL; if (!md_mkspecial(ofname,hd->clen,sdata)) { if (sdata!=NULL) free(sdata); break; } if (sdata!=NULL) free(sdata); if (touch) md_setft(ofname,md_systime()); else md_setft(ofname,hd->time); if (!quiet) printf("DONE"); break; case M_DIR: if (!(newdir=access(ofname,F_OK)) && useattr) { if (!yesno("\nRemake directory %s ? (y/n/a) ",ofname)) break; } if (!quiet) { printf("\nMaking DIR %s",ofname); backstep(strlen(ofname)+8); } if (newdir) { if (mkdir(ofname,DEF_DIRATTR)<0) error(0,ERR_MKDIR,ofname); } if (touch) md_setft(ofname,md_systime()); else md_setft(ofname,hd->time); if (useattr) md_setfattrs(ofname); if (!quiet) printf("DONE"); break; default: of=open(ofname,O_WRONLY|O_BINARY|O_CREAT|O_EXCL,DEF_FILEATTR); if (of<0) { if (!yesno("\nOverwrite file %s ? (y/n/a) ",ofname)) continue; if (remove(ofname)<0) { error(0,ERR_REMOVE,ofname); continue; } if ((of=open(ofname,O_WRONLY|O_BINARY|O_CREAT|O_EXCL, DEF_FILEATTR))<0) error(0,ERR_OPEN,ofname); } setinput(arcfile,0,arcname); if (quiet) setoutput(of,CRCCALC,ofname); else setoutput(of,CRCCALC|PROGDISP,ofname); if (!quiet) { printf("\nUnpacking %s %s", method[hd->type].name,ofname); backstep(strlen(ofname)+8); } fflush(stdout); if (hd->olen!=0) { totalsize=hd->olen; cumark=cu_add(CU_FUNC,method[hd->type].cleanup); cu_add(CU_RMFILE|CU_CANRELAX,ofname,of); (*method[hd->type].decode)(); cu_relax(cumark); cu_do(cumark); } else if (!quiet) printf("100 %%"); fflush(stdout); close(of); if (hd->crc!=getcrc()) error(0,ERR_CRC,NULL); if (touch) md_setft(ofname,md_systime()); else md_setft(ofname,hd->time); if (useattr) md_setfattrs(ofname); break; } } while ((hd=arc_seek())!=NULL); if (!quiet) printf("\n"); } static void do_test(void) { Fheader *hd; char *ofname; void *cumark; arc_reset(); if ((hd=arc_seek())==NULL) error(1,ERR_NOFILES); do { ofname=md_tomdpath(fullpath(hd->path,hd->name)); switch(hd->type) { case M_DIR: if (!quiet) printf("\nTesting DIR DONE %s",ofname); break; case M_SPECIAL: if (!quiet) printf("\nTesting SPC DONE %s",ofname); break; default: setinput(arcfile,0,arcname); if (quiet) setoutput(-1,CRCCALC,"none ??"); else setoutput(-1,CRCCALC|PROGDISP,"none ??"); if (!quiet) { printf("\nTesting %s %s",method[hd->type].name,ofname); backstep(strlen(ofname)+8); fflush(stdout); } if (hd->olen!=0) { totalsize=hd->olen; cumark=cu_add(CU_FUNC,method[hd->type].cleanup); (*method[hd->type].decode)(); cu_do(cumark); } else if (!quiet) printf("100 %%"); fflush(stdout); if (hd->crc!=getcrc()) error(0,ERR_CRC,NULL); break; } } while ((hd=arc_seek())!=NULL); if (!quiet) printf("\n"); } static void do_delete(void) { Fheader *hd; arc_reset(); if ((hd=arc_seek())==NULL) error(1,ERR_NOFILES); do { if (!quiet) { printf("\nDeleting %s",md_tomdpath(fullpath(hd->path,hd->name))); fflush(stdout); } arc_delete(); } while ((hd=arc_seek())!=NULL); if (!quiet) printf("\n"); } static int adddir(char *path, char *name) { char *fullname; fullname=md_pconcat(0,path,name); if (!quiet) { printf("\nSaving DIR %s",fullname); backstep(strlen(fullname)+10); fflush(stdout); } arc_newfile(usepath?path:"",name); if (arc_adddir()){ if (!quiet) { printf(" DONE"); fflush(stdout); } if (move) cu_add(CU_RMDIR,fullname); free(fullname); return 1; } else { free(fullname); return 0; } } static int addspecial(char *path, char *name) { char *fullname; fullname=md_pconcat(0,path,name); if (!quiet) { printf("\nSaving SPC %s",fullname); backstep(strlen(fullname)+10); fflush(stdout); } arc_newfile(usepath?path:"",name); if (arc_addspecial(fullname)) { if (!quiet) { printf(" DONE"); fflush(stdout); } if (move) { if (remove(fullname)<0) { error(0,ERR_REMOVE,fullname); } } free(fullname); return 1; } else { free(fullname); return 0; } } static int addfile(char *path, char *name) { char *fullname; int i,best,inf; U32B bestsize; void *cumark; bestsize=totalsize=md_curfilesize(); best=M_CPY; arc_newfile(usepath?path:"",name); fullname=md_pconcat(0,path,name); if ((inf=open(fullname,O_RDONLY|O_BINARY))<0) { error(0,ERR_OPEN,fullname); free(fullname); return 0; } if (!quiet) printf("\n"); setoutput(arcfile,0,arcname); if (quiet) setinput(inf,CRCCALC,fullname); else setinput(inf,CRCCALC|PROGDISP,fullname); if (totalsize) { for (i=0;;) { arc_trynext(); cumark=cu_add(CU_FUNC,method[metqueue[i]].cleanup); if (!quiet) { printf("\rPacking %s %s", method[metqueue[i]].name,fullname); backstep(strlen(fullname)+10); fflush(stdout); } (*method[metqueue[i]].encode)(); cu_do(cumark); if (ocnttime>=md_curfiletime()) return 0; return 1; } static int updatetest(char *path, char *name) { Fheader *hd; char *ptab[1]; ptab[0]=fullpath(md_tohapath(path),name); patterns=ptab; patcnt=1; arc_reset(); if ((hd=arc_seek())!=NULL && hd->time>=md_curfiletime()) return 0; return 1; } static int addindir(char *path, char *pattern) { int found; char *newpath; DIR *dir; struct dirent *ent; void *cumark; found=0; if (*path) dir=opendir(path); else dir=opendir("."); if (dir==NULL) { error(0,ERR_DIROPEN,path); return found; } cumark=cu_getmark(); while ((ent=readdir(dir))!=NULL) { switch(md_filetype(path,md_strcase(ent->d_name))) { case T_DIR: if (savedir && addthis(path,ent->d_name)) found|=adddir(path,ent->d_name); if (!recurse) break; newpath=md_pconcat(1,path,ent->d_name); found|=addindir(newpath,pattern); free(newpath); break; case T_SPECIAL: if (!md_namecmp(pattern,ent->d_name) || !special) break; if (addthis(path,ent->d_name)) found|=addspecial(path,ent->d_name); break; case T_REGULAR: if (!md_namecmp(pattern,ent->d_name)) break; if (addthis(path,ent->d_name)) found|=addfile(path,ent->d_name); break; } } closedir(dir); cu_do(cumark); return found; } static void do_add(void) { int i,found; char *path,*pattern; for (found=i=0;i