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