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 #ifdef WIN32 29 #include <windows.h> 30 #include <shlwapi.h> 31 #endif 32 33 #include "file.h" 34 35 #ifndef lint 36 FILE_RCSID("@(#)$File: magic.c,v 1.73 2011/05/10 17:08:14 christos Exp $") 37 #endif /* lint */ 38 39 #include "magic.h" 40 41 #include <stdlib.h> 42 #include <unistd.h> 43 #include <string.h> 44 #ifdef QUICK 45 #include <sys/mman.h> 46 #endif 47 #ifdef HAVE_LIMITS_H 48 #include <limits.h> /* for PIPE_BUF */ 49 #endif 50 51 #if defined(HAVE_UTIMES) 52 # include <sys/time.h> 53 #elif defined(HAVE_UTIME) 54 # if defined(HAVE_SYS_UTIME_H) 55 # include <sys/utime.h> 56 # elif defined(HAVE_UTIME_H) 57 # include <utime.h> 58 # endif 59 #endif 60 61 #ifdef HAVE_UNISTD_H 62 #include <unistd.h> /* for read() */ 63 #endif 64 65 #ifndef PIPE_BUF 66 /* Get the PIPE_BUF from pathconf */ 67 #ifdef _PC_PIPE_BUF 68 #define PIPE_BUF pathconf(".", _PC_PIPE_BUF) 69 #else 70 #define PIPE_BUF 512 71 #endif 72 #endif 73 74 private void free_mlist(struct mlist *); 75 private void close_and_restore(const struct magic_set *, const char *, int, 76 const struct stat *); 77 private int unreadable_info(struct magic_set *, mode_t, const char *); 78 private const char* get_default_magic(void); 79 #ifndef COMPILE_ONLY 80 private 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 87 #ifdef WIN32 88 BOOL WINAPI DllMain(HINSTANCE hinstDLL, 89 DWORD fdwReason __attribute__((__unused__)), 90 LPVOID lpvReserved __attribute__((__unused__))); 91 92 CHAR dllpath[MAX_PATH + 1] = { 0 }; 93 94 BOOL WINAPI DllMain(HINSTANCE hinstDLL, 95 DWORD fdwReason __attribute__((__unused__)), 96 LPVOID lpvReserved __attribute__((__unused__))) 97 { 98 if (dllpath[0] == 0 && 99 GetModuleFileNameA(hinstDLL, dllpath, MAX_PATH) != 0) 100 PathRemoveFileSpecA(dllpath); 101 return TRUE; 102 } 103 #endif 104 105 private const char * 106 get_default_magic(void) 107 { 108 static const char hmagic[] = "/.magic/magic.mgc"; 109 static char *default_magic; 110 char *home, *hmagicpath; 111 112 #ifndef WIN32 113 struct stat st; 114 115 if (default_magic) { 116 free(default_magic); 117 default_magic = NULL; 118 } 119 if ((home = getenv("HOME")) == NULL) 120 return MAGIC; 121 122 if (asprintf(&hmagicpath, "%s/.magic", home) < 0) 123 return MAGIC; 124 if (stat(hmagicpath, &st) == -1) 125 goto out; 126 if (S_ISDIR(st.st_mode)) { 127 free(hmagicpath); 128 if (asprintf(&hmagicpath, "%s/%s", home, hmagic) < 0) 129 return MAGIC; 130 if (access(hmagicpath, R_OK) == -1) 131 goto out; 132 } 133 134 if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0) 135 goto out; 136 free(hmagicpath); 137 return default_magic; 138 out: 139 default_magic = NULL; 140 free(hmagicpath); 141 return MAGIC; 142 #else 143 char *hmagicp = hmagicpath; 144 char *tmppath = NULL; 145 146 #define APPENDPATH() \ 147 do { \ 148 if (tmppath && access(tmppath, R_OK) != -1) { \ 149 if (hmagicpath == NULL) { \ 150 hmagicpath = tmppath; \ 151 tmppath = NULL; \ 152 } else { \ 153 free(tmppath); \ 154 if (asprintf(&hmagicp, "%s%c%s", hmagicpath, \ 155 PATHSEP, tmppath) >= 0) { \ 156 free(hmagicpath); \ 157 hmagicpath = hmagicp; \ 158 } \ 159 } \ 160 } while (/*CONSTCOND*/0) 161 162 if (default_magic) { 163 free(default_magic); 164 default_magic = NULL; 165 } 166 167 /* First, try to get user-specific magic file */ 168 if ((home = getenv("LOCALAPPDATA")) == NULL) { 169 if ((home = getenv("USERPROFILE")) != NULL) 170 if (asprintf(&tmppath, 171 "%s/Local Settings/Application Data%s", home, 172 hmagic) < 0) 173 tmppath = NULL; 174 } else { 175 if (asprintf(&tmppath, "%s%s", home, hmagic) < 0) 176 tmppath = NULL; 177 } 178 179 APPENDPATH(); 180 181 /* Second, try to get a magic file from Common Files */ 182 if ((home = getenv("COMMONPROGRAMFILES")) != NULL) { 183 if (asprintf(&tmppath, "%s%s", home, hmagic) >= 0) 184 APPENDPATH(); 185 } 186 187 188 /* Third, try to get magic file relative to dll location */ 189 if (dllpath[0] != 0) { 190 if (strlen(dllpath) > 3 && 191 stricmp(&dllpath[strlen(dllpath) - 3], "bin") == 0) { 192 if (asprintf(&tmppath, 193 "%s/../share/misc/magic.mgc", dllpath) >= 0) 194 APPENDPATH(); 195 } else { 196 if (asprintf(&tmppath, 197 "%s/share/misc/magic.mgc", dllpath) >= 0) 198 APPENDPATH(); 199 else if (asprintf(&tmppath, 200 "%s/magic.mgc", dllpath) >= 0) 201 APPENDPATH(); 202 } 203 } 204 205 /* Don't put MAGIC constant - it likely points to a file within MSys 206 tree */ 207 default_magic = hmagicpath; 208 return default_magic; 209 #endif 210 } 211 212 public const char * 213 magic_getpath(const char *magicfile, int action) 214 { 215 if (magicfile != NULL) 216 return magicfile; 217 218 magicfile = getenv("MAGIC"); 219 if (magicfile != NULL) 220 return magicfile; 221 222 return action == FILE_LOAD ? get_default_magic() : MAGIC; 223 } 224 225 public struct magic_set * 226 magic_open(int flags) 227 { 228 struct magic_set *ms; 229 size_t len; 230 231 if ((ms = CAST(struct magic_set *, calloc((size_t)1, 232 sizeof(struct magic_set)))) == NULL) 233 return NULL; 234 235 if (magic_setflags(ms, flags) == -1) { 236 errno = EINVAL; 237 goto free; 238 } 239 240 ms->o.buf = ms->o.pbuf = NULL; 241 len = (ms->c.len = 10) * sizeof(*ms->c.li); 242 243 if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) 244 goto free; 245 246 ms->event_flags = 0; 247 ms->error = -1; 248 ms->mlist = NULL; 249 ms->file = "unknown"; 250 ms->line = 0; 251 return ms; 252 free: 253 free(ms); 254 return NULL; 255 } 256 257 private void 258 free_mlist(struct mlist *mlist) 259 { 260 struct mlist *ml; 261 262 if (mlist == NULL) 263 return; 264 265 for (ml = mlist->next; ml != mlist;) { 266 struct mlist *next = ml->next; 267 struct magic *mg = ml->magic; 268 file_delmagic(mg, ml->mapped, ml->nmagic); 269 free(ml); 270 ml = next; 271 } 272 free(ml); 273 } 274 275 private int 276 unreadable_info(struct magic_set *ms, mode_t md, const char *file) 277 { 278 /* We cannot open it, but we were able to stat it. */ 279 if (access(file, W_OK) == 0) 280 if (file_printf(ms, "writable, ") == -1) 281 return -1; 282 if (access(file, X_OK) == 0) 283 if (file_printf(ms, "executable, ") == -1) 284 return -1; 285 if (S_ISREG(md)) 286 if (file_printf(ms, "regular file, ") == -1) 287 return -1; 288 if (file_printf(ms, "no read permission") == -1) 289 return -1; 290 return 0; 291 } 292 293 public void 294 magic_close(struct magic_set *ms) 295 { 296 free_mlist(ms->mlist); 297 free(ms->o.pbuf); 298 free(ms->o.buf); 299 free(ms->c.li); 300 free(ms); 301 } 302 303 /* 304 * load a magic file 305 */ 306 public int 307 magic_load(struct magic_set *ms, const char *magicfile) 308 { 309 struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD); 310 if (ml) { 311 free_mlist(ms->mlist); 312 ms->mlist = ml; 313 return 0; 314 } 315 return -1; 316 } 317 318 public int 319 magic_compile(struct magic_set *ms, const char *magicfile) 320 { 321 struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE); 322 free_mlist(ml); 323 return ml ? 0 : -1; 324 } 325 326 public int 327 magic_check(struct magic_set *ms, const char *magicfile) 328 { 329 struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK); 330 free_mlist(ml); 331 return ml ? 0 : -1; 332 } 333 334 public int 335 magic_list(struct magic_set *ms, const char *magicfile) 336 { 337 struct mlist *ml = file_apprentice(ms, magicfile, FILE_LIST); 338 free_mlist(ml); 339 return ml ? 0 : -1; 340 } 341 342 private void 343 close_and_restore(const struct magic_set *ms, const char *name, int fd, 344 const struct stat *sb) 345 { 346 if (fd == STDIN_FILENO) 347 return; 348 (void) close(fd); 349 350 if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) { 351 /* 352 * Try to restore access, modification times if read it. 353 * This is really *bad* because it will modify the status 354 * time of the file... And of course this will affect 355 * backup programs 356 */ 357 #ifdef HAVE_UTIMES 358 struct timeval utsbuf[2]; 359 (void)memset(utsbuf, 0, sizeof(utsbuf)); 360 utsbuf[0].tv_sec = sb->st_atime; 361 utsbuf[1].tv_sec = sb->st_mtime; 362 363 (void) utimes(name, utsbuf); /* don't care if loses */ 364 #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H) 365 struct utimbuf utbuf; 366 367 (void)memset(&utbuf, 0, sizeof(utbuf)); 368 utbuf.actime = sb->st_atime; 369 utbuf.modtime = sb->st_mtime; 370 (void) utime(name, &utbuf); /* don't care if loses */ 371 #endif 372 } 373 } 374 375 #ifndef COMPILE_ONLY 376 377 /* 378 * find type of descriptor 379 */ 380 public const char * 381 magic_descriptor(struct magic_set *ms, int fd) 382 { 383 return file_or_fd(ms, NULL, fd); 384 } 385 386 /* 387 * find type of named file 388 */ 389 public const char * 390 magic_file(struct magic_set *ms, const char *inname) 391 { 392 return file_or_fd(ms, inname, STDIN_FILENO); 393 } 394 395 private const char * 396 file_or_fd(struct magic_set *ms, const char *inname, int fd) 397 { 398 int rv = -1; 399 unsigned char *buf; 400 struct stat sb; 401 ssize_t nbytes = 0; /* number of bytes read from a datafile */ 402 int ispipe = 0; 403 404 /* 405 * one extra for terminating '\0', and 406 * some overlapping space for matches near EOF 407 */ 408 #define SLOP (1 + sizeof(union VALUETYPE)) 409 if ((buf = CAST(unsigned char *, malloc(HOWMANY + SLOP))) == NULL) 410 return NULL; 411 412 if (file_reset(ms) == -1) 413 goto done; 414 415 switch (file_fsmagic(ms, inname, &sb)) { 416 case -1: /* error */ 417 goto done; 418 case 0: /* nothing found */ 419 break; 420 default: /* matched it and printed type */ 421 rv = 0; 422 goto done; 423 } 424 425 if (inname == NULL) { 426 if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) 427 ispipe = 1; 428 } else { 429 int flags = O_RDONLY|O_BINARY; 430 431 if (stat(inname, &sb) == 0 && S_ISFIFO(sb.st_mode)) { 432 #ifdef O_NONBLOCK 433 flags |= O_NONBLOCK; 434 #endif 435 ispipe = 1; 436 } 437 438 errno = 0; 439 if ((fd = open(inname, flags)) < 0) { 440 if (unreadable_info(ms, sb.st_mode, inname) == -1) 441 goto done; 442 rv = 0; 443 goto done; 444 } 445 #ifdef O_NONBLOCK 446 if ((flags = fcntl(fd, F_GETFL)) != -1) { 447 flags &= ~O_NONBLOCK; 448 (void)fcntl(fd, F_SETFL, flags); 449 } 450 #endif 451 } 452 453 /* 454 * try looking at the first HOWMANY bytes 455 */ 456 if (ispipe) { 457 ssize_t r = 0; 458 459 while ((r = sread(fd, (void *)&buf[nbytes], 460 (size_t)(HOWMANY - nbytes), 1)) > 0) { 461 nbytes += r; 462 if (r < PIPE_BUF) break; 463 } 464 465 if (nbytes == 0) { 466 /* We can not read it, but we were able to stat it. */ 467 if (unreadable_info(ms, sb.st_mode, inname) == -1) 468 goto done; 469 rv = 0; 470 goto done; 471 } 472 473 } else { 474 if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) { 475 file_error(ms, errno, "cannot read `%s'", inname); 476 goto done; 477 } 478 } 479 480 (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */ 481 if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1) 482 goto done; 483 rv = 0; 484 done: 485 free(buf); 486 close_and_restore(ms, inname, fd, &sb); 487 return rv == 0 ? file_getbuffer(ms) : NULL; 488 } 489 490 491 public const char * 492 magic_buffer(struct magic_set *ms, const void *buf, size_t nb) 493 { 494 if (file_reset(ms) == -1) 495 return NULL; 496 /* 497 * The main work is done here! 498 * We have the file name and/or the data buffer to be identified. 499 */ 500 if (file_buffer(ms, -1, NULL, buf, nb) == -1) { 501 return NULL; 502 } 503 return file_getbuffer(ms); 504 } 505 #endif 506 507 public const char * 508 magic_error(struct magic_set *ms) 509 { 510 return (ms->event_flags & EVENT_HAD_ERR) ? ms->o.buf : NULL; 511 } 512 513 public int 514 magic_errno(struct magic_set *ms) 515 { 516 return (ms->event_flags & EVENT_HAD_ERR) ? ms->error : 0; 517 } 518 519 public int 520 magic_setflags(struct magic_set *ms, int flags) 521 { 522 #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES) 523 if (flags & MAGIC_PRESERVE_ATIME) 524 return -1; 525 #endif 526 ms->flags = flags; 527 return 0; 528 } 529