magic.c revision 175296
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 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include "file.h" 29#include "magic.h" 30 31#include <stdio.h> 32#include <stdlib.h> 33#include <unistd.h> 34#include <string.h> 35#include <sys/types.h> 36#include <sys/param.h> /* for MAXPATHLEN */ 37#include <sys/stat.h> 38#ifdef QUICK 39#include <sys/mman.h> 40#endif 41#include <limits.h> /* for PIPE_BUF */ 42 43#if defined(HAVE_UTIMES) 44# include <sys/time.h> 45#elif defined(HAVE_UTIME) 46# if defined(HAVE_SYS_UTIME_H) 47# include <sys/utime.h> 48# elif defined(HAVE_UTIME_H) 49# include <utime.h> 50# endif 51#endif 52 53#ifdef HAVE_UNISTD_H 54#include <unistd.h> /* for read() */ 55#endif 56 57#ifdef HAVE_LOCALE_H 58#include <locale.h> 59#endif 60 61#include <netinet/in.h> /* for byte swapping */ 62 63#include "patchlevel.h" 64 65#ifndef lint 66FILE_RCSID("@(#)$File: magic.c,v 1.45 2007/12/27 16:35:59 christos Exp $") 67#endif /* lint */ 68 69#ifdef __EMX__ 70private char *apptypeName = NULL; 71protected int file_os2_apptype(struct magic_set *ms, const char *fn, 72 const void *buf, size_t nb); 73#endif /* __EMX__ */ 74 75private void free_mlist(struct mlist *); 76private void close_and_restore(const struct magic_set *, const char *, int, 77 const struct stat *); 78private int info_from_stat(struct magic_set *, mode_t); 79#ifndef COMPILE_ONLY 80private const char *file_or_fd(struct magic_set *, const char *, int); 81#endif 82 83#ifndef STDIN_FILENO 84#define STDIN_FILENO 0 85#endif 86 87public struct magic_set * 88magic_open(int flags) 89{ 90 struct magic_set *ms; 91 92 if ((ms = calloc((size_t)1, sizeof(struct magic_set))) == NULL) 93 return NULL; 94 95 if (magic_setflags(ms, flags) == -1) { 96 errno = EINVAL; 97 goto free1; 98 } 99 100 ms->o.ptr = ms->o.buf = malloc(ms->o.left = ms->o.size = 1024); 101 if (ms->o.buf == NULL) 102 goto free1; 103 104 ms->o.pbuf = malloc(ms->o.psize = 1024); 105 if (ms->o.pbuf == NULL) 106 goto free2; 107 108 ms->c.li = malloc((ms->c.len = 10) * sizeof(*ms->c.li)); 109 if (ms->c.li == NULL) 110 goto free3; 111 112 ms->haderr = 0; 113 ms->error = -1; 114 ms->mlist = NULL; 115 ms->file = "unknown"; 116 ms->line = 0; 117 return ms; 118free3: 119 free(ms->o.pbuf); 120free2: 121 free(ms->o.buf); 122free1: 123 free(ms); 124 return NULL; 125} 126 127private void 128free_mlist(struct mlist *mlist) 129{ 130 struct mlist *ml; 131 132 if (mlist == NULL) 133 return; 134 135 for (ml = mlist->next; ml != mlist;) { 136 struct mlist *next = ml->next; 137 struct magic *mg = ml->magic; 138 file_delmagic(mg, ml->mapped, ml->nmagic); 139 free(ml); 140 ml = next; 141 } 142 free(ml); 143} 144 145private int 146info_from_stat(struct magic_set *ms, mode_t md) 147{ 148 /* We cannot open it, but we were able to stat it. */ 149 if (md & 0222) 150 if (file_printf(ms, "writable, ") == -1) 151 return -1; 152 if (md & 0111) 153 if (file_printf(ms, "executable, ") == -1) 154 return -1; 155 if (S_ISREG(md)) 156 if (file_printf(ms, "regular file, ") == -1) 157 return -1; 158 if (file_printf(ms, "no read permission") == -1) 159 return -1; 160 return 0; 161} 162 163public void 164magic_close(struct magic_set *ms) 165{ 166 free_mlist(ms->mlist); 167 free(ms->o.pbuf); 168 free(ms->o.buf); 169 free(ms->c.li); 170 free(ms); 171} 172 173/* 174 * load a magic file 175 */ 176public int 177magic_load(struct magic_set *ms, const char *magicfile) 178{ 179 struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD); 180 if (ml) { 181 free_mlist(ms->mlist); 182 ms->mlist = ml; 183 return 0; 184 } 185 return -1; 186} 187 188public int 189magic_compile(struct magic_set *ms, const char *magicfile) 190{ 191 struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE); 192 free_mlist(ml); 193 return ml ? 0 : -1; 194} 195 196public int 197magic_check(struct magic_set *ms, const char *magicfile) 198{ 199 struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK); 200 free_mlist(ml); 201 return ml ? 0 : -1; 202} 203 204private void 205close_and_restore(const struct magic_set *ms, const char *name, int fd, 206 const struct stat *sb) 207{ 208 if (fd == STDIN_FILENO) 209 return; 210 (void) close(fd); 211 212 if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) { 213 /* 214 * Try to restore access, modification times if read it. 215 * This is really *bad* because it will modify the status 216 * time of the file... And of course this will affect 217 * backup programs 218 */ 219#ifdef HAVE_UTIMES 220 struct timeval utsbuf[2]; 221 utsbuf[0].tv_sec = sb->st_atime; 222 utsbuf[1].tv_sec = sb->st_mtime; 223 224 (void) utimes(name, utsbuf); /* don't care if loses */ 225#elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H) 226 struct utimbuf utbuf; 227 228 utbuf.actime = sb->st_atime; 229 utbuf.modtime = sb->st_mtime; 230 (void) utime(name, &utbuf); /* don't care if loses */ 231#endif 232 } 233} 234 235#ifndef COMPILE_ONLY 236 237/* 238 * find type of descriptor 239 */ 240public const char * 241magic_descriptor(struct magic_set *ms, int fd) 242{ 243 return file_or_fd(ms, NULL, fd); 244} 245 246/* 247 * find type of named file 248 */ 249public const char * 250magic_file(struct magic_set *ms, const char *inname) 251{ 252 return file_or_fd(ms, inname, STDIN_FILENO); 253} 254 255private const char * 256file_or_fd(struct magic_set *ms, const char *inname, int fd) 257{ 258 int rv = -1; 259 unsigned char *buf; 260 struct stat sb; 261 ssize_t nbytes = 0; /* number of bytes read from a datafile */ 262 int ispipe = 0; 263 264 /* 265 * one extra for terminating '\0', and 266 * some overlapping space for matches near EOF 267 */ 268#define SLOP (1 + sizeof(union VALUETYPE)) 269 if ((buf = malloc(HOWMANY + SLOP)) == NULL) 270 return NULL; 271 272 if (file_reset(ms) == -1) 273 goto done; 274 275 switch (file_fsmagic(ms, inname, &sb)) { 276 case -1: /* error */ 277 goto done; 278 case 0: /* nothing found */ 279 break; 280 default: /* matched it and printed type */ 281 rv = 0; 282 goto done; 283 } 284 285 if (inname == NULL) { 286 if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) 287 ispipe = 1; 288 } else { 289 int flags = O_RDONLY|O_BINARY; 290 291 if (stat(inname, &sb) == 0 && S_ISFIFO(sb.st_mode)) { 292 flags |= O_NONBLOCK; 293 ispipe = 1; 294 } 295 296 errno = 0; 297 if ((fd = open(inname, flags)) < 0) { 298#ifdef __CYGWIN__ 299 char *tmp = alloca(strlen(inname) + 5); 300 (void)strcat(strcpy(tmp, inname), ".exe"); 301 if ((fd = open(tmp, flags)) < 0) { 302#endif 303 if (info_from_stat(ms, sb.st_mode) == -1) 304 goto done; 305 rv = 0; 306 goto done; 307#ifdef __CYGWIN__ 308 } 309#endif 310 } 311#ifdef O_NONBLOCK 312 if ((flags = fcntl(fd, F_GETFL)) != -1) { 313 flags &= ~O_NONBLOCK; 314 (void)fcntl(fd, F_SETFL, flags); 315 } 316#endif 317 } 318 319 /* 320 * try looking at the first HOWMANY bytes 321 */ 322 if (ispipe) { 323 ssize_t r = 0; 324 325 while ((r = sread(fd, (void *)&buf[nbytes], 326 (size_t)(HOWMANY - nbytes), 1)) > 0) { 327 nbytes += r; 328 if (r < PIPE_BUF) break; 329 } 330 331 if (nbytes == 0) { 332 /* We can not read it, but we were able to stat it. */ 333 if (info_from_stat(ms, sb.st_mode) == -1) 334 goto done; 335 rv = 0; 336 goto done; 337 } 338 339 } else { 340 if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) { 341 file_error(ms, errno, "cannot read `%s'", inname); 342 goto done; 343 } 344 } 345 346 (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */ 347 if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1) 348 goto done; 349 rv = 0; 350done: 351 free(buf); 352 close_and_restore(ms, inname, fd, &sb); 353 return rv == 0 ? file_getbuffer(ms) : NULL; 354} 355 356 357public const char * 358magic_buffer(struct magic_set *ms, const void *buf, size_t nb) 359{ 360 if (file_reset(ms) == -1) 361 return NULL; 362 /* 363 * The main work is done here! 364 * We have the file name and/or the data buffer to be identified. 365 */ 366 if (file_buffer(ms, -1, NULL, buf, nb) == -1) { 367 return NULL; 368 } 369 return file_getbuffer(ms); 370} 371#endif 372 373public const char * 374magic_error(struct magic_set *ms) 375{ 376 return ms->haderr ? ms->o.buf : NULL; 377} 378 379public int 380magic_errno(struct magic_set *ms) 381{ 382 return ms->haderr ? ms->error : 0; 383} 384 385public int 386magic_setflags(struct magic_set *ms, int flags) 387{ 388#if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES) 389 if (flags & MAGIC_PRESERVE_ATIME) 390 return -1; 391#endif 392 ms->flags = flags; 393 return 0; 394} 395