xref: /minix3/external/bsd/file/dist/src/is_tar.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: is_tar.c,v 1.1.1.4 2015/01/02 20:34:27 christos Exp $	*/
2ef01931fSBen Gras 
3ef01931fSBen Gras /*
4ef01931fSBen Gras  * Copyright (c) Ian F. Darwin 1986-1995.
5ef01931fSBen Gras  * Software written by Ian F. Darwin and others;
6ef01931fSBen Gras  * maintained 1995-present by Christos Zoulas and others.
7ef01931fSBen Gras  *
8ef01931fSBen Gras  * Redistribution and use in source and binary forms, with or without
9ef01931fSBen Gras  * modification, are permitted provided that the following conditions
10ef01931fSBen Gras  * are met:
11ef01931fSBen Gras  * 1. Redistributions of source code must retain the above copyright
12ef01931fSBen Gras  *    notice immediately at the beginning of the file, without modification,
13ef01931fSBen Gras  *    this list of conditions, and the following disclaimer.
14ef01931fSBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
15ef01931fSBen Gras  *    notice, this list of conditions and the following disclaimer in the
16ef01931fSBen Gras  *    documentation and/or other materials provided with the distribution.
17ef01931fSBen Gras  *
18ef01931fSBen Gras  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19ef01931fSBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20ef01931fSBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21ef01931fSBen Gras  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22ef01931fSBen Gras  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23ef01931fSBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24ef01931fSBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25ef01931fSBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26ef01931fSBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27ef01931fSBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28ef01931fSBen Gras  * SUCH DAMAGE.
29ef01931fSBen Gras  */
30ef01931fSBen Gras /*
31ef01931fSBen Gras  * is_tar() -- figure out whether file is a tar archive.
32ef01931fSBen Gras  *
33ef01931fSBen Gras  * Stolen (by the author!) from the public domain tar program:
34ef01931fSBen Gras  * Public Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
35ef01931fSBen Gras  *
36ef01931fSBen Gras  * @(#)list.c 1.18 9/23/86 Public Domain - gnu
37ef01931fSBen Gras  *
38ef01931fSBen Gras  * Comments changed and some code/comments reformatted
39ef01931fSBen Gras  * for file command by Ian Darwin.
40ef01931fSBen Gras  */
41ef01931fSBen Gras 
42ef01931fSBen Gras #include "file.h"
43ef01931fSBen Gras 
44ef01931fSBen Gras #ifndef lint
45ef01931fSBen Gras #if 0
46835f6802SDirk Vogt FILE_RCSID("@(#)$File: is_tar.c,v 1.37 2010/11/30 14:58:53 rrt Exp $")
47ef01931fSBen Gras #else
48*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: is_tar.c,v 1.1.1.4 2015/01/02 20:34:27 christos Exp $");
49ef01931fSBen Gras #endif
50ef01931fSBen Gras #endif
51ef01931fSBen Gras 
52ef01931fSBen Gras #include "magic.h"
53ef01931fSBen Gras #include <string.h>
54ef01931fSBen Gras #include <ctype.h>
55ef01931fSBen Gras #include "tar.h"
56ef01931fSBen Gras 
57ef01931fSBen Gras #define	isodigit(c)	( ((c) >= '0') && ((c) <= '7') )
58ef01931fSBen Gras 
59ef01931fSBen Gras private int is_tar(const unsigned char *, size_t);
60ef01931fSBen Gras private int from_oct(int, const char *);	/* Decode octal number */
61ef01931fSBen Gras 
62ef01931fSBen Gras static const char tartype[][32] = {
63ef01931fSBen Gras 	"tar archive",
64ef01931fSBen Gras 	"POSIX tar archive",
65ef01931fSBen Gras 	"POSIX tar archive (GNU)",
66ef01931fSBen Gras };
67ef01931fSBen Gras 
68ef01931fSBen Gras protected int
file_is_tar(struct magic_set * ms,const unsigned char * buf,size_t nbytes)69ef01931fSBen Gras file_is_tar(struct magic_set *ms, const unsigned char *buf, size_t nbytes)
70ef01931fSBen Gras {
71ef01931fSBen Gras 	/*
72ef01931fSBen Gras 	 * Do the tar test first, because if the first file in the tar
73ef01931fSBen Gras 	 * archive starts with a dot, we can confuse it with an nroff file.
74ef01931fSBen Gras 	 */
75ef01931fSBen Gras 	int tar;
76ef01931fSBen Gras 	int mime = ms->flags & MAGIC_MIME;
77ef01931fSBen Gras 
78ef01931fSBen Gras 	if ((ms->flags & MAGIC_APPLE) != 0)
79ef01931fSBen Gras 		return 0;
80ef01931fSBen Gras 
81ef01931fSBen Gras 	tar = is_tar(buf, nbytes);
82ef01931fSBen Gras 	if (tar < 1 || tar > 3)
83ef01931fSBen Gras 		return 0;
84ef01931fSBen Gras 
85ef01931fSBen Gras 	if (file_printf(ms, "%s", mime ? "application/x-tar" :
86ef01931fSBen Gras 	    tartype[tar - 1]) == -1)
87ef01931fSBen Gras 		return -1;
88ef01931fSBen Gras 	return 1;
89ef01931fSBen Gras }
90ef01931fSBen Gras 
91ef01931fSBen Gras /*
92ef01931fSBen Gras  * Return
93ef01931fSBen Gras  *	0 if the checksum is bad (i.e., probably not a tar archive),
94ef01931fSBen Gras  *	1 for old UNIX tar file,
95ef01931fSBen Gras  *	2 for Unix Std (POSIX) tar file,
96ef01931fSBen Gras  *	3 for GNU tar file.
97ef01931fSBen Gras  */
98ef01931fSBen Gras private int
is_tar(const unsigned char * buf,size_t nbytes)99ef01931fSBen Gras is_tar(const unsigned char *buf, size_t nbytes)
100ef01931fSBen Gras {
101ef01931fSBen Gras 	const union record *header = (const union record *)(const void *)buf;
102ef01931fSBen Gras 	int	i;
103ef01931fSBen Gras 	int	sum, recsum;
104835f6802SDirk Vogt 	const unsigned char	*p;
105ef01931fSBen Gras 
106ef01931fSBen Gras 	if (nbytes < sizeof(union record))
107ef01931fSBen Gras 		return 0;
108ef01931fSBen Gras 
109ef01931fSBen Gras 	recsum = from_oct(8,  header->header.chksum);
110ef01931fSBen Gras 
111ef01931fSBen Gras 	sum = 0;
112ef01931fSBen Gras 	p = header->charptr;
113835f6802SDirk Vogt 	for (i = sizeof(union record); --i >= 0;)
114835f6802SDirk Vogt 		sum += *p++;
115ef01931fSBen Gras 
116ef01931fSBen Gras 	/* Adjust checksum to count the "chksum" field as blanks. */
117ef01931fSBen Gras 	for (i = sizeof(header->header.chksum); --i >= 0;)
118835f6802SDirk Vogt 		sum -= header->header.chksum[i];
119ef01931fSBen Gras 	sum += ' ' * sizeof header->header.chksum;
120ef01931fSBen Gras 
121ef01931fSBen Gras 	if (sum != recsum)
122ef01931fSBen Gras 		return 0;	/* Not a tar archive */
123ef01931fSBen Gras 
124ef01931fSBen Gras 	if (strcmp(header->header.magic, GNUTMAGIC) == 0)
125ef01931fSBen Gras 		return 3;		/* GNU Unix Standard tar archive */
126ef01931fSBen Gras 	if (strcmp(header->header.magic, TMAGIC) == 0)
127ef01931fSBen Gras 		return 2;		/* Unix Standard tar archive */
128ef01931fSBen Gras 
129ef01931fSBen Gras 	return 1;			/* Old fashioned tar archive */
130ef01931fSBen Gras }
131ef01931fSBen Gras 
132ef01931fSBen Gras 
133ef01931fSBen Gras /*
134ef01931fSBen Gras  * Quick and dirty octal conversion.
135ef01931fSBen Gras  *
136835f6802SDirk Vogt  * Result is -1 if the field is invalid (all blank, or non-octal).
137ef01931fSBen Gras  */
138ef01931fSBen Gras private int
from_oct(int digs,const char * where)139ef01931fSBen Gras from_oct(int digs, const char *where)
140ef01931fSBen Gras {
141ef01931fSBen Gras 	int	value;
142ef01931fSBen Gras 
143ef01931fSBen Gras 	while (isspace((unsigned char)*where)) {	/* Skip spaces */
144ef01931fSBen Gras 		where++;
145ef01931fSBen Gras 		if (--digs <= 0)
146ef01931fSBen Gras 			return -1;		/* All blank field */
147ef01931fSBen Gras 	}
148ef01931fSBen Gras 	value = 0;
149835f6802SDirk Vogt 	while (digs > 0 && isodigit(*where)) {	/* Scan til non-octal */
150ef01931fSBen Gras 		value = (value << 3) | (*where++ - '0');
151ef01931fSBen Gras 		--digs;
152ef01931fSBen Gras 	}
153ef01931fSBen Gras 
154ef01931fSBen Gras 	if (digs > 0 && *where && !isspace((unsigned char)*where))
155835f6802SDirk Vogt 		return -1;			/* Ended on non-(space/NUL) */
156ef01931fSBen Gras 
157ef01931fSBen Gras 	return value;
158ef01931fSBen Gras }
159