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