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