/* savefile.c - storying regular files into (tape) archive * This is the part of the Tar program (see file tar.c) * Author: T.V.Shaporev * Creation date 11 Mar 1993 */ #include #include "sysup.h" #include "modern.h" #include "compress.h" #include "zippipe.h" #include "crc32.h" #include "define.h" extern char longname[]; extern char *deleft __ARGS__(( char * )); extern void newhead __ARGS__(( char *, long )); extern void prcsum __ARGS__(( register header * )); extern void proctl __ARGS__(( char *, long )); static void prhexl __ARGS__(( char *, long )); static void prhexl(dest, l) char *dest; long l; { register int i; static char h[] = "0123456789AbCdEf"; *dest++ = '0'; *dest++ = 'x'; for (i=32; i;) *dest++ = h[(int)(l >> (i -= 4)) & 15]; *dest++ = ' '; *dest++ = '\0'; } #ifdef UNIX static werelost = FALSE; #endif #ifdef MSDOS # include # ifdef __TURBOC__ # include # else # include # endif # include static int skipdots __ARGS__(( char *, int )); static int unperiod __ARGS__(( char *, int )); static int nextchar __ARGS__(( char *, int )); static int skipdots(char *s, int n) { while (n>0 && s[n]=='/' && s[n-1]=='.' && (n<2 || s[n-2]=='/')) n -= 2; return n; } static int unperiod(char *s, int n) { while (n>2 && s[n]=='/' && s[n-1]=='.' && s[n-2]=='.' && s[n-3]=='/') { if ((n -= 3) > 0) { for (n=nextchar(s, n); n>=0 && s[n]!='/'; n--) ; } } return n; } static int nextchar(char *s, int n) { if (n >= 0) n -= 1; while (n>0 && s[n]=='/' && s[n-1]=='.' && ((n<2 || s[n-2]=='/') || n>2 && s[n-2]=='.' && s[n-3]=='/')) { if (n>1 && s[n-2]=='.') { n = unperiod(s, n); } else { n = skipdots(s, n); } } return n; } #else int strlen(); char *strcpy(), *strcat(), *strncpy(); int open(), read(), close(), unlink(); long lseek(); #endif #include "lzpack.h" #include "roll.h" void cantopen(name) char *name; { (void)fprintf(myout, "Tar: can\'t open \'%s\'\n", name); } static void tmpput __ARGS__(( int )); static void no_mem __ARGS__(( int )); static void errproc __ARGS__(( char * )); static void tmpput(c) int c; { ++codesize; if (rputc(c) != 0) errproc(hblock->m.name); } static void no_mem(flag) int flag; { (void)fprintf(stderr, "No memory for encoding."); if (flag) { (void)fprintf(stderr, " Continue? "); if (YES_NO()) return; } else { (void)fprintf(stderr, "\n"); } done(ESMALL); } static void errproc(fname) char *fname; { (void)fprintf(myout, "\nTar: error processing \'%s\'\n", fname); done(EINTER); } void savefile(fname) char *fname; { register i; register c; register char *p; register long blocks; register packok; register node *t; node *prev; int infile; long this; p = deleft(fname); if (u_flag) { if ((t = finditem(p, &prev, timehead)) != NONE) { i = t->info.time >= st.st_mtime; delitem(t, &timehead); if (i) return; } } if (isfile) {/* compare file to store with the archive one */ #ifdef UNIX if (st.st_ino == sa.st_ino && st.st_dev == sa.st_dev) return; #endif #ifdef MSDOS /* The following comparison algorithm may fail */ /* on combination of substed and real drives */ register char *p1, *p2; register j1, j2; register d2; char b[2*MAXPATH]; if (st.st_dev != sa.st_dev) goto next; /* Sinse 'st_dev' field gives the real drive number */ /* there is no need to compare drive names */ j1 = strlen(p1 = archname); p2 = fname; if (p2[0]>='a' && p2[0]<='z' && p2[1]==':') { d2 = p2[0] - ('a'-1); p2 += 2; } else { d2 = 0; } j2 = strlen(p2); while (j1>0 && p1[j1-1]!='/' && j2>0 && p2[j2-1]!='/') { if (p1[--j1] != p2[--j2]) goto next; } if (p2[0] != '/') { *(int *)b = '/'; (void)getcurdir(d2, b+1); takename(b, b); i = strlen(b); b[i++] = '/'; strcpy(b+i, p2); p2 = b; j2 += i; } do { j1 = nextchar(p1, j1); j2 = nextchar(p2, j2); if (j1 >= 0 && j2 >= 0 && p1[j1] != p2[j2]) goto next; } while (j1>=0 && j2>=0); if (j1 == j2) return; #endif } #ifdef MSDOS next: i = st.st_mode & 0700; st.st_mode |= (i>>3)|(i>>6); #endif if (w_flag && !okwork('a', ' ', &st, fname)) return; if ((infile = open(fname, O_RDONLY+O_BINARY)) < 0) { cantopen(fname); return; } newhead(p, st.st_size); #ifdef UNIX if (st.st_nlink > 1) { prev = t = linkhead; i = 1; while (t && i>0) { i = st.st_ino - t->info.data.inode; if (!i) i = st.st_dev - t->info.data.device; if (i>0) { prev = t; t = t->next; } } if (i || !t) {/* entry not found */ if ((t = additem(p, prev, &linkhead)) == NONE) { if (!werelost) { (void)fprintf(myout, "Tar: out of memory; link(s) lost\n"); werelost = TRUE; } } else { t->info.data.count = st.st_nlink - 1; t->info.data.device = st.st_dev; t->info.data.inode = st.st_ino; } } else {/* previous entry found */ (void)strncpy(hblock->m.linkname, t->name, MAXTNAME); hblock->m.filetype = TF_LNK; prcsum(hblock); if (v_flag) { (void)fprintf(myout, "a %s link to %s\n", p, t->name); } if (--(t->info.data.count) < 1) delitem(t, &linkhead); (void)close(infile); return; } } #endif blocks = (st.st_size + (BLKSIZE-1)) / BLKSIZE; packok = FALSE; if (blocks > 1) { if (pktype == PKDEF) { if (zipalloc()!=0 || newroll("TAROLLXXXXXX")!=0) { delroll(); #ifndef MSDOS if (!w_flag) { no_mem(0); } else #endif { no_mem(1); pktype = PKNONE; goto run; } } (void)rewroll(0); if (v_flag) (void)fprintf(stderr, "e %s", p); (void)fflush(stderr); if (zipcreat(tmpput, ZIP_RAW, ziplevel) != 0) { (void)fprintf(stderr, "Zip error: %s\n", ziperrlist[ziperror]); done(EINTER); } this = 0; do { if ((i = read(infile, pk_inp, pksize)) < 0) { errproc(hblock->m.name); } if (i > 0) { (void)zipwrite(pk_inp, i); if (v_flag) percent((this += i), st.st_size); } } while (i == pksize); codesize = zipclose(); } #ifdef USE_COMPRESS else if (pktype == PKfLZW) { if (strlen(hblock->m.name) > MAXTNAME-2) { #ifndef MSDOS if (!w_flag) { (void)fprintf(stderr, longname, hblock->m.name, "\n"); } else #endif { (void)fprintf(stderr, longname, hblock->m.name, " Store uncompressed? "); if (YES_NO()) goto run; } return; } if (newroll("TAROLLXXXXXX")!=0) { delroll(); #ifndef MSDOS if (!w_flag) { no_mem(0); } else #endif { no_mem(1); pktype = PKNONE; goto run; } } if ((i = z_gettab(lzwbits)) < lzwbits) { if (i > 0) { #ifndef MSDOS if (!w_flag) { (void)fprintf(stderr, "Can only handle %d bits.\n", i); lzwbits = i; } else #endif { (void)fprintf(stderr, "Can only handle %d bits. Continue? ", i); lzwbits = YES_NO() ? i : -1; } } if (i <= 0) { no_mem(1); z_reltab(); pktype = PKNONE; goto run; } } (void)rewroll(0); if (v_flag) (void)fprintf(stderr, "z %s", p); (void)fflush(stderr); if (cbegin(lzwbits, tmpput, st.st_size) < lzwbits) no_mem(0); this = 0; do { if ((i = read(infile, pk_inp, pksize)) < 0) { errproc(hblock->m.name); } if (i > 0) { cpiece(pk_inp, i); if (v_flag) percent((this += i), st.st_size); } } while (i == pksize); codesize = cflush(); } #endif if (v_flag) (void)fprintf(stderr, "\r"); if (pkfile) { register long b; if ((b = (codesize + (BLKSIZE-1)) / BLKSIZE) < blocks) { packok = TRUE; blocks = b; } else if (lseek(infile, 0L, 0) < 0) { (void)fprintf(myout, "Tar: \'%s\' seek error\n", fname); done(ERREAD); } } } run : if (v_flag || j_flag) { (void)fprintf(myout, "a %s %ld blocks\n", p, blocks); } if (j_flag) { (void)fprintf(stderr, "> "); for (i=0; (c=getc(myinp))!='\n'; ) { if (i < sizeof(hblock->m.comment)-1) { hblock->m.comment[i++] = c; } } hblock->m.comment[i] = 0; } else { hblock->m.comment[0] = 0; } if (packok) { proctl(hblock->m.size, codesize); if (pktype == PKfLZW) { (void)strcat(hblock->m.name, ".Z"); } else { /* pktype == PKDEF */ prhexl(hblock->m.srcsum, getcrc()); prhexl(hblock->m.srclen, st.st_size); } prcsum(hblock); if (rewroll(1) != 0) errproc(p); while (codesize-- > 0) { if ((c = rgetc()) == EOF) errproc(p); writebyte(c); } } else {/* common store file */ prcsum(hblock); if ((blocks -= writearch(infile, st.st_size, fname)) != 0) { (void)fprintf(myout, "Tar: \'%s\' decreased size\n", fname); while (blocks-- > 0) nullblock(steptape()); } } (void)close(infile); if (y_flag) { #ifdef MDSOS if (!(st.st_mode & S_IWRITE)) (void)chmod(fname, S_IWRITE); #endif if (unlink(fname)) { (void)fprintf(myout, "Tar: can\'t delete \'%s\'\n", fname); } } }