|
|
1.1 root 1: /* $Source: /src386/usr/bin/pax/list.c,v $
2: *
3: * $Revision: 1.1 $
4: *
5: * list.c - List all files on an archive
6: *
7: * DESCRIPTION
8: *
9: * These function are needed to support archive table of contents and
10: * verbose mode during extraction and creation of achives.
11: *
12: * AUTHOR
13: *
14: * Mark H. Colburn, NAPS International ([email protected])
15: *
16: * Sponsored by The USENIX Association for public distribution.
17: *
18: * Copyright (c) 1989 Mark H. Colburn.
19: * All rights reserved.
20: *
21: * Redistribution and use in source and binary forms are permitted
22: * provided that the above copyright notice is duplicated in all such
23: * forms and that any documentation, advertising materials, and other
24: * materials related to such distribution and use acknowledge that the
25: * software was developed * by Mark H. Colburn and sponsored by The
26: * USENIX Association.
27: *
28: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31: *
32: * $Log: list.c,v $
33: * Revision 1.1 92/08/28 08:02:15 bin
34: * Initial revision
35: *
36: * Revision 1.1 89/02/14 16:47:59 jep
37: * Initial revision
38: *
39: * Revision 1.1 88/12/23 18:02:14 mark
40: * Initial revision
41: *
42: */
43:
44: #ifndef lint
45: static char *ident = "$Id: list.c,v 1.1 92/08/28 08:02:15 bin Exp Locker: bin $";
46: static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
47: #endif /* ! lint */
48:
49:
50: /* Headers */
51:
52: #include "pax.h"
53:
54:
55: /* Defines */
56:
57: /*
58: * isodigit returns non zero iff argument is an octal digit, zero otherwise
59: */
60: #define ISODIGIT(c) (((c) >= '0') && ((c) <= '7'))
61:
62:
63: /* Function Prototypes */
64:
65: #if __STDC__
66:
67: static void cpio_entry(char *, Stat *);
68: static void tar_entry(char *, Stat *);
69: static void pax_entry(char *, Stat *);
70: static void print_mode(ushort);
71: static long from_oct(int digs, char *where);
72:
73: #else /* !__STDC__ */
74:
75: static void cpio_entry();
76: static void tar_entry();
77: static void pax_entry();
78: static void print_mode();
79: static long from_oct();
80:
81: #endif /* __STDC__ */
82:
83:
84: /* Internal Identifiers */
85:
86: static char *monnames[] = {
87: "Jan", "Feb", "Mar", "Apr", "May", "Jun",
88: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
89: };
90:
91:
92: /* read_header - read a header record
93: *
94: * DESCRIPTION
95: *
96: * Read a record that's supposed to be a header record. Return its
97: * address in "head", and if it is good, the file's size in
98: * asb->sb_size. Decode things from a file header record into a "Stat".
99: * Also set "head_standard" to !=0 or ==0 depending whether header record
100: * is "Unix Standard" tar format or regular old tar format.
101: *
102: * PARAMETERS
103: *
104: * char *name - pointer which will contain name of file
105: * Stat *asb - pointer which will contain stat info
106: *
107: * RETURNS
108: *
109: * Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a
110: * record full of zeros (EOF marker).
111: */
112:
113: #if __STDC__
114:
115: int read_header(char *name, Stat *asb)
116:
117: #else
118:
119: int read_header(name, asb)
120: char *name;
121: Stat *asb;
122:
123: #endif
124: {
125: int i;
126: long sum;
127: long recsum;
128: Link *link;
129: char *p;
130: char hdrbuf[BLOCKSIZE];
131:
132: memset((char *)asb, 0, sizeof(Stat));
133: /* read the header from the buffer */
134: if (buf_read(hdrbuf, BLOCKSIZE) != 0) {
135: return (EOF);
136: }
137:
138: strcpy(name, hdrbuf);
139:
140: recsum = from_oct(8, &hdrbuf[148]);
141: sum = 0;
142: p = hdrbuf;
143: for (i = 0 ; i < 500; i++) {
144:
145: /*
146: * We can't use unsigned char here because of old compilers, e.g. V7.
147: */
148: sum += 0xFF & *p++;
149: }
150:
151: /* Adjust checksum to count the "chksum" field as blanks. */
152: for (i = 0; i < 8; i++) {
153: sum -= 0xFF & hdrbuf[148 + i];
154: }
155: sum += ' ' * 8;
156:
157: if (sum == 8 * ' ') {
158:
159: /*
160: * This is a zeroed record...whole record is 0's except for the 8
161: * blanks we faked for the checksum field.
162: */
163: return (2);
164: }
165: if (sum == recsum) {
166: /*
167: * Good record. Decode file size and return.
168: */
169: if (hdrbuf[156] != LNKTYPE) {
170: asb->sb_size = from_oct(1 + 12, &hdrbuf[124]);
171: }
172: asb->sb_mtime = from_oct(1 + 12, &hdrbuf[136]);
173: asb->sb_mode = from_oct(8, &hdrbuf[100]);
174:
175: if (strcmp(&hdrbuf[257], TMAGIC) == 0) {
176: /* Unix Standard tar archive */
177: head_standard = 1;
178: #ifdef NONAMES
179: asb->sb_uid = from_oct(8, &hdrbuf[108]);
180: asb->sb_gid = from_oct(8, &hdrbuf[116]);
181: #else
182: asb->sb_uid = finduid(&hdrbuf[265]);
183: asb->sb_gid = findgid(&hdrbuf[297]);
184: #endif
185: switch (hdrbuf[156]) {
186: case BLKTYPE:
187: case CHRTYPE:
188: asb->sb_rdev = makedev(from_oct(8, &hdrbuf[329]),
189: from_oct(8, &hdrbuf[337]));
190: break;
191: default:
192: /* do nothing... */
193: break;
194: }
195: } else {
196: /* Old fashioned tar archive */
197: head_standard = 0;
198: asb->sb_uid = from_oct(8, &hdrbuf[108]);
199: asb->sb_gid = from_oct(8, &hdrbuf[116]);
200: }
201:
202: switch (hdrbuf[156]) {
203: case REGTYPE:
204: case AREGTYPE:
205: /*
206: * Berkeley tar stores directories as regular files with a
207: * trailing /
208: */
209: if (name[strlen(name) - 1] == '/') {
210: name[strlen(name) - 1] = '\0';
211: asb->sb_mode |= S_IFDIR;
212: } else {
213: asb->sb_mode |= S_IFREG;
214: }
215: break;
216: case LNKTYPE:
217: asb->sb_nlink = 2;
218: linkto(&hdrbuf[157], asb);
219: linkto(name, asb);
220: asb->sb_mode |= S_IFREG;
221: break;
222: case BLKTYPE:
223: asb->sb_mode |= S_IFBLK;
224: break;
225: case CHRTYPE:
226: asb->sb_mode |= S_IFCHR;
227: break;
228: case DIRTYPE:
229: asb->sb_mode |= S_IFDIR;
230: break;
231: #ifdef S_IFLNK
232: case SYMTYPE:
233: asb->sb_mode |= S_IFLNK;
234: strcpy(asb->sb_link, &hdrbuf[157]);
235: break;
236: #endif
237: #ifdef S_IFIFO
238: case FIFOTYPE:
239: asb->sb_mode |= S_IFIFO;
240: break;
241: #endif
242: #ifdef S_IFCTG
243: case CONTTYPE:
244: asb->sb_mode |= S_IFCTG;
245: break;
246: #endif
247: }
248: return (1);
249: }
250: return (0);
251: }
252:
253:
254: /* print_entry - print a single table-of-contents entry
255: *
256: * DESCRIPTION
257: *
258: * Print_entry prints a single line of file information. The format
259: * of the line is the same as that used by the LS command. For some
260: * archive formats, various fields may not make any sense, such as
261: * the link count on tar archives. No error checking is done for bad
262: * or invalid data.
263: *
264: * PARAMETERS
265: *
266: * char *name - pointer to name to print an entry for
267: * Stat *asb - pointer to the stat structure for the file
268: */
269:
270: #if __STDC__
271:
272: void print_entry(char *name, Stat *asb)
273:
274: #else
275:
276: void print_entry(name, asb)
277: char *name;
278: Stat *asb;
279:
280: #endif
281: {
282: switch (ar_interface) {
283: case TAR:
284: tar_entry(name, asb);
285: break;
286: case CPIO:
287: cpio_entry(name, asb);
288: break;
289: case PAX: pax_entry(name, asb);
290: break;
291: }
292: }
293:
294:
295: /* cpio_entry - print a verbose cpio-style entry
296: *
297: * DESCRIPTION
298: *
299: * Print_entry prints a single line of file information. The format
300: * of the line is the same as that used by the traditional cpio
301: * command. No error checking is done for bad or invalid data.
302: *
303: * PARAMETERS
304: *
305: * char *name - pointer to name to print an entry for
306: * Stat *asb - pointer to the stat structure for the file
307: */
308:
309: #if __STDC__
310:
311: static void cpio_entry(char *name, Stat *asb)
312:
313: #else
314:
315: static void cpio_entry(name, asb)
316: char *name;
317: Stat *asb;
318:
319: #endif
320: {
321: struct tm *atm;
322: Link *from;
323: struct passwd *pwp;
324: struct group *grp;
325:
326: if (f_list && f_verbose) {
327: fprintf(msgfile, "%-7o", asb->sb_mode);
328: atm = localtime(&asb->sb_mtime);
329: if (pwp = getpwuid((int) USH(asb->sb_uid))) {
330: fprintf(msgfile, "%-6s", pwp->pw_name);
331: } else {
332: fprintf(msgfile, "%-6u", USH(asb->sb_uid));
333: }
334: fprintf(msgfile,"%7ld %3s %2d %02d:%02d:%02d %4d ",
335: asb->sb_size, monnames[atm->tm_mon],
336: atm->tm_mday, atm->tm_hour, atm->tm_min,
337: atm->tm_sec, atm->tm_year + 1900);
338: }
339: fprintf(msgfile, "%s", name);
340: if ((asb->sb_nlink > 1) && (from = islink(name, asb))) {
341: fprintf(msgfile, " linked to %s", from->l_name);
342: }
343: #ifdef S_IFLNK
344: if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
345: fprintf(msgfile, " symbolic link to %s", asb->sb_link);
346: }
347: #endif /* S_IFLNK */
348: putc('\n', msgfile);
349: }
350:
351:
352: /* tar_entry - print a tar verbose mode entry
353: *
354: * DESCRIPTION
355: *
356: * Print_entry prints a single line of tar file information. The format
357: * of the line is the same as that produced by the traditional tar
358: * command. No error checking is done for bad or invalid data.
359: *
360: * PARAMETERS
361: *
362: * char *name - pointer to name to print an entry for
363: * Stat *asb - pointer to the stat structure for the file
364: */
365:
366: #if __STDC__
367:
368: static void tar_entry(char *name, Stat *asb)
369:
370: #else
371:
372: static void tar_entry(name, asb)
373: char *name;
374: Stat *asb;
375:
376: #endif
377: {
378: struct tm *atm;
379: int i;
380: int mode;
381: char *symnam = "NULL";
382: Link *link;
383:
384: if ((mode = asb->sb_mode & S_IFMT) == S_IFDIR) {
385: return; /* don't print directories */
386: }
387: if (f_extract) {
388: switch (mode) {
389: #ifdef S_IFLNK
390: case S_IFLNK: /* This file is a symbolic link */
391: i = readlink(name, symnam, PATH_MAX - 1);
392: if (i < 0) { /* Could not find symbolic link */
393: warn("can't read symbolic link", strerror());
394: } else { /* Found symbolic link filename */
395: symnam[i] = '\0';
396: fprintf(msgfile, "x %s symbolic link to %s\n", name, symnam);
397: }
398: break;
399: #endif
400: case S_IFREG: /* It is a link or a file */
401: if ((asb->sb_nlink > 1) && (link = islink(name, asb))) {
402: fprintf(msgfile, "%s linked to %s\n", name, link->l_name);
403: } else {
404: fprintf(msgfile, "x %s, %ld bytes, %d tape blocks\n",
405: name, asb->sb_size, ROUNDUP(asb->sb_size,
406: BLOCKSIZE) / BLOCKSIZE);
407: }
408: }
409: } else if (f_append || f_create) {
410: switch (mode) {
411: #ifdef S_IFLNK
412: case S_IFLNK: /* This file is a symbolic link */
413: i = readlink(name, symnam, PATH_MAX - 1);
414: if (i < 0) { /* Could not find symbolic link */
415: warn("can't read symbolic link", strerror());
416: } else { /* Found symbolic link filename */
417: symnam[i] = '\0';
418: fprintf(msgfile, "a %s symbolic link to %s\n", name, symnam);
419: }
420: break;
421: #endif
422: case S_IFREG: /* It is a link or a file */
423: fprintf(msgfile, "a %s ", name);
424: if ((asb->sb_nlink > 1) && (link = islink(name, asb))) {
425: fprintf(msgfile, "link to %s\n", link->l_name);
426: } else {
427: fprintf(msgfile, "%ld Blocks\n",
428: ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE);
429: }
430: break;
431: }
432: } else if (f_list) {
433: if (f_verbose) {
434: atm = localtime(&asb->sb_mtime);
435: print_mode(asb->sb_mode);
436: fprintf(msgfile," %d/%d %6d %3s %2d %02d:%02d %4d %s",
437: asb->sb_uid, asb->sb_gid, asb->sb_size,
438: monnames[atm->tm_mon], atm->tm_mday, atm->tm_hour,
439: atm->tm_min, atm->tm_year + 1900, name);
440: } else {
441: fprintf(msgfile, "%s", name);
442: }
443: switch (mode) {
444: #ifdef S_IFLNK
445: case S_IFLNK: /* This file is a symbolic link */
446: i = readlink(name, symnam, PATH_MAX - 1);
447: if (i < 0) { /* Could not find symbolic link */
448: warn("can't read symbolic link", strerror());
449: } else { /* Found symbolic link filename */
450: symnam[i] = '\0';
451: fprintf(msgfile, " symbolic link to %s", symnam);
452: }
453: break;
454: #endif
455: case S_IFREG: /* It is a link or a file */
456: if ((asb->sb_nlink > 1) && (link = islink(name, asb))) {
457: fprintf(msgfile, " linked to %s", link->l_name);
458: }
459: break; /* Do not print out directories */
460: }
461: fputc('\n', msgfile);
462: } else {
463: fprintf(msgfile, "? %s %ld blocks\n", name,
464: ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE);
465: }
466: }
467:
468:
469: /* pax_entry - print a verbose cpio-style entry
470: *
471: * DESCRIPTION
472: *
473: * Print_entry prints a single line of file information. The format
474: * of the line is the same as that used by the LS command.
475: * No error checking is done for bad or invalid data.
476: *
477: * PARAMETERS
478: *
479: * char *name - pointer to name to print an entry for
480: * Stat *asb - pointer to the stat structure for the file
481: */
482:
483: #if __STDC__
484:
485: static void pax_entry(char *name, Stat *asb)
486:
487: #else
488:
489: static void pax_entry(name, asb)
490: char *name;
491: Stat *asb;
492:
493: #endif
494: {
495: struct tm *atm;
496: Link *from;
497: struct passwd *pwp;
498: struct group *grp;
499:
500: if (f_list && f_verbose) {
501: print_mode(asb->sb_mode);
502: fprintf(msgfile, " %2d", asb->sb_nlink);
503: atm = localtime(&asb->sb_mtime);
504: if (pwp = getpwuid((int) USH(asb->sb_uid))) {
505: fprintf(msgfile, " %-8s", pwp->pw_name);
506: } else {
507: fprintf(msgfile, " %-8u", USH(asb->sb_uid));
508: }
509: if (grp = getgrgid((int) USH(asb->sb_gid))) {
510: fprintf(msgfile, " %-8s", grp->gr_name);
511: } else {
512: fprintf(msgfile, " %-8u", USH(asb->sb_gid));
513: }
514: switch (asb->sb_mode & S_IFMT) {
515: case S_IFBLK:
516: case S_IFCHR:
517: fprintf(msgfile, "\t%3d, %3d",
518: major(asb->sb_rdev), minor(asb->sb_rdev));
519: break;
520: case S_IFREG:
521: fprintf(msgfile, "\t%8ld", asb->sb_size);
522: break;
523: default:
524: fprintf(msgfile, "\t ");
525: }
526: fprintf(msgfile," %3s %2d %02d:%02d ",
527: monnames[atm->tm_mon], atm->tm_mday,
528: atm->tm_hour, atm->tm_min);
529: }
530: fprintf(msgfile, "%s", name);
531: if ((asb->sb_nlink > 1) && (from = islink(name, asb))) {
532: fprintf(msgfile, " == %s", from->l_name);
533: }
534: #ifdef S_IFLNK
535: if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
536: fprintf(msgfile, " -> %s", asb->sb_link);
537: }
538: #endif /* S_IFLNK */
539: putc('\n', msgfile);
540: }
541:
542:
543: /* print_mode - fancy file mode display
544: *
545: * DESCRIPTION
546: *
547: * Print_mode displays a numeric file mode in the standard unix
548: * representation, ala ls (-rwxrwxrwx). No error checking is done
549: * for bad mode combinations. FIFOS, sybmbolic links, sticky bits,
550: * block- and character-special devices are supported if supported
551: * by the hosting implementation.
552: *
553: * PARAMETERS
554: *
555: * ushort mode - The integer representation of the mode to print.
556: */
557:
558: #if __STDC__
559:
560: static void print_mode(ushort mode)
561:
562: #else
563:
564: static void print_mode(mode)
565: ushort mode;
566:
567: #endif
568: {
569: /* Tar does not print the leading identifier... */
570: if (ar_interface != TAR) {
571: switch (mode & S_IFMT) {
572: case S_IFDIR:
573: putc('d', msgfile);
574: break;
575: #ifdef S_IFLNK
576: case S_IFLNK:
577: putc('l', msgfile);
578: break;
579: #endif /* S_IFLNK */
580: case S_IFBLK:
581: putc('b', msgfile);
582: break;
583: case S_IFCHR:
584: putc('c', msgfile);
585: break;
586: #ifdef S_IFIFO
587: case S_IFIFO:
588: putc('p', msgfile);
589: break;
590: #endif /* S_IFIFO */
591: case S_IFREG:
592: default:
593: putc('-', msgfile);
594: break;
595: }
596: }
597: putc(mode & 0400 ? 'r' : '-', msgfile);
598: putc(mode & 0200 ? 'w' : '-', msgfile);
599: putc(mode & 0100
600: ? mode & 04000 ? 's' : 'x'
601: : mode & 04000 ? 'S' : '-', msgfile);
602: putc(mode & 0040 ? 'r' : '-', msgfile);
603: putc(mode & 0020 ? 'w' : '-', msgfile);
604: putc(mode & 0010
605: ? mode & 02000 ? 's' : 'x'
606: : mode & 02000 ? 'S' : '-', msgfile);
607: putc(mode & 0004 ? 'r' : '-', msgfile);
608: putc(mode & 0002 ? 'w' : '-', msgfile);
609: putc(mode & 0001
610: ? mode & 01000 ? 't' : 'x'
611: : mode & 01000 ? 'T' : '-', msgfile);
612: }
613:
614:
615: /* from_oct - quick and dirty octal conversion
616: *
617: * DESCRIPTION
618: *
619: * From_oct will convert an ASCII representation of an octal number
620: * to the numeric representation. The number of characters to convert
621: * is given by the parameter "digs". If there are less numbers than
622: * specified by "digs", then the routine returns -1.
623: *
624: * PARAMETERS
625: *
626: * int digs - Number to of digits to convert
627: * char *where - Character representation of octal number
628: *
629: * RETURNS
630: *
631: * The value of the octal number represented by the first digs
632: * characters of the string where. Result is -1 if the field
633: * is invalid (all blank, or nonoctal).
634: *
635: * ERRORS
636: *
637: * If the field is all blank, then the value returned is -1.
638: *
639: */
640:
641: #if __STDC__
642:
643: static long from_oct(int digs, char *where)
644:
645: #else
646:
647: static long from_oct(digs, where)
648: int digs; /* number of characters to convert */
649: char *where; /* character representation of octal number */
650:
651: #endif
652: {
653: long value;
654:
655: while (isspace(*where)) { /* Skip spaces */
656: where++;
657: if (--digs <= 0) {
658: return(-1); /* All blank field */
659: }
660: }
661: value = 0;
662: while (digs > 0 && ISODIGIT(*where)) { /* Scan til nonoctal */
663: value = (value << 3) | (*where++ - '0');
664: --digs;
665: }
666:
667: if (digs > 0 && *where && !isspace(*where)) {
668: return(-1); /* Ended on non-space/nul */
669: }
670: return(value);
671: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.