1133359Sobrien/* 2133359Sobrien * Copyright (c) Christos Zoulas 2003. 3133359Sobrien * All Rights Reserved. 4186690Sobrien * 5133359Sobrien * Redistribution and use in source and binary forms, with or without 6133359Sobrien * modification, are permitted provided that the following conditions 7133359Sobrien * are met: 8133359Sobrien * 1. Redistributions of source code must retain the above copyright 9133359Sobrien * notice immediately at the beginning of the file, without modification, 10133359Sobrien * this list of conditions, and the following disclaimer. 11133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright 12133359Sobrien * notice, this list of conditions and the following disclaimer in the 13133359Sobrien * documentation and/or other materials provided with the distribution. 14186690Sobrien * 15133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19133359Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25133359Sobrien * SUCH DAMAGE. 26133359Sobrien */ 27133359Sobrien 28226048Sobrien#ifdef WIN32 29226048Sobrien#include <windows.h> 30226048Sobrien#include <shlwapi.h> 31226048Sobrien#endif 32226048Sobrien 33133359Sobrien#include "file.h" 34191736Sobrien 35191736Sobrien#ifndef lint 36284193SdelphijFILE_RCSID("@(#)$File: magic.c,v 1.91 2014/12/16 23:18:40 christos Exp $") 37191736Sobrien#endif /* lint */ 38191736Sobrien 39133359Sobrien#include "magic.h" 40133359Sobrien 41133359Sobrien#include <stdlib.h> 42133359Sobrien#include <unistd.h> 43133359Sobrien#include <string.h> 44133359Sobrien#ifdef QUICK 45133359Sobrien#include <sys/mman.h> 46133359Sobrien#endif 47186690Sobrien#ifdef HAVE_LIMITS_H 48169942Sobrien#include <limits.h> /* for PIPE_BUF */ 49186690Sobrien#endif 50133359Sobrien 51133359Sobrien#if defined(HAVE_UTIMES) 52133359Sobrien# include <sys/time.h> 53133359Sobrien#elif defined(HAVE_UTIME) 54133359Sobrien# if defined(HAVE_SYS_UTIME_H) 55133359Sobrien# include <sys/utime.h> 56133359Sobrien# elif defined(HAVE_UTIME_H) 57133359Sobrien# include <utime.h> 58133359Sobrien# endif 59133359Sobrien#endif 60133359Sobrien 61133359Sobrien#ifdef HAVE_UNISTD_H 62133359Sobrien#include <unistd.h> /* for read() */ 63133359Sobrien#endif 64133359Sobrien 65186690Sobrien#ifndef PIPE_BUF 66186690Sobrien/* Get the PIPE_BUF from pathconf */ 67186690Sobrien#ifdef _PC_PIPE_BUF 68186690Sobrien#define PIPE_BUF pathconf(".", _PC_PIPE_BUF) 69186690Sobrien#else 70186690Sobrien#define PIPE_BUF 512 71186690Sobrien#endif 72186690Sobrien#endif 73186690Sobrien 74133359Sobrienprivate void close_and_restore(const struct magic_set *, const char *, int, 75133359Sobrien const struct stat *); 76186690Sobrienprivate int unreadable_info(struct magic_set *, mode_t, const char *); 77226048Sobrienprivate const char* get_default_magic(void); 78175296Sobrien#ifndef COMPILE_ONLY 79175296Sobrienprivate const char *file_or_fd(struct magic_set *, const char *, int); 80175296Sobrien#endif 81133359Sobrien 82159764Sobrien#ifndef STDIN_FILENO 83159764Sobrien#define STDIN_FILENO 0 84159764Sobrien#endif 85159764Sobrien 86226048Sobrienprivate const char * 87226048Sobrienget_default_magic(void) 88226048Sobrien{ 89226048Sobrien static const char hmagic[] = "/.magic/magic.mgc"; 90226048Sobrien static char *default_magic; 91226048Sobrien char *home, *hmagicpath; 92226048Sobrien 93226048Sobrien#ifndef WIN32 94226048Sobrien struct stat st; 95226048Sobrien 96226048Sobrien if (default_magic) { 97226048Sobrien free(default_magic); 98226048Sobrien default_magic = NULL; 99226048Sobrien } 100226048Sobrien if ((home = getenv("HOME")) == NULL) 101226048Sobrien return MAGIC; 102226048Sobrien 103267843Sdelphij if (asprintf(&hmagicpath, "%s/.magic.mgc", home) < 0) 104226048Sobrien return MAGIC; 105267843Sdelphij if (stat(hmagicpath, &st) == -1) { 106226048Sobrien free(hmagicpath); 107267843Sdelphij if (asprintf(&hmagicpath, "%s/.magic", home) < 0) 108226048Sobrien return MAGIC; 109267843Sdelphij if (stat(hmagicpath, &st) == -1) 110226048Sobrien goto out; 111267843Sdelphij if (S_ISDIR(st.st_mode)) { 112267843Sdelphij free(hmagicpath); 113267843Sdelphij if (asprintf(&hmagicpath, "%s/%s", home, hmagic) < 0) 114267843Sdelphij return MAGIC; 115267843Sdelphij if (access(hmagicpath, R_OK) == -1) 116267843Sdelphij goto out; 117267843Sdelphij } 118226048Sobrien } 119226048Sobrien 120226048Sobrien if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0) 121226048Sobrien goto out; 122226048Sobrien free(hmagicpath); 123226048Sobrien return default_magic; 124226048Sobrienout: 125226048Sobrien default_magic = NULL; 126226048Sobrien free(hmagicpath); 127226048Sobrien return MAGIC; 128226048Sobrien#else 129267843Sdelphij char *hmagicp; 130226048Sobrien char *tmppath = NULL; 131284193Sdelphij LPTSTR dllpath; 132267843Sdelphij hmagicpath = NULL; 133226048Sobrien 134226048Sobrien#define APPENDPATH() \ 135226048Sobrien do { \ 136226048Sobrien if (tmppath && access(tmppath, R_OK) != -1) { \ 137226048Sobrien if (hmagicpath == NULL) \ 138226048Sobrien hmagicpath = tmppath; \ 139226048Sobrien else { \ 140226048Sobrien if (asprintf(&hmagicp, "%s%c%s", hmagicpath, \ 141226048Sobrien PATHSEP, tmppath) >= 0) { \ 142226048Sobrien free(hmagicpath); \ 143226048Sobrien hmagicpath = hmagicp; \ 144226048Sobrien } \ 145226048Sobrien free(tmppath); \ 146226048Sobrien } \ 147226048Sobrien tmppath = NULL; \ 148226048Sobrien } \ 149226048Sobrien } while (/*CONSTCOND*/0) 150226048Sobrien 151226048Sobrien if (default_magic) { 152226048Sobrien free(default_magic); 153226048Sobrien default_magic = NULL; 154226048Sobrien } 155226048Sobrien 156226048Sobrien /* First, try to get user-specific magic file */ 157226048Sobrien if ((home = getenv("LOCALAPPDATA")) == NULL) { 158226048Sobrien if ((home = getenv("USERPROFILE")) != NULL) 159226048Sobrien if (asprintf(&tmppath, 160226048Sobrien "%s/Local Settings/Application Data%s", home, 161226048Sobrien hmagic) < 0) 162226048Sobrien tmppath = NULL; 163226048Sobrien } else { 164226048Sobrien if (asprintf(&tmppath, "%s%s", home, hmagic) < 0) 165226048Sobrien tmppath = NULL; 166226048Sobrien } 167226048Sobrien 168226048Sobrien APPENDPATH(); 169226048Sobrien 170226048Sobrien /* Second, try to get a magic file from Common Files */ 171226048Sobrien if ((home = getenv("COMMONPROGRAMFILES")) != NULL) { 172226048Sobrien if (asprintf(&tmppath, "%s%s", home, hmagic) >= 0) 173226048Sobrien APPENDPATH(); 174226048Sobrien } 175226048Sobrien 176226048Sobrien /* Third, try to get magic file relative to dll location */ 177284193Sdelphij dllpath = malloc(sizeof(*dllpath) * (MAX_PATH + 1)); 178226048Sobrien dllpath[MAX_PATH] = 0; /* just in case long path gets truncated and not null terminated */ 179226048Sobrien if (GetModuleFileNameA(NULL, dllpath, MAX_PATH)){ 180226048Sobrien PathRemoveFileSpecA(dllpath); 181226048Sobrien if (strlen(dllpath) > 3 && 182226048Sobrien stricmp(&dllpath[strlen(dllpath) - 3], "bin") == 0) { 183226048Sobrien if (asprintf(&tmppath, 184226048Sobrien "%s/../share/misc/magic.mgc", dllpath) >= 0) 185226048Sobrien APPENDPATH(); 186226048Sobrien } else { 187226048Sobrien if (asprintf(&tmppath, 188226048Sobrien "%s/share/misc/magic.mgc", dllpath) >= 0) 189226048Sobrien APPENDPATH(); 190226048Sobrien else if (asprintf(&tmppath, 191226048Sobrien "%s/magic.mgc", dllpath) >= 0) 192226048Sobrien APPENDPATH(); 193226048Sobrien } 194226048Sobrien } 195226048Sobrien 196226048Sobrien /* Don't put MAGIC constant - it likely points to a file within MSys 197226048Sobrien tree */ 198226048Sobrien default_magic = hmagicpath; 199226048Sobrien return default_magic; 200226048Sobrien#endif 201226048Sobrien} 202226048Sobrien 203226048Sobrienpublic const char * 204226048Sobrienmagic_getpath(const char *magicfile, int action) 205226048Sobrien{ 206226048Sobrien if (magicfile != NULL) 207226048Sobrien return magicfile; 208226048Sobrien 209226048Sobrien magicfile = getenv("MAGIC"); 210226048Sobrien if (magicfile != NULL) 211226048Sobrien return magicfile; 212226048Sobrien 213226048Sobrien return action == FILE_LOAD ? get_default_magic() : MAGIC; 214226048Sobrien} 215226048Sobrien 216133359Sobrienpublic struct magic_set * 217133359Sobrienmagic_open(int flags) 218133359Sobrien{ 219267843Sdelphij return file_ms_alloc(flags); 220133359Sobrien} 221133359Sobrien 222169942Sobrienprivate int 223186690Sobrienunreadable_info(struct magic_set *ms, mode_t md, const char *file) 224169942Sobrien{ 225267843Sdelphij if (file) { 226267843Sdelphij /* We cannot open it, but we were able to stat it. */ 227267843Sdelphij if (access(file, W_OK) == 0) 228267843Sdelphij if (file_printf(ms, "writable, ") == -1) 229267843Sdelphij return -1; 230267843Sdelphij if (access(file, X_OK) == 0) 231267843Sdelphij if (file_printf(ms, "executable, ") == -1) 232267843Sdelphij return -1; 233267843Sdelphij } 234169942Sobrien if (S_ISREG(md)) 235169942Sobrien if (file_printf(ms, "regular file, ") == -1) 236169942Sobrien return -1; 237169942Sobrien if (file_printf(ms, "no read permission") == -1) 238169942Sobrien return -1; 239169942Sobrien return 0; 240169942Sobrien} 241169942Sobrien 242133359Sobrienpublic void 243169942Sobrienmagic_close(struct magic_set *ms) 244133359Sobrien{ 245267843Sdelphij if (ms == NULL) 246267843Sdelphij return; 247267843Sdelphij file_ms_free(ms); 248133359Sobrien} 249133359Sobrien 250133359Sobrien/* 251133359Sobrien * load a magic file 252133359Sobrien */ 253133359Sobrienpublic int 254133359Sobrienmagic_load(struct magic_set *ms, const char *magicfile) 255133359Sobrien{ 256267843Sdelphij if (ms == NULL) 257267843Sdelphij return -1; 258267843Sdelphij return file_apprentice(ms, magicfile, FILE_LOAD); 259133359Sobrien} 260133359Sobrien 261284193Sdelphij#ifndef COMPILE_ONLY 262284193Sdelphij/* 263284193Sdelphij * Install a set of compiled magic buffers. 264284193Sdelphij */ 265133359Sobrienpublic int 266284193Sdelphijmagic_load_buffers(struct magic_set *ms, void **bufs, size_t *sizes, 267284193Sdelphij size_t nbufs) 268284193Sdelphij{ 269284193Sdelphij if (ms == NULL) 270284193Sdelphij return -1; 271284193Sdelphij return buffer_apprentice(ms, (struct magic **)bufs, sizes, nbufs); 272284193Sdelphij} 273284193Sdelphij#endif 274284193Sdelphij 275284193Sdelphijpublic int 276133359Sobrienmagic_compile(struct magic_set *ms, const char *magicfile) 277133359Sobrien{ 278267843Sdelphij if (ms == NULL) 279267843Sdelphij return -1; 280267843Sdelphij return file_apprentice(ms, magicfile, FILE_COMPILE); 281133359Sobrien} 282133359Sobrien 283133359Sobrienpublic int 284133359Sobrienmagic_check(struct magic_set *ms, const char *magicfile) 285133359Sobrien{ 286267843Sdelphij if (ms == NULL) 287267843Sdelphij return -1; 288267843Sdelphij return file_apprentice(ms, magicfile, FILE_CHECK); 289133359Sobrien} 290133359Sobrien 291226048Sobrienpublic int 292226048Sobrienmagic_list(struct magic_set *ms, const char *magicfile) 293226048Sobrien{ 294267843Sdelphij if (ms == NULL) 295267843Sdelphij return -1; 296267843Sdelphij return file_apprentice(ms, magicfile, FILE_LIST); 297226048Sobrien} 298226048Sobrien 299133359Sobrienprivate void 300133359Sobrienclose_and_restore(const struct magic_set *ms, const char *name, int fd, 301133359Sobrien const struct stat *sb) 302133359Sobrien{ 303267843Sdelphij if (fd == STDIN_FILENO || name == NULL) 304159764Sobrien return; 305133359Sobrien (void) close(fd); 306159764Sobrien 307159764Sobrien if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) { 308133359Sobrien /* 309133359Sobrien * Try to restore access, modification times if read it. 310133359Sobrien * This is really *bad* because it will modify the status 311133359Sobrien * time of the file... And of course this will affect 312133359Sobrien * backup programs 313133359Sobrien */ 314133359Sobrien#ifdef HAVE_UTIMES 315133359Sobrien struct timeval utsbuf[2]; 316186690Sobrien (void)memset(utsbuf, 0, sizeof(utsbuf)); 317133359Sobrien utsbuf[0].tv_sec = sb->st_atime; 318133359Sobrien utsbuf[1].tv_sec = sb->st_mtime; 319133359Sobrien 320133359Sobrien (void) utimes(name, utsbuf); /* don't care if loses */ 321133359Sobrien#elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H) 322133359Sobrien struct utimbuf utbuf; 323133359Sobrien 324191736Sobrien (void)memset(&utbuf, 0, sizeof(utbuf)); 325133359Sobrien utbuf.actime = sb->st_atime; 326133359Sobrien utbuf.modtime = sb->st_mtime; 327133359Sobrien (void) utime(name, &utbuf); /* don't care if loses */ 328133359Sobrien#endif 329133359Sobrien } 330133359Sobrien} 331133359Sobrien 332133359Sobrien#ifndef COMPILE_ONLY 333175296Sobrien 334133359Sobrien/* 335175296Sobrien * find type of descriptor 336175296Sobrien */ 337175296Sobrienpublic const char * 338175296Sobrienmagic_descriptor(struct magic_set *ms, int fd) 339175296Sobrien{ 340267843Sdelphij if (ms == NULL) 341267843Sdelphij return NULL; 342175296Sobrien return file_or_fd(ms, NULL, fd); 343175296Sobrien} 344175296Sobrien 345175296Sobrien/* 346133359Sobrien * find type of named file 347133359Sobrien */ 348133359Sobrienpublic const char * 349133359Sobrienmagic_file(struct magic_set *ms, const char *inname) 350133359Sobrien{ 351267843Sdelphij if (ms == NULL) 352267843Sdelphij return NULL; 353175296Sobrien return file_or_fd(ms, inname, STDIN_FILENO); 354175296Sobrien} 355175296Sobrien 356175296Sobrienprivate const char * 357175296Sobrienfile_or_fd(struct magic_set *ms, const char *inname, int fd) 358175296Sobrien{ 359159764Sobrien int rv = -1; 360159764Sobrien unsigned char *buf; 361133359Sobrien struct stat sb; 362133359Sobrien ssize_t nbytes = 0; /* number of bytes read from a datafile */ 363169942Sobrien int ispipe = 0; 364267843Sdelphij off_t pos = (off_t)-1; 365133359Sobrien 366267843Sdelphij if (file_reset(ms) == -1) 367267843Sdelphij goto out; 368267843Sdelphij 369159764Sobrien /* 370159764Sobrien * one extra for terminating '\0', and 371159764Sobrien * some overlapping space for matches near EOF 372159764Sobrien */ 373159764Sobrien#define SLOP (1 + sizeof(union VALUETYPE)) 374186690Sobrien if ((buf = CAST(unsigned char *, malloc(HOWMANY + SLOP))) == NULL) 375133359Sobrien return NULL; 376133359Sobrien 377133359Sobrien switch (file_fsmagic(ms, inname, &sb)) { 378169942Sobrien case -1: /* error */ 379159764Sobrien goto done; 380169942Sobrien case 0: /* nothing found */ 381133359Sobrien break; 382169942Sobrien default: /* matched it and printed type */ 383159764Sobrien rv = 0; 384159764Sobrien goto done; 385133359Sobrien } 386133359Sobrien 387267843Sdelphij#ifdef WIN32 388267843Sdelphij /* Place stdin in binary mode, so EOF (Ctrl+Z) doesn't stop early. */ 389267843Sdelphij if (fd == STDIN_FILENO) 390267843Sdelphij _setmode(STDIN_FILENO, O_BINARY); 391267843Sdelphij#endif 392267843Sdelphij 393169942Sobrien if (inname == NULL) { 394169942Sobrien if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) 395169942Sobrien ispipe = 1; 396267843Sdelphij else 397267843Sdelphij pos = lseek(fd, (off_t)0, SEEK_CUR); 398169942Sobrien } else { 399169942Sobrien int flags = O_RDONLY|O_BINARY; 400267843Sdelphij int okstat = stat(inname, &sb) == 0; 401169942Sobrien 402267843Sdelphij if (okstat && S_ISFIFO(sb.st_mode)) { 403226048Sobrien#ifdef O_NONBLOCK 404169942Sobrien flags |= O_NONBLOCK; 405226048Sobrien#endif 406169942Sobrien ispipe = 1; 407169942Sobrien } 408169942Sobrien 409169942Sobrien errno = 0; 410169942Sobrien if ((fd = open(inname, flags)) < 0) { 411267843Sdelphij#ifdef WIN32 412267843Sdelphij /* 413267843Sdelphij * Can't stat, can't open. It may have been opened in 414267843Sdelphij * fsmagic, so if the user doesn't have read permission, 415267843Sdelphij * allow it to say so; otherwise an error was probably 416267843Sdelphij * displayed in fsmagic. 417267843Sdelphij */ 418267843Sdelphij if (!okstat && errno == EACCES) { 419267843Sdelphij sb.st_mode = S_IFBLK; 420267843Sdelphij okstat = 1; 421267843Sdelphij } 422267843Sdelphij#endif 423267843Sdelphij if (okstat && 424267843Sdelphij unreadable_info(ms, sb.st_mode, inname) == -1) 425175296Sobrien goto done; 426192348Sdelphij rv = 0; 427192348Sdelphij goto done; 428169942Sobrien } 429169942Sobrien#ifdef O_NONBLOCK 430169942Sobrien if ((flags = fcntl(fd, F_GETFL)) != -1) { 431169942Sobrien flags &= ~O_NONBLOCK; 432169942Sobrien (void)fcntl(fd, F_SETFL, flags); 433169942Sobrien } 434169942Sobrien#endif 435133359Sobrien } 436133359Sobrien 437133359Sobrien /* 438133359Sobrien * try looking at the first HOWMANY bytes 439133359Sobrien */ 440169942Sobrien if (ispipe) { 441169942Sobrien ssize_t r = 0; 442169942Sobrien 443169942Sobrien while ((r = sread(fd, (void *)&buf[nbytes], 444169962Sobrien (size_t)(HOWMANY - nbytes), 1)) > 0) { 445169942Sobrien nbytes += r; 446169942Sobrien if (r < PIPE_BUF) break; 447169942Sobrien } 448169942Sobrien 449169942Sobrien if (nbytes == 0) { 450169942Sobrien /* We can not read it, but we were able to stat it. */ 451186690Sobrien if (unreadable_info(ms, sb.st_mode, inname) == -1) 452169942Sobrien goto done; 453169942Sobrien rv = 0; 454169942Sobrien goto done; 455169942Sobrien } 456169942Sobrien 457169942Sobrien } else { 458267843Sdelphij /* Windows refuses to read from a big console buffer. */ 459267843Sdelphij size_t howmany = 460267843Sdelphij#if defined(WIN32) && HOWMANY > 8 * 1024 461267843Sdelphij _isatty(fd) ? 8 * 1024 : 462267843Sdelphij#endif 463267843Sdelphij HOWMANY; 464267843Sdelphij if ((nbytes = read(fd, (char *)buf, howmany)) == -1) { 465267843Sdelphij if (inname == NULL && fd != STDIN_FILENO) 466267843Sdelphij file_error(ms, errno, "cannot read fd %d", fd); 467267843Sdelphij else 468267843Sdelphij file_error(ms, errno, "cannot read `%s'", 469267843Sdelphij inname == NULL ? "/dev/stdin" : inname); 470169942Sobrien goto done; 471169942Sobrien } 472133359Sobrien } 473133359Sobrien 474175296Sobrien (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */ 475175296Sobrien if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1) 476175296Sobrien goto done; 477159764Sobrien rv = 0; 478133359Sobriendone: 479159764Sobrien free(buf); 480267843Sdelphij if (pos != (off_t)-1) 481267843Sdelphij (void)lseek(fd, pos, SEEK_SET); 482133359Sobrien close_and_restore(ms, inname, fd, &sb); 483267843Sdelphijout: 484159764Sobrien return rv == 0 ? file_getbuffer(ms) : NULL; 485133359Sobrien} 486133359Sobrien 487133359Sobrien 488133359Sobrienpublic const char * 489133359Sobrienmagic_buffer(struct magic_set *ms, const void *buf, size_t nb) 490133359Sobrien{ 491267843Sdelphij if (ms == NULL) 492267843Sdelphij return NULL; 493133359Sobrien if (file_reset(ms) == -1) 494133359Sobrien return NULL; 495133359Sobrien /* 496133359Sobrien * The main work is done here! 497186690Sobrien * We have the file name and/or the data buffer to be identified. 498133359Sobrien */ 499169962Sobrien if (file_buffer(ms, -1, NULL, buf, nb) == -1) { 500133359Sobrien return NULL; 501133359Sobrien } 502133359Sobrien return file_getbuffer(ms); 503133359Sobrien} 504133359Sobrien#endif 505133359Sobrien 506133359Sobrienpublic const char * 507133359Sobrienmagic_error(struct magic_set *ms) 508133359Sobrien{ 509267843Sdelphij if (ms == NULL) 510267843Sdelphij return "Magic database is not open"; 511191736Sobrien return (ms->event_flags & EVENT_HAD_ERR) ? ms->o.buf : NULL; 512133359Sobrien} 513133359Sobrien 514133359Sobrienpublic int 515133359Sobrienmagic_errno(struct magic_set *ms) 516133359Sobrien{ 517267843Sdelphij if (ms == NULL) 518267843Sdelphij return EINVAL; 519191736Sobrien return (ms->event_flags & EVENT_HAD_ERR) ? ms->error : 0; 520133359Sobrien} 521133359Sobrien 522133359Sobrienpublic int 523133359Sobrienmagic_setflags(struct magic_set *ms, int flags) 524133359Sobrien{ 525267843Sdelphij if (ms == NULL) 526267843Sdelphij return -1; 527133359Sobrien#if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES) 528133359Sobrien if (flags & MAGIC_PRESERVE_ATIME) 529133359Sobrien return -1; 530133359Sobrien#endif 531133359Sobrien ms->flags = flags; 532133359Sobrien return 0; 533133359Sobrien} 534267843Sdelphij 535267843Sdelphijpublic int 536267843Sdelphijmagic_version(void) 537267843Sdelphij{ 538267843Sdelphij return MAGIC_VERSION; 539267843Sdelphij} 540284193Sdelphij 541284193Sdelphijpublic int 542284193Sdelphijmagic_setparam(struct magic_set *ms, int param, const void *val) 543284193Sdelphij{ 544284193Sdelphij switch (param) { 545284193Sdelphij case MAGIC_PARAM_INDIR_MAX: 546284193Sdelphij ms->indir_max = *(const size_t *)val; 547284193Sdelphij return 0; 548284193Sdelphij case MAGIC_PARAM_NAME_MAX: 549284193Sdelphij ms->name_max = *(const size_t *)val; 550284193Sdelphij return 0; 551284193Sdelphij case MAGIC_PARAM_ELF_PHNUM_MAX: 552284193Sdelphij ms->elf_phnum_max = *(const size_t *)val; 553284193Sdelphij return 0; 554284193Sdelphij case MAGIC_PARAM_ELF_SHNUM_MAX: 555284193Sdelphij ms->elf_shnum_max = *(const size_t *)val; 556284193Sdelphij return 0; 557284193Sdelphij case MAGIC_PARAM_ELF_NOTES_MAX: 558284193Sdelphij ms->elf_notes_max = *(const size_t *)val; 559284193Sdelphij return 0; 560284193Sdelphij default: 561284193Sdelphij errno = EINVAL; 562284193Sdelphij return -1; 563284193Sdelphij } 564284193Sdelphij} 565284193Sdelphij 566284193Sdelphijpublic int 567284193Sdelphijmagic_getparam(struct magic_set *ms, int param, void *val) 568284193Sdelphij{ 569284193Sdelphij switch (param) { 570284193Sdelphij case MAGIC_PARAM_INDIR_MAX: 571284193Sdelphij *(size_t *)val = ms->indir_max; 572284193Sdelphij return 0; 573284193Sdelphij case MAGIC_PARAM_NAME_MAX: 574284193Sdelphij *(size_t *)val = ms->name_max; 575284193Sdelphij return 0; 576284193Sdelphij case MAGIC_PARAM_ELF_PHNUM_MAX: 577284193Sdelphij *(size_t *)val = ms->elf_phnum_max; 578284193Sdelphij return 0; 579284193Sdelphij case MAGIC_PARAM_ELF_SHNUM_MAX: 580284193Sdelphij *(size_t *)val = ms->elf_shnum_max; 581284193Sdelphij return 0; 582284193Sdelphij case MAGIC_PARAM_ELF_NOTES_MAX: 583284193Sdelphij *(size_t *)val = ms->elf_notes_max; 584284193Sdelphij return 0; 585284193Sdelphij default: 586284193Sdelphij errno = EINVAL; 587284193Sdelphij return -1; 588284193Sdelphij } 589284193Sdelphij} 590