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