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. 5226048Sobrien * 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. 15226048Sobrien * 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" 41191736Sobrien 42191736Sobrien#ifndef lint 43354939SdelphijFILE_RCSID("@(#)$File: is_tar.c,v 1.44 2019/02/20 02:35:27 christos Exp $") 44191736Sobrien#endif 45191736Sobrien 46133359Sobrien#include "magic.h" 4768349Sobrien#include <string.h> 4868349Sobrien#include <ctype.h> 4968349Sobrien#include "tar.h" 5068349Sobrien 5168349Sobrien#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') ) 5268349Sobrien 53133359Sobrienprivate int is_tar(const unsigned char *, size_t); 54328874Seadlerprivate int from_oct(const char *, size_t); /* Decode octal number */ 5568349Sobrien 56337827Seadlerstatic const char tartype[][32] = { /* should be equal to messages */ 57337827Seadler "tar archive", /* found in ../magic/Magdir/archive */ 58175296Sobrien "POSIX tar archive", 59337827Seadler "POSIX tar archive (GNU)", /* */ 60175296Sobrien}; 61175296Sobrien 62133359Sobrienprotected int 63337827Seadlerfile_is_tar(struct magic_set *ms, const struct buffer *b) 64133359Sobrien{ 65354939Sdelphij const unsigned char *buf = CAST(const unsigned char *, b->fbuf); 66337827Seadler size_t nbytes = b->flen; 67133359Sobrien /* 68133359Sobrien * Do the tar test first, because if the first file in the tar 69133359Sobrien * archive starts with a dot, we can confuse it with an nroff file. 70133359Sobrien */ 71191736Sobrien int tar; 72175296Sobrien int mime = ms->flags & MAGIC_MIME; 73175296Sobrien 74284237Sdelphij if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0) 75133359Sobrien return 0; 76175296Sobrien 77191736Sobrien tar = is_tar(buf, nbytes); 78191736Sobrien if (tar < 1 || tar > 3) 79175296Sobrien return 0; 80175296Sobrien 81354939Sdelphij if (mime == MAGIC_MIME_ENCODING) 82354939Sdelphij return 1; 83354939Sdelphij 84191736Sobrien if (file_printf(ms, "%s", mime ? "application/x-tar" : 85175296Sobrien tartype[tar - 1]) == -1) 86175296Sobrien return -1; 87354939Sdelphij 88175296Sobrien return 1; 89133359Sobrien} 90133359Sobrien 9168349Sobrien/* 92226048Sobrien * Return 93226048Sobrien * 0 if the checksum is bad (i.e., probably not a tar archive), 9468349Sobrien * 1 for old UNIX tar file, 95186690Sobrien * 2 for Unix Std (POSIX) tar file, 96186690Sobrien * 3 for GNU tar file. 9768349Sobrien */ 98133359Sobrienprivate int 99133359Sobrienis_tar(const unsigned char *buf, size_t nbytes) 10068349Sobrien{ 101354939Sdelphij const union record *header = RCAST(const union record *, 102354939Sdelphij RCAST(const void *, buf)); 103328874Seadler size_t i; 104328874Seadler int sum, recsum; 105328874Seadler const unsigned char *p, *ep; 10668349Sobrien 107328874Seadler if (nbytes < sizeof(*header)) 10868349Sobrien return 0; 10968349Sobrien 110328874Seadler recsum = from_oct(header->header.chksum, sizeof(header->header.chksum)); 11168349Sobrien 11268349Sobrien sum = 0; 11368349Sobrien p = header->charptr; 114328874Seadler ep = header->charptr + sizeof(*header); 115328874Seadler while (p < ep) 116226048Sobrien sum += *p++; 11768349Sobrien 11868349Sobrien /* Adjust checksum to count the "chksum" field as blanks. */ 119328874Seadler for (i = 0; i < sizeof(header->header.chksum); i++) 120226048Sobrien sum -= header->header.chksum[i]; 121328874Seadler sum += ' ' * sizeof(header->header.chksum); 12268349Sobrien 12368349Sobrien if (sum != recsum) 12468349Sobrien return 0; /* Not a tar archive */ 125226048Sobrien 126328874Seadler if (strncmp(header->header.magic, GNUTMAGIC, 127328874Seadler sizeof(header->header.magic)) == 0) 128169942Sobrien return 3; /* GNU Unix Standard tar archive */ 129328874Seadler 130328874Seadler if (strncmp(header->header.magic, TMAGIC, 131328874Seadler sizeof(header->header.magic)) == 0) 13268349Sobrien return 2; /* Unix Standard tar archive */ 13368349Sobrien 13468349Sobrien return 1; /* Old fashioned tar archive */ 13568349Sobrien} 13668349Sobrien 13768349Sobrien 13868349Sobrien/* 13968349Sobrien * Quick and dirty octal conversion. 14068349Sobrien * 141226048Sobrien * Result is -1 if the field is invalid (all blank, or non-octal). 14268349Sobrien */ 143133359Sobrienprivate int 144328874Seadlerfrom_oct(const char *where, size_t digs) 14568349Sobrien{ 14668349Sobrien int value; 14768349Sobrien 148328874Seadler if (digs == 0) 149328874Seadler return -1; 150328874Seadler 151354939Sdelphij while (isspace(CAST(unsigned char, *where))) { /* Skip spaces */ 15268349Sobrien where++; 153328874Seadler if (digs-- == 0) 15468349Sobrien return -1; /* All blank field */ 15568349Sobrien } 15668349Sobrien value = 0; 157226048Sobrien while (digs > 0 && isodigit(*where)) { /* Scan til non-octal */ 15868349Sobrien value = (value << 3) | (*where++ - '0'); 159328874Seadler digs--; 16068349Sobrien } 16168349Sobrien 162354939Sdelphij if (digs > 0 && *where && !isspace(CAST(unsigned char, *where))) 163226048Sobrien return -1; /* Ended on non-(space/NUL) */ 16468349Sobrien 16568349Sobrien return value; 16668349Sobrien} 167