is_tar.c revision 175296
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. 5133359Sobrien * 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. 15133359Sobrien * 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" 41133359Sobrien#include "magic.h" 4268349Sobrien#include <string.h> 4368349Sobrien#include <ctype.h> 4468349Sobrien#include <sys/types.h> 4568349Sobrien#include "tar.h" 4668349Sobrien 4768349Sobrien#ifndef lint 48175296SobrienFILE_RCSID("@(#)$File: is_tar.c,v 1.29 2007/10/17 19:33:31 christos Exp $") 4968349Sobrien#endif 5068349Sobrien 5168349Sobrien#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') ) 5268349Sobrien 53133359Sobrienprivate int is_tar(const unsigned char *, size_t); 54133359Sobrienprivate int from_oct(int, const char *); /* Decode octal number */ 5568349Sobrien 56175296Sobrienstatic const char *tartype[] = { 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 */ 69175296Sobrien int tar = is_tar(buf, nbytes); 70175296Sobrien int mime = ms->flags & MAGIC_MIME; 71175296Sobrien 72175296Sobrien if (tar < 1 || tar > 3) 73133359Sobrien return 0; 74175296Sobrien 75175296Sobrien if (mime == MAGIC_MIME_ENCODING) 76175296Sobrien return 0; 77175296Sobrien 78175296Sobrien if (file_printf(ms, mime ? "application/x-tar" : 79175296Sobrien tartype[tar - 1]) == -1) 80175296Sobrien return -1; 81175296Sobrien return 1; 82133359Sobrien} 83133359Sobrien 8468349Sobrien/* 8568349Sobrien * Return 8668349Sobrien * 0 if the checksum is bad (i.e., probably not a tar archive), 8768349Sobrien * 1 for old UNIX tar file, 8868349Sobrien * 2 for Unix Std (POSIX) tar file. 8968349Sobrien */ 90133359Sobrienprivate int 91133359Sobrienis_tar(const unsigned char *buf, size_t nbytes) 9268349Sobrien{ 93133359Sobrien const union record *header = (const union record *)(const void *)buf; 9468349Sobrien int i; 9568349Sobrien int sum, recsum; 96133359Sobrien const char *p; 9768349Sobrien 9868349Sobrien if (nbytes < sizeof(union record)) 9968349Sobrien return 0; 10068349Sobrien 10168349Sobrien recsum = from_oct(8, header->header.chksum); 10268349Sobrien 10368349Sobrien sum = 0; 10468349Sobrien p = header->charptr; 10568349Sobrien for (i = sizeof(union record); --i >= 0;) { 10668349Sobrien /* 107133359Sobrien * We cannot use unsigned char here because of old compilers, 10868349Sobrien * e.g. V7. 10968349Sobrien */ 11068349Sobrien sum += 0xFF & *p++; 11168349Sobrien } 11268349Sobrien 11368349Sobrien /* Adjust checksum to count the "chksum" field as blanks. */ 11468349Sobrien for (i = sizeof(header->header.chksum); --i >= 0;) 11568349Sobrien sum -= 0xFF & header->header.chksum[i]; 11668349Sobrien sum += ' '* sizeof header->header.chksum; 11768349Sobrien 11868349Sobrien if (sum != recsum) 11968349Sobrien return 0; /* Not a tar archive */ 12068349Sobrien 121169942Sobrien if (strcmp(header->header.magic, GNUTMAGIC) == 0) 122169942Sobrien return 3; /* GNU Unix Standard tar archive */ 123169942Sobrien if (strcmp(header->header.magic, TMAGIC) == 0) 12468349Sobrien return 2; /* Unix Standard tar archive */ 12568349Sobrien 12668349Sobrien return 1; /* Old fashioned tar archive */ 12768349Sobrien} 12868349Sobrien 12968349Sobrien 13068349Sobrien/* 13168349Sobrien * Quick and dirty octal conversion. 13268349Sobrien * 13368349Sobrien * Result is -1 if the field is invalid (all blank, or nonoctal). 13468349Sobrien */ 135133359Sobrienprivate int 136133359Sobrienfrom_oct(int digs, const char *where) 13768349Sobrien{ 13868349Sobrien int value; 13968349Sobrien 14068349Sobrien while (isspace((unsigned char)*where)) { /* Skip spaces */ 14168349Sobrien where++; 14268349Sobrien if (--digs <= 0) 14368349Sobrien return -1; /* All blank field */ 14468349Sobrien } 14568349Sobrien value = 0; 14668349Sobrien while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */ 14768349Sobrien value = (value << 3) | (*where++ - '0'); 14868349Sobrien --digs; 14968349Sobrien } 15068349Sobrien 15168349Sobrien if (digs > 0 && *where && !isspace((unsigned char)*where)) 15268349Sobrien return -1; /* Ended on non-space/nul */ 15368349Sobrien 15468349Sobrien return value; 15568349Sobrien} 156