is_tar.c revision 68349
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 * Public 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.13 2000/08/05 17:36:48 christos 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#include "file.h"
19
20#ifndef lint
21FILE_RCSID("@(#)$Id: is_tar.c,v 1.13 2000/08/05 17:36:48 christos Exp $")
22#endif
23
24#define	isodigit(c)	( ((c) >= '0') && ((c) <= '7') )
25
26static int from_oct __P((int, char *));	/* Decode octal number */
27
28/*
29 * Return
30 *	0 if the checksum is bad (i.e., probably not a tar archive),
31 *	1 for old UNIX tar file,
32 *	2 for Unix Std (POSIX) tar file.
33 */
34int
35is_tar(buf, nbytes)
36	unsigned char *buf;
37	int nbytes;
38{
39	union record *header = (union record *)buf;
40	int	i;
41	int	sum, recsum;
42	char	*p;
43
44	if (nbytes < sizeof(union record))
45		return 0;
46
47	recsum = from_oct(8,  header->header.chksum);
48
49	sum = 0;
50	p = header->charptr;
51	for (i = sizeof(union record); --i >= 0;) {
52		/*
53		 * We can't use unsigned char here because of old compilers,
54		 * e.g. V7.
55		 */
56		sum += 0xFF & *p++;
57	}
58
59	/* Adjust checksum to count the "chksum" field as blanks. */
60	for (i = sizeof(header->header.chksum); --i >= 0;)
61		sum -= 0xFF & header->header.chksum[i];
62	sum += ' '* sizeof header->header.chksum;
63
64	if (sum != recsum)
65		return 0;	/* Not a tar archive */
66
67	if (0==strcmp(header->header.magic, TMAGIC))
68		return 2;		/* Unix Standard tar archive */
69
70	return 1;			/* Old fashioned tar archive */
71}
72
73
74/*
75 * Quick and dirty octal conversion.
76 *
77 * Result is -1 if the field is invalid (all blank, or nonoctal).
78 */
79static int
80from_oct(digs, where)
81	int	digs;
82	char	*where;
83{
84	int	value;
85
86	while (isspace((unsigned char)*where)) {	/* Skip spaces */
87		where++;
88		if (--digs <= 0)
89			return -1;		/* All blank field */
90	}
91	value = 0;
92	while (digs > 0 && isodigit(*where)) {	/* Scan til nonoctal */
93		value = (value << 3) | (*where++ - '0');
94		--digs;
95	}
96
97	if (digs > 0 && *where && !isspace((unsigned char)*where))
98		return -1;			/* Ended on non-space/nul */
99
100	return value;
101}
102