Subject: v17i070: Zoo archive program, Part07/10 Newsgroups: comp.sources.unix Approved: rsalz@uunet.UU.NET Submitted-by: Rahul Dhesi Posting-number: Volume 17, Issue 70 Archive-name: zoo2/part07 #! /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 'vmsbugs.doc' <<'END_OF_FILE' X X X Zoo 2.0 on VAX/VMS X by X Rahul Dhesi X X XThe zoo archiver is used to create and maintain archives containing mul- Xtiple files that may be stored in compressed format. Consult the zoo Xmanual for more details. This document describes those features of XVAX/VMS zoo that are specific to the VAX/VMS implementation. X X X INSTALLATION X XThe file "descrip.mms" is a makefile suitable for use with DEC's imple- Xmentation of make, called MMS. To avoid any confusion, delete the file Xcalled "makefile" as that is not for VAX/VMS systems and it might con- Xfuse MMS. With all source files in the current directory, simply type XMMS and wait while all files get compiled and linked. (If your system Xdoes not have MMS, you will have to compile each C source file by hand, Xproviding the C compiler with the necessary defines on the command line. XIf you are not familiar with the format of makefiles, find somebody who Xis, and do what MMS would have done by following what is in X"descrip.mms".) The result should be the executable program "zoo.exe". X XThen give the command "mms fiz" to build "fiz.exe". X XOptionally, the command "mms zoobig.exe" will create a version of the Xexecutable that is linked without the shareable library. This may be Xmore portable if you intend to transfer it to an VMS system that does Xnot have its own C compiler. But "zoobig.exe" will be about twice the Xsize of "zoo.exe". X XAlso compile the program "bilf.c". This is done manually and not from Xthe makefile. Compile with "cc bilf.c" and link with "link bilf, Xoptions/opt". X XTo run zoo, bilf, and fiz, you will need to set up symbols by giving Xcommands similar to the following, either by typing them at the system Xprompt or by putting them in your "login.com" file. X X $ zoo :== $ user$disk:[userdir]zoo.exe X $ fiz :== $ user$disk:[userfir]fiz.exe X $ bilf :== $ user$disk:[userdir]bilf.exe X XIn place of "user$disk" use the name of the device on which Xyour login directory is located, and instead of "userdir" use Xthe name of the directory in which you have placed the executable Xprograms "zoo.exe" and "fiz.exe". X X X WARNING -- VMS BUGS X XVAX/VMS peculiarities cause unusual bahavior. X X - VMS C does not preserve uppercase characters in a command line. To X specify a command containing an uppercase character, enclose the X command in double quotes. For example, the command X X zoo aM stuff * X X will not work under VMS. To make this command work under VMS, use X double quotes like this: X X zoo "aM" stuff * X X - For most text files that are not in stream-LF format, VMS returns X an incorrect file size to zoo. This will be evident if you use the X "f" modifier to tell zoo to archive files without compression. X Files that were in stream-LF format will be stored with the correct X size; other text files will be stored with an incorrect value for X the original size of the file. X X When such files are extracted, however, they are extracted in X stream-LF format, which is the only file format that VMS seems to X handle correctly. Thus, so far as I can determine, no file con- X tents are actually lost, and the only evidence of the problem is X that in archive listings, files stored without compression may X still appear to be compressed by about 1 to 5 percent, or occasion- X ally by some meaningless value. X X - I have not yet found a way of making zoo for VMS restore file X timestamps at extraction time. The standard utime() function seems X to be entirely missing in VMS C. One of these days I will have to X figure out RMS extended attribute blocks. X X - VAX/VMS uses many different types of file structures. Zoo creates X archives in stream-LF format, and all archives used by zoo in any X way must be in this format. It is dangerous to use zoo on an X archive that is in any other format, because it may permanently X corrupt the archive contents. Thus, if you have uploaded an X archive to a VMS system using Kermit, do not try to manipulate it X with zoo until you have converted it to stream-LF format. File X conversion instructions are given later in this document. X X - The VAX/VMS batch system causes the C statement X X fflush(stdout); X X to become equivalent to: X X printf("\n"); X X The result is that if files are added to a zoo archive from a batch X run, the batch log will look very strange and contain spurious new- X lines. X X"Again," says my VMS C manual, "VAX C adds functionality". The internal Xworking of zoo has been designed to evade this added functionality. I Xbelieve that text files and executable files are currently correctly Xhandled by zoo. But each version of VMS C seems to have its own special Xfeatures, and it is hard to say how future changes in the VMS C compiler Xwill affect the zoo archiver. I believe I will be able to follow these Xchanges, and to continue to work around past, present, and future added Xfunctionality in VMS C, but don't bet your life on it. X X X ARCHIVING SELECTED FILES X XZoo can read filenames from standard input. This allows you to use an Xexternal program to generate a list of files to be archived. When this Xlist is fed to zoo, it will archive only the selected files. X XFor this example, assume that files are to be archived in an archive Xcalled "backups.zoo". X XTo achieve redirection of input under VAX/VMS, the following steps are Xnecessary: X X 1. Create a file containing the filenames to be archived. Suppose X this file is called "names.lis". X X 2. Redirect zoo's standard input thus: X X $ define /user_mode SYS$INPUT names.lis X X X 3. Invoke zoo thus: X X $ zoo "aI" backups X X This command line will cause zoo to read a list of filenames from X its standard input, and archive them into "backups.zoo". Since the X logical name SYS$INPUT was changed to refer to the file X "names.lis", zoo will read filenames from that file. X XA good way of creating a list of files to be archived is to use the vms X"directory" command. Include at least the switches shown: X X $ directory /noheading /notrailing /column=1 /output=names.lis X XThis tells VMS to produce a list of filenames, one per line, and to Xstore the resulting output in the file "names.lis". You can also add Xadditional selection options. For example, to select all files that Xhave been modified in the last 12 hours: X X $ dir/nohead/notrail/col=1/out=names.lis/since=-12:00/modified X XA good way to decrease the effort is to create a symbol as follows: X X $ select:=="dir/nohead/notrail/col=1/out=names.lis/modified/since=" X XNow you can archive all *.c files modified in the last 60 minutes by Xgiving the following commands: X X $ select -1:00:00 *.c X $ define/user sys$input names.lis X $ zoo "aI" backups X X X FILE TRANSFERS WITH KERMIT X XZoo archives can be uploaded to a VAX/VMS system and downloaded from it Xusing Kermit. Due to VMS limitations, some file conversions must be Xdone to avoid a corrupted zoo archive. X XZoo always expects zoo archives to be in stream-LF format. However, the Xstandard VAX/VMS Kermit does not create stream-LF files, and treats them Xas text files when it reads them, resulting in corrupted downloads. XThus you must handle Kermit transfers with care. The following discus- Xsions refers solely to the standard Kermit-32, which I believe is from Xthe Stevens Institute of Technology. If the following instructions are Xcarefully followed, you should be able to transfer zoo archives between Xa VAX/VMS system and a microcomputer running Kermit. X XKERMIT UPLOADS: To transfer a zoo archive from a microcomputer to a XVAX/VMS system, do the following. X X 1. Invoke VAX/VMS Kermit as shown below. It will prompt you with the X string "Kermit-32>". Give it a command as shown to tell it to X receive a binary file: X X $ kermit X Kermit-32> set file type binary X Kermit-32> set block-check 3 X Kermit-32> receive X X Note: Do not use the command "set file type fixed". In most cases X it will not work. X X The command to set the block-check is optional, but tells Kermit to X use a 16-bit CRC, which is much more reliable than the default 6- X bit CRC. Use this command if your version of Kermit does not use a X 16-bit CRC by default. X X 2. At this point, VAX/VMS Kermit is waiting for you to send it a file. X Now tell your local Kermit to send the file. On an MS-DOS system, X using MS-Kermit, you would do this by first typing the local escape X sequence to get to the local mode, where the prompt is "MS- X Kermit>", then telling your local Kermit to send the zoo archive as X a binary file. A typical sequence of commands is: X X (type escape sequence to get back to local mode) X MS-Kermit> set eof noctrl-z X MS-Kermit> send stuff.zoo X X It is important that your local Kermit send the zoo archive as a X binary file, not a text file. How you do this depends on your sys- X tem; on MS-DOS systems it suffices to give say "set eof noctrl-z". X X 3. Wait until the Kermit upload is complete. Then tell your local X Kermit to go into terminal mode (usually by giving the command CON- X NECT), and exit from VAX/VMS Kermit with the command EXIT. A typi- X cal sequence is: X X MS-Kermit> connect X (stuff from MS-Kermit printed...) X (hit carriage return if necessary to get the next prompt) X Kermit-32> exit X $ X X Now you are back at the VAX/VMS prompt. At this point, you must X convert the uploaded zoo archive, which is currently in binary for- X mat, to stream-LF format so that it can be used by VAX/VMS zoo. X You do this by using the Bilf utility, which can convert files X between binary and stream-LF formats. Give the command: X X $ bilf l stuff.zoo X X 4. After Bilf has done the conversion, you will have a new generation X of stuff.zoo that is in stream-LF format. Now you can manipulate X it normally with VAX/VMS zoo. X XDON'T TRY TO USE ZOO TO MANIPULATE AN UPLOADED ARCHIVE WITHOUT PERFORM- XING THE CONVERSION TO STREAM-LF FORMAT, ELSE YOU MAY PERMANENTLY DESTROY XARCHIVE CONTENTS. X XKERMIT DOWNLOADS: Before downloading a zoo archive from VAX/VMS to a Xmicrocomputer, you must convert it to binary format. Then use VMS XKermit normally. A sample sequence is shown. X X 1. Convert the zoo archive to binary format. X X $ bilf b stuff.zoo X X 2. Invoke VMS Kermit and tell it to send the file. X X $ kermit X Kermit-32> set block-check 3 X Kermit-32> send stuff.zoo X X 3. Get back to your local Kermit and tell it to receive a binary file. X X (type escape sequence to get into local mode) X MS-Kermit> set eof noctrl-z X MS-Kermit> receive X (transfer takes place) X X X FILE TRANSFER SUMMARY X XHere are pictorial summaries of the steps involved in performing file Xtransfers of zoo archives using Kermit. X X====================================================================== X XDOWNLOADS: X files on a VMS X system to be archived X using zoo X | X archive created | X using zoo.exe | X or zoobig.exe | X on a VMS system | X v X Xzoo archive on VMS bilf b zoo archive on VMS, in Xin fixed-length <---------------- in stream-LF format Xbinary format X | X | X | archive transferred X | from VMS to microcomputer X | using Kermit; receiving X | Kermit must be told this X | is a binary file; sending X | Kermit may need to be told too X | X v Xzoo archive Xon microcomputer Xsystem X X====================================================================== X XUPLOADS: X Xzoo archive Xon microcomputer Xsystem X | X | X | archive uploaded to VMS using Kermit; X | receiving Kermit on VMS must be given X | command "set file type binary" X | (NOTE: "set file type fixed" will X | usually not work); sending Kermit X | must be told this is a binary file X | X v Xzoo archive on VMS, bilf l zoo archive on VMS, in Xin variable-length ----------------> in stream-LF format Xbinary format | X | extract X | normally using X | zoo on VMS X | X v X files extracted from zoo X archive on a VMS system X X====================================================================== X X X ENSURING ARCHIVE INTEGRITY X XAfter performing a transfer of a zoo archive using Kermit (and perform- Xing any file conversion necessary for VMS), make it a habit to immedi- Xately test the integrity of the transferred archive with the -test com- Xmand of zoo, illustrated for VMS: X X $ zoo -test stuff X XIn addition, also get a listing of the archive contents: X X $ zoo -list stuff X XIf neither command reports an error, it is reasonable to assume that Xarchive integrity was not harmed by the Kermit transfer. X XThe -test command tests the integrity of each stored file. The -list Xcommand tests the integrity of the internal archive structure. Both are Xchecked using separate cyclic redundancy codes, one for each archived Xfile, and one for each directory entry in the archived. (Actually, the X-list command ignores deleted entries, so if the archive contains any, Xuse the "ld" command instead.) X X X WILDCARDS X XAll implementations of zoo on all systems use the same wildcard charac- Xters: "*" matches any sequence of zero or more characters, and "?" Xmatches any one character. X XADDING FILES: For specifying directory names when adding files, use the Xusual VAX/VMS syntax. Thus, to recursively archive all files in the Xcurrent directory and all its subdirectories, the command syntax is: X X $ zoo a stuff [...]* X X The character range wildcard of the form "c-c" is also available, which X will select all files beginning with the specified character range. X For example, X X $ zoo a stuff [...]a-d [...]x-z X X will archive all files beginning with the characters a through d, and X with the characters x through z, in the current directory and all its X subdirectories. A side-effect of this is that during addition to X archives, dots in filenames must be explicitly matched. Thus to add X all files with an extension of DOC, you would type: X X $ zoo a stuff *.doc X X and "*doc" will not work. As a special case, a trailing "*.*" in any X filename you specify can always be replaced by just a trailing "*". X The safest rule to follow when adding files is to always specify the X dot in each filename. X X EXTRACTING FILES: During extraction, both the directory name and the X filename must be specified according to zoo syntax. Thus you could say X X $ zoo x stuff [*xyz*]*.doc X X to extract all archived files with filenames that match "*.doc" and X that contain the string "xyz" in the directory name. Note that VMS X syntax for selecting directories won't work here: X X $ zoo x stuff [...]*.doc ! won't work for extraction X X If you do not specify the directory name at all, zoo will only perform X the match against filenames; thus X X $ zoo x stuff *.doc X X will extract all files matching *.doc regardless of the directory name. X X Also note that if you specify extraction of "*.*", as in X X $ zoo x stuff *.* X X it will result in the extraction of files whose filename contains at X least one dot. Similarly, the command X X $ zoo x stuff *_* X X will select all filename containing at least one underscore. X X To extract all files, specify no filename, e.g. X X $ zoo x stuff X X or use "*" rather than "*.*". X X SAFEST RULE OF THUMB: WHEN SELECTING FILES ON DISK, SPECIFY THE DOT IN X EACH FILENAME; WHEN SELECTING FILES INSIDE A ZOO ARCHIVE, SPECIFY A X DOT ONLY IF YOU NEED ONE. But to select all files, you can always just X use "*". X X X FILE GENERATIONS X X When a file is added to an archive, the generation number (if any) that X it is given in the archive is not related to the generation number it X had in the VAX/VMS filesystem. At extraction time a new version is X always created for an extracted file. The overwrite option ("O") does X not cause overwriting, but simply suppresses the warning message that X zoo normally gives when it finds that a file about to be extracted X already exists. X X X FILE STRUCTURES X X At extraction time, zoo preserves all data bytes in binary files, and X stores all text files as lines of text terminated with linefeeds. The X internal file structure maintained by DEC's RMS is not currently X preserved. (Support for this is planned for the distant future.) X Thus, the following two types of files can be safely archived and X restored: X X - All text files are extracted in stream-LF format. Most VMS utili- X ties that accept text files will accept such files. The EDT edi- X tor may complain, but will still work. X X - VMS executable files, when stored and then extracted, are X extracted in stream-LF format. Such files can be restored to X their original state using Bilf with the "b" option. (However, X current versions of VAX/VMS seem to be able to load and execute X stream-LF files, so conversion may not be necessary.) X X HANDLING VMS EXECUTABLE FILES. You can archive an executable program X called "xyz.exe": X X $ zoo a stuff xyz.exe X $ delete xyz.exe;* X X Now the only copy of xyz.exe is in the archive "stuff.zoo". Extract X it: X X $ zoo x stuff xyz.exe X X The extracted copy of "xyz.exe" is in stream-LF format and VMS may or X may not execute it. Now we convert it back to fixed-length record for- X mat thus: X X $ bilf b xyz.exe X $ purge xyz.exe X X Now "xyz.exe" has been converted to binary format and can be executed. X It should be identical to the original copy of "xyz.exe" that was X archived. X X TEXT FILES FROM OTHER SYSTEMS. A text file archived on a different X computer system will use either linefeeds, or carriage returns plus X linefeeds, as line terminators. Text files with linfeeds only can be X be extracted and used exactly as if they had been archived on a VAX/VMS X system. Text files containing carriage returns plus linefeeds will, X when extracted, contain a spurious carriage return at the end of each X line. This extra carriage return can be removed using EDT's "substi- X tute" command while in screen mode. Simply replace all carriage returns X with nothing. The VMS C compiler currently appears to accept trailing X carriage returns in files without any trouble. X X Text files trasnferred from MS-DOS or CP/M or similar systems may con- X tain a trailing control Z character. This may cause problems on VMS X and should be edited out with a text editor. X X -- Rahul Dhesi 1988/02/04 END_OF_FILE if test 19668 -ne `wc -c <'vmsbugs.doc'`; then echo shar: \"'vmsbugs.doc'\" unpacked with wrong size! fi # end of 'vmsbugs.doc' fi if test -f 'zoolist.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'zoolist.c'\" else echo shar: Extracting \"'zoolist.c'\" \(18889 characters\) sed "s/^X//" >'zoolist.c' <<'END_OF_FILE' X#ifndef LINT X/* @(#) zoolist.c 2.27 88/08/15 11:03:16 */ Xstatic char sccsid[]="@(#) zoolist.c 2.27 88/08/15 11:03:16"; X#endif /* LINT */ X X/* XIf TRACE_LIST is defined, any list command may be followed Xby 'D' to show verbose information about each directory Xentry in the archive. Do not define both TRACE_LIST and XTRACE_IO else a symbol conflict will occur and in any case Xduplicate information will be dumped. X*/ X X/* #define TRACE_LIST */ 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#include "portable.h" X#include "zoomem.h" /* to get ZOOCOUNT */ X X/* Lists files in archive */ X#include "zoo.h" X#include "errors.i" X#include "zooio.h" X#include "various.h" X#include "zoofns.h" X X#ifdef TRACE_LIST Xvoid show_dir PARMS ((struct direntry *direntry)); Xstatic int trace_list = 0; X#endif /* TRACE_LIST */ X Xstatic char tot_fmt[] = "%8lu %3u%% %8lu %4d file"; Xstatic char tot_line[] = X /* "------------ -------- --- -------- --------- --------\n"; */ X "-------- --- -------- --------- --------\n"; X Xstatic char dbl_percent[] = "Archive %s: %s"; X Xextern int quiet; /* assumed initialized to zero */ X X#ifdef LINT_ARGS Xvoid show_comment (struct direntry *, ZOOFILE, int, char *); Xint ver_too_high (struct zoo_header *); Xint needed (char *, struct direntry *, struct zoo_header *); Xvoid printtz (int); X#else Xvoid show_comment (); Xint ver_too_high (); Xint needed (); Xvoid printtz (); X#endif X Xvoid zoolist (argv, option, argc) Xchar **argv, *option; Xint argc; X{ Xchar whichname[PATHSIZE]; /* which name to use */ Xchar *this_zoo; /* currently matched archive name */ Xregister ZOOFILE zoo_file; Xchar *flist[ZOOCOUNT]; /* list of ptrs to input archive names */ Xint fptr; /* will point to within list of archive names */ X Xstruct direntry direntry; Xstruct zoo_header zoo_header; Xint size_factor; Xunsigned long tot_org_siz = 0L, tot_siz_now = 0L; Xint tot_sf; Xint file_count = 0; Xint del_count = 0; /* number of deleted entries */ Xint bad_pack; /* 1 if packing method is unknown */ Xstatic char *month_list="000JanFebMarAprMayJunJulAugSepOctNovDec"; Xstatic char dashes[] = "------------\n"; Xint year, month, day, hours, min, sec; Xint list_deleted = 0; /* list deleted files too */ Xint fast = 0; /* fast list */ Xlong fiz_ofs = 0; /* offset where to start */ Xlong dat_ofs = 0; /* ... data offset of file data */ Xint verb_list = 0; /* if verbose listing needed */ Xint show_name = 0; /* if archive name to be included in listing */ Xint show_crc = 0; /* if crc should be listed */ Xint zoocount = 1; /* number of archives to list */ Xint biglist = 0; /* multiarchive listing */ Xint one_col = 0; /* one column listing requested */ Xint showdir = 0; /* show directory name in fast listing */ Xint longest; /* length of longest archive name */ Xint talking; /* opposite of quiet */ Xint column = 0; /* for column printing */ Xint first_ever = 1; /* first time ever -- very special case */ Xint neednl = 0; /* whether to print a newline */ Xint need_acmt = 0; /* show archive comment */ Xint show_gen = 0; /* show generation count */ Xint genson = 1; /* enable/disable generations */ X#ifdef FATTR Xint show_mode = 0; /* show file protection */ X#endif Xint first_dir = 1; /* if first direntry -- to adjust dat_ofs */ X Xwhile (*option) { X switch (*option) { X case 'a': show_name++; break; X#ifdef TRACE_LIST X case 'D': trace_list++; break; X#endif /* TRACE_LIST */ X case 'd': list_deleted++; break; X case 'f': fast++; break; X case 'g': show_gen++; break; X case '/': showdir++; break; X case 'A': X case 'v': need_acmt++; break; X case 'V': need_acmt++; /* fall through */ X case 'c': verb_list++; break; X case 'C': show_crc++; break; X case 'l': break; X case 'L': biglist++; zoocount = argc; break; X#ifdef FATTR X case 'm': show_mode++; break; X#endif X case '1': one_col++; break; X case '+': genson = 1; break; X case '-': genson = 0; break; X /* following code same as in zooext.c */ X case '@': /* if @m,n specified, fiz_ofs = m, dat_ofs = n */ X { X char *comma_pos; X ++option; X comma_pos = strchr(option, ','); X if (comma_pos != NULL) { X dat_ofs = calc_ofs (comma_pos + 1); X *comma_pos = '\0'; X } X fiz_ofs = calc_ofs(option); X goto no_more; X } X case 'q': quiet++; break; X default: X prterror ('w', option_ignored, *option); X } X option++; X} X Xno_more: /* come from exit from while loop above */ X Xif (fast && show_name) { /* don't allow 'a' with 'f' */ X show_name = 0; X prterror ('w', option_ignored, 'a'); X} X Xtalking = !quiet; /* for convenience */ X X#ifdef WILDCARD X /* For each archive name supplied, if it is not a char range and X does not contain a dot, append "*.zoo". */ X { X int i; X for (i = 0; i < argc; i++) { X if (strchr (nameptr (argv[i]), EXT_CH) == NULL && X !match_half (nameptr (argv[0]), "?-?")) X argv[i] = newcat (argv[i], "*.zoo"); X } X } X#endif X Xmakelist (zoocount, argv, flist, ZOOCOUNT-2, (char *) NULL,".","..", &longest); X/* ^argc ^argv ^list_pointer ^max_no_files ^exclude */ X Xfor (fptr = 0; (this_zoo = flist[fptr]) != NULL; fptr++) { X int ercount; /* count of errors */ X int entrycount; /* count of directory entries */ X int expl_deleted; /* explain what D means */ X int expl_comment; /* explain what comment means */ X int expl_ver; /* Explain what V means */ X int expl_star; /* Explain what * means */ X int first_time; /* first time through loop for an archive */ X X ercount = entrycount = del_count = X expl_deleted = expl_comment = expl_ver = expl_star = 0; X X if (talking) X column = 0; /* if quiet, names will run together */ X X first_time = 1; X X#ifndef WILDCARD X /* Add default extension if none supplied */ X if (strchr (nameptr (this_zoo), EXT_CH) == NULL) X this_zoo = newcat (this_zoo, EXT_DFLT); X#endif X X zoo_file = zooopen (this_zoo, Z_READ); X X if (zoo_file == NOFILE) { X prterror ('e', could_not_open, this_zoo); X continue; X } else if (!show_name && talking) X printf ("\nArchive %s:\n", this_zoo); X Xif (fiz_ofs != 0L) { /* if offset specified, start there */ X prterror ('m', start_ofs, fiz_ofs, dat_ofs); X zooseek (zoo_file, fiz_ofs, 0); X} else { X if (frd_zooh (&zoo_header, zoo_file) == -1 || X zoo_header.zoo_tag != ZOO_TAG) { X prterror ('e', dbl_percent, this_zoo, invalid_header); X goto loop_end; X } X#if 0 X if (talking && (!show_name || verb_list || need_acmt)) X#else X if (need_acmt && talking) X#endif X { X void show_acmt PARMS ((struct zoo_header *, ZOOFILE, int)); X show_acmt (&zoo_header, zoo_file, 0); /* show archive comment */ X } X X /* Seek to the beginning of the first directory entry */ X if (zooseek (zoo_file, zoo_header.zoo_start, 0) != 0) { X ercount++; X prterror ('e', dbl_percent, this_zoo, bad_directory); X goto loop_end; X } X if (!show_name && ver_too_high (&zoo_header)) { X ercount++; X if (ercount < 2) X prterror ('M', wrong_version, X zoo_header.major_ver, zoo_header.minor_ver); X } X} /* end if (fiz_ofs !- 0L) */ X X /* Now we print information about each file in the archive */ X X if (!show_name) { /* initialize for each file only if not disk catalog */ X tot_org_siz = 0L; X tot_siz_now = 0L; X file_count = 0; X del_count = 0; X } X X while (1) { X if (readdir (&direntry, zoo_file, 0) == -1) { X prterror ('F', dbl_percent, this_zoo, bad_directory); X goto givesummary; X } X if (direntry.zoo_tag != ZOO_TAG) { X long currpos, zoolength; X prterror ('F', dbl_percent, this_zoo, invalid_header); X if ((currpos = zootell (zoo_file)) != -1L) X if (zooseek (zoo_file, 0L, 2) == 0) X if ((zoolength = zootell (zoo_file)) != -1L) X printf (cant_process, zoolength - currpos); X goto givesummary; X } X X if (direntry.next == 0L) /* EXIT on end of chain */ X break; X else X entrycount++; /* Number of directory entries */ X /* first direntry read, change dat_ofs from abs. pos. to rel. offset */ X if (first_dir && dat_ofs != 0) { X dat_ofs -= direntry.offset; X first_dir = 0; X } X direntry.next += dat_ofs; /* allow for user-specified offset */ X if (direntry.comment != 0L) X direntry.comment += dat_ofs; /* so show_comment finds it */ X X if (direntry.deleted) X ++del_count; X X#ifdef TRACE_LIST X if (trace_list) X show_dir (&direntry); X#endif /* TRACE_LIST */ X X /* Into `whichname' put the filename to display. Use long filename if X it exists, else use short filename. */ X strcpy (whichname, fullpath (&direntry)); X if (zoo_header.vdata & VFL_ON) X add_version (whichname, &direntry); /* add version suffix */ X#ifdef DEBUG X printf("matching against [%s] and [%s]\n", X nameptr(whichname), whichname); X#endif X X if ( ( (list_deleted && direntry.deleted) || X (list_deleted < 2 && !direntry.deleted) X ) X && (biglist || needed(whichname, &direntry, &zoo_header))) { X /* if generations forced off, then strip added version field */ X if (!genson) { /* HORRENDOUSLY INEFFICIENT AND REPETITIOUS */ X char *ver_pos; X ver_pos = findlast (whichname, VER_DISPLAY); X if (ver_pos != NULL) X *ver_pos = '\0'; X } X X file_count++; X X if (direntry.packing_method > MAX_PACK) { X bad_pack = 1; X expl_ver = 1; X } else X bad_pack = 0; X X size_factor = cfactor (direntry.org_size, direntry.size_now); X X year = ((unsigned int) direntry.date >> 9) & 0x7f; X month = ((unsigned int) direntry.date >> 5) & 0x0f; X day = direntry.date & 0x1f; X X hours = ((unsigned int) direntry.time >> 11)& 0x1f; X min = ((unsigned int) direntry.time >> 5) & 0x3f; X sec = ((unsigned int) direntry.time & 0x1f) * 2; X X /* Alignment in columns is a horrendously complex undertaking. */ X X if (fast) { X int space_left; X int namelen; X int next_col; X#if 0 X if ( (quiet && !first_ever || !first_time) && one_col) X fputchar ('\n'); X first_ever = 0; X#endif X /* If we are showing directories, whichname already contains the X full pathname string. Else we only use the filename as follows: X long filename if possible, else short filename */ X if (!showdir) { X strcpy (whichname, X (direntry.namlen != 0) ? direntry.lfname : direntry.fname); X if (genson && zoo_header.vdata & VFL_ON) X add_version (whichname, &direntry); /* add version suffix */ X } X namelen = strlen (whichname); X X#define MARGIN 78 X#define COL_WIDTH 16 X#if 1 X /* if not enough space left, move to next line */ X if (!one_col && column != 0) { X space_left = MARGIN - column; X if (namelen > space_left) { X neednl = 1; X column = 0; X } X } X#endif X if ( (quiet && !first_ever || !first_time) && (neednl || one_col)) X printf ("\n"); X first_ever = 0; X neednl = 0; X X printf("%s", whichname); X fflush (stdout); X /* move to next column stop */ X column += namelen; X next_col = ((column + (COL_WIDTH - 1)) / COL_WIDTH) * COL_WIDTH; X if (next_col - column < 2) /* need at least 2 spaces */ X next_col += COL_WIDTH; X if (next_col > MARGIN) { X neednl = 1; X column = 0; X } else { X if (!one_col) X printf ("%*s", (next_col - column), " "); X column = next_col; X } X X } else { X if (talking && first_time && !show_name) {/*print archive header */ X printf ("Length CF Size Now Date Time\n"); X printf (tot_line); X } X printf ("%8lu %3u%% %8lu %2d %-.3s %02d %02d:%02d:%02d", X direntry.org_size, X size_factor, direntry.size_now, X day, &month_list[month*3], X (day && month) ? (year+80) % 100 : 0, X hours, min, sec); X tot_org_siz += direntry.org_size; X tot_siz_now += direntry.size_now; X#ifdef GETTZ X printtz ((int) direntry.tz); /* show timezone */ X#else X printf (" "); X#endif X X if (show_crc) X printf ("%04x ", direntry.file_crc); X if (show_gen) { X if (direntry.vflag & VFL_ON) X printf ("%2dg ", direntry.vflag & VFL_GEN); X else X printf ("--g "); X } X X if (direntry.cmt_size) { X expl_comment++; X printf ("C"); X } else X printf (" "); X X if (direntry.deleted) { X expl_deleted++; X printf ("D"); X } else X printf (" "); X if (list_deleted) X printf (" "); X if (show_name) X printf ("%-*s ", longest, this_zoo); X X#ifdef FATTR X if (show_mode) { X if (direntry.fattr == 0) X printf ("--- "); X else if ((direntry.fattr >> 22) == 1) X printf ("%03o ", direntry.fattr & 0x1ff); X else X printf ("??? "); X } X#endif /* FATTR */ X X /* new code to get around a common compiler bug */ X printf ("%s", whichname); X if (direntry.dir_crc != 0) { X expl_star++; X printf ("*"); X } X X if (bad_pack) X printf (" (V%d.%d)", direntry.major_ver, direntry.minor_ver); X printf ("\n"); X } X first_time = 0; X X /* if verbose listing requested show any comment. f overrrides v */ X if (verb_list && !fast) X show_comment (&direntry, zoo_file, 0, (char *) NULL); X } /* end if (lots of conditions) */ X X /* ..seek to next dir entry */ X zooseek (zoo_file, direntry.next, 0); X } /* end while */ X X givesummary: X X if (fast && talking) { X if (file_count) { X if (del_count || (show_gen && zoo_header.type > 0)) X printf ("\n-----\n"); X else X fputchar ('\n'); X } X if (del_count) X printf ("%d deleted.\n", del_count); X if (show_gen && zoo_header.type > 0) { X printf ("Generation limit %u", X zoo_header.vdata & VFL_GEN); X if ((zoo_header.vdata & VFL_ON) == 0) X printf (" (off).\n"); X else X printf (".\n"); X } X } /* end if (fast && talking) */ X X if (talking && !show_name) { X if (!fast && file_count) { X tot_sf = cfactor (tot_org_siz, tot_siz_now); X printf (tot_line); X X printf (tot_fmt, tot_org_siz, tot_sf, tot_siz_now, file_count); X if (file_count > 1) X printf ("s\n"); X else X printf ("\n"); X X if (del_count || expl_ver || expl_deleted || expl_comment || X expl_star || (show_gen && (zoo_header.type > 0))) X printf (dashes); X } X X if (!fast) { X if (del_count) { X if (expl_deleted) X printf ("D: deleted file.\n"); X else { X if (del_count == 1) X printf ("There is 1 deleted file.\n"); X else X printf ("There are %d deleted files.\n", del_count); X } X } X } X if (expl_comment && !fast && !verb_list) X printf ("C: file has attached comment.\n"); X if (expl_ver && !fast) X printf ("V: minimum version of Zoo needed to extract this file.\n"); X if (expl_star && !fast) X printf ("*: directory entry may be corrupted.\n"); X if (!file_count) X printf ("Zoo: %s", no_match); X X if (!entrycount && !fiz_ofs) X printf ("(The archive is empty.)\n"); X if (show_gen && (zoo_header.type > 0) && !fast) { X printf ("Archive generation limit is %u", X zoo_header.vdata & VFL_GEN); X if ((zoo_header.vdata & VFL_ON) == 0) X printf (" (generations off).\n"); X else X printf (".\n"); X } X } /* end if (talking && !show_name) */ Xloop_end: /* jump here on badly structured archive */ X zooclose (zoo_file); X} /* end for */ X Xif (talking && show_name) { X if (file_count) { X tot_sf = cfactor (tot_org_siz, tot_siz_now); X printf (tot_line); X printf (tot_fmt, tot_org_siz, tot_sf, tot_siz_now, file_count); X if (file_count > 1) X printf ("s\n"); X else X printf ("\n"); X } X} else if (fast && quiet) X fputchar ('\n'); X X Xif (!file_count) X zooexit (1); /* Consider it an error if there were no files */ X} /* zoolist() */ X X#ifdef GETTZ Xvoid printtz (file_tz) Xint file_tz; X{ X long gettz(); X int diff_tz; /* timezone difference */ X if (file_tz == NO_TZ) /* if no timezone stored ..*/ X printf (" "); /* .. just pad with blanks */ X else { X diff_tz = (file_tz / 4) - (int) (gettz() / 3600); X if (diff_tz == 0) X printf (" "); /* print nothing if same */ X else if (diff_tz > 0) /* else print signed difference */ X printf ("+%1d ", diff_tz); X else X printf ("-%1d ", -diff_tz); X } X} X#endif X X/* XFOLLOWING CODE IS FOR DEBUGGING ONLY. IT IS COMPILED IN ONLY XIF THE SYMBOL TRACE_LIST IS DEFINED X*/ X X#ifdef TRACE_LIST X/* code copied from portable.c near end */ X/* dump contents of directory entry */ Xvoid show_dir (direntry) Xstruct direntry *direntry; X{ X printf ("Directory entry for file [%s][%s]:\n", X direntry->fname, direntry->lfname); X printf ("tag = [%8lx] type = [%d] PM = [%d] Next = [%8lx] Offset = [%8lx]\n", X direntry->zoo_tag, (int) direntry->type, X (int) direntry->packing_method, direntry->next, X direntry->offset); X printf ("Orig size = [%ld] Size now = [%ld] dmaj_v.dmin_v = [%d.%d]\n", X direntry->org_size, direntry->size_now, X (int) direntry->major_ver, (int) direntry->minor_ver); X printf ("Struc = [%d] DEL = [%d] comment_offset = [%8lx] cmt_size = [%d]\n", X (int) direntry->struc, (int) direntry->deleted, direntry->comment, X direntry->cmt_size); X printf ("var_dir_len = [%d] TZ = [%d] dir_crc = [%4x]\n", X direntry->var_dir_len, (int) direntry->tz, direntry->dir_crc); X printf ("system_id = [%d] dirlen = [%d] namlen = [%d] fattr=[%24lx]\n", X direntry->system_id, direntry->dirlen, direntry->namlen, direntry->fattr); X printf ("vflag = [%4x] version_no = [%4x]\n", X direntry->vflag, direntry->version_no); X if (direntry->dirlen > 0) X printf ("dirname = [%s]\n", direntry->dirname); X printf ("---------\n"); X} X#endif /* TRACE_IO */ END_OF_FILE if test 18889 -ne `wc -c <'zoolist.c'`; then echo shar: \"'zoolist.c'\" unpacked with wrong size! fi # end of 'zoolist.c' fi echo shar: End of archive 7 \(of 10\). cp /dev/null ark7isdone 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