magic.c revision 133359
1/* 2 * Copyright (c) Christos Zoulas 2003. 3 * All Rights Reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice immediately at the beginning of the file, without modification, 10 * this list of conditions, and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 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 */ 29 30#include "file.h" 31#include "magic.h" 32 33#include <stdio.h> 34#include <stdlib.h> 35#include <unistd.h> 36#include <string.h> 37#include <sys/types.h> 38#include <sys/param.h> /* for MAXPATHLEN */ 39#include <sys/stat.h> 40#include <fcntl.h> /* for open() */ 41#ifdef QUICK 42#include <sys/mman.h> 43#endif 44 45#if defined(HAVE_UTIMES) 46# include <sys/time.h> 47#elif defined(HAVE_UTIME) 48# if defined(HAVE_SYS_UTIME_H) 49# include <sys/utime.h> 50# elif defined(HAVE_UTIME_H) 51# include <utime.h> 52# endif 53#endif 54 55#ifdef HAVE_UNISTD_H 56#include <unistd.h> /* for read() */ 57#endif 58 59#ifdef HAVE_LOCALE_H 60#include <locale.h> 61#endif 62 63#include <netinet/in.h> /* for byte swapping */ 64 65#include "patchlevel.h" 66 67#ifndef lint 68FILE_RCSID("@(#)$Id: magic.c,v 1.22 2004/07/24 19:55:17 christos Exp $") 69#endif /* lint */ 70 71#ifdef __EMX__ 72private char *apptypeName = NULL; 73protected int file_os2_apptype(struct magic_set *ms, const char *fn, 74 const void *buf, size_t nb); 75#endif /* __EMX__ */ 76 77private void free_mlist(struct mlist *); 78private void close_and_restore(const struct magic_set *, const char *, int, 79 const struct stat *); 80 81public struct magic_set * 82magic_open(int flags) 83{ 84 struct magic_set *ms; 85 86 if ((ms = malloc(sizeof(struct magic_set))) == NULL) 87 return NULL; 88 89 if (magic_setflags(ms, flags) == -1) { 90 free(ms); 91 errno = EINVAL; 92 return NULL; 93 } 94 95 ms->o.ptr = ms->o.buf = malloc(ms->o.size = 1024); 96 ms->o.len = 0; 97 if (ms->o.buf == NULL) { 98 free(ms); 99 return NULL; 100 } 101 ms->o.pbuf = malloc(ms->o.psize = 1024); 102 if (ms->o.pbuf == NULL) { 103 free(ms->o.buf); 104 free(ms); 105 return NULL; 106 } 107 ms->c.off = malloc((ms->c.len = 10) * sizeof(*ms->c.off)); 108 if (ms->c.off == NULL) { 109 free(ms->o.pbuf); 110 free(ms->o.buf); 111 free(ms); 112 return NULL; 113 } 114 ms->haderr = 0; 115 ms->error = -1; 116 ms->mlist = NULL; 117 return ms; 118} 119 120private void 121free_mlist(struct mlist *mlist) 122{ 123 struct mlist *ml; 124 125 if (mlist == NULL) 126 return; 127 128 for (ml = mlist->next; ml != mlist;) { 129 struct mlist *next = ml->next; 130 struct magic *mg = ml->magic; 131 file_delmagic(mg, ml->mapped, ml->nmagic); 132 free(ml); 133 ml = next; 134 } 135 free(ml); 136} 137 138public void 139magic_close(ms) 140 struct magic_set *ms; 141{ 142 free_mlist(ms->mlist); 143 free(ms->o.buf); 144 free(ms->c.off); 145 free(ms); 146} 147 148/* 149 * load a magic file 150 */ 151public int 152magic_load(struct magic_set *ms, const char *magicfile) 153{ 154 struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD); 155 if (ml) { 156 free_mlist(ms->mlist); 157 ms->mlist = ml; 158 return 0; 159 } 160 return -1; 161} 162 163public int 164magic_compile(struct magic_set *ms, const char *magicfile) 165{ 166 struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE); 167 free_mlist(ml); 168 return ml ? 0 : -1; 169} 170 171public int 172magic_check(struct magic_set *ms, const char *magicfile) 173{ 174 struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK); 175 free_mlist(ml); 176 return ml ? 0 : -1; 177} 178 179private void 180close_and_restore(const struct magic_set *ms, const char *name, int fd, 181 const struct stat *sb) 182{ 183 (void) close(fd); 184 if (fd != STDIN_FILENO && (ms->flags & MAGIC_PRESERVE_ATIME) != 0) { 185 /* 186 * Try to restore access, modification times if read it. 187 * This is really *bad* because it will modify the status 188 * time of the file... And of course this will affect 189 * backup programs 190 */ 191#ifdef HAVE_UTIMES 192 struct timeval utsbuf[2]; 193 utsbuf[0].tv_sec = sb->st_atime; 194 utsbuf[1].tv_sec = sb->st_mtime; 195 196 (void) utimes(name, utsbuf); /* don't care if loses */ 197#elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H) 198 struct utimbuf utbuf; 199 200 utbuf.actime = sb->st_atime; 201 utbuf.modtime = sb->st_mtime; 202 (void) utime(name, &utbuf); /* don't care if loses */ 203#endif 204 } 205} 206 207#ifndef COMPILE_ONLY 208/* 209 * find type of named file 210 */ 211public const char * 212magic_file(struct magic_set *ms, const char *inname) 213{ 214 int fd = 0; 215 unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */ 216 struct stat sb; 217 ssize_t nbytes = 0; /* number of bytes read from a datafile */ 218 219 if (file_reset(ms) == -1) 220 return NULL; 221 222 switch (file_fsmagic(ms, inname, &sb)) { 223 case -1: 224 return NULL; 225 case 0: 226 break; 227 default: 228 return file_getbuffer(ms); 229 } 230 231#ifndef STDIN_FILENO 232#define STDIN_FILENO 0 233#endif 234 if (inname == NULL) 235 fd = STDIN_FILENO; 236 else if ((fd = open(inname, O_RDONLY)) < 0) { 237 /* We cannot open it, but we were able to stat it. */ 238 if (sb.st_mode & 0222) 239 if (file_printf(ms, "writable, ") == -1) 240 return NULL; 241 if (sb.st_mode & 0111) 242 if (file_printf(ms, "executable, ") == -1) 243 return NULL; 244 if (S_ISREG(sb.st_mode)) 245 if (file_printf(ms, "regular file, ") == -1) 246 return NULL; 247 if (file_printf(ms, "no read permission") == -1) 248 return NULL; 249 return file_getbuffer(ms); 250 } 251 252 /* 253 * try looking at the first HOWMANY bytes 254 */ 255 if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) { 256 file_error(ms, errno, "cannot read `%s'", inname); 257 goto done; 258 } 259 260 if (nbytes == 0) { 261 if (file_printf(ms, (ms->flags & MAGIC_MIME) ? 262 "application/x-empty" : "empty") == -1) 263 goto done; 264 goto gotit; 265 } else if (nbytes == 1) { 266 if (file_printf(ms, "very short file (no magic)") == -1) 267 goto done; 268 goto gotit; 269 } else { 270 buf[nbytes] = '\0'; /* null-terminate it */ 271#ifdef __EMX__ 272 switch (file_os2_apptype(ms, inname, buf, nbytes)) { 273 case -1: 274 goto done; 275 case 0: 276 break; 277 default: 278 goto gotit; 279 } 280#endif 281 if (file_buffer(ms, buf, (size_t)nbytes) == -1) 282 goto done; 283#ifdef BUILTIN_ELF 284 if (nbytes > 5) { 285 /* 286 * We matched something in the file, so this *might* 287 * be an ELF file, and the file is at least 5 bytes 288 * long, so if it's an ELF file it has at least one 289 * byte past the ELF magic number - try extracting 290 * information from the ELF headers that cannot easily 291 * be extracted with rules in the magic file. 292 */ 293 file_tryelf(ms, fd, buf, (size_t)nbytes); 294 } 295#endif 296 } 297gotit: 298 close_and_restore(ms, inname, fd, &sb); 299 return file_getbuffer(ms); 300done: 301 close_and_restore(ms, inname, fd, &sb); 302 return NULL; 303} 304 305 306public const char * 307magic_buffer(struct magic_set *ms, const void *buf, size_t nb) 308{ 309 if (file_reset(ms) == -1) 310 return NULL; 311 /* 312 * The main work is done here! 313 * We have the file name and/or the data buffer to be identified. 314 */ 315 if (file_buffer(ms, buf, nb) == -1) { 316 return NULL; 317 } 318 return file_getbuffer(ms); 319} 320#endif 321 322public const char * 323magic_error(struct magic_set *ms) 324{ 325 return ms->haderr ? ms->o.buf : NULL; 326} 327 328public int 329magic_errno(struct magic_set *ms) 330{ 331 return ms->haderr ? ms->error : 0; 332} 333 334public int 335magic_setflags(struct magic_set *ms, int flags) 336{ 337#if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES) 338 if (flags & MAGIC_PRESERVE_ATIME) 339 return -1; 340#endif 341 ms->flags = flags; 342 return 0; 343} 344