magic.c revision 328874
1252277Sjimharris/* 2252277Sjimharris * Copyright (c) Christos Zoulas 2003. 3252277Sjimharris * All Rights Reserved. 4252277Sjimharris * 5252277Sjimharris * Redistribution and use in source and binary forms, with or without 6252277Sjimharris * modification, are permitted provided that the following conditions 7252277Sjimharris * are met: 8252277Sjimharris * 1. Redistributions of source code must retain the above copyright 9252277Sjimharris * notice immediately at the beginning of the file, without modification, 10252277Sjimharris * this list of conditions, and the following disclaimer. 11252277Sjimharris * 2. Redistributions in binary form must reproduce the above copyright 12252277Sjimharris * notice, this list of conditions and the following disclaimer in the 13252277Sjimharris * documentation and/or other materials provided with the distribution. 14252277Sjimharris * 15252277Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16252277Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17252277Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18252277Sjimharris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19252277Sjimharris * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20252277Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21252277Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22252277Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23252277Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24252277Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25252277Sjimharris * SUCH DAMAGE. 26252277Sjimharris */ 27252277Sjimharris 28252277Sjimharris#ifdef WIN32 29252277Sjimharris#include <windows.h> 30252277Sjimharris#include <shlwapi.h> 31252277Sjimharris#endif 32252277Sjimharris 33252277Sjimharris#include "file.h" 34252277Sjimharris 35252277Sjimharris#ifndef lint 36252277SjimharrisFILE_RCSID("@(#)$File: magic.c,v 1.102 2017/08/28 13:39:18 christos Exp $") 37253109Sjimharris#endif /* lint */ 38252277Sjimharris 39252277Sjimharris#include "magic.h" 40252277Sjimharris 41252277Sjimharris#include <stdlib.h> 42252277Sjimharris#include <unistd.h> 43252277Sjimharris#include <string.h> 44252277Sjimharris#ifdef QUICK 45328668Smav#include <sys/mman.h> 46252277Sjimharris#endif 47328668Smav#ifdef HAVE_LIMITS_H 48328668Smav#include <limits.h> /* for PIPE_BUF */ 49328668Smav#endif 50328668Smav 51252277Sjimharris#if defined(HAVE_UTIMES) 52252277Sjimharris# include <sys/time.h> 53252277Sjimharris#elif defined(HAVE_UTIME) 54252277Sjimharris# if defined(HAVE_SYS_UTIME_H) 55252277Sjimharris# include <sys/utime.h> 56328741Smav# elif defined(HAVE_UTIME_H) 57252277Sjimharris# include <utime.h> 58328674Smav# endif 59328674Smav#endif 60328674Smav 61328674Smav#ifdef HAVE_UNISTD_H 62328674Smav#include <unistd.h> /* for read() */ 63328674Smav#endif 64328674Smav 65328674Smav#ifndef PIPE_BUF 66328674Smav/* Get the PIPE_BUF from pathconf */ 67328674Smav#ifdef _PC_PIPE_BUF 68328674Smav#define PIPE_BUF pathconf(".", _PC_PIPE_BUF) 69328674Smav#else 70328674Smav#define PIPE_BUF 512 71328674Smav#endif 72328674Smav#endif 73328674Smav 74328674Smavprivate void close_and_restore(const struct magic_set *, const char *, int, 75328674Smav const struct stat *); 76328674Smavprivate int unreadable_info(struct magic_set *, mode_t, const char *); 77328721Smavprivate const char* get_default_magic(void); 78328741Smav#ifndef COMPILE_ONLY 79328721Smavprivate const char *file_or_fd(struct magic_set *, const char *, int); 80328741Smav#endif 81328741Smav 82328741Smav#ifndef STDIN_FILENO 83328741Smav#define STDIN_FILENO 0 84328741Smav#endif 85328741Smav 86328741Smav#ifdef WIN32 87328741Smav/* HINSTANCE of this shared library. Needed for get_default_magic() */ 88328721Smavstatic HINSTANCE _w32_dll_instance = NULL; 89328721Smav 90328721Smavstatic void 91252277Sjimharris_w32_append_path(char **hmagicpath, const char *fmt, ...) 92253109Sjimharris{ 93252277Sjimharris char *tmppath; 94252277Sjimharris char *newpath; 95252277Sjimharris va_list ap; 96253109Sjimharris 97253109Sjimharris va_start(ap, fmt); 98253109Sjimharris if (vasprintf(&tmppath, fmt, ap) < 0) { 99252277Sjimharris va_end(ap); 100252277Sjimharris return; 101252277Sjimharris } 102252277Sjimharris va_end(ap); 103252277Sjimharris 104328673Smav if (access(tmppath, R_OK) == -1) 105252277Sjimharris goto out; 106252277Sjimharris 107252277Sjimharris if (*hmagicpath == NULL) { 108252277Sjimharris *hmagicpath = tmppath; 109252277Sjimharris return; 110252277Sjimharris } 111252277Sjimharris 112252277Sjimharris if (asprintf(&newpath, "%s%c%s", *hmagicpath, PATHSEP, tmppath) < 0) 113252277Sjimharris goto out; 114252277Sjimharris 115252277Sjimharris free(*hmagicpath); 116252277Sjimharris free(tmppath); 117252277Sjimharris *hmagicpath = newpath; 118253109Sjimharris return; 119253109Sjimharrisout: 120252277Sjimharris free(tmppath); 121253109Sjimharris} 122253109Sjimharris 123252277Sjimharrisstatic void 124252277Sjimharris_w32_get_magic_relative_to(char **hmagicpath, HINSTANCE module) 125252277Sjimharris{ 126328741Smav static const char *trypaths[] = { 127252277Sjimharris "%s/share/misc/magic.mgc", 128252277Sjimharris "%s/magic.mgc", 129252277Sjimharris }; 130252277Sjimharris LPSTR dllpath; 131252277Sjimharris size_t sp; 132252277Sjimharris 133252277Sjimharris dllpath = calloc(MAX_PATH + 1, sizeof(*dllpath)); 134252277Sjimharris 135252277Sjimharris if (!GetModuleFileNameA(module, dllpath, MAX_PATH)) 136252277Sjimharris goto out; 137252277Sjimharris 138252277Sjimharris PathRemoveFileSpecA(dllpath); 139252277Sjimharris 140252277Sjimharris if (module) { 141252277Sjimharris char exepath[MAX_PATH]; 142252277Sjimharris GetModuleFileNameA(NULL, exepath, MAX_PATH); 143252277Sjimharris PathRemoveFileSpecA(exepath); 144252277Sjimharris if (stricmp(exepath, dllpath) == 0) 145252277Sjimharris goto out; 146252277Sjimharris } 147252277Sjimharris 148252277Sjimharris sp = strlen(dllpath); 149252277Sjimharris if (sp > 3 && stricmp(&dllpath[sp - 3], "bin") == 0) { 150252277Sjimharris _w32_append_path(hmagicpath, 151252277Sjimharris "%s/../share/misc/magic.mgc", dllpath); 152252277Sjimharris goto out; 153252277Sjimharris } 154252277Sjimharris 155252277Sjimharris for (sp = 0; sp < __arraycount(trypaths); sp++) 156252277Sjimharris _w32_append_path(hmagicpath, trypaths[sp], dllpath); 157252277Sjimharrisout: 158252277Sjimharris free(dllpath); 159252277Sjimharris} 160252277Sjimharris 161252277Sjimharris/* Placate GCC by offering a sacrificial previous prototype */ 162252277SjimharrisBOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID); 163252277Sjimharris 164252277SjimharrisBOOL WINAPI 165252277SjimharrisDllMain(HINSTANCE hinstDLL, DWORD fdwReason, 166328669Smav LPVOID lpvReserved __attribute__((__unused__))) 167328669Smav{ 168328669Smav if (fdwReason == DLL_PROCESS_ATTACH) 169328669Smav _w32_dll_instance = hinstDLL; 170328669Smav return 1; 171328669Smav} 172328669Smav#endif 173328741Smav 174252277Sjimharrisprivate const char * 175252277Sjimharrisget_default_magic(void) 176328668Smav{ 177328669Smav static const char hmagic[] = "/.magic/magic.mgc"; 178252277Sjimharris static char *default_magic; 179252277Sjimharris char *home, *hmagicpath; 180252277Sjimharris 181252277Sjimharris#ifndef WIN32 182252277Sjimharris struct stat st; 183252277Sjimharris 184252277Sjimharris if (default_magic) { 185252277Sjimharris free(default_magic); 186252277Sjimharris default_magic = NULL; 187252277Sjimharris } 188252277Sjimharris if ((home = getenv("HOME")) == NULL) 189252277Sjimharris return MAGIC; 190252277Sjimharris 191252277Sjimharris if (asprintf(&hmagicpath, "%s/.magic.mgc", home) < 0) 192252277Sjimharris return MAGIC; 193252277Sjimharris if (stat(hmagicpath, &st) == -1) { 194328669Smav free(hmagicpath); 195328669Smav if (asprintf(&hmagicpath, "%s/.magic", home) < 0) 196252277Sjimharris return MAGIC; 197252277Sjimharris if (stat(hmagicpath, &st) == -1) 198252277Sjimharris goto out; 199252277Sjimharris if (S_ISDIR(st.st_mode)) { 200252277Sjimharris free(hmagicpath); 201252277Sjimharris if (asprintf(&hmagicpath, "%s/%s", home, hmagic) < 0) 202252277Sjimharris return MAGIC; 203328669Smav if (access(hmagicpath, R_OK) == -1) 204328668Smav goto out; 205328669Smav } 206328668Smav } 207328668Smav 208328668Smav if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0) 209328668Smav goto out; 210328668Smav free(hmagicpath); 211328668Smav return default_magic; 212328668Smavout: 213328668Smav default_magic = NULL; 214328668Smav free(hmagicpath); 215328668Smav return MAGIC; 216328668Smav#else 217328668Smav hmagicpath = NULL; 218328668Smav 219328668Smav if (default_magic) { 220328668Smav free(default_magic); 221328668Smav default_magic = NULL; 222328668Smav } 223328669Smav 224328669Smav /* First, try to get a magic file from user-application data */ 225328669Smav if ((home = getenv("LOCALAPPDATA")) != NULL) 226328669Smav _w32_append_path(&hmagicpath, "%s%s", home, hmagic); 227328669Smav 228328669Smav /* Second, try to get a magic file from the user profile data */ 229328669Smav if ((home = getenv("USERPROFILE")) != NULL) 230328669Smav _w32_append_path(&hmagicpath, 231328669Smav "%s/Local Settings/Application Data%s", home, hmagic); 232252277Sjimharris 233252277Sjimharris /* Third, try to get a magic file from Common Files */ 234252277Sjimharris if ((home = getenv("COMMONPROGRAMFILES")) != NULL) 235328741Smav _w32_append_path(&hmagicpath, "%s%s", home, hmagic); 236252277Sjimharris 237328748Smav /* Fourth, try to get magic file relative to exe location */ 238252277Sjimharris _w32_get_magic_relative_to(&hmagicpath, NULL); 239252277Sjimharris 240252277Sjimharris /* Fifth, try to get magic file relative to dll location */ 241252277Sjimharris _w32_get_magic_relative_to(&hmagicpath, _w32_dll_instance); 242252277Sjimharris 243252277Sjimharris /* Avoid MAGIC constant - it likely points to a file within MSys tree */ 244328748Smav default_magic = hmagicpath; 245328748Smav return default_magic; 246328748Smav#endif 247328748Smav} 248328748Smav 249328748Smavpublic const char * 250252277Sjimharrismagic_getpath(const char *magicfile, int action) 251252277Sjimharris{ 252252277Sjimharris if (magicfile != NULL) 253252277Sjimharris return magicfile; 254252277Sjimharris 255252277Sjimharris magicfile = getenv("MAGIC"); 256252277Sjimharris if (magicfile != NULL) 257252277Sjimharris return magicfile; 258252277Sjimharris 259252277Sjimharris return action == FILE_LOAD ? get_default_magic() : MAGIC; 260252277Sjimharris} 261252277Sjimharris 262252277Sjimharrispublic struct magic_set * 263252277Sjimharrismagic_open(int flags) 264252277Sjimharris{ 265252277Sjimharris return file_ms_alloc(flags); 266252277Sjimharris} 267252277Sjimharris 268328708Smavprivate int 269328708Smavunreadable_info(struct magic_set *ms, mode_t md, const char *file) 270328708Smav{ 271328708Smav if (file) { 272328708Smav /* We cannot open it, but we were able to stat it. */ 273328708Smav if (access(file, W_OK) == 0) 274328708Smav if (file_printf(ms, "writable, ") == -1) 275328673Smav return -1; 276328741Smav if (access(file, X_OK) == 0) 277328673Smav if (file_printf(ms, "executable, ") == -1) 278328673Smav return -1; 279328673Smav } 280328673Smav if (S_ISREG(md)) 281328673Smav if (file_printf(ms, "regular file, ") == -1) 282328673Smav return -1; 283328673Smav if (file_printf(ms, "no read permission") == -1) 284328673Smav return -1; 285328673Smav return 0; 286328673Smav} 287328673Smav 288328673Smavpublic void 289328673Smavmagic_close(struct magic_set *ms) 290328673Smav{ 291328673Smav if (ms == NULL) 292328673Smav return; 293328673Smav file_ms_free(ms); 294328673Smav} 295328673Smav 296328673Smav/* 297328673Smav * load a magic file 298328712Smav */ 299328712Smavpublic int 300328712Smavmagic_load(struct magic_set *ms, const char *magicfile) 301328712Smav{ 302328708Smav if (ms == NULL) 303328741Smav return -1; 304328712Smav return file_apprentice(ms, magicfile, FILE_LOAD); 305328712Smav} 306328712Smav 307328712Smav#ifndef COMPILE_ONLY 308328712Smav/* 309328712Smav * Install a set of compiled magic buffers. 310328712Smav */ 311328712Smavpublic int 312328712Smavmagic_load_buffers(struct magic_set *ms, void **bufs, size_t *sizes, 313328712Smav size_t nbufs) 314328712Smav{ 315328712Smav if (ms == NULL) 316328712Smav return -1; 317328712Smav return buffer_apprentice(ms, (struct magic **)bufs, sizes, nbufs); 318328712Smav} 319328741Smav#endif 320328712Smav 321328712Smavpublic int 322328712Smavmagic_compile(struct magic_set *ms, const char *magicfile) 323328712Smav{ 324328741Smav if (ms == NULL) 325328712Smav return -1; 326328712Smav return file_apprentice(ms, magicfile, FILE_COMPILE); 327328712Smav} 328328741Smav 329328712Smavpublic int 330328712Smavmagic_check(struct magic_set *ms, const char *magicfile) 331328712Smav{ 332328712Smav if (ms == NULL) 333328741Smav return -1; 334328712Smav return file_apprentice(ms, magicfile, FILE_CHECK); 335328712Smav} 336328712Smav 337328725Smavpublic int 338328712Smavmagic_list(struct magic_set *ms, const char *magicfile) 339328712Smav{ 340328741Smav if (ms == NULL) 341328708Smav return -1; 342328708Smav return file_apprentice(ms, magicfile, FILE_LIST); 343328708Smav} 344328708Smav 345328708Smavprivate void 346328708Smavclose_and_restore(const struct magic_set *ms, const char *name, int fd, 347328708Smav const struct stat *sb) 348328708Smav{ 349328708Smav if (fd == STDIN_FILENO || name == NULL) 350328708Smav return; 351328708Smav (void) close(fd); 352328708Smav 353328708Smav if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) { 354328708Smav /* 355328708Smav * Try to restore access, modification times if read it. 356328708Smav * This is really *bad* because it will modify the status 357328708Smav * time of the file... And of course this will affect 358328708Smav * backup programs 359328708Smav */ 360328708Smav#ifdef HAVE_UTIMES 361328708Smav struct timeval utsbuf[2]; 362328708Smav (void)memset(utsbuf, 0, sizeof(utsbuf)); 363328708Smav utsbuf[0].tv_sec = sb->st_atime; 364328708Smav utsbuf[1].tv_sec = sb->st_mtime; 365328708Smav 366328708Smav (void) utimes(name, utsbuf); /* don't care if loses */ 367328708Smav#elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H) 368328708Smav struct utimbuf utbuf; 369328708Smav 370328708Smav (void)memset(&utbuf, 0, sizeof(utbuf)); 371328708Smav utbuf.actime = sb->st_atime; 372328708Smav utbuf.modtime = sb->st_mtime; 373328708Smav (void) utime(name, &utbuf); /* don't care if loses */ 374328708Smav#endif 375328708Smav } 376328708Smav} 377328708Smav 378328708Smav#ifndef COMPILE_ONLY 379328708Smav 380328708Smav/* 381328708Smav * find type of descriptor 382328708Smav */ 383328708Smavpublic const char * 384328708Smavmagic_descriptor(struct magic_set *ms, int fd) 385328708Smav{ 386328708Smav if (ms == NULL) 387328708Smav return NULL; 388328708Smav return file_or_fd(ms, NULL, fd); 389328708Smav} 390328708Smav 391328708Smav/* 392328708Smav * find type of named file 393328708Smav */ 394328708Smavpublic const char * 395328708Smavmagic_file(struct magic_set *ms, const char *inname) 396328708Smav{ 397328708Smav if (ms == NULL) 398328708Smav return NULL; 399328708Smav return file_or_fd(ms, inname, STDIN_FILENO); 400328708Smav} 401328673Smav 402328674Smavprivate const char * 403328674Smavfile_or_fd(struct magic_set *ms, const char *inname, int fd) 404328674Smav{ 405328674Smav int rv = -1; 406328674Smav unsigned char *buf; 407328674Smav struct stat sb; 408328674Smav ssize_t nbytes = 0; /* number of bytes read from a datafile */ 409328674Smav int ispipe = 0; 410328674Smav off_t pos = (off_t)-1; 411328674Smav 412328674Smav if (file_reset(ms, 1) == -1) 413328674Smav goto out; 414328674Smav 415328674Smav /* 416328674Smav * one extra for terminating '\0', and 417328674Smav * some overlapping space for matches near EOF 418328674Smav */ 419328674Smav#define SLOP (1 + sizeof(union VALUETYPE)) 420328674Smav if ((buf = CAST(unsigned char *, malloc(ms->bytes_max + SLOP))) == NULL) 421328674Smav return NULL; 422328674Smav 423328674Smav switch (file_fsmagic(ms, inname, &sb)) { 424328674Smav case -1: /* error */ 425328674Smav goto done; 426328674Smav case 0: /* nothing found */ 427328674Smav break; 428328674Smav default: /* matched it and printed type */ 429328674Smav rv = 0; 430328674Smav goto done; 431328674Smav } 432328674Smav 433328674Smav#ifdef WIN32 434328674Smav /* Place stdin in binary mode, so EOF (Ctrl+Z) doesn't stop early. */ 435328674Smav if (fd == STDIN_FILENO) 436328674Smav _setmode(STDIN_FILENO, O_BINARY); 437328674Smav#endif 438328674Smav 439328674Smav if (inname == NULL) { 440328674Smav if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) 441328674Smav ispipe = 1; 442328674Smav else 443328674Smav pos = lseek(fd, (off_t)0, SEEK_CUR); 444328674Smav } else { 445328674Smav int flags = O_RDONLY|O_BINARY; 446328674Smav int okstat = stat(inname, &sb) == 0; 447328674Smav 448328674Smav if (okstat && S_ISFIFO(sb.st_mode)) { 449328674Smav#ifdef O_NONBLOCK 450328674Smav flags |= O_NONBLOCK; 451328674Smav#endif 452328674Smav ispipe = 1; 453328674Smav } 454328674Smav 455328674Smav errno = 0; 456328674Smav if ((fd = open(inname, flags)) < 0) { 457328674Smav#ifdef WIN32 458328674Smav /* 459328674Smav * Can't stat, can't open. It may have been opened in 460328674Smav * fsmagic, so if the user doesn't have read permission, 461328674Smav * allow it to say so; otherwise an error was probably 462328674Smav * displayed in fsmagic. 463328674Smav */ 464328674Smav if (!okstat && errno == EACCES) { 465328674Smav sb.st_mode = S_IFBLK; 466328674Smav okstat = 1; 467328674Smav } 468328674Smav#endif 469328674Smav if (okstat && 470328674Smav unreadable_info(ms, sb.st_mode, inname) == -1) 471328674Smav goto done; 472328674Smav rv = 0; 473328674Smav goto done; 474328674Smav } 475328674Smav#ifdef O_NONBLOCK 476328674Smav if ((flags = fcntl(fd, F_GETFL)) != -1) { 477328674Smav flags &= ~O_NONBLOCK; 478328674Smav (void)fcntl(fd, F_SETFL, flags); 479328674Smav } 480328674Smav#endif 481328674Smav } 482328674Smav 483328674Smav /* 484328674Smav * try looking at the first ms->bytes_max bytes 485328674Smav */ 486328674Smav if (ispipe) { 487328674Smav ssize_t r = 0; 488328674Smav 489328674Smav while ((r = sread(fd, (void *)&buf[nbytes], 490328674Smav (size_t)(ms->bytes_max - nbytes), 1)) > 0) { 491328674Smav nbytes += r; 492328674Smav if (r < PIPE_BUF) break; 493328674Smav } 494328674Smav 495328674Smav if (nbytes == 0 && inname) { 496328674Smav /* We can not read it, but we were able to stat it. */ 497328674Smav if (unreadable_info(ms, sb.st_mode, inname) == -1) 498328674Smav goto done; 499328674Smav rv = 0; 500328674Smav goto done; 501328674Smav } 502328674Smav 503328674Smav } else { 504328674Smav /* Windows refuses to read from a big console buffer. */ 505328674Smav size_t howmany = 506328674Smav#if defined(WIN32) 507328674Smav _isatty(fd) ? 8 * 1024 : 508328674Smav#endif 509328674Smav ms->bytes_max; 510328674Smav if ((nbytes = read(fd, (char *)buf, howmany)) == -1) { 511328674Smav if (inname == NULL && fd != STDIN_FILENO) 512328674Smav file_error(ms, errno, "cannot read fd %d", fd); 513328674Smav else 514328674Smav file_error(ms, errno, "cannot read `%s'", 515328674Smav inname == NULL ? "/dev/stdin" : inname); 516328674Smav goto done; 517328674Smav } 518328674Smav } 519328674Smav 520328674Smav (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */ 521328674Smav if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1) 522328674Smav goto done; 523328674Smav rv = 0; 524328674Smavdone: 525328674Smav free(buf); 526328674Smav if (fd != -1) { 527328674Smav if (pos != (off_t)-1) 528328674Smav (void)lseek(fd, pos, SEEK_SET); 529328674Smav close_and_restore(ms, inname, fd, &sb); 530328674Smav } 531328674Smavout: 532328674Smav return rv == 0 ? file_getbuffer(ms) : NULL; 533328674Smav} 534328674Smav 535328674Smav 536328674Smavpublic const char * 537328674Smavmagic_buffer(struct magic_set *ms, const void *buf, size_t nb) 538328674Smav{ 539328674Smav if (ms == NULL) 540328674Smav return NULL; 541328674Smav if (file_reset(ms, 1) == -1) 542328674Smav return NULL; 543328674Smav /* 544328674Smav * The main work is done here! 545328674Smav * We have the file name and/or the data buffer to be identified. 546328674Smav */ 547328674Smav if (file_buffer(ms, -1, NULL, buf, nb) == -1) { 548328674Smav return NULL; 549328674Smav } 550328674Smav return file_getbuffer(ms); 551328674Smav} 552328674Smav#endif 553328674Smav 554328674Smavpublic const char * 555328674Smavmagic_error(struct magic_set *ms) 556328674Smav{ 557328674Smav if (ms == NULL) 558328674Smav return "Magic database is not open"; 559328674Smav return (ms->event_flags & EVENT_HAD_ERR) ? ms->o.buf : NULL; 560328674Smav} 561328674Smav 562328674Smavpublic int 563328674Smavmagic_errno(struct magic_set *ms) 564328674Smav{ 565328674Smav if (ms == NULL) 566328674Smav return EINVAL; 567328674Smav return (ms->event_flags & EVENT_HAD_ERR) ? ms->error : 0; 568328674Smav} 569328674Smav 570328674Smavpublic int 571328674Smavmagic_getflags(struct magic_set *ms) 572328674Smav{ 573328674Smav if (ms == NULL) 574328674Smav return -1; 575328674Smav 576328674Smav return ms->flags; 577328674Smav} 578328674Smav 579328674Smavpublic int 580328674Smavmagic_setflags(struct magic_set *ms, int flags) 581328674Smav{ 582328674Smav if (ms == NULL) 583328674Smav return -1; 584328674Smav#if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES) 585328674Smav if (flags & MAGIC_PRESERVE_ATIME) 586328674Smav return -1; 587328674Smav#endif 588328674Smav ms->flags = flags; 589328674Smav return 0; 590328674Smav} 591328674Smav 592328674Smavpublic int 593328674Smavmagic_version(void) 594328674Smav{ 595328674Smav return MAGIC_VERSION; 596328674Smav} 597328674Smav 598328674Smavpublic int 599328674Smavmagic_setparam(struct magic_set *ms, int param, const void *val) 600328674Smav{ 601328674Smav switch (param) { 602328674Smav case MAGIC_PARAM_INDIR_MAX: 603328674Smav ms->indir_max = (uint16_t)*(const size_t *)val; 604328674Smav return 0; 605328674Smav case MAGIC_PARAM_NAME_MAX: 606328674Smav ms->name_max = (uint16_t)*(const size_t *)val; 607328674Smav return 0; 608328674Smav case MAGIC_PARAM_ELF_PHNUM_MAX: 609328674Smav ms->elf_phnum_max = (uint16_t)*(const size_t *)val; 610328674Smav return 0; 611328674Smav case MAGIC_PARAM_ELF_SHNUM_MAX: 612328674Smav ms->elf_shnum_max = (uint16_t)*(const size_t *)val; 613328674Smav return 0; 614328674Smav case MAGIC_PARAM_ELF_NOTES_MAX: 615328674Smav ms->elf_notes_max = (uint16_t)*(const size_t *)val; 616328674Smav return 0; 617328674Smav case MAGIC_PARAM_REGEX_MAX: 618328674Smav ms->elf_notes_max = (uint16_t)*(const size_t *)val; 619328674Smav return 0; 620328674Smav case MAGIC_PARAM_BYTES_MAX: 621328674Smav ms->bytes_max = *(const size_t *)val; 622328674Smav return 0; 623328674Smav default: 624328674Smav errno = EINVAL; 625328674Smav return -1; 626328674Smav } 627328674Smav} 628328674Smav 629328674Smavpublic int 630328674Smavmagic_getparam(struct magic_set *ms, int param, void *val) 631328674Smav{ 632328674Smav switch (param) { 633328674Smav case MAGIC_PARAM_INDIR_MAX: 634328674Smav *(size_t *)val = ms->indir_max; 635328674Smav return 0; 636328674Smav case MAGIC_PARAM_NAME_MAX: 637328674Smav *(size_t *)val = ms->name_max; 638328674Smav return 0; 639328674Smav case MAGIC_PARAM_ELF_PHNUM_MAX: 640328674Smav *(size_t *)val = ms->elf_phnum_max; 641328674Smav return 0; 642328674Smav case MAGIC_PARAM_ELF_SHNUM_MAX: 643328674Smav *(size_t *)val = ms->elf_shnum_max; 644328674Smav return 0; 645328674Smav case MAGIC_PARAM_ELF_NOTES_MAX: 646328674Smav *(size_t *)val = ms->elf_notes_max; 647328674Smav return 0; 648328674Smav case MAGIC_PARAM_REGEX_MAX: 649328674Smav *(size_t *)val = ms->regex_max; 650328674Smav return 0; 651328674Smav case MAGIC_PARAM_BYTES_MAX: 652328674Smav *(size_t *)val = ms->bytes_max; 653328674Smav return 0; 654328674Smav default: 655328674Smav errno = EINVAL; 656328674Smav return -1; 657328674Smav } 658328674Smav} 659328674Smav