home *** CD-ROM | disk | FTP | other *** search
- /* vi:tabstop=4:shiftwidth=4:smartindent
- *
- * tar.c
- *
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include "tar.h"
-
- #define DIRSEP '/'
- #define ARCSEP '.'
-
- /* Filenames for which the end two parts are swapped. e.g. c.fred -> fred.c
- * This is overridden by the environment variable ARCSWAP
- */
- #define ARCSWAP "a:c:f:h:i:l:o:p:s:y:w:vim:info"
- char *swap = ARCSWAP;
-
- /* Filenames for which the last two parts make a filename.extension.
- * e.g. tmp.fred.tex -> tmp/fred.tex
- * This is overridden by the environment variable ARCDOT
- */
- #define ARCDOT "txt:tex:dvi:eps:ps:bib:sty:bst:log:blg:aux:bbl:lof:lot:toc"
- char *dot = ARCDOT;
-
- int octal(char *str, int len);
- char *munge(char *file);
-
- int main(int argc, char **argv)
- {
- FILE *fp, *fo;
- char buf[TBLOCK], *p;
- union hblock header;
- char *filename, *linkname;
- int mode, uid, gid, size, cksum, link, nblocks, ex;
- time_t mtime;
-
- if ((argc != 3) || (argv[1][1] != '\0') ||
- ((argv[1][0] != 't') && (argv[1][0] != 'x')))
- {
- fprintf(stderr, "Usage: %s [xt] tarfile\n", *argv);
- exit(1);
- }
-
- ex = (argv[1][0] == 'x');
-
- /* Get the environment variables
- */
- if ((p=getenv("ARCSWAP")) != NULL)
- {
- swap = p;
- }
-
- if ((p=getenv("ARCDOT")) != NULL)
- {
- dot = p;
- }
-
- fp = fopen(argv[2], "rb");
- if (fp == NULL)
- {
- fprintf(stderr, "Can't open %s\n", argv[1]);
- exit(1);
- }
-
- while (fread(&header, 1, TBLOCK, fp) == TBLOCK)
- {
- int i, z;
-
- z=0;
- for (i=0; i<TBLOCK; i++)
- {
- z |= header.dummy[i];
- }
- if (z == 0)
- {
- fread(&header, 1, TBLOCK, fp);
- for (i=0; i<TBLOCK; i++)
- {
- z |= header.dummy[i];
- }
- if (z == 0)
- {
- break;
- }
- }
-
- filename=header.dbuf.name;
-
- mode = octal(header.dbuf.mode, 6);
- uid = octal(header.dbuf.uid, 6);
- gid = octal(header.dbuf.gid, 6);
- size = octal(header.dbuf.size, 11);
- mtime= octal(header.dbuf.mtime, 11);
- cksum= octal(header.dbuf.chksum, 6);
- link = octal(&header.dbuf.linkflag, 1);
-
- linkname=header.dbuf.linkname;
-
- /* Don't do anything with non-files. Directories will be
- * created when needed to store things.
- */
- if (!link)
- {
- /* Doing things simply. So don't bother about the checksum,
- * id, mode or time.
- */
- printf("%-8d %30s", size, filename);
- nblocks = (size + TBLOCK - 1) / TBLOCK;
-
- /* Fiddle the filename into the other machine's format
- */
- filename = munge(filename);
-
- /* Make the directory in which it resides
- */
- if (ex)
- {
- for (p=filename; *p; p++)
- {
- if (*p == DIRSEP)
- {
- *p = '\0';
- mkdir(filename);
- *p = DIRSEP;
- }
- }
- }
-
- printf(" -> %s\n", filename);
- if (nblocks != 0)
- {
- if (ex)
- {
- fo = fopen(filename, "wb");
- if (fo == NULL)
- {
- printf("Can't write %s", filename);
- perror(": ");
- }
- }
- else
- {
- fo = NULL;
- }
-
- for (i=0; i<nblocks; i++)
- {
- fread(buf, 1, TBLOCK, fp);
- if (fo != NULL)
- {
- fwrite(buf, 1, (size > TBLOCK) ? TBLOCK : size, fo);
- }
- size -= TBLOCK;
- }
-
- if (fo != NULL)
- {
- fclose(fo);
- }
- }
- }
- }
- exit(0);
- }
-
- int octal(char *str, int len)
- {
- int i, n = 0;
-
- for (i=0; i<len; i++)
- {
- if ((str[i] >= '0') && (str[i] <= '8'))
- {
- n = (n << 3) | (str[i] - '0');
- }
- }
-
- return n;
- }
-
- char *munge(char *file)
- {
- static char new[1024];
- char *ld, *lld, tmp[1024], *s, *t;
- int i;
-
- /* Find the last dot in the name
- */
- ld = strrchr(file, ARCSEP);
- if (ld == NULL)
- {
- /* No change to be made.
- */
- return file;
- }
-
- /* Trailing dots get zapped.
- */
- if (ld[1] == '\0')
- {
- ld[0] = '\0';
- ld = strrchr(file, ARCSEP);
- if (ld == NULL)
- {
- return file;
- }
- }
-
- /* Find the second last dot if there is one.
- */
- *ld = '\0';
- lld = strrchr(file, ARCSEP);
- *ld = ARCSEP;
-
- /* For every dot in the name up to and including the second last
- * we may copy the filename, changing ARCSEP to DIRSEP.
- */
- new[0] = 0;
- if (lld)
- {
- for (i=0; file+i<=lld; i++)
- {
- new[i] = (file[i] == ARCSEP ? DIRSEP : file[i]);
- }
- new[i] = '\0';
- file = lld+1;
- }
-
- /* We now have file=possible leaf name to be checked and
- * new containing the possible dir name
- */
- *ld++ = '\0';
-
- /* Now file=part before the dot and ld=part after it.
- * Check the two parts for matches in dot and swap.
- * swap takes precedence.
- */
- strcpy(tmp, swap);
-
- /* Before final conversion, replace '/' with '.'
- * in both dirname and filename
- */
- for (s=file; *s; s++)
- {
- if (*s == '/')
- {
- *s = '.';
- }
- }
- for (s=ld; *s; s++)
- {
- if (*s == '/')
- {
- *s = '.';
- }
- }
-
- t = tmp;
- while ((s=strtok(t, ":")) != NULL)
- {
- t=NULL;
- if (!strcmp(s, file))
- {
- sprintf(new+strlen(new), "%s.%s", ld, file);
- return new;
- }
- }
-
- strcpy(tmp, dot);
- t = tmp;
- while ((s=strtok(t, ":")) != NULL)
- {
- t=NULL;
- if (!strcmp(s, ld))
- {
- sprintf(new+strlen(new), "%s.%s", file, ld);
- return new;
- }
- }
-
- sprintf(new+strlen(new), "%s%c%s", file, DIRSEP, ld);
- return new;
- }
-