Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/file/src/is_tar.c
39478 views
1
/*
2
* Copyright (c) Ian F. Darwin 1986-1995.
3
* Software written by Ian F. Darwin and others;
4
* maintained 1995-present by Christos Zoulas and others.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice immediately at the beginning of the file, without modification,
11
* this list of conditions, and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
/*
29
* is_tar() -- figure out whether file is a tar archive.
30
*
31
* Stolen (by the author!) from the file_public domain tar program:
32
* Public Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
33
*
34
* @(#)list.c 1.18 9/23/86 Public Domain - gnu
35
*
36
* Comments changed and some code/comments reformatted
37
* for file command by Ian Darwin.
38
*/
39
40
#include "file.h"
41
42
#ifndef lint
43
FILE_RCSID("@(#)$File: is_tar.c,v 1.50 2022/12/26 17:31:14 christos Exp $")
44
#endif
45
46
#include "magic.h"
47
#include <string.h>
48
#include <ctype.h>
49
#include "tar.h"
50
51
#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
52
53
file_private int is_tar(const unsigned char *, size_t);
54
file_private int from_oct(const char *, size_t); /* Decode octal number */
55
56
static const char tartype[][32] = { /* should be equal to messages */
57
"tar archive", /* found in ../magic/Magdir/archive */
58
"POSIX tar archive",
59
"POSIX tar archive (GNU)", /* */
60
};
61
62
file_protected int
63
file_is_tar(struct magic_set *ms, const struct buffer *b)
64
{
65
const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
66
size_t nbytes = b->flen;
67
/*
68
* Do the tar test first, because if the first file in the tar
69
* archive starts with a dot, we can confuse it with an nroff file.
70
*/
71
int tar;
72
int mime = ms->flags & MAGIC_MIME;
73
74
if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0)
75
return 0;
76
77
tar = is_tar(buf, nbytes);
78
if (tar < 1 || tar > 3)
79
return 0;
80
81
if (mime == MAGIC_MIME_ENCODING)
82
return 1;
83
84
if (file_printf(ms, "%s", mime ? "application/x-tar" :
85
tartype[tar - 1]) == -1)
86
return -1;
87
88
return 1;
89
}
90
91
/*
92
* Return
93
* 0 if the checksum is bad (i.e., probably not a tar archive),
94
* 1 for old UNIX tar file,
95
* 2 for Unix Std (POSIX) tar file,
96
* 3 for GNU tar file.
97
*/
98
file_private int
99
is_tar(const unsigned char *buf, size_t nbytes)
100
{
101
static const char gpkg_match[] = "/gpkg-1";
102
103
const union record *header = RCAST(const union record *,
104
RCAST(const void *, buf));
105
size_t i;
106
int sum, recsum;
107
const unsigned char *p, *ep;
108
const char *nulp;
109
110
if (nbytes < sizeof(*header))
111
return 0;
112
113
/* If the file looks like Gentoo GLEP 78 binary package (GPKG),
114
* don't waste time on further checks and fall back to magic rules.
115
*/
116
nulp = CAST(const char *,
117
memchr(header->header.name, 0, sizeof(header->header.name)));
118
if (nulp != NULL && nulp >= header->header.name + sizeof(gpkg_match) &&
119
memcmp(nulp - sizeof(gpkg_match) + 1, gpkg_match,
120
sizeof(gpkg_match)) == 0)
121
return 0;
122
123
recsum = from_oct(header->header.chksum, sizeof(header->header.chksum));
124
125
sum = 0;
126
p = header->charptr;
127
ep = header->charptr + sizeof(*header);
128
while (p < ep)
129
sum += *p++;
130
131
/* Adjust checksum to count the "chksum" field as blanks. */
132
for (i = 0; i < sizeof(header->header.chksum); i++)
133
sum -= header->header.chksum[i];
134
sum += ' ' * sizeof(header->header.chksum);
135
136
if (sum != recsum)
137
return 0; /* Not a tar archive */
138
139
if (strncmp(header->header.magic, GNUTMAGIC,
140
sizeof(header->header.magic)) == 0)
141
return 3; /* GNU Unix Standard tar archive */
142
143
if (strncmp(header->header.magic, TMAGIC,
144
sizeof(header->header.magic)) == 0)
145
return 2; /* Unix Standard tar archive */
146
147
return 1; /* Old fashioned tar archive */
148
}
149
150
151
/*
152
* Quick and dirty octal conversion.
153
*
154
* Result is -1 if the field is invalid (all blank, or non-octal).
155
*/
156
file_private int
157
from_oct(const char *where, size_t digs)
158
{
159
int value;
160
161
if (digs == 0)
162
return -1;
163
164
while (isspace(CAST(unsigned char, *where))) { /* Skip spaces */
165
where++;
166
if (digs-- == 0)
167
return -1; /* All blank field */
168
}
169
value = 0;
170
while (digs > 0 && isodigit(*where)) { /* Scan til non-octal */
171
value = (value << 3) | (*where++ - '0');
172
digs--;
173
}
174
175
if (digs > 0 && *where && !isspace(CAST(unsigned char, *where)))
176
return -1; /* Ended on non-(space/NUL) */
177
178
return value;
179
}
180
181