#ifndef LINT /* derived from: zoolist.c 2.27 88/08/15 11:03:16 */ static char sccsid[]="$Source: /usr/home/dhesi/zoo/RCS/zoolist.c,v $\n\ $Id: zoolist.c,v 1.4 91/07/09 01:54:16 dhesi Exp $"; #endif /* LINT */ /* If TRACE_LIST is defined, any list command may be followed by 'D' to show verbose information about each directory entry in the archive. Do not define both TRACE_LIST and TRACE_IO else a symbol conflict will occur and in any case duplicate information will be dumped. */ /* #define TRACE_LIST */ /* Copyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved (C) Copyright 1988 Rahul Dhesi -- All rights reserved */ #include "options.h" #include "portable.h" #include "zoomem.h" /* to get ZOOCOUNT */ /* Lists files in archive */ #include "zoo.h" #include "errors.i" #include "zooio.h" #include "various.h" #include "zoofns.h" #ifdef TRACE_LIST void show_dir PARMS ((struct direntry *direntry)); static int trace_list = 0; #endif /* TRACE_LIST */ static char tot_fmt[] = "%8lu %3u%% %8lu %4d file"; static char tot_line[] = /* "------------ -------- --- -------- --------- --------\n"; */ "-------- --- -------- --------- --------\n"; static char dbl_percent[] = "Archive %s: %s"; extern int quiet; /* assumed initialized to zero */ void show_comment PARMS((struct direntry *, ZOOFILE, int, char *)); int ver_too_high PARMS((struct zoo_header *)); int needed PARMS((char *, struct direntry *, struct zoo_header *)); void printtz PARMS((int)); int fputchar PARMS ((int)); void zoolist (argv, option, argc) char **argv, *option; int argc; { char whichname[PATHSIZE]; /* which name to use */ char *this_zoo; /* currently matched archive name */ register ZOOFILE zoo_file; char *flist[ZOOCOUNT]; /* list of ptrs to input archive names */ int fptr; /* will point to within list of archive names */ struct direntry direntry; struct zoo_header zoo_header; int size_factor; unsigned long tot_org_siz = 0L, tot_siz_now = 0L; int tot_sf; int file_count = 0; int del_count = 0; /* number of deleted entries */ int bad_pack; /* 1 if packing method is unknown */ static char *month_list="000JanFebMarAprMayJunJulAugSepOctNovDec"; static char dashes[] = "------------\n"; int year, month, day, hours, min, sec; int list_deleted = 0; /* list deleted files too */ int fast = 0; /* fast list */ long fiz_ofs = 0; /* offset where to start */ long dat_ofs = 0; /* ... data offset of file data */ int verb_list = 0; /* if verbose listing needed */ int show_name = 0; /* if archive name to be included in listing */ int show_crc = 0; /* if crc should be listed */ int zoocount = 1; /* number of archives to list */ int biglist = 0; /* multiarchive listing */ int one_col = 0; /* one column listing requested */ int showdir = 0; /* show directory name in fast listing */ int longest; /* length of longest archive name */ int talking; /* opposite of quiet */ int column = 0; /* for column printing */ int first_ever = 1; /* first time ever -- very special case */ int neednl = 0; /* whether to print a newline */ int need_acmt = 0; /* show archive comment */ int show_gen = 0; /* show generation count */ int genson = 1; /* enable/disable generations */ #ifdef FATTR int show_mode = 0; /* show file protection */ #endif int first_dir = 1; /* if first direntry -- to adjust dat_ofs */ while (*option) { switch (*option) { case 'a': show_name++; break; #ifdef TRACE_LIST case 'D': trace_list++; break; #endif /* TRACE_LIST */ case 'd': list_deleted++; break; case 'f': fast++; break; case 'g': show_gen++; break; case '/': showdir++; break; case 'A': case 'v': need_acmt++; break; case 'V': need_acmt++; /* fall through */ case 'c': verb_list++; break; case 'C': show_crc++; break; case 'l': break; case 'L': biglist++; zoocount = argc; break; #ifdef FATTR case 'm': show_mode++; break; #endif case '1': one_col++; break; case '+': genson = 1; break; case '-': genson = 0; break; /* following code same as in zooext.c */ case '@': /* if @m,n specified, fiz_ofs = m, dat_ofs = n */ { char *comma_pos; ++option; comma_pos = strchr(option, ','); if (comma_pos != NULL) { dat_ofs = calc_ofs (comma_pos + 1); *comma_pos = '\0'; } fiz_ofs = calc_ofs(option); goto no_more; } case 'q': quiet++; break; default: prterror ('w', option_ignored, *option); } option++; } no_more: /* come from exit from while loop above */ if (fast && show_name) { /* don't allow 'a' with 'f' */ show_name = 0; prterror ('w', option_ignored, 'a'); } talking = !quiet; /* for convenience */ #ifdef WILDCARD /* For each archive name supplied, if it is not a char range and does not contain a dot, append "*.zoo". */ { int i; for (i = 0; i < argc; i++) { if (strchr (nameptr (argv[i]), EXT_CH) == NULL && !match_half (nameptr (argv[0]), "?-?")) argv[i] = newcat (argv[i], "*.zoo"); } } #endif makelist (zoocount, argv, flist, ZOOCOUNT-2, (char *) NULL,".","..", &longest); /* ^argc ^argv ^list_pointer ^max_no_files ^exclude */ for (fptr = 0; (this_zoo = flist[fptr]) != NULL; fptr++) { int ercount; /* count of errors */ int entrycount; /* count of directory entries */ int expl_deleted; /* explain what D means */ int expl_comment; /* explain what comment means */ int expl_ver; /* Explain what V means */ int expl_star; /* Explain what * means */ int first_time; /* first time through loop for an archive */ ercount = entrycount = del_count = expl_deleted = expl_comment = expl_ver = expl_star = 0; if (talking) column = 0; /* if quiet, names will run together */ first_time = 1; #ifndef WILDCARD /* Add default extension if none supplied */ if (strchr (nameptr (this_zoo), EXT_CH) == NULL) this_zoo = newcat (this_zoo, EXT_DFLT); #endif zoo_file = zooopen (this_zoo, Z_READ); if (zoo_file == NOFILE) { prterror ('e', could_not_open, this_zoo); continue; } else if (!show_name && talking) printf ("\nArchive %s:\n", this_zoo); if (fiz_ofs != 0L) { /* if offset specified, start there */ prterror ('m', start_ofs, fiz_ofs, dat_ofs); zooseek (zoo_file, fiz_ofs, 0); } else { if (frd_zooh (&zoo_header, zoo_file) == -1 || zoo_header.zoo_tag != ZOO_TAG) { prterror ('e', dbl_percent, this_zoo, invalid_header); goto loop_end; } #if 0 if (talking && (!show_name || verb_list || need_acmt)) #else if (need_acmt && talking) #endif { void show_acmt PARMS ((struct zoo_header *, ZOOFILE, int)); show_acmt (&zoo_header, zoo_file, 0); /* show archive comment */ } /* Seek to the beginning of the first directory entry */ if (zooseek (zoo_file, zoo_header.zoo_start, 0) != 0) { ercount++; prterror ('e', dbl_percent, this_zoo, bad_directory); goto loop_end; } if (!show_name && ver_too_high (&zoo_header)) { ercount++; if (ercount < 2) prterror ('M', wrong_version, zoo_header.major_ver, zoo_header.minor_ver); } } /* end if (fiz_ofs !- 0L) */ /* Now we print information about each file in the archive */ if (!show_name) { /* initialize for each file only if not disk catalog */ tot_org_siz = 0L; tot_siz_now = 0L; file_count = 0; del_count = 0; } while (1) { if (readdir (&direntry, zoo_file, 0) == -1) { prterror ('F', dbl_percent, this_zoo, bad_directory); goto givesummary; } if (direntry.zoo_tag != ZOO_TAG) { long currpos, zoolength; prterror ('F', dbl_percent, this_zoo, invalid_header); if ((currpos = zootell (zoo_file)) != -1L) if (zooseek (zoo_file, 0L, 2) == 0) if ((zoolength = zootell (zoo_file)) != -1L) printf (cant_process, zoolength - currpos); goto givesummary; } if (direntry.next == 0L) /* EXIT on end of chain */ break; else entrycount++; /* Number of directory entries */ /* first direntry read, change dat_ofs from abs. pos. to rel. offset */ if (first_dir && dat_ofs != 0) { dat_ofs -= direntry.offset; first_dir = 0; } direntry.next += dat_ofs; /* allow for user-specified offset */ if (direntry.comment != 0L) direntry.comment += dat_ofs; /* so show_comment finds it */ if (direntry.deleted) ++del_count; #ifdef TRACE_LIST if (trace_list) show_dir (&direntry); #endif /* TRACE_LIST */ /* Into `whichname' put the filename to display. Use long filename if it exists, else use short filename. */ strcpy (whichname, fullpath (&direntry)); if (zoo_header.vdata & VFL_ON) add_version (whichname, &direntry); /* add version suffix */ #ifdef DEBUG printf("matching against [%s] and [%s]\n", nameptr(whichname), whichname); #endif if ( ( (list_deleted && direntry.deleted) || (list_deleted < 2 && !direntry.deleted) ) && (biglist || needed(whichname, &direntry, &zoo_header))) { /* if generations forced off, then strip added version field */ if (!genson) { /* HORRENDOUSLY INEFFICIENT AND REPETITIOUS */ char *ver_pos; ver_pos = findlast (whichname, VER_DISPLAY); if (ver_pos != NULL) *ver_pos = '\0'; } file_count++; if (direntry.packing_method > MAX_PACK) { bad_pack = 1; expl_ver = 1; } else bad_pack = 0; size_factor = cfactor (direntry.org_size, direntry.size_now); year = ((unsigned int) direntry.date >> 9) & 0x7f; month = ((unsigned int) direntry.date >> 5) & 0x0f; day = direntry.date & 0x1f; hours = ((unsigned int) direntry.time >> 11)& 0x1f; min = ((unsigned int) direntry.time >> 5) & 0x3f; sec = ((unsigned int) direntry.time & 0x1f) * 2; /* Alignment in columns is a horrendously complex undertaking. */ if (fast) { int space_left; int namelen; int next_col; #if 0 if ( (quiet && !first_ever || !first_time) && one_col) fputchar ('\n'); first_ever = 0; #endif /* If we are showing directories, whichname already contains the full pathname string. Else we only use the filename as follows: long filename if possible, else short filename */ if (!showdir) { strcpy (whichname, (direntry.namlen != 0) ? direntry.lfname : direntry.fname); if (genson && zoo_header.vdata & VFL_ON) add_version (whichname, &direntry); /* add version suffix */ } namelen = strlen (whichname); #define MARGIN 78 #define COL_WIDTH 16 #if 1 /* if not enough space left, move to next line */ if (!one_col && column != 0) { space_left = MARGIN - column; if (namelen > space_left) { neednl = 1; column = 0; } } #endif if ( (quiet && !first_ever || !first_time) && (neednl || one_col)) printf ("\n"); first_ever = 0; neednl = 0; printf("%s", whichname); fflush (stdout); /* move to next column stop */ column += namelen; next_col = ((column + (COL_WIDTH - 1)) / COL_WIDTH) * COL_WIDTH; if (next_col - column < 2) /* need at least 2 spaces */ next_col += COL_WIDTH; if (next_col > MARGIN) { neednl = 1; column = 0; } else { if (!one_col) printf ("%*s", (next_col - column), " "); column = next_col; } } else { if (talking && first_time && !show_name) {/*print archive header */ printf ("Length CF Size Now Date Time\n"); printf (tot_line); } printf ("%8lu %3u%% %8lu %2d %-.3s %02d %02d:%02d:%02d", direntry.org_size, size_factor, direntry.size_now, day, &month_list[month*3], (day && month) ? (year+80) % 100 : 0, hours, min, sec); tot_org_siz += direntry.org_size; tot_siz_now += direntry.size_now; #ifdef GETTZ printtz ((int) direntry.tz); /* show timezone */ #else printf (" "); #endif if (show_crc) printf ("%04x ", direntry.file_crc); if (show_gen) { if (direntry.vflag & VFL_ON) printf ("%2dg ", direntry.vflag & VFL_GEN); else printf ("--g "); } if (direntry.cmt_size) { expl_comment++; printf ("C"); } else printf (" "); if (direntry.deleted) { expl_deleted++; printf ("D"); } else printf (" "); if (list_deleted) printf (" "); if (show_name) printf ("%-*s ", longest, this_zoo); #ifdef FATTR if (show_mode) { if (direntry.fattr == 0) printf ("--- "); else if ((direntry.fattr >> 22) == 1) printf ("%03lo ", direntry.fattr & 0x1ff); else printf ("??? "); } #endif /* FATTR */ /* new code to get around a common compiler bug */ printf ("%s", whichname); if (direntry.dir_crc != 0) { expl_star++; printf ("*"); } if (bad_pack) printf (" (V%d.%d)", direntry.major_ver, direntry.minor_ver); printf ("\n"); } first_time = 0; /* if verbose listing requested show any comment. f overrrides v */ if (verb_list && !fast) show_comment (&direntry, zoo_file, 0, (char *) NULL); } /* end if (lots of conditions) */ /* ..seek to next dir entry */ zooseek (zoo_file, direntry.next, 0); } /* end while */ givesummary: if (fast && talking) { if (file_count) { if (del_count || (show_gen && zoo_header.type > 0)) printf ("\n-----\n"); else fputchar ('\n'); } if (del_count) printf ("%d deleted.\n", del_count); if (show_gen && zoo_header.type > 0) { printf ("Generation limit %u", zoo_header.vdata & VFL_GEN); if ((zoo_header.vdata & VFL_ON) == 0) printf (" (off).\n"); else printf (".\n"); } } /* end if (fast && talking) */ if (talking && !show_name) { if (!fast && file_count) { tot_sf = cfactor (tot_org_siz, tot_siz_now); printf (tot_line); printf (tot_fmt, tot_org_siz, tot_sf, tot_siz_now, file_count); if (file_count > 1) printf ("s\n"); else printf ("\n"); if (del_count || expl_ver || expl_deleted || expl_comment || expl_star || (show_gen && (zoo_header.type > 0))) printf (dashes); } if (!fast) { if (del_count) { if (expl_deleted) printf ("D: deleted file.\n"); else { if (del_count == 1) printf ("There is 1 deleted file.\n"); else printf ("There are %d deleted files.\n", del_count); } } } if (expl_comment && !fast && !verb_list) printf ("C: file has attached comment.\n"); if (expl_ver && !fast) printf ("V: minimum version of Zoo needed to extract this file.\n"); if (expl_star && !fast) printf ("*: directory entry may be corrupted.\n"); if (!file_count) printf ("Zoo: %s", no_match); if (!entrycount && !fiz_ofs) printf ("(The archive is empty.)\n"); if (show_gen && (zoo_header.type > 0) && !fast) { printf ("Archive generation limit is %u", zoo_header.vdata & VFL_GEN); if ((zoo_header.vdata & VFL_ON) == 0) printf (" (generations off).\n"); else printf (".\n"); } } /* end if (talking && !show_name) */ loop_end: /* jump here on badly structured archive */ zooclose (zoo_file); } /* end for */ if (talking && show_name) { if (file_count) { tot_sf = cfactor (tot_org_siz, tot_siz_now); printf (tot_line); printf (tot_fmt, tot_org_siz, tot_sf, tot_siz_now, file_count); if (file_count > 1) printf ("s\n"); else printf ("\n"); } } else if (fast && quiet) fputchar ('\n'); if (!file_count) zooexit (1); /* Consider it an error if there were no files */ } /* zoolist() */ #ifdef GETTZ void printtz (file_tz) int file_tz; { long gettz(); int diff_tz; /* timezone difference */ if (file_tz == NO_TZ) /* if no timezone stored ..*/ printf (" "); /* .. just pad with blanks */ else { diff_tz = (file_tz / 4) - (int) (gettz() / 3600); if (diff_tz == 0) printf (" "); /* print nothing if same */ else if (diff_tz > 0) /* else print signed difference */ printf ("+%1d ", diff_tz); else printf ("-%1d ", -diff_tz); } } #endif /* FOLLOWING CODE IS FOR DEBUGGING ONLY. IT IS COMPILED IN ONLY IF THE SYMBOL TRACE_LIST IS DEFINED */ #ifdef TRACE_LIST /* code copied from portable.c near end */ /* dump contents of directory entry */ void show_dir (direntry) struct direntry *direntry; { printf ("Directory entry for file [%s][%s]:\n", direntry->fname, direntry->lfname); printf ("tag = [%8lx] type = [%d] PM = [%d] Next = [%8lx] Offset = [%8lx]\n", direntry->zoo_tag, (int) direntry->type, (int) direntry->packing_method, direntry->next, direntry->offset); printf ("Orig size = [%ld] Size now = [%ld] dmaj_v.dmin_v = [%d.%d]\n", direntry->org_size, direntry->size_now, (int) direntry->major_ver, (int) direntry->minor_ver); printf ("Struc = [%d] DEL = [%d] comment_offset = [%8lx] cmt_size = [%d]\n", (int) direntry->struc, (int) direntry->deleted, direntry->comment, direntry->cmt_size); printf ("var_dir_len = [%d] TZ = [%d] dir_crc = [%4x]\n", direntry->var_dir_len, (int) direntry->tz, direntry->dir_crc); printf ("system_id = [%d] dirlen = [%d] namlen = [%d] fattr=[%24lx]\n", direntry->system_id, direntry->dirlen, direntry->namlen, direntry->fattr); printf ("vflag = [%4x] version_no = [%4x]\n", direntry->vflag, direntry->version_no); if (direntry->dirlen > 0) printf ("dirname = [%s]\n", direntry->dirname); printf ("---------\n"); } #endif /* TRACE_IO */