home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hall of Fame
/
HallofFameCDROM.cdr
/
proglc
/
zoo141_c.lzh
/
ZOOEXT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1987-02-07
|
21KB
|
626 lines
/* zooext.c */
/*
Copyright (C) 1986 Rahul Dhesi -- All rights reserved
*/
#include "options.h"
/* Extract file from archive. Extracts files specified in parameter-list
from archive zoo_path. If none specified, extracts all files from
archive. */
#include "zoo.h"
#include "parse.h" /* defines struct for parse() */
#include "portable.h" /* portable I/O definitions */
#include "machine.h" /* machine-specific declarations */
#include <stdio.h>
#include "various.h"
#ifndef NOSIGNAL
#include <signal.h>
#endif
#include "zoofns.h"
/* for low-level I/O */
#ifdef FLAT
#include <types.h>
#include <stat.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif
#ifdef NOFCNTL
#include <file.h>
#else
#include <fcntl.h>
#endif
extern int quiet;
#include "errors.i"
/* Following two are used by ctrl_c() also, hence declared here */
char extfname[LFNAMESIZE]; /* filename of extracted file */
static int this_han; /* handle of file to extract */
static int tofile; /* true if not pipe or null device */
extern unsigned int crccode;
extern char *out_buf_adr; /* address of output buffer */
void zooext(zoo_path, option)
char *zoo_path, *option;
{
char *whichname; /* which name to extract */
char matchname[PATHSIZE]; /* for pattern matching only */
#ifndef NOSIGNAL
int (*oldsignal)(); /* to save previous SIGINT handler */
#endif
int zoo_han; /* handle for open archive */
long next_ptr; /* pointer to within archive */
struct zoo_header zoo_header; /* header for archive */
int status; /* error status */
char ans[3]; /* answer to "Overwrite?" */
int error_message = 1; /* Whether to give error message */
unsigned long disk_space; /* disk space left */
int matched = 0; /* Any files matched? */
int overwrite = 0; /* force overwrite of files? */
int needdel = 0; /* extract deleted files too */
int usepath = 0; /* use path for extraction */
int todot = 0; /* extract relative to . */
int zootime = 0; /* just set archive time */
int badcrc_count = 0; /* how many files with bad CRC */
int bad_header = 0; /* to avoid spurious messages later */
long fiz_ofs = 0; /* offset where to start */
int pipe = 0; /* are we piping output? */
int fast_ext = 0; /* fast extract as *.?Z? */
int null_device = 0; /* are we sending to null device? */
int alloc_size; /* disk allocation unit size */
struct direntry direntry; /* directory entry */
#ifdef OOZ
static char extract_ver[] = "A higher version of OOZ is needed to extract ";
static char no_space[] = "Insufficient disk space to extract ";
#else
static char extract_ver[] = "Zoo %d.%d is needed to extract %s.\n";
static char no_space[] = "Insufficient disk space to extract %s.\n";
#endif
#ifndef OOZ
while (*option) {
switch (*option) {
#ifndef PORTABLE
case 'z': fast_ext++; break;
#endif
case 'x':
case 'e': break;
case 'N': null_device++; break;
case 'O': overwrite += 2; break;
case 'o': overwrite++; break;
case 'p': pipe++; break;
case 'd': needdel++; break;
case 'q': quiet++; break;
case '/': usepath++; break;
case '.': todot++; break;
case '@':
++option;
fiz_ofs = calc_ofs(option);
goto no_more;
default:
prterror ('w', option_ignored, *option);
break;
}
option++;
}
no_more: /* come from exit in while loop above */
if (overwrite == 1) /* must be at least 2 to begin with */
overwrite--;
if (null_device && pipe) {
prterror ('w', option_ignored, 'p');
pipe = 0;
}
if (overwrite && pipe)
prterror ('w', option_ignored, 'O');
if (null_device && fast_ext) {
prterror ('w', option_ignored, 'N');
null_device = 0;
}
tofile = !pipe && !null_device; /* sending to actual file */
#else
tofile = 1;
#endif
zoo_han = OPEN(zoo_path, F_READ);
if (zoo_han == -1)
#ifdef OOZ
prterror ('f', could_not_open, zoo_path, ".\n");
#else
prterror ('f', could_not_open, zoo_path);
#endif
if (fiz_ofs != 0L) { /* if offset specified, start there */
prterror('m', "Starting at %ld\n", fiz_ofs);
lseek (zoo_han, fiz_ofs, 0);
} else {
/* read header */
rd_zooh (&zoo_header, zoo_han);
/* read (zoo_han, (char *) &zoo_header, sizeof(zoo_header)); */
if ((zoo_header.zoo_start + zoo_header.zoo_minus) != 0L) {
prterror ('w', failed_consistency, NULL, NULL);
bad_header++;
}
lseek (zoo_han, zoo_header.zoo_start, 0); /* seek to where data begins */
}
#ifndef PORTABLE
disk_space = space (0, &alloc_size); /* remember disk space left */
#else
alloc_size = 0;
disk_space = MAXLONG; /* infinite disk space */
#endif
#ifndef OOZ
/* Ooz does no piping */
/* if piping output we open the output device just once */
/* NOTE: the DOS device "NUL" was causing the system to hang up.
therefore we create our own. All functions called must recognize
-2 as a null output handle and ignore all output to that */
if (null_device) { /* -2 means null device */
this_han = -2;
} else if (pipe)
this_han = (int) fileno(stdout); /* standard output */
#endif
while (1) {
rd_dir (&direntry, zoo_han);
/* read (zoo_han, (char *) &direntry, sizeof(direntry)); */
if (direntry.zoo_tag != ZOO_TAG) {
long currpos, zoolength;
#ifdef OOZ
prterror ('f', invalid_header, NULL, NULL);
#else
prterror ('F', invalid_header);
/* Note: if header was bad, there's no point trying to find
how many more bytes aren't processed -- our seek position is
likely very wrong */
if (!bad_header)
if ((currpos = tell (zoo_han)) != -1L)
if (lseek (zoo_han, 0L, 2) != -1)
if ((zoolength = tell (zoo_han)) != -1L)
printf (cant_process, zoolength - currpos);
exit (1);
#endif
}
if (direntry.next == 0L) { /* END OF CHAIN */
break; /* EXIT on end of chain */
}
next_ptr = direntry.next; /* ptr to next dir entry */
whichname = choosefname(&direntry); /* which filename */
fixfname(whichname); /* fix syntax */
combine (matchname,
direntry.dirlen > 0 ? direntry.dirname : "",
(direntry.namlen > 0) ? direntry.lfname : direntry.fname
);
if (todot && *direntry.dirname == *PATH_CH) {
char tmpstr[PATHSIZE];
strcpy(tmpstr, direntry.dirname);
strcpy(direntry.dirname,CUR_DIR);
strcat(direntry.dirname, tmpstr);
}
/* matchname now holds the full pathname for pattern matching */
if ( ( (needdel && direntry.deleted) ||
(needdel < 2 && !direntry.deleted)
) && needed(matchname)) {
matched++; /* update count of files extracted */
if (direntry.major_ver > MAJOR_EXT_VER ||
(direntry.major_ver == MAJOR_EXT_VER &&
direntry.minor_ver > MINOR_EXT_VER)) {
#ifdef OOZ
prterror ('e', extract_ver, whichname, ".\n");
#else
prterror ('e', extract_ver, direntry.major_ver,
direntry.minor_ver, whichname);
#endif
goto loop_again;
}
/*
If extracting to null device, or if user requested extraction
of entire path, include any directory name in filename.
If extraction to current directory requested, and if extfname
begins with path separator, fix it */
strcpy (extfname, whichname);
if ((usepath || null_device) && direntry.dirlen > 0) {
combine(extfname, direntry.dirname, whichname);
if (usepath > 1 && !null_device)
makepath(direntry.dirname); /* make dir prefix */
}
if (tofile) {
int present = 0;
#ifndef OOZ
#ifndef PORTABLE
/*
if Z format (fast) extraction, extension is created as
follows: for no current extension, new extension is "zzz";
for current extension "a", new extension is "azz"; for
current extension "ab", new extension is "azb"; and for
current extension "abc", new extension is "azc".
*/
if (fast_ext) {
int length;
struct path_st path_st;
parse (&path_st, extfname); /* split filename */
strcpy (extfname, path_st.fname); /* just root filename */
length = strlen (path_st.ext);
strcat (extfname, ".");
if (length == 0)
strcat (extfname, "zzz"); /* no ext -> .zzz */
else if (length == 1) {
strcat (extfname, path_st.ext);
strcat (extfname, "zz"); /* *.? -> *.?zz */
} else { /* length is 2 or 3 */
if (length == 2) /* allow .aa, .ab, etc. */
path_st.ext[2] = path_st.ext[1];
path_st.ext[1] = 'z';
strcat (extfname, path_st.ext); /* *.?? -> *.?z? */
}
}
#endif /* ifndef PORTABLE */
#endif /* ifndef OOZ */
if (overwrite) {
this_han = CREATE(extfname, F_RDWR);
} else {
if (exists (extfname)) {
present = 1;
this_han = -1;
} else
this_han = CREATE(extfname, F_RDWR);
}
if (this_han == -1) {
if (present == 1) { /* if file exists already */
do {
#ifdef OOZ
putstr ("Overwrite "); putstr (extfname);
putstr (" (Yes/No/All)? ");
#else
printf ("Overwrite %s (Yes/No/All)? ", extfname);
#endif
fflush (stdin);
fgets (ans, 3, stdin);
strlwr (ans);
} while (*ans != 'y' && *ans != 'n' && *ans != 'a');
/* NOTE: We use CREAT even if we are trying to overwrite
the file, because a data path utility (Search or Dpath)
could have fooled us before. */
if (*ans == 'a')
overwrite++;
if (*ans == 'y' || *ans == 'a') {
this_han = CREATE(extfname, F_RDWR);
error_message = 1; /* give error message if open fails */
} else {
error_message = 0; /* user said 'n', so no error message */
}
} else {
error_message = 1; /* Real error -- give error message */
}
} /* end if */
} /* end if */
if (this_han == -1) { /* file couldn't be opened */
if (error_message == 1) {
unlink (extfname);
#ifdef OOZ
prterror ('e', could_not_open, extfname, " for output.\n");
#else
prterror ('e', "Can't open %s for output.\n", extfname);
#endif
#ifndef PORTABLE
/* if error was due to full disk, abort */
if (space(0, &alloc_size) < alloc_size)
#endif
prterror ('f', disk_full, NULL, NULL);
}
} else if (lseek (zoo_han, direntry.offset, 0) == -1L) {
prterror ('e', "Could not seek to file data.\n");
close_han (this_han);
} else {
#ifndef PORTABLE
/* check Dos's free disk space if we seem to be running low
(within 1 cluster of being full) */
if (tofile && disk_space < direntry.org_size + alloc_size) {
disk_space = space (0, &alloc_size);
if (disk_space < alloc_size) {
close_han (this_han);
unlink (extfname);
prterror ('f', disk_full, NULL, NULL);
}
}
#endif
if (tofile && disk_space < direntry.org_size) {
#ifdef PORTABLE
;
#else
#ifdef OOZ
prterror ('e', no_space, extfname, ".\n");
#else
prterror ('e', no_space, extfname);
#endif
unlink (extfname); /* delete any created file */
#endif /* portable */
} else {
#ifndef OOZ
#ifndef PORTABLE
if (fast_ext) { /* fast ext -> create header */
void make_tnh();
struct tiny_header tiny_header;
make_tnh(&tiny_header, &direntry);
write (this_han, (char *) &tiny_header, sizeof (tiny_header));
if (direntry.cmt_size != 0) { /* copy comment */
long save_pos;
save_pos = tell (zoo_han);
lseek (zoo_han, direntry.comment, 0);
getfile (zoo_han, this_han,
(long) direntry.cmt_size, 0);
lseek (zoo_han, save_pos, 0);
}
}
#endif /* ifndef PORTABLE */
#endif /* ifndef OOZ */
crccode = 0; /* Initialize CRC before extraction */
#ifdef OOZ
putstr (extfname);
{
register int i;
for (i = strlen(direntry.fname); i < 13; i++)
putstr (" ");
putstr ("-- ");
}
#else
if (!pipe) {
#ifdef PORTABLE
prterror ('m', "%-14s -- ", extfname);
#else
if (fast_ext)
prterror ('m', "%-12s ==> %-12s -- ",
direntry.fname, extfname);
else
prterror ('m', "%-12s -- ", extfname);
#ifdef COMMENT
prterror ('m',
fast_ext ? "%-12s ==> %-12s -- " : "%-12s -- ",
direntry.fname, extfname);
#endif /* COMMENT */
#endif /* PORTABLE */
} else { /* must be pipe */
prterror ('M', "\n\n********\n%s\n********\n", direntry.fname);
fflush (stdout); /* make 'm appear right here */
#ifdef COMMENT
#ifdef SETMODE
MODE_BIN(this_han); /* make std output binary so
^Z won't cause error */
#endif
#endif
}
#endif /* OOZ */
#ifndef NOSIGNAL
#ifndef OOZ
if (tofile)
#endif /* not OOZ */
{
oldsignal = signal (SIGINT, SIG_IGN);
if (oldsignal != SIG_IGN)
signal (SIGINT, ctrl_c); /* Trap ^C & erase partial file */
}
#endif /* not NOSIGNAL */
if (direntry.packing_method == 0)
/* 4th param 1 means CRC update */
status = getfile (zoo_han, this_han, direntry.size_now, 1);
#ifndef OOZ
else if (fast_ext)
/* 4th param 0 means no CRC update */
status = getfile (zoo_han, this_han, direntry.size_now, 0);
#endif
else if (direntry.packing_method == 1)
status = lzd (zoo_han, this_han); /* uncompress */
else {
#ifdef OOZ
prterror ('e', "File ", whichname,
": impossible packing method.\n", "");
#else
prterror ('e', "File %s: impossible packing method.\n",
whichname);
#endif
unlink(extfname);
goto loop_again;
}
#ifndef NOSIGNAL
#ifndef OOZ
if (tofile)
#endif /* not OOZ */
signal (SIGINT, oldsignal);
#endif /* not NOSIGNAL */
#ifdef COMMENT
#ifndef OOZ
#ifdef SETMODE
if (pipe)
MODE_TEXT(this_han); /* restore text mode */
#endif
#endif
#endif
#ifndef OOZ
if (tofile) {
#endif
/* set date/time of file being extracted */
#ifdef NIXTIME
close_han (this_han);
setutime (direntry.fname, direntry.date, direntry.time);
#else
settime (this_han, direntry.date, direntry.time);
close_han (this_han);
#endif
#ifndef OOZ
}
#endif
if (status != 0) {
if (tofile)
unlink (extfname);
if (status == 1) {
memerr();
/* To avoid spurious errors due to ^Z being sent to screen,
we don't check for I/O error if output was piped */
} else if (!pipe && (status == 2 || status == 3)) {
#ifdef OOZ
prterror ('e', no_space, direntry.fname, ".\n");
#else
prterror ('e', no_space, direntry.fname);
#endif
}
} else {
/* file extracted, so update disk space. */
/* we subtract the original size of the file, rounded
UP to the nearest multiple of the disk allocation
size. */
#ifndef PORTABLE
{
unsigned long temp;
temp = (direntry.org_size + alloc_size) / alloc_size;
disk_space -= temp * alloc_size;
}
#endif
#ifdef OOZ
if (direntry.file_crc != crccode)
putstr ("extracted \007WARNING: Bad CRC.\n");
else
putstr ("extracted\n");
#else
if (!fast_ext && direntry.file_crc != crccode) {
badcrc_count++;
if (!pipe) {
if (!null_device)
prterror ('M', "extracted ");
prterror ('w', bad_crc, direntry.fname);
}
else { /* duplicate to standard error */
static char stars[] = "\n******\n";
putstr (stars);
prterror ('w', bad_crc, direntry.fname);
putstr (stars);
fprintf (stderr, "WARNING: ");
fprintf (stderr, bad_crc, direntry.fname);
}
} else
if (!pipe)
prterror ('M', null_device ? "OK\n" : "extracted\n");
#endif
} /* end if */
} /* end if */
} /* end if */
} /* end if */
loop_again:
lseek (zoo_han, next_ptr, 0); /* ..seek to next dir entry */
} /* end while */
close (zoo_han);
if (!matched)
putstr (no_match);
#ifndef OOZ
if (badcrc_count) {
prterror ('w', "%d File(s) with bad CRC.\n", badcrc_count);
exit (1);
} else if (null_device)
prterror ('m', "Archive seems OK.\n");
#endif
} /* end zooext */
/* close_han() */
/* closes a handle if and only if we aren't sending output to
a pipe or to the null device */
void close_han (handle)
int handle;
{
if (tofile)
close (handle);
}
/* Ctrl_c() is called if ^C is hit while a file is being extracted.
It closes the files, deletes it, and exits. */
int ctrl_c()
{
#ifndef NOSIGNAL
signal (SIGINT, SIG_IGN); /* ignore any more */
#endif
close (this_han);
unlink (extfname);
exit (1);
}
/* make_tnh copies creates a tiny_header */
void make_tnh (tiny_header, direntry)
struct tiny_header *tiny_header;
struct direntry *direntry;
{
tiny_header->tinytag = TINYTAG;
tiny_header->type = 1;
tiny_header->packing_method = direntry->packing_method;
tiny_header->date = direntry->date;
tiny_header->time = direntry->time;
tiny_header->file_crc = direntry->file_crc;
tiny_header->org_size = direntry->org_size;
tiny_header->size_now = direntry->size_now;
tiny_header->major_ver = direntry->major_ver;
tiny_header->minor_ver = direntry->minor_ver;
tiny_header->cmt_size = direntry->cmt_size;
strcpy (tiny_header->fname, direntry->fname);
}