home *** CD-ROM | disk | FTP | other *** search
- /*
- ** $VER: DeTar.c 1.3 (27.10.97)
- **
- ** DeTar main module
- **
- ** written in 1995-97 by Andreas R. Kleinert, based on code by Steve Sampson
- ** Public Domain. (See DeTar.doc)
- */
-
- /* ------------------------------------------------------------------------------ */
-
- /*
- * detar.c
- *
- * Version 1.1
- *
- * Fixed bug in convert() wich produced errors on files without
- * a slash '/' in them.
- *
- * Unix Tape Archive (TAR) Extractor for MSDOS
- *
- * Public Domain January 1988, Steve Sampson
- * Based on the public domain TAR program by John Gilmore
- *
- * Compiled with ECO-C88 V3.21
- *
- */
-
- /* Includes */
-
- #define __USE_SYSBASE
-
- #include <exec/types.h>
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <time.h>
-
- #include <proto/exec.h>
- #include <proto/dos.h>
-
- #include "detar.h"
-
- /* Defines */
-
- #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
-
- /* Globals */
-
- FILE *fdi,
- *fdo;
-
- union record *head; /* the archive file header */
- struct stat hstat; /* the decoded stat info */
- struct {
- long year;
- long month;
- long day;
- long hour;
- long min;
- long sec;
- } tm;
-
- long ugswidth = 11;
- long dir_only = 0;
-
- char tempname[102];
-
- char version [] = "\0$VER: detar 1.3 (27.10.97)";
-
-
- /* Forward References, Prototypes */
-
- void dir_tar(void);
- void de_tar(void);
- void decode_header(union record *header, struct stat *st, long *stdp);
- void demode(unsigned mode, char *string);
- long from_oct(long digs, char *where);
-
-
- /* Main Program */
-
- void main(long argc, char **argv)
- {
- char *p;
-
- /* The operator can ask for directory only or de-tar only. */
-
- argv++;
-
- if (argc == 3 && **argv == 'd')
- {
- dir_only++;
- argc--;
- argv++;
- }
-
- if (argc != 2)
- {
- fprintf(stderr, &version[7]);
-
- fprintf(stderr, "\nAmiga Port by Andreas R. Kleinert in 1995-97. Public Domain."
- "\nPublic Domain January 1988, Steve Sampson"
- "\nBased on the public domain TAR program by John Gilmore");
-
- fprintf(stderr, "\nUsage: detar [d] filename[.tar]");
- fprintf(stderr, "\nWhere d means directory only\n");
-
- exit(1);
- }
-
- for (p = *argv; *p; p++) *p = (char)toupper(*p);
-
- /* parse the many possibilities, this stuff not needed with MSC */
-
- if ((p = strrchr(*argv, '.')) == (char *)NULL) goto add;
- else if (strcmp(p, ".TAR") == NULL) strcpy(tempname, *argv);
- else if (*(p+1) == '/' || *(p+1) == '\\')
- {
- add: strcpy(tempname, *argv);
- strcat(tempname, ".TAR");
- }else
- {
- fprintf(stderr, "File '%s' not a TAR archive\n", *argv);
-
- exit(1);
- }
-
- if ((fdi = fopen(tempname, "rb")) == (FILE *)NULL)
- {
- fprintf(stderr, "Tar File '%s' Not Found\n", tempname);
- exit(1);
- }
-
- head = (union record *)malloc(512);
-
- if (dir_only) dir_tar();
- else de_tar();
-
- free(head);
-
- exit(0);
- }
-
-
- /*
- * Produce a directory of the files contained on the TAR
- */
-
- void dir_tar(void)
- {
- char modes[11], *timestamp;
- char uform[11], gform[11];
- char *user, *group, size[24];
- long n, pad, header_std;
- time_t timeval;
-
- for (;;)
- {
- if ((n = fread((char *)head, 1, 512, fdi)) == EOF)
- {
- fclose(fdi);
- return;
- }
-
- decode_header(head, &hstat, &header_std);
-
- /* File type and modes */
-
- modes[0] = '?';
-
- switch (head->header.linkflag)
- {
- case LF_NORMAL:
- case LF_OLDNORMAL:
- case LF_LINK:
- {
- modes[0] = '-';
- if ('/' == head->header.name[strlen(head->header.name)-1])
- modes[0] = 'd';
- break;
- }
- case LF_DIR:
- {
- modes[0] = 'd';
- break;
- }
- case LF_SYMLINK:
- {
- modes[0] = 'l';
- break;
- }
- case LF_BLK:
- {
- modes[0] = 'b';
- break;
- }
- case LF_CHR:
- {
- modes[0] = 'c';
- break;
- }
- case LF_FIFO:
- {
- modes[0] = 'f';
- break;
- }
- case LF_CONTIG:
- {
- modes[0] = '=';
- break;
- }
- }
-
- demode(hstat.st_mode, modes+1);
-
- /* Timestamp */
-
- timeval = hstat.st_mtime;
- timestamp = ctime(&timeval);
- timestamp[16] = '\0';
- timestamp[24] = '\0';
-
- /* User and group names */
-
- if (*head->header.uname && header_std)
- {
- user = head->header.uname;
- }else
- {
- user = uform;
- sprintf(uform, "%ld", (long)hstat.st_uid);
- }
-
- if (*head->header.gname && header_std)
- {
- group = head->header.gname;
- }else
- {
- group = gform;
- sprintf(gform, "%ld", (long)hstat.st_gid);
- }
-
- /* Format the file size or major/minor device numbers */
-
- switch (head->header.linkflag)
- {
- case LF_CHR:
- case LF_BLK:
- {
- sprintf(size, "%ld, %ld",
- (long)from_oct(8, head->header.devmajor),
- (long)from_oct(8, head->header.devminor));
- break;
- }
- default:
- {
- sprintf(size, "%ld", hstat.st_size);
-
- break;
- }
- }
-
-
- /* Figure out padding and print the whole line. */
-
- pad = strlen(user) + strlen(group) + strlen(size) + 1;
-
- if (pad > ugswidth) ugswidth = pad;
-
- printf("%s %s/%s %*s%s %s %s %.*s",
- modes,
- user,
- group,
- ugswidth - pad,
- "",
- size,
- timestamp+4, timestamp+20,
- sizeof(head->header.name),
- head->header.name);
-
- switch (head->header.linkflag)
- {
- case LF_SYMLINK:
- {
- printf(" -> %s\n", head->header.linkname);
- break;
- }
- case LF_LINK:
- {
- printf(" link to %s\n", head->header.linkname);
- break;
- }
-
- default:
- {
- printf(" unknown file type '%c'\n", head->header.linkflag);
- break;
- }
-
- case LF_OLDNORMAL:
- case LF_NORMAL:
- case LF_CHR:
- case LF_BLK:
- case LF_DIR:
- case LF_FIFO:
- case LF_CONTIG:
- {
- putc('\n', stdout);
- break;
- }
- }
-
- /* Seek to next file */
-
- fseek(fdi, hstat.st_size, 1);
-
- /* File starts on 512 byte boundary */
-
- fseek(fdi, 512L - (hstat.st_size % 512L), 1);
- }
- }
-
-
- /*
- * Extract the files from the TAR archive
- *
- */
-
- void de_tar(void)
- {
- ULONG size, filesize;
- long header_std, c;
- char *workfile;
-
- for (;!feof(fdi);)
- {
- if ( fread((char *)head, 1, 512, fdi) == EOF) break;
-
- decode_header(head, &hstat, &header_std);
- workfile = head->header.name;
- size = filesize = hstat.st_size;
-
- if( workfile[strlen(workfile)-1] == '/'
- || workfile[strlen(workfile)-1] == ':' )
- {
- ULONG lock;
-
- printf("Creating: %s ...", workfile);
-
- workfile[strlen(workfile)-1] = (char) 0;
-
- lock = CreateDir(workfile);
- if(lock)
- {
- printf(" OK\n");
- UnLock(lock);
- }else printf(" Failed\n");
-
- fseek(fdi, filesize, 1);
-
- continue;
- }
-
- printf("Extracting: %s\n", workfile);
-
- fdo = fopen(workfile, "w");
-
- while ((c = getc(fdi)) != EOF) {
-
- /*
- * Convert Linefeed to MSDOS
- * Carriage Return, Linefeed pair
- *
- */
-
- if (c == 0x0A)
- putc('\n', fdo);
- else
- putc(c, fdo);
-
- if (--size == 0L) {
-
- /*
- * Get to next 512 byte boundary
- */
-
- fseek(fdi, 512L - (filesize % 512L), 1);
- break;
- }
- }
-
- fclose(fdo);
- }
-
- fclose(fdi);
- }
-
-
- /*
- * Break down the header info into stat info
- *
- * Set "*stdp" to != 0 or == 0 depending whether
- * header record is "Unix Standard" or "old" tar format.
- *
- */
-
- void decode_header(union record *header, struct stat *st, long *stdp)
- {
- st->st_mode = (long)from_oct( 8, header->header.mode);
- st->st_mtime = from_oct(12, header->header.mtime);
- st->st_size = from_oct(12, header->header.size);
-
- if (0 == strcmp(header->header.magic, TMAGIC)) {
-
- /* Unix Standard tar archive */
-
- *stdp = 1;
- st->st_dev = 0;
-
- } else {
-
- /* Old fashioned tar archive */
-
- *stdp = 0;
- st->st_uid = (long)from_oct(8, header->header.uid);
- st->st_gid = (long)from_oct(8, header->header.gid);
- st->st_dev = 0;
- }
- }
-
-
- /*
- * Decode the mode string from a stat entry into a 9-char string
- */
-
- void demode(unsigned mode, char *string)
- {
- register unsigned mask;
- register char *rwx = "rwxrwxrwx";
-
- for (mask = 0400; mask != 0; mask >>= 1) {
- if (mode & mask)
- *string++ = *rwx++;
- else {
- *string++ = '-';
- rwx++;
- }
- }
-
- if (mode & S_ISUID)
- if (string[-7] == 'x')
- string[-7] = 's';
- else
- string[-7] = 'S';
-
- if (mode & S_ISGID)
- if (string[-4] == 'x')
- string[-4] = 's';
- else
- string[-4] = 'S';
-
- if (mode & S_ISVTX)
- if (string[-1] == 'x')
- string[-1] = 't';
- else
- string[-1] = 'T';
-
- *string = '\0';
- }
-
-
- /*
- * Quick and dirty octal conversion.
- *
- * Result is -1 if the field is invalid (all blank, or nonoctal).
- */
-
- long from_oct(long digs, char *where)
- {
- register long value;
-
- while (isspace(*where)) { /* Skip spaces */
- where++;
- if (--digs <= 0)
- return -1; /* All blank field */
- }
-
- value = 0;
- while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */
- value = (value << 3) | (*where++ - '0');
- --digs;
- }
-
- if (digs > 0 && *where && !isspace(*where))
- return -1; /* Ended on non-space/nul */
-
- return value;
- }
-