xref: /386bsd/usr/src/usr.bin/file/new/is_tar.c (revision a2142627)
1 /*
2  * is_tar() -- figure out whether file is a tar archive.
3  *
4  * Stolen (by the author!) from the public domain tar program:
5  * Pubic Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
6  *
7  * @(#)list.c 1.18 9/23/86 Public Domain - gnu
8  * $Id: is_tar.c,v 1.7 92/09/08 15:32:19 ian Exp $
9  *
10  * Comments changed and some code/comments reformatted
11  * for file command by Ian Darwin.
12  */
13 
14 #include <string.h>
15 #include <ctype.h>
16 #include <sys/types.h>
17 #include "tar.h"
18 
19 #define	isodigit(c)	( ((c) >= '0') && ((c) <= '7') )
20 
21 #if	defined(__STDC__) || defined(__cplusplus)
22 static long from_oct(int, char*);	/* Decode octal number */
23 #else
24 static long from_oct();
25 #endif
26 
27 /*
28  * Return
29  *	0 if the checksum is bad (i.e., probably not a tar archive),
30  *	1 for old UNIX tar file,
31  *	2 for Unix Std (POSIX) tar file.
32  */
33 int
is_tar(buf)34 is_tar(buf)
35 unsigned char *buf;
36 {
37 	register union record *header = (union record *)buf;
38 	register int	i;
39 	register long	sum, recsum;
40 	register char	*p;
41 
42 	recsum = from_oct(8,  header->header.chksum);
43 
44 	sum = 0;
45 	p = header->charptr;
46 	for (i = sizeof(union record); --i >= 0;) {
47 		/*
48 		 * We can't use unsigned char here because of old compilers,
49 		 * e.g. V7.
50 		 */
51 		sum += 0xFF & *p++;
52 	}
53 
54 	/* Adjust checksum to count the "chksum" field as blanks. */
55 	for (i = sizeof(header->header.chksum); --i >= 0;)
56 		sum -= 0xFF & header->header.chksum[i];
57 	sum += ' '* sizeof header->header.chksum;
58 
59 	if (sum != recsum)
60 		return 0;	/* Not a tar archive */
61 
62 	if (0==strcmp(header->header.magic, TMAGIC))
63 		return 2;		/* Unix Standard tar archive */
64 
65 	return 1;			/* Old fashioned tar archive */
66 }
67 
68 
69 /*
70  * Quick and dirty octal conversion.
71  *
72  * Result is -1 if the field is invalid (all blank, or nonoctal).
73  */
74 static long
from_oct(digs,where)75 from_oct(digs, where)
76 	register int	digs;
77 	register char	*where;
78 {
79 	register long	value;
80 
81 	while (isspace(*where)) {		/* Skip spaces */
82 		where++;
83 		if (--digs <= 0)
84 			return -1;		/* All blank field */
85 	}
86 	value = 0;
87 	while (digs > 0 && isodigit(*where)) {	/* Scan til nonoctal */
88 		value = (value << 3) | (*where++ - '0');
89 		--digs;
90 	}
91 
92 	if (digs > 0 && *where && !isspace(*where))
93 		return -1;			/* Ended on non-space/nul */
94 
95 	return value;
96 }
97