Annotation of src/usr.bin/file/is_tar.c, Revision 1.9
1.9 ! chl 1: /* $OpenBSD: is_tar.c,v 1.8 2008/05/08 01:40:56 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"
1.7 tedu 47:
48: #ifndef lint
1.9 ! chl 49: FILE_RCSID("@(#)$Id: is_tar.c,v 1.8 2008/05/08 01:40:56 chl Exp $")
1.7 tedu 50: #endif
1.1 deraadt 51:
52: #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
53:
1.7 tedu 54: private int is_tar(const unsigned char *, size_t);
55: private int from_oct(int, const char *); /* Decode octal number */
56:
1.9 ! chl 57: static const char tartype[][32] = {
! 58: "tar archive",
! 59: "POSIX tar archive",
! 60: "POSIX tar archive (GNU)",
! 61: };
! 62:
1.7 tedu 63: protected int
64: file_is_tar(struct magic_set *ms, const unsigned char *buf, size_t nbytes)
65: {
66: /*
67: * Do the tar test first, because if the first file in the tar
68: * archive starts with a dot, we can confuse it with an nroff file.
69: */
1.9 ! chl 70: int tar = is_tar(buf, nbytes);
! 71: int mime = ms->flags & MAGIC_MIME;
! 72:
! 73: if (tar < 1 || tar > 3)
1.7 tedu 74: return 0;
1.9 ! chl 75:
! 76: if (mime == MAGIC_MIME_ENCODING)
! 77: return 0;
! 78:
! 79: if (file_printf(ms, mime ? "application/x-tar" :
! 80: tartype[tar - 1]) == -1)
! 81: return -1;
! 82: return 1;
1.7 tedu 83: }
1.1 deraadt 84:
85: /*
86: * Return
87: * 0 if the checksum is bad (i.e., probably not a tar archive),
88: * 1 for old UNIX tar file,
1.9 ! chl 89: * 2 for Unix Std (POSIX) tar file,
! 90: * 3 for GNU tar file.
1.1 deraadt 91: */
1.7 tedu 92: private int
93: is_tar(const unsigned char *buf, size_t nbytes)
1.1 deraadt 94: {
1.7 tedu 95: const union record *header = (const union record *)(const void *)buf;
1.4 mpech 96: int i;
97: int sum, recsum;
1.7 tedu 98: const char *p;
1.1 deraadt 99:
100: if (nbytes < sizeof(union record))
101: return 0;
102:
103: recsum = from_oct(8, header->header.chksum);
104:
105: sum = 0;
106: p = header->charptr;
107: for (i = sizeof(union record); --i >= 0;) {
108: /*
1.7 tedu 109: * We cannot use unsigned char here because of old compilers,
1.1 deraadt 110: * e.g. V7.
111: */
112: sum += 0xFF & *p++;
113: }
114:
115: /* Adjust checksum to count the "chksum" field as blanks. */
116: for (i = sizeof(header->header.chksum); --i >= 0;)
117: sum -= 0xFF & header->header.chksum[i];
118: sum += ' '* sizeof header->header.chksum;
119:
120: if (sum != recsum)
121: return 0; /* Not a tar archive */
122:
1.8 chl 123: if (strcmp(header->header.magic, GNUTMAGIC) == 0)
124: return 3; /* GNU Unix Standard tar archive */
125: if (strcmp(header->header.magic, TMAGIC) == 0)
1.1 deraadt 126: return 2; /* Unix Standard tar archive */
127:
128: return 1; /* Old fashioned tar archive */
129: }
130:
131:
132: /*
133: * Quick and dirty octal conversion.
134: *
135: * Result is -1 if the field is invalid (all blank, or nonoctal).
136: */
1.7 tedu 137: private int
138: from_oct(int digs, const char *where)
1.1 deraadt 139: {
1.4 mpech 140: int value;
1.1 deraadt 141:
1.7 tedu 142: while (isspace((unsigned char)*where)) { /* Skip spaces */
1.1 deraadt 143: where++;
144: if (--digs <= 0)
145: return -1; /* All blank field */
146: }
147: value = 0;
148: while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */
149: value = (value << 3) | (*where++ - '0');
150: --digs;
151: }
152:
1.7 tedu 153: if (digs > 0 && *where && !isspace((unsigned char)*where))
1.1 deraadt 154: return -1; /* Ended on non-space/nul */
155:
156: return value;
157: }