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 43328875SeadlerFILE_RCSID("@(#)$File: is_tar.c,v 1.39 2017/03/17 20:45:01 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); 54328875Seadlerprivate int from_oct(const char *, size_t); /* Decode octal number */ 5568349Sobrien 56186690Sobrienstatic const char tartype[][32] = { 57175296Sobrien "tar archive", 58175296Sobrien "POSIX tar archive", 59175296Sobrien "POSIX tar archive (GNU)", 60175296Sobrien}; 61175296Sobrien 62133359Sobrienprotected int 63133359Sobrienfile_is_tar(struct magic_set *ms, const unsigned char *buf, size_t nbytes) 64133359Sobrien{ 65133359Sobrien /* 66133359Sobrien * Do the tar test first, because if the first file in the tar 67133359Sobrien * archive starts with a dot, we can confuse it with an nroff file. 68133359Sobrien */ 69191736Sobrien int tar; 70175296Sobrien int mime = ms->flags & MAGIC_MIME; 71175296Sobrien 72284778Sdelphij if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0) 73133359Sobrien return 0; 74175296Sobrien 75191736Sobrien tar = is_tar(buf, nbytes); 76191736Sobrien if (tar < 1 || tar > 3) 77175296Sobrien return 0; 78175296Sobrien 79191736Sobrien if (file_printf(ms, "%s", mime ? "application/x-tar" : 80175296Sobrien tartype[tar - 1]) == -1) 81175296Sobrien return -1; 82175296Sobrien return 1; 83133359Sobrien} 84133359Sobrien 8568349Sobrien/* 86226048Sobrien * Return 87226048Sobrien * 0 if the checksum is bad (i.e., probably not a tar archive), 8868349Sobrien * 1 for old UNIX tar file, 89186690Sobrien * 2 for Unix Std (POSIX) tar file, 90186690Sobrien * 3 for GNU tar file. 9168349Sobrien */ 92133359Sobrienprivate int 93133359Sobrienis_tar(const unsigned char *buf, size_t nbytes) 9468349Sobrien{ 95133359Sobrien const union record *header = (const union record *)(const void *)buf; 96328875Seadler size_t i; 97328875Seadler int sum, recsum; 98328875Seadler const unsigned char *p, *ep; 9968349Sobrien 100328875Seadler if (nbytes < sizeof(*header)) 10168349Sobrien return 0; 10268349Sobrien 103328875Seadler recsum = from_oct(header->header.chksum, sizeof(header->header.chksum)); 10468349Sobrien 10568349Sobrien sum = 0; 10668349Sobrien p = header->charptr; 107328875Seadler ep = header->charptr + sizeof(*header); 108328875Seadler while (p < ep) 109226048Sobrien sum += *p++; 11068349Sobrien 11168349Sobrien /* Adjust checksum to count the "chksum" field as blanks. */ 112328875Seadler for (i = 0; i < sizeof(header->header.chksum); i++) 113226048Sobrien sum -= header->header.chksum[i]; 114328875Seadler sum += ' ' * sizeof(header->header.chksum); 11568349Sobrien 11668349Sobrien if (sum != recsum) 11768349Sobrien return 0; /* Not a tar archive */ 118226048Sobrien 119328875Seadler if (strncmp(header->header.magic, GNUTMAGIC, 120328875Seadler sizeof(header->header.magic)) == 0) 121169942Sobrien return 3; /* GNU Unix Standard tar archive */ 122328875Seadler 123328875Seadler if (strncmp(header->header.magic, TMAGIC, 124328875Seadler sizeof(header->header.magic)) == 0) 12568349Sobrien return 2; /* Unix Standard tar archive */ 12668349Sobrien 12768349Sobrien return 1; /* Old fashioned tar archive */ 12868349Sobrien} 12968349Sobrien 13068349Sobrien 13168349Sobrien/* 13268349Sobrien * Quick and dirty octal conversion. 13368349Sobrien * 134226048Sobrien * Result is -1 if the field is invalid (all blank, or non-octal). 13568349Sobrien */ 136133359Sobrienprivate int 137328875Seadlerfrom_oct(const char *where, size_t digs) 13868349Sobrien{ 13968349Sobrien int value; 14068349Sobrien 141328875Seadler if (digs == 0) 142328875Seadler return -1; 143328875Seadler 14468349Sobrien while (isspace((unsigned char)*where)) { /* Skip spaces */ 14568349Sobrien where++; 146328875Seadler if (digs-- == 0) 14768349Sobrien return -1; /* All blank field */ 14868349Sobrien } 14968349Sobrien value = 0; 150226048Sobrien while (digs > 0 && isodigit(*where)) { /* Scan til non-octal */ 15168349Sobrien value = (value << 3) | (*where++ - '0'); 152328875Seadler digs--; 15368349Sobrien } 15468349Sobrien 15568349Sobrien if (digs > 0 && *where && !isspace((unsigned char)*where)) 156226048Sobrien return -1; /* Ended on non-(space/NUL) */ 15768349Sobrien 15868349Sobrien return value; 15968349Sobrien} 160