is_tar.c revision 175296
168349Sobrien/*
2133359Sobrien * Copyright (c) Ian F. Darwin 1986-1995.
3133359Sobrien * Software written by Ian F. Darwin and others;
4133359Sobrien * maintained 1995-present by Christos Zoulas and others.
5133359Sobrien *
6133359Sobrien * Redistribution and use in source and binary forms, with or without
7133359Sobrien * modification, are permitted provided that the following conditions
8133359Sobrien * are met:
9133359Sobrien * 1. Redistributions of source code must retain the above copyright
10133359Sobrien *    notice immediately at the beginning of the file, without modification,
11133359Sobrien *    this list of conditions, and the following disclaimer.
12133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright
13133359Sobrien *    notice, this list of conditions and the following disclaimer in the
14133359Sobrien *    documentation and/or other materials provided with the distribution.
15133359Sobrien *
16133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20133359Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26133359Sobrien * SUCH DAMAGE.
27133359Sobrien */
28133359Sobrien/*
2968349Sobrien * is_tar() -- figure out whether file is a tar archive.
3068349Sobrien *
3168349Sobrien * Stolen (by the author!) from the public domain tar program:
3268349Sobrien * Public Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
3368349Sobrien *
3468349Sobrien * @(#)list.c 1.18 9/23/86 Public Domain - gnu
3568349Sobrien *
3668349Sobrien * Comments changed and some code/comments reformatted
3768349Sobrien * for file command by Ian Darwin.
3868349Sobrien */
3968349Sobrien
40103373Sobrien#include "file.h"
41133359Sobrien#include "magic.h"
4268349Sobrien#include <string.h>
4368349Sobrien#include <ctype.h>
4468349Sobrien#include <sys/types.h>
4568349Sobrien#include "tar.h"
4668349Sobrien
4768349Sobrien#ifndef lint
48175296SobrienFILE_RCSID("@(#)$File: is_tar.c,v 1.29 2007/10/17 19:33:31 christos Exp $")
4968349Sobrien#endif
5068349Sobrien
5168349Sobrien#define	isodigit(c)	( ((c) >= '0') && ((c) <= '7') )
5268349Sobrien
53133359Sobrienprivate int is_tar(const unsigned char *, size_t);
54133359Sobrienprivate int from_oct(int, const char *);	/* Decode octal number */
5568349Sobrien
56175296Sobrienstatic const char *tartype[] = {
57175296Sobrien	"tar archive",
58175296Sobrien	"POSIX tar archive",
59175296Sobrien	"POSIX tar archive (GNU)",
60175296Sobrien};
61175296Sobrien
62133359Sobrienprotected int
63133359Sobrienfile_is_tar(struct magic_set *ms, const unsigned char *buf, size_t nbytes)
64133359Sobrien{
65133359Sobrien	/*
66133359Sobrien	 * Do the tar test first, because if the first file in the tar
67133359Sobrien	 * archive starts with a dot, we can confuse it with an nroff file.
68133359Sobrien	 */
69175296Sobrien	int tar = is_tar(buf, nbytes);
70175296Sobrien	int mime = ms->flags & MAGIC_MIME;
71175296Sobrien
72175296Sobrien	if (tar < 1 || tar > 3)
73133359Sobrien		return 0;
74175296Sobrien
75175296Sobrien	if (mime == MAGIC_MIME_ENCODING)
76175296Sobrien		return 0;
77175296Sobrien
78175296Sobrien	if (file_printf(ms, mime ? "application/x-tar" :
79175296Sobrien	    tartype[tar - 1]) == -1)
80175296Sobrien		return -1;
81175296Sobrien	return 1;
82133359Sobrien}
83133359Sobrien
8468349Sobrien/*
8568349Sobrien * Return
8668349Sobrien *	0 if the checksum is bad (i.e., probably not a tar archive),
8768349Sobrien *	1 for old UNIX tar file,
8868349Sobrien *	2 for Unix Std (POSIX) tar file.
8968349Sobrien */
90133359Sobrienprivate int
91133359Sobrienis_tar(const unsigned char *buf, size_t nbytes)
9268349Sobrien{
93133359Sobrien	const union record *header = (const union record *)(const void *)buf;
9468349Sobrien	int	i;
9568349Sobrien	int	sum, recsum;
96133359Sobrien	const char	*p;
9768349Sobrien
9868349Sobrien	if (nbytes < sizeof(union record))
9968349Sobrien		return 0;
10068349Sobrien
10168349Sobrien	recsum = from_oct(8,  header->header.chksum);
10268349Sobrien
10368349Sobrien	sum = 0;
10468349Sobrien	p = header->charptr;
10568349Sobrien	for (i = sizeof(union record); --i >= 0;) {
10668349Sobrien		/*
107133359Sobrien		 * We cannot use unsigned char here because of old compilers,
10868349Sobrien		 * e.g. V7.
10968349Sobrien		 */
11068349Sobrien		sum += 0xFF & *p++;
11168349Sobrien	}
11268349Sobrien
11368349Sobrien	/* Adjust checksum to count the "chksum" field as blanks. */
11468349Sobrien	for (i = sizeof(header->header.chksum); --i >= 0;)
11568349Sobrien		sum -= 0xFF & header->header.chksum[i];
11668349Sobrien	sum += ' '* sizeof header->header.chksum;
11768349Sobrien
11868349Sobrien	if (sum != recsum)
11968349Sobrien		return 0;	/* Not a tar archive */
12068349Sobrien
121169942Sobrien	if (strcmp(header->header.magic, GNUTMAGIC) == 0)
122169942Sobrien		return 3;		/* GNU Unix Standard tar archive */
123169942Sobrien	if (strcmp(header->header.magic, TMAGIC) == 0)
12468349Sobrien		return 2;		/* Unix Standard tar archive */
12568349Sobrien
12668349Sobrien	return 1;			/* Old fashioned tar archive */
12768349Sobrien}
12868349Sobrien
12968349Sobrien
13068349Sobrien/*
13168349Sobrien * Quick and dirty octal conversion.
13268349Sobrien *
13368349Sobrien * Result is -1 if the field is invalid (all blank, or nonoctal).
13468349Sobrien */
135133359Sobrienprivate int
136133359Sobrienfrom_oct(int digs, const char *where)
13768349Sobrien{
13868349Sobrien	int	value;
13968349Sobrien
14068349Sobrien	while (isspace((unsigned char)*where)) {	/* Skip spaces */
14168349Sobrien		where++;
14268349Sobrien		if (--digs <= 0)
14368349Sobrien			return -1;		/* All blank field */
14468349Sobrien	}
14568349Sobrien	value = 0;
14668349Sobrien	while (digs > 0 && isodigit(*where)) {	/* Scan til nonoctal */
14768349Sobrien		value = (value << 3) | (*where++ - '0');
14868349Sobrien		--digs;
14968349Sobrien	}
15068349Sobrien
15168349Sobrien	if (digs > 0 && *where && !isspace((unsigned char)*where))
15268349Sobrien		return -1;			/* Ended on non-space/nul */
15368349Sobrien
15468349Sobrien	return value;
15568349Sobrien}
156