[comp.sources.unix] v17i069: Zoo archive program, Part06/10

rsalz@uunet.uu.net (Rich Salz) (02/03/89)

Submitted-by: Rahul Dhesi <bsu-cs!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 <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 6 (of 10)."
# Wrapped by rsalz@papaya.bbn.com on Thu Feb  2 18:04:02 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'options.doc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'options.doc'\"
else
echo shar: Extracting \"'options.doc'\" \(14950 characters\)
sed "s/^X//" >'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 <signal.h>
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
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.