Subject: v17i069: Zoo archive program, Part06/10 Newsgroups: comp.sources.unix Approved: rsalz@uunet.UU.NET Submitted-by: Rahul Dhesi Posting-number: Volume 17, Issue 69 Archive-name: zoo2/part06 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'options.doc' <<'END_OF_FILE' X/* @(#) options.doc 1.4 88/08/22 15:24:59 */ X XDocumentation about the file options.h. X XThe file options.h defines various symbols and macros that are needed Xto ensure system-independence. The basic philosophy is to use a Xdistinct symbol for each attribute that varies from machine to machine. XThen, for each new system, we define symbols corresponding to its Xattributes. Thus, ideally, the only place in Zoo code that we actually Xuse the name of a machine is in this file, in portable.h, and possibly in Xmachine.h and options.c. Everywhere else in the code we only use Xnames of attributes. X XMachine names: X XMSC Microsoft C 3.0 under MS-DOS (not currently in use) XTURBOC Turbo C 1.0 under MS-DOS (works, compiled version is X separately distributed) XDLC Datalight C under MS-DOS (not currently in use*) XFLEX FlexDOS (not currently in use*) XSYS_V UNIX System V release 2 (works) XVMS VAX/VMS 4.4 through 4.6 (works, stream-LF files only) XBSD4_3 4.3BSD (works) XMCH_AMIGA AmigaDOS Aztec/Manx C (compiled version is separately X distributed) X----- X*Mark Alexander provided me with changes to allow compilation using XFlexDOS and also Datalight's Optimum C under MSDOS but they have not Xyet been incorporated into this release. X XNOTE: The term "zoofile" below refers to an open file of type XZOOFILE. Currently this is defined to be equivalent to a standard Xbuffered file pointer of type "ZOOFILE *" but this may change in the Xfuture. Dependence on exact definition of ZOOFILE is localized to a Xfew files: options.h, portable.h, portable.c, and machine.c. X XAttributes of systems: X XCHEKDIR X Test each supplied filename and if it is a directory or other special X type of file, do not try to add it to an archive. If CHEKDIR is X defined, then machine.c must also contain function isadir() that X tests a supplied zoofile and returns 1 if it corresponds to a X directory or other special type of file, else 0. XCHEKUDIR X Like CHEKDIR but use function isuadir() that tests a pathname, not X a zoofile. Both CHEKDIR and CHEKUDIR may be defined, if both X functions isadir() and isuadir() are available; in this case X zoo code will use both and will execute slightly faster. X (However, simultaneous definition of CHEKDIR and CHEKUDIR has X not been tested.) XDISK_CH X If defined, must hold the value of a character that separates a X disk name from the rest of the pathname. All characters up to and X including this character will be removed from a pathname before it X is stored in an archive. Usually a colon (':'). XEXISTS X If defined, is assumed to be a macro that accepts a filename and X returns an int value of 1 if the file exists and 0 if it doesn't. X If not defined, existence of files is tested by attempting to open X them for read or write access. XFATTR X If defined, file attributes will be preserved. A function X getfattr(f) must also exist that returns the attributes of a X zoofile f (or of a pathname f, if the symbol FATTR_FNAME is X also defined); and a function setfattr(f, a) must exist that X sets the attributes of a file with pathname f to the value a. X For more details see the source code in sysv.c and bsd.c. Currently X the attribute value a is required to be in the zoo portable X format. The lowest nine bits of this format correspond to X the **IX mode bits described for chmod(2) and these are the only X bits currently used. XFATTR_FNAME X If defined, and if FATTR is also defined, zoo code will X obtain the attributes of a file by calling the function X getfattr(f) and supplying it with filename f. If FATTR_FNAME X is not defined, then getfattr(f) is supplied a zoofile f. XLINT_ARGS X Use ANSI-style function argument lists in declarations. The symbols X MORE, NOTHING, and VOIDPTR must also be defined. XMORE X In function prototypes, a variable number of trailing arguments X is specified with the symbol MORE following a trailing comma. X For ANSI-conformant compilers, MORE will be defined to be three X dots (...); for others, it can be defined as necessary X (empty string for Microsoft C 3.0). XNOTHING X In a prototype for a function that takes no parameters, NOTHING is X used as the parameter. For ANSI-compatible compilers NOTHING should X be defined to be `void'. For other compilers it should be defined X to be empty. XVOIDPTR X VOIDPTR should be defined as void * if the compiler supports this X (e.g. Turbo C), else it should be defined as char * (e.g. Microsoft X C). XLINT X If defined, SCCS identifier strings will not be included in the X generated code. This will make the code smaller and will also X avoid complaints from lint about unused variables. This symbol X should be defined in the Makefile, NOT in `options.h', otherwise X it will not be fully effective. XFOLD X Fold filenames to lowercase. Define this for case-insensitive filesystems XFPUTCHAR X If defined, a library function fputchar() is assumed available X that is like fput() but is a function, not a macro, to save X space. If not defined Zoo uses its own fputchar() function. XPORTABLE X Use portable functions --- define for every system except MS-DOS XPURIFY X When filenames are being read from standard input, ignore all X characters begining with the first blank or tab encountered. X This will allow filenames to be fed from a program that produces X lines containing filenames followed by other information that X should be ignored. Should be defined for most non-**IX systems. XDONT_SORT X Don't sort filename arguments -- files will be stored in the X exact order in which names are supplied on the command line. X Not currently used for any system, but could be used if memory X is really tight. XNOENUM X Compiler does not support enumerations XDUMB_ASS X Dumb assertions must be used because the preprocessor doesn't define X the symbols __FILE__ and __LINE__ (which hold the name of the current X file and the number of the current line) XFNLIMIT X Pathname length limit for this system XNEEDCTYP X If defined, tells the code to include the header file ctype.h for X use by character conversion macros. If and only if NEEDCTYP is not X defined, macros or appropriate function declarations can be put in X portable.h. Zoo uses isupper(), isdigit(), toascii(), and tolower(). X If NEEDCTYP is not defined, the symbol USE_ASCII can be defined to X cause zoo to assume the ASCII character set and use its own isupper(), X isdigit(), toascii(), and tolower() functions, possibly making the X executable code smaller. XUSE_ASCII X See description of NEEDCTYP. USE_ASCII should not be defined if X NEEDCTYP is defined, else there may be conflicts between macro X and function names. XNIXTIME X If defined, a function setutime() must be defined that will set the X date and time of a file whose pathname is supplied. If not defined, X a function settime() must be defined that will do the same for X a zoofile. XGETUTIME X If defined, a function getutime() must be defined that will return X the MS-DOS format date and time of the specified filename. If this X symbol is not defined, then a function gettime() must be defined X that will do the same for a zoofile instead of a filename. XNOSIGNAL X don't use signals because library doesn't support them XPATH_CH X The character that separates the directory name from the filename X in a pathname. String value. XPATH_SEP X The set of characters that may separate preceding directory/device X information from the filename. String value. XEXT_SEP is the union of PATH_SEP and the set of characters separating a X filename extension from the rest of the filename. String value. XEXT_CH X Character that separates base part of filename from extension. X Char value. XMEMSET X If defined, a library function memset() is assumed available that X conforms to that available under System V. If not defined, Zoo uses X its own memset() function. XEXT_DFLT X default extension for archives. String. Currently ".zoo". XNIXFNAME X If defined, PATH_CH, PATH_SEP, EXT_SEP, EXT_CH, and EXT_DFLT get defined X to conform to **IX conventions and should not be separately defined XMSFNAME X if defined, PATH_CH, PATH_SEP, EXT_SEP, EXT_CH, EXT_DFLT, and X DISK_CH get defined to conform to MS-DOS conventions and should X not be separately defined (not currently implemented) XFORCESLASH X If defined any backslashes in names of files will be converted to X slashes before the files are added to an archive. This is useful X for MSDOS-like systems that accept both slashes and backslashes, X since the standard archive format allows only slashes as directory X separators. XREN_LINK X Rename a file by using link() followed by unlink() (e.g. Xenix, System V) XREN_NORM X Use normal rename function: "int rename(new, old)" (e.g. Microsoft C) XREN_REV X Use reverse rename function: "int rename(old, new)" (e.g. 4.3BSD, X Turbo C). Note: define exactly one of REN_LINK, REN_NORM, and REN_REV. XSETMODE X Change mode of standard output to binary when piping output, then change X it back to text. Macros MODE_BIN(zoofile) and MODE_TEXT(zoofile) must X also be defined. XSETBUF X Standard output should be set to be unbuffered so output shows up X quickly. Currently used only in Fiz, not in Zoo. XSPECNEXT X If defined, a machine-dependent function nextfile() must be defined that X will expand wildcards in a supplied pathname. If not defined, any X wildcard expansion must have been done before the command line parameters X are supplied to the program. For details see the file nextfile.c. XSTRLWR X If defined, a library function strlwr() is assumed available that converts X a supplied string to lowercase and returns a pointer it. If not X defined, Zoo uses its own strlwr() function. XSTRDUP X If defined, a library function strdup() is assumed available that X returns a pointer to a copy of a supplied string. If not defined, X Zoo uses its own strdup() function. XSPECEXIT X Custom exit handler is needed. A function called zooexit() X must be defined. If SPECEXIT is not defined, zoo uses its X own zooexit() function which simply calls exit(). XSPECINIT X If defined, zoo's main() function will call spec_init() before X doing anything else. Any system-specific initialization may be X done at this point. XGETTZ X If defined, a function gettz() must also be defined that will X return the current timezone, in seconds west of GMT, as a long X value. Currently such a function is already defined in files X bsd.c and sysv.c. If and only if GETTZ is defined, zoo will X store the current timezone for each file that is archived, X and will list the timezone for each file that has one when it X lists archive contents. XALWAYS_INT X In function prototypes for fgetc(), fread(), and fwrite(), X traditional practice made certain arguments int, though X they ought to be char and unsigned respectively. If X ALWAYS_INT is defined, prototypes will use int only, X else the correct types are used. XIO_MACROS X If defined, some portable I/O functions are defined as macros, X saving space. XZOOCOMMENT X If defined, archive comments are fully enabled. If not defined, X zoo code will be smaller at the cost that archive comments will X be listed but cannot be updated. COMPILATION WITHOUT ZOOCOMMENT X DEFINED HAS NOT YET BEEN TESTED. XTRACE_IO X This is for debugging. If defined, it will cause code to X be compiled that will trace all archive header and directory X entry I/O by showing it on the screen in human-readable format. X The tracing will then occur if any Expert command given to zoo X is preceded by a colon. E.g., if compiled with TRACE_IO on and X given the command "zoo :l xyz", zoo will give a directory X listing of xyz.zoo exactly as it would with "zoo l xyz" except X that all archive header and directory entry reads and writes X will be shown on the screen. The tracing code is localized X to the files zoo.c and portable.c, so just these two files X can be compiled afresh when TRACE_IO is turned on or switched X off. NOTE: The symbol TRACE_LIST, internal to the file X "zoolist.c", enables debugging information too. Do not define X both TRACE_IO and TRACE_LIST because (a) a symbol conflict will X occur and (b) the debugging information will be duplicated. XUNBUF_IO X If defined, some I/O is done using low-level system calls read() and X write(). To do this, the low-level file descriptor is synchronized with X the buffered zoofile before such I/O is done. To do this, read(), X write(), and lseek() system calls must be available and the fileno() X macro must return the file descriptor for a buffered file. This is X not portable and should definitely not be done by most end users. If X UNBUF_IO is defined, also defined must be a symbol UNBUF_LIMIT with a X numerical value that specifies the threshold over which unbuffered I/O X should be used. For example, if the value of UNBUF_LIMIT is 512, then X any I/O on a zoofile that reads or writes more than 512 bytes will be X done using read() or write() system calls. The use of unbuffered I/O X with a threshold in the range 512 to 1024 can enhance performance by up X to 50%. The corruption of data is a serious matter. Do not define X UNBUF_IO unless you are willing to exhaustively test the compiled code X on your system to make sure it works, and accept full responsibility for X any adverse consequences. Some standard I/O libraries may attempt to X optimize the working of fseek() on files opened for read access only, X and cause UNBUF_IO to fail. XUNBUF_LIMIT X Needed if and only if UNBUF_IO is defined. Holds a numeric value. X All I/O done in blocks that are larger than UNBUF_LIMIT bytes X will be done unbuffered. See UNBUF_IO. XFILTER X If defined, code will be compiled in to enable the fc and fd X commands (compress or decompress, reading standard input and X writing to standard output). These commands are useful only X on systems that allow programs to easily act as filters. XVER_DISPLAY X The character that will separate filenames from generation numbers X in listings of archive contents. Must be a single character X in double quotes. XVER_INPUT X The characters that will be accepted as separating filenames X from generation numbers when typed as an argument to select X specific files from an archive. String value. May include X one or more characters; any of them may then be typed and X will work. XNOSTRCHR X Although 4.3BSD as distributed from Berkeley includes strchr() X and strrchr() library functions, 4.2BSD and similar systems X may not. If so, defining NOSTRCHR will cause zoo to use X index() and rindex() instead. END_OF_FILE if test 14950 -ne `wc -c <'options.doc'`; then echo shar: \"'options.doc'\" unpacked with wrong size! fi # end of 'options.doc' fi if test -f 'zoo.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'zoo.h'\" else echo shar: Extracting \"'zoo.h'\" \(10113 characters\) sed "s/^X//" >'zoo.h' <<'END_OF_FILE' X/* @(#) zoo.h 2.16 88/01/27 23:21:36 */ X X/* XThe contents of this file are hereby released to the public domain. X X -- Rahul Dhesi 1986/11/14 X*/ X X X/* Global data structures and also some information about archive structure. X XAmong other things, the archive header contains: X X(a) A text message. In the MS-DOS version this message is terminated by Xcontrol Z. This allows naive users to type the archive to the screen Xand see a brief but meaningful message instead of garbage. The contents of Xthe text message are however not used by Zoo and they may be anything. XIn particular, the text message may identify the type or archive or the Xparticular computer system it was created on. When an archive is packed Xby any version of Zoo, the text message is changed to the text message Xused by that version. For example, if Zoo 1.10 packs an archive created Xby Zoo 1.31, the text message changes to "Zoo 1.10 archive.". This Xwas once considered a shortcoming, but it is now an essential feature, Xbecause packing will also update an old archiver header structure Xinto a new one. X X(b) A four-byte tag that identifies all Zoo archives. This helps prevent Xarbitrary binary files from being treated as Zoo archives. The tag value is Xarbitrary, but seemed to be unlikely to occur in an executable file. The Xsame tag value is used to identify each directory entry. X X(c) A long pointer to where in the file the archive starts. This pointer Xis stored along with its negation for consistency checking. It is hoped Xthat if the archive is damaged, both the pointer and its negation won't Xbe damaged and at least one would still be usable to tell us where the Xdata begins. X X(d) A two-byte value giving the major and minor version number of the Xminimum version of Zoo that is needed to fully manipulate the archive. XAs the archive structure is modified, this version number may increase. XCurrently version 1.71 of Zoo creates archives that may be fully manipulated Xby version 1.40 onwards. X X(e) With zoo 2.00 addtional fields have been added in the archive Xheader to store information about the archive comment and generation Xlimit. X XVersion numbering: XThe directory entry of each file will contain the minimum version number of XZoo needed to extract that file. As far as possible, version 1.00 of Zoo Xwill be able to extract files from future version archives. X*/ X X#define H_TYPE 1 /* archive header type */ X X/* Define major and minor version numbers */ X#define MAJOR_VER 2 /* needed to manipulate archive */ X#define MINOR_VER 0 X X#define MAJOR_EXT_VER 1 /* needed to extract file */ X#define MINOR_EXT_VER 0 X X#define CTRL_Z 26 X X/* should be 0xFDC4A7DCUL but many c compilers don't recognize UL at end */ X#define ZOO_TAG ((unsigned long) 0xFDC4A7DCL) /* A random choice */ X#define TEXT "ZOO 2.00 Archive.\032" /* Header text for archive. */ X#define SIZ_TEXT 20 /* Size of header text */ X X#define PATHSIZE 256 /* Max length of pathname */ X#define FNAMESIZE 13 /* Size of DOS filename */ X#define LFNAMESIZE 256 /* Size of long filename */ X#define ROOTSIZE 8 /* Size of fname without extension */ X#define EXTLEN 3 /* Size of extension */ X#define FILE_LEADER "@)#(" /* Allowing location of file data */ X#define SIZ_FLDR 5 /* 4 chars plus null */ X#define MAX_PACK 1 /* max packing method we can handle */ X#define BACKUP_EXT ".bak" /* extension of backup file */ X X#ifdef OOZ X#define FIRST_ARG 2 X#endif X X#ifdef ZOO X#define FIRST_ARG 3 /* argument position of filename list */ X#endif X Xtypedef unsigned char uchar; X X/* WARNING: Static initialization in zooadd.c or zooext.c depends on the X order of fields in struct zoo_header */ Xstruct zoo_header { X char text[SIZ_TEXT]; /* archive header text */ X unsigned long zoo_tag; /* identifies archives */ X long zoo_start; /* where the archive's data starts */ X long zoo_minus; /* for consistency checking of zoo_start */ X uchar major_ver; X uchar minor_ver; /* minimum version to extract all files */ X uchar type; /* type of archive header */ X long acmt_pos; /* position of archive comment */ X unsigned int acmt_len; /* length of archive comment */ X unsigned int vdata; /* byte in archive; data about versions */ X}; X Xstruct direntry { X unsigned long zoo_tag; /* tag -- redundancy check */ X uchar type; /* type of directory entry. always 1 for now */ X uchar packing_method; /* 0 = no packing, 1 = normal LZW */ X long next; /* pos'n of next directory entry */ X long offset; /* position of this file */ X unsigned int date; /* DOS format date */ X unsigned int time; /* DOS format time */ X unsigned int file_crc; /* CRC of this file */ X long org_size; X long size_now; X uchar major_ver; X uchar minor_ver; /* minimum version needed to extract */ X uchar deleted; /* will be 1 if deleted, 0 if not */ X uchar struc; /* file structure if any */ X long comment; /* points to comment; zero if none */ X unsigned int cmt_size; /* length of comment, 0 if none */ X char fname[FNAMESIZE]; /* filename */ X X int var_dir_len; /* length of variable part of dir entry */ X uchar tz; /* timezone where file was archived */ X unsigned int dir_crc; /* CRC of directory entry */ X X /* fields for variable part of directory entry follow */ X uchar namlen; /* length of long filename */ X uchar dirlen; /* length of directory name */ X char lfname[LFNAMESIZE]; /* long filename */ X char dirname[PATHSIZE]; /* directory name */ X unsigned int system_id; /* Filesystem ID */ X unsigned long fattr; /* File attributes -- 24 bits */ X unsigned int vflag; /* version flag bits -- one byte in archive */ X unsigned int version_no; /* file version number if any */ X}; X X/* Values for direntry.system_id */ X#define SYSID_NIX 0 /* UNIX and similar filesystems */ X#define SYSID_MS 1 /* MS-DOS filesystem */ X#define SYSID_PORTABLE 2 /* Portable syntax */ X X/* Structure of header of small archive containing just one file */ X X#define TINYTAG 0x07FE /* magic number */ X X#ifndef PORTABLE Xstruct tiny_header { /* one-file small archive */ X int tinytag; /* magic number */ X char type; /* always 1 for now */ X char packing_method; X unsigned int date; X unsigned int time; X unsigned int file_crc; X long org_size; X long size_now; X char major_ver; X char minor_ver; X unsigned int cmt_size; /* length of comment, 0 if none */ X char fname[FNAMESIZE]; /* filename */ X}; X#endif /* ifndef PORTABLE */ X X#define FIXED_OFFSET 34 /* zoo_start in old archives */ X#define MINZOOHSIZ 34 /* minimum size of archive header */ X#define SIZ_ZOOH 42 /* length of current archive header */ X X/* offsets of items within the canonical zoo archive header */ X#define TEXT_I 0 /* text in header */ X#define ZTAG_I 20 /* zoo tag */ X#define ZST_I 24 /* start offset */ X#define ZSTM_I 28 /* negative of start offset */ X#define MAJV_I 32 /* major version */ X#define MINV_I 33 /* minor version */ X#define HTYPE_I 34 /* archive header type */ X#define ACMTPOS_I 35 /* position of archive comment */ X#define ACMTLEN_I 39 /* length of archive comment */ X#define HVDATA_I 41 /* version data */ X X/* offsets of items within the canonical directory entry structure */ X#define SIZ_DIR 51 /* length of type 1 directory entry */ X#define SIZ_DIRL 56 /* length of type 2 directory entry */ X#define DTAG_I 0 /* tag within directory entry */ X#define DTYP_I 4 /* type of directory entry */ X#define PKM_I 5 /* packing method */ X#define NXT_I 6 /* pos'n of next directory entry */ X#define OFS_I 10 /* position (offset) of this file */ X#define DAT_I 14 /* DOS format date */ X#define TIM_I 16 /* DOS format time */ X#define CRC_I 18 /* CRC of this file */ X#define ORGS_I 20 /* original size */ X#define SIZNOW_I 24 /* size now */ X#define DMAJ_I 28 /* major version number */ X#define DMIN_I 29 /* minor version number */ X#define DEL_I 30 /* deleted or not */ X#define STRUC_I 31 /* file structure */ X#define CMT_I 32 /* comment [offset] */ X#define CMTSIZ_I 36 /* comment size */ X#define FNAME_I 38 /* filename */ X#define VARDIRLEN_I 51 /* length of var. direntry */ X#define TZ_I 53 /* timezone */ X#define DCRC_I 54 /* CRC of directory entry */ X X#define FNM_SIZ 13 /* size of stored filename */ X X/* Offsets within variable part of directory entry */ X#define NAMLEN_I (SIZ_DIRL + 0) X#define DIRLEN_I (SIZ_DIRL + 1) X#define LFNAME_I (SIZ_DIRL + 2) X#define DIRNAME_I LFNAME_I /* plus length of filename */ X X/* XTotal size of fixed plus variable directory recognized currently: XOne byte each for dirlen and namlen, 256 each for long filename and Xdirectory name, 2 for system id, 3 for file attributes, 1 for Xversion flag, 2 for version number, plus a fudge factor of 5. X*/ X#define MAXDIRSIZE (SIZ_DIRL+1+1+256+256+2+3+1+2+5) X X/* Value used to stuff into timezone field if it is not known */ X#define NO_TZ 127 X X/* Value for no file attributes */ X#define NO_FATTR 0L X X/* version flag bits */ X#define VFL_ON 0x80 /* enable version numbering */ X#define VFL_GEN 0x0f /* generation count */ X#define VFL_LAST 0x40 /* last generation of this file */ X X/* default generation value for archive */ X#define GEN_DEFAULT 1 X/* max generation count, file or archive */ X#define MAXGEN 0x0f X/* version mask to prune down to correct size on large-word machines */ X#define VER_MASK 0xffff END_OF_FILE if test 10113 -ne `wc -c <'zoo.h'`; then echo shar: \"'zoo.h'\" unpacked with wrong size! fi # end of 'zoo.h' fi if test -f 'zoopack.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'zoopack.c'\" else echo shar: Extracting \"'zoopack.c'\" \(13207 characters\) sed "s/^X//" >'zoopack.c' <<'END_OF_FILE' X#ifndef LINT X/* @(#) zoopack.c 2.16 88/08/22 15:51:20 */ Xstatic char sccsid[]="@(#) zoopack.c 2.16 88/08/22 15:51:20"; X#endif /* LINT */ X X/* XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved X(C) Copyright 1988 Rahul Dhesi -- All rights reserved X*/ X#include "options.h" X/* Packs an archive. The sequence is: X 1. Copy all files from current archive to new one. X 2. If the user didn't want a backup, delete the old archive X else rename it to same name with extension of .BAK. X 3. Rename temporary archive to old name. X*/ X X/* define this to make packing noisless */ X#define QUIETPACK 1 X X X#include "portable.h" X#include "zooio.h" X#include "various.h" X#include "zoo.h" X#include "zoofns.h" X#include "errors.i" X#ifndef NOSIGNAL X#include X#endif X X#ifdef LINT_ARGS Xchar *mktemp (char *); X#else Xchar *mktemp (); X#endif X X Xstruct zoo_header zoo_header = { X TEXT, X ZOO_TAG, X (long) SIZ_ZOOH, X (long) (-SIZ_ZOOH), X MAJOR_VER, X MINOR_VER, X H_TYPE, X 0L, /* comment position */ X 0, /* comment length */ X GEN_DEFAULT /* generations */ X}; Xchar file_leader[] = FILE_LEADER; Xextern int quiet; Xint break_hit; X X#ifdef LINT_ARGS Xint ver_too_high (struct zoo_header *); X#else Xint ver_too_high(); X#endif X Xvoid zoopack(zoo_path, option) Xchar *zoo_path, *option; X{ Xchar temp_file[PATHSIZE]; Xstatic char xes[]="XXXXXX"; /* template for temp file */ X X#ifndef NOSIGNAL Xint (*oldsignal)(); X#endif Xregister ZOOFILE zoo_file; /* archive */ XZOOFILE new_file; /* destination archive */ Xlong next_ptr; /* pointer to within archive */ Xlong new_dir_pos; /* ditto */ Xstruct direntry direntry; /* directory entry */ Xstruct zoo_header old_zoo_header; /* just for reading old header */ Xint status; /* error status */ Xint nobackup = 0; /* keep backup */ Xint force = 0; /* force overwrite of old backup */ Xint extcount = 0; /* how many files moved */ Xchar backup_name[PATHSIZE]; /* name of backup */ Xint bad_header = 0; /* if archive has bad header */ Xint latest_date = 0; /* latest date on any file moved */ Xint latest_time = 0; /* ...likewise */ Xint curr_dir = 0; /* create backup in curr dir */ Xstatic char partial_msg[] = X "Partially packed archive left in %s.\n"; X X#ifdef FATTR Xunsigned long zoofattr; /* zoo archive protection */ Xint setfattr PARMS ((char *, unsigned long)); Xunsigned long getfattr /* params below */ X# ifdef FATTR_FNAME X PARMS ((char *)); X# else X PARMS ((ZOOFILE)); X# endif /* FATTR_FNAME */ X#endif /* FATTR */ X Xwhile (*option) { X switch (*option) { X case 'P': force++; break; X case 'E': nobackup++; break; X case 'q': quiet++; break; X case '.': curr_dir++; break; X default: X prterror ('f', inv_option, *option); X } X option++; X} Xif (force == 1) /* force only if P was doubled */ X force--; X Xzoo_path = addext (zoo_path, EXT_DFLT); /* add default extension */ X X/* Create a backup name by replacing any extension by backup extension. */ Xstrcpy (backup_name, zoo_path); X{ X char *temp; X if ((temp = strrchr (backup_name,EXT_CH)) != 0) /* if dot found */ X strcpy (temp, BACKUP_EXT); /* replace old extension */ X else X strcat (backup_name, BACKUP_EXT); /* else just append */ X} X X/* XOpen original archive for read-write access. Although we will only Xread from it and never write to it, we want to avoid packing an Xarchive that is read-only, since presumably the user didn't want Xto risk changing it in any way. X*/ Xzoo_file = zooopen(zoo_path, Z_RDWR); X Xif (zoo_file == NOFILE) X prterror ('f', could_not_open, zoo_path); X X/* If possible, save protection code of old archive for propagation to new */ X#ifdef FATTR X# ifdef FATTR_FNAME X zoofattr = getfattr (zoo_path); X# else X zoofattr = getfattr (zoo_file); X# endif /* FATTR_FNAME */ X#endif /* FATTR */ X X/* Read the header of the old archive. */ Xfrd_zooh(&old_zoo_header, zoo_file); X Xif ((old_zoo_header.zoo_start + old_zoo_header.zoo_minus) != 0L) { X prterror ('w', failed_consistency); X ++bad_header; /* remember for future error message */ X} X X/* Refuse to pack it if its version number is higher than we can accept */ Xif (ver_too_high (&old_zoo_header)) X prterror ('f', wrong_version, old_zoo_header.major_ver, X old_zoo_header.minor_ver); X X/* Now see if the archive already exists with the backup extension. If so, X give an error message and abort. However, we skip this test if the user X specified overwriting the backup */ X Xif (!force) { X if (exists (backup_name)) X prterror ('f', "File %s already exists. Delete it or use PP option.\n", X backup_name); X} X X/* XOpen the new archive by a temporary name. If not otherwise specified, Xwe open the new archive in the same directory as the original. But if Xthe curr_dir switch was given, we just put XXXXXX into temp_file. X*/ Xif (!curr_dir) { X strcpy (temp_file, zoo_path); /* original archive name */ X *nameptr (temp_file) = '\0'; /* ... minus original filename */ X strcat (temp_file, xes); /* ... plus XXXXXX */ X} else { X strcpy (temp_file, xes); X} Xmktemp (temp_file); /* ... and make unique */ Xnew_file = zoocreate (temp_file); Xif (new_file == NOFILE) X prterror ('f', "Could not create temporary file %s.\n", temp_file); X X/* XIf old_zoo_header greater than type 0, we update zoo_header as follows: Xnew archive comment will be just after archive header; zoo_start will Xpoint to just beyond archive comment. But if old_zoo_header is of Xtype 0, we leave zoo_header unchanged. However, we always Xunconditionally update the header type to be type H_TYPE. X(Note: zoo_header.type is initialized to H_TYPE in the Xglobal declaration of zoo_header.) X*/ Xif (old_zoo_header.type > 0) { X zoo_header.zoo_start = SIZ_ZOOH + old_zoo_header.acmt_len; X zoo_header.zoo_minus = -zoo_header.zoo_start; X zoo_header.acmt_pos = SIZ_ZOOH; /* new comment just after header */ X zoo_header.acmt_len = old_zoo_header.acmt_len; X zoo_header.vdata = old_zoo_header.vdata; X} else /* keep generations off if using old format archive */ X zoo_header.vdata &= (~VFL_ON); X X/* Write the header of the new archive, updated with our own data */ Xfwr_zooh (&zoo_header, new_file); X X/* copy archive comment */ Xif (old_zoo_header.acmt_len != 0) { X zooseek (zoo_file, old_zoo_header.acmt_pos, 0); /* find archive comment */ X getfile (zoo_file, new_file, (long) zoo_header.acmt_len, 0); /* copy it */ X} X X/* WARNING: CHECK FOR SEEK BEYOND END OF FILE */ Xzooseek (new_file, zoo_header.zoo_start, 0); /* position to add files */ X Xzooseek (zoo_file, old_zoo_header.zoo_start, 0); /* seek to where data begins */ X X/* Now we loop through the old archive's files and add each to the new Xarchive. The only changes needed are to update the .next and .offset Xfields of the directory entry. */ X Xwhile (1) { X frd_dir(&direntry, zoo_file); X if (direntry.zoo_tag != ZOO_TAG) { X long currpos, zoolength; X prterror ('F', bad_directory); X if (bad_header) { /* bad headers means don't save temp file */ X zooclose (new_file); X unlink (temp_file); X } else { X writenull (new_file, MAXDIRSIZE); /* write final null entry */ X printf (partial_msg, temp_file); X if ((currpos = ftell (zoo_file)) != -1L) X if (zooseek (zoo_file, 0L, 2) == 0) X if ((zoolength = ftell (zoo_file)) != -1L) X printf (cant_process, zoolength - currpos); X } X zooexit (1); X } X if (direntry.next == 0L) { /* END OF CHAIN */ X break; /* EXIT on end of chain */ X } X next_ptr = direntry.next; /* ptr to next dir entry */ X X if (!direntry.deleted) { X#ifdef QUIETPACK X/* nothing */ X#else X prterror ('m', "%-14s -- ", X direntry.namlen > 0 ? direntry.lfname : direntry.fname); X#endif X X if (zooseek (zoo_file, direntry.offset, 0) == -1L) { X prterror ('f', "Could not seek to file data.\n"); X } else { X extcount++; /* update count of files extracted */ X X /* write a directory entry for this file */ X new_dir_pos = zootell (new_file); /* new direntry pos in new archive */ X X /* X Write a null directory entry to preserve integrity in case of X program being interrupted. Note: I don't think it is X necessary to save direntry.next but I haven't checked. X */ X { X long oldnext; X oldnext = direntry.next; X direntry.next = 0L; X fwr_dir(&direntry, new_file); X direntry.next = oldnext; X } X X zooseek (zoo_file, direntry.offset, 0); /* where to start copying */ X /* Write file leader and remember position of new file data */ X zoowrite (new_file, file_leader, SIZ_FLDR); X direntry.offset = zootell (new_file); X status = getfile (zoo_file, new_file, direntry.size_now, 0); X /* if no error copy any comment attached to file */ X if (status == 0 && direntry.cmt_size != 0) { X zooseek (zoo_file, direntry.comment, 0); /* seek to old comment */ X direntry.comment = zootell (new_file); /* location of new comment */ X status = getfile (zoo_file, new_file, X (long) direntry.cmt_size, 0); X } X X if (status != 0) { X if (status == 1) { X memerr(); X } else X if (status == 2 || status == 3) { X prterror ('F', disk_full); X printf (partial_msg, temp_file); X zooexit (1); X } else X prterror ('f', internal_error); X } else { X if (latest_date < direntry.date || X (latest_date == direntry.date && X latest_time < direntry.time)) { X latest_date = direntry.date; X latest_time = direntry.time; X } X } X direntry.next = zootell (new_file); X zooseek (new_file, new_dir_pos, 0); /* position to write direntry */ X X break_hit = 0; X#ifndef NOSIGNAL X oldsignal = signal (SIGINT, SIG_IGN); X if (oldsignal != SIG_IGN) X signal (SIGINT, handle_break); X#endif X X /* Bug fix thanks to Mark Alexander */ X if (fwr_dir (&direntry, new_file) != -1 && X zoowrite (new_file, file_leader, SIZ_FLDR) == SIZ_FLDR) { X#ifdef QUIETPACK X /* prterror ('M', "."); */ ; X#else X prterror ('M', "moved\n"); X#endif X } else X prterror ('f', "Write to temporary packed archive %s failed.\n", temp_file); X#ifndef NOSIGNAL X signal (SIGINT, oldsignal); X#endif X if (break_hit) X zooexit (1); X zooseek (new_file, direntry.next, 0); /* back to end of new archive */ X } /* end if (lseek ... */ X } /* end if (!direntry.deleted) */ X Xzooseek (zoo_file, next_ptr, 0); /* ..seek to next dir entry */ X} /* end while */ X Xzooclose (zoo_file); X X/* write a final null entry */ Xwritenull (new_file, MAXDIRSIZE); X X#ifdef NIXTIME Xzooclose (new_file); Xsetutime (temp_file, latest_date, latest_time); X#else Xsettime (new_file, latest_date, latest_time); /* adjust its time */ Xzooclose (new_file); X#endif X X/* Important note: At this point, it is assumed that the archive was X packed and written to a new file without error. If control reaches X here without the new archive having been written properly, then X loss of data due to deletion of the original file could occur. In X other words, if something went wrong, execution MUST NOT reach here. */ X Xif (extcount == 0) { X unlink (temp_file); X prterror ('m', "No files moved.\n"); X} else { X /* (a) if user requested, delete original, else rename it to X *.bak. (b) rename temp file to same base name as zoo_file. */ X X#ifdef QUIETPACK X /* prterror('M', "\n"); */ X#endif X X unlink (backup_name); /* remove any previous backup in any case */ X if (nobackup) X unlink (zoo_path); X else X chname (backup_name, zoo_path); X X /* if we are packing into current directory, we will rename temp file X to same basename but without the preceding pathname */ X if (curr_dir) X zoo_path = nameptr (zoo_path); /* strip pathname */ X X X if (chname (zoo_path, temp_file)) { X prterror ('w', "Renaming error. Packed archive is now in %s.\n", temp_file); X zooexit (1); X } X X/* XSet protection on packed archive -- after renaming, since some XOSs might not allow renaming of read-only files X*/ X#ifdef FATTR X setfattr (zoo_path, zoofattr); X#endif /* FATTR */ X X} /* end if */ X X} /* end zoopack() */ X X/* handle_break() */ X/* Sets break_hit to 1 when called */ Xint handle_break() X{ X#ifndef NOSIGNAL X signal (SIGINT, SIG_IGN); /* ignore future control ^Cs for now */ X break_hit = 1; X#endif X} END_OF_FILE if test 13207 -ne `wc -c <'zoopack.c'`; then echo shar: \"'zoopack.c'\" unpacked with wrong size! fi # end of 'zoopack.c' fi echo shar: End of archive 6 \(of 10\). cp /dev/null ark6isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 10 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0