1284194Sdelphij/*
2284194Sdelphij * Copyright (c) Christos Zoulas 2003.
3284194Sdelphij * All Rights Reserved.
4284194Sdelphij *
5284194Sdelphij * Redistribution and use in source and binary forms, with or without
6284194Sdelphij * modification, are permitted provided that the following conditions
7284194Sdelphij * are met:
8284194Sdelphij * 1. Redistributions of source code must retain the above copyright
9284194Sdelphij *    notice immediately at the beginning of the file, without modification,
10284194Sdelphij *    this list of conditions, and the following disclaimer.
11284194Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
12284194Sdelphij *    notice, this list of conditions and the following disclaimer in the
13284194Sdelphij *    documentation and/or other materials provided with the distribution.
14284194Sdelphij *
15284194Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16284194Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17284194Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18284194Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19284194Sdelphij * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20284194Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21284194Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22284194Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23284194Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24284194Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25284194Sdelphij * SUCH DAMAGE.
26284194Sdelphij */
27284194Sdelphij
28284194Sdelphij#ifdef WIN32
29284194Sdelphij#include <windows.h>
30284194Sdelphij#include <shlwapi.h>
31284194Sdelphij#endif
32284194Sdelphij
33284194Sdelphij#include "file.h"
34284194Sdelphij
35284194Sdelphij#ifndef	lint
36284194SdelphijFILE_RCSID("@(#)$File: magic.c,v 1.91 2014/12/16 23:18:40 christos Exp $")
37284194Sdelphij#endif	/* lint */
38284194Sdelphij
39284194Sdelphij#include "magic.h"
40284194Sdelphij
41284194Sdelphij#include <stdlib.h>
42284194Sdelphij#include <unistd.h>
43284194Sdelphij#include <string.h>
44284194Sdelphij#ifdef QUICK
45284194Sdelphij#include <sys/mman.h>
46284194Sdelphij#endif
47284194Sdelphij#ifdef HAVE_LIMITS_H
48284194Sdelphij#include <limits.h>	/* for PIPE_BUF */
49284194Sdelphij#endif
50284194Sdelphij
51284194Sdelphij#if defined(HAVE_UTIMES)
52284194Sdelphij# include <sys/time.h>
53284194Sdelphij#elif defined(HAVE_UTIME)
54284194Sdelphij# if defined(HAVE_SYS_UTIME_H)
55284194Sdelphij#  include <sys/utime.h>
56284194Sdelphij# elif defined(HAVE_UTIME_H)
57284194Sdelphij#  include <utime.h>
58284194Sdelphij# endif
59284194Sdelphij#endif
60284194Sdelphij
61284194Sdelphij#ifdef HAVE_UNISTD_H
62284194Sdelphij#include <unistd.h>	/* for read() */
63284194Sdelphij#endif
64284194Sdelphij
65284194Sdelphij#ifndef PIPE_BUF
66284194Sdelphij/* Get the PIPE_BUF from pathconf */
67284194Sdelphij#ifdef _PC_PIPE_BUF
68284194Sdelphij#define PIPE_BUF pathconf(".", _PC_PIPE_BUF)
69284194Sdelphij#else
70284194Sdelphij#define PIPE_BUF 512
71284194Sdelphij#endif
72284194Sdelphij#endif
73284194Sdelphij
74284194Sdelphijprivate void close_and_restore(const struct magic_set *, const char *, int,
75284194Sdelphij    const struct stat *);
76284194Sdelphijprivate int unreadable_info(struct magic_set *, mode_t, const char *);
77284194Sdelphijprivate const char* get_default_magic(void);
78284194Sdelphij#ifndef COMPILE_ONLY
79284194Sdelphijprivate const char *file_or_fd(struct magic_set *, const char *, int);
80284194Sdelphij#endif
81284194Sdelphij
82284194Sdelphij#ifndef	STDIN_FILENO
83284194Sdelphij#define	STDIN_FILENO	0
84284194Sdelphij#endif
85284194Sdelphij
86284194Sdelphijprivate const char *
87284194Sdelphijget_default_magic(void)
88284194Sdelphij{
89284194Sdelphij	static const char hmagic[] = "/.magic/magic.mgc";
90284194Sdelphij	static char *default_magic;
91284194Sdelphij	char *home, *hmagicpath;
92284194Sdelphij
93284194Sdelphij#ifndef WIN32
94284194Sdelphij	struct stat st;
95284194Sdelphij
96284194Sdelphij	if (default_magic) {
97284194Sdelphij		free(default_magic);
98284194Sdelphij		default_magic = NULL;
99284194Sdelphij	}
100284194Sdelphij	if ((home = getenv("HOME")) == NULL)
101284194Sdelphij		return MAGIC;
102284194Sdelphij
103284194Sdelphij	if (asprintf(&hmagicpath, "%s/.magic.mgc", home) < 0)
104284194Sdelphij		return MAGIC;
105284194Sdelphij	if (stat(hmagicpath, &st) == -1) {
106284194Sdelphij		free(hmagicpath);
107284194Sdelphij		if (asprintf(&hmagicpath, "%s/.magic", home) < 0)
108284194Sdelphij			return MAGIC;
109284194Sdelphij		if (stat(hmagicpath, &st) == -1)
110284194Sdelphij			goto out;
111284194Sdelphij		if (S_ISDIR(st.st_mode)) {
112284194Sdelphij			free(hmagicpath);
113284194Sdelphij			if (asprintf(&hmagicpath, "%s/%s", home, hmagic) < 0)
114284194Sdelphij				return MAGIC;
115284194Sdelphij			if (access(hmagicpath, R_OK) == -1)
116284194Sdelphij				goto out;
117284194Sdelphij		}
118284194Sdelphij	}
119284194Sdelphij
120284194Sdelphij	if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0)
121284194Sdelphij		goto out;
122284194Sdelphij	free(hmagicpath);
123284194Sdelphij	return default_magic;
124284194Sdelphijout:
125284194Sdelphij	default_magic = NULL;
126284194Sdelphij	free(hmagicpath);
127284194Sdelphij	return MAGIC;
128284194Sdelphij#else
129284194Sdelphij	char *hmagicp;
130284194Sdelphij	char *tmppath = NULL;
131284194Sdelphij	LPTSTR dllpath;
132284194Sdelphij	hmagicpath = NULL;
133284194Sdelphij
134284194Sdelphij#define APPENDPATH() \
135284194Sdelphij	do { \
136284194Sdelphij		if (tmppath && access(tmppath, R_OK) != -1) { \
137284194Sdelphij			if (hmagicpath == NULL) \
138284194Sdelphij				hmagicpath = tmppath; \
139284194Sdelphij			else { \
140284194Sdelphij				if (asprintf(&hmagicp, "%s%c%s", hmagicpath, \
141284194Sdelphij				    PATHSEP, tmppath) >= 0) { \
142284194Sdelphij					free(hmagicpath); \
143284194Sdelphij					hmagicpath = hmagicp; \
144284194Sdelphij				} \
145284194Sdelphij				free(tmppath); \
146284194Sdelphij			} \
147284194Sdelphij			tmppath = NULL; \
148284194Sdelphij		} \
149284194Sdelphij	} while (/*CONSTCOND*/0)
150284194Sdelphij
151284194Sdelphij	if (default_magic) {
152284194Sdelphij		free(default_magic);
153284194Sdelphij		default_magic = NULL;
154284194Sdelphij	}
155284194Sdelphij
156284194Sdelphij	/* First, try to get user-specific magic file */
157284194Sdelphij	if ((home = getenv("LOCALAPPDATA")) == NULL) {
158284194Sdelphij		if ((home = getenv("USERPROFILE")) != NULL)
159284194Sdelphij			if (asprintf(&tmppath,
160284194Sdelphij			    "%s/Local Settings/Application Data%s", home,
161284194Sdelphij			    hmagic) < 0)
162284194Sdelphij				tmppath = NULL;
163284194Sdelphij	} else {
164284194Sdelphij		if (asprintf(&tmppath, "%s%s", home, hmagic) < 0)
165284194Sdelphij			tmppath = NULL;
166284194Sdelphij	}
167284194Sdelphij
168284194Sdelphij	APPENDPATH();
169284194Sdelphij
170284194Sdelphij	/* Second, try to get a magic file from Common Files */
171284194Sdelphij	if ((home = getenv("COMMONPROGRAMFILES")) != NULL) {
172284194Sdelphij		if (asprintf(&tmppath, "%s%s", home, hmagic) >= 0)
173284194Sdelphij			APPENDPATH();
174284194Sdelphij	}
175284194Sdelphij
176284194Sdelphij	/* Third, try to get magic file relative to dll location */
177284194Sdelphij	dllpath = malloc(sizeof(*dllpath) * (MAX_PATH + 1));
178284194Sdelphij	dllpath[MAX_PATH] = 0;	/* just in case long path gets truncated and not null terminated */
179284194Sdelphij	if (GetModuleFileNameA(NULL, dllpath, MAX_PATH)){
180284194Sdelphij		PathRemoveFileSpecA(dllpath);
181284194Sdelphij		if (strlen(dllpath) > 3 &&
182284194Sdelphij		    stricmp(&dllpath[strlen(dllpath) - 3], "bin") == 0) {
183284194Sdelphij			if (asprintf(&tmppath,
184284194Sdelphij			    "%s/../share/misc/magic.mgc", dllpath) >= 0)
185284194Sdelphij				APPENDPATH();
186284194Sdelphij		} else {
187284194Sdelphij			if (asprintf(&tmppath,
188284194Sdelphij			    "%s/share/misc/magic.mgc", dllpath) >= 0)
189284194Sdelphij				APPENDPATH();
190284194Sdelphij			else if (asprintf(&tmppath,
191284194Sdelphij			    "%s/magic.mgc", dllpath) >= 0)
192284194Sdelphij				APPENDPATH();
193284194Sdelphij		}
194284194Sdelphij	}
195284194Sdelphij
196284194Sdelphij	/* Don't put MAGIC constant - it likely points to a file within MSys
197284194Sdelphij	tree */
198284194Sdelphij	default_magic = hmagicpath;
199284194Sdelphij	return default_magic;
200284194Sdelphij#endif
201284194Sdelphij}
202284194Sdelphij
203284194Sdelphijpublic const char *
204284194Sdelphijmagic_getpath(const char *magicfile, int action)
205284194Sdelphij{
206284194Sdelphij	if (magicfile != NULL)
207284194Sdelphij		return magicfile;
208284194Sdelphij
209284194Sdelphij	magicfile = getenv("MAGIC");
210284194Sdelphij	if (magicfile != NULL)
211284194Sdelphij		return magicfile;
212284194Sdelphij
213284194Sdelphij	return action == FILE_LOAD ? get_default_magic() : MAGIC;
214284194Sdelphij}
215284194Sdelphij
216284194Sdelphijpublic struct magic_set *
217284194Sdelphijmagic_open(int flags)
218284194Sdelphij{
219284194Sdelphij	return file_ms_alloc(flags);
220284194Sdelphij}
221284194Sdelphij
222284194Sdelphijprivate int
223284194Sdelphijunreadable_info(struct magic_set *ms, mode_t md, const char *file)
224284194Sdelphij{
225284194Sdelphij	if (file) {
226284194Sdelphij		/* We cannot open it, but we were able to stat it. */
227284194Sdelphij		if (access(file, W_OK) == 0)
228284194Sdelphij			if (file_printf(ms, "writable, ") == -1)
229284194Sdelphij				return -1;
230284194Sdelphij		if (access(file, X_OK) == 0)
231284194Sdelphij			if (file_printf(ms, "executable, ") == -1)
232284194Sdelphij				return -1;
233284194Sdelphij	}
234284194Sdelphij	if (S_ISREG(md))
235284194Sdelphij		if (file_printf(ms, "regular file, ") == -1)
236284194Sdelphij			return -1;
237284194Sdelphij	if (file_printf(ms, "no read permission") == -1)
238284194Sdelphij		return -1;
239284194Sdelphij	return 0;
240284194Sdelphij}
241284194Sdelphij
242284194Sdelphijpublic void
243284194Sdelphijmagic_close(struct magic_set *ms)
244284194Sdelphij{
245284194Sdelphij	if (ms == NULL)
246284194Sdelphij		return;
247284194Sdelphij	file_ms_free(ms);
248284194Sdelphij}
249284194Sdelphij
250284194Sdelphij/*
251284194Sdelphij * load a magic file
252284194Sdelphij */
253284194Sdelphijpublic int
254284194Sdelphijmagic_load(struct magic_set *ms, const char *magicfile)
255284194Sdelphij{
256284194Sdelphij	if (ms == NULL)
257284194Sdelphij		return -1;
258284194Sdelphij	return file_apprentice(ms, magicfile, FILE_LOAD);
259284194Sdelphij}
260284194Sdelphij
261284194Sdelphij#ifndef COMPILE_ONLY
262284194Sdelphij/*
263284194Sdelphij * Install a set of compiled magic buffers.
264284194Sdelphij */
265284194Sdelphijpublic int
266284194Sdelphijmagic_load_buffers(struct magic_set *ms, void **bufs, size_t *sizes,
267284194Sdelphij    size_t nbufs)
268284194Sdelphij{
269284194Sdelphij	if (ms == NULL)
270284194Sdelphij		return -1;
271284194Sdelphij	return buffer_apprentice(ms, (struct magic **)bufs, sizes, nbufs);
272284194Sdelphij}
273284194Sdelphij#endif
274284194Sdelphij
275284194Sdelphijpublic int
276284194Sdelphijmagic_compile(struct magic_set *ms, const char *magicfile)
277284194Sdelphij{
278284194Sdelphij	if (ms == NULL)
279284194Sdelphij		return -1;
280284194Sdelphij	return file_apprentice(ms, magicfile, FILE_COMPILE);
281284194Sdelphij}
282284194Sdelphij
283284194Sdelphijpublic int
284284194Sdelphijmagic_check(struct magic_set *ms, const char *magicfile)
285284194Sdelphij{
286284194Sdelphij	if (ms == NULL)
287284194Sdelphij		return -1;
288284194Sdelphij	return file_apprentice(ms, magicfile, FILE_CHECK);
289284194Sdelphij}
290284194Sdelphij
291284194Sdelphijpublic int
292284194Sdelphijmagic_list(struct magic_set *ms, const char *magicfile)
293284194Sdelphij{
294284194Sdelphij	if (ms == NULL)
295284194Sdelphij		return -1;
296284194Sdelphij	return file_apprentice(ms, magicfile, FILE_LIST);
297284194Sdelphij}
298284194Sdelphij
299284194Sdelphijprivate void
300284194Sdelphijclose_and_restore(const struct magic_set *ms, const char *name, int fd,
301284194Sdelphij    const struct stat *sb)
302284194Sdelphij{
303284194Sdelphij	if (fd == STDIN_FILENO || name == NULL)
304284194Sdelphij		return;
305284194Sdelphij	(void) close(fd);
306284194Sdelphij
307284194Sdelphij	if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
308284194Sdelphij		/*
309284194Sdelphij		 * Try to restore access, modification times if read it.
310284194Sdelphij		 * This is really *bad* because it will modify the status
311284194Sdelphij		 * time of the file... And of course this will affect
312284194Sdelphij		 * backup programs
313284194Sdelphij		 */
314284194Sdelphij#ifdef HAVE_UTIMES
315284194Sdelphij		struct timeval  utsbuf[2];
316284194Sdelphij		(void)memset(utsbuf, 0, sizeof(utsbuf));
317284194Sdelphij		utsbuf[0].tv_sec = sb->st_atime;
318284194Sdelphij		utsbuf[1].tv_sec = sb->st_mtime;
319284194Sdelphij
320284194Sdelphij		(void) utimes(name, utsbuf); /* don't care if loses */
321284194Sdelphij#elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
322284194Sdelphij		struct utimbuf  utbuf;
323284194Sdelphij
324284194Sdelphij		(void)memset(&utbuf, 0, sizeof(utbuf));
325284194Sdelphij		utbuf.actime = sb->st_atime;
326284194Sdelphij		utbuf.modtime = sb->st_mtime;
327284194Sdelphij		(void) utime(name, &utbuf); /* don't care if loses */
328284194Sdelphij#endif
329284194Sdelphij	}
330284194Sdelphij}
331284194Sdelphij
332284194Sdelphij#ifndef COMPILE_ONLY
333284194Sdelphij
334284194Sdelphij/*
335284194Sdelphij * find type of descriptor
336284194Sdelphij */
337284194Sdelphijpublic const char *
338284194Sdelphijmagic_descriptor(struct magic_set *ms, int fd)
339284194Sdelphij{
340284194Sdelphij	if (ms == NULL)
341284194Sdelphij		return NULL;
342284194Sdelphij	return file_or_fd(ms, NULL, fd);
343284194Sdelphij}
344284194Sdelphij
345284194Sdelphij/*
346284194Sdelphij * find type of named file
347284194Sdelphij */
348284194Sdelphijpublic const char *
349284194Sdelphijmagic_file(struct magic_set *ms, const char *inname)
350284194Sdelphij{
351284194Sdelphij	if (ms == NULL)
352284194Sdelphij		return NULL;
353284194Sdelphij	return file_or_fd(ms, inname, STDIN_FILENO);
354284194Sdelphij}
355284194Sdelphij
356284194Sdelphijprivate const char *
357284194Sdelphijfile_or_fd(struct magic_set *ms, const char *inname, int fd)
358284194Sdelphij{
359284194Sdelphij	int	rv = -1;
360284194Sdelphij	unsigned char *buf;
361284194Sdelphij	struct stat	sb;
362284194Sdelphij	ssize_t nbytes = 0;	/* number of bytes read from a datafile */
363284194Sdelphij	int	ispipe = 0;
364284194Sdelphij	off_t	pos = (off_t)-1;
365284194Sdelphij
366284194Sdelphij	if (file_reset(ms) == -1)
367284194Sdelphij		goto out;
368284194Sdelphij
369284194Sdelphij	/*
370284194Sdelphij	 * one extra for terminating '\0', and
371284194Sdelphij	 * some overlapping space for matches near EOF
372284194Sdelphij	 */
373284194Sdelphij#define SLOP (1 + sizeof(union VALUETYPE))
374284194Sdelphij	if ((buf = CAST(unsigned char *, malloc(HOWMANY + SLOP))) == NULL)
375284194Sdelphij		return NULL;
376284194Sdelphij
377284194Sdelphij	switch (file_fsmagic(ms, inname, &sb)) {
378284194Sdelphij	case -1:		/* error */
379284194Sdelphij		goto done;
380284194Sdelphij	case 0:			/* nothing found */
381284194Sdelphij		break;
382284194Sdelphij	default:		/* matched it and printed type */
383284194Sdelphij		rv = 0;
384284194Sdelphij		goto done;
385284194Sdelphij	}
386284194Sdelphij
387284194Sdelphij#ifdef WIN32
388284194Sdelphij	/* Place stdin in binary mode, so EOF (Ctrl+Z) doesn't stop early. */
389284194Sdelphij	if (fd == STDIN_FILENO)
390284194Sdelphij		_setmode(STDIN_FILENO, O_BINARY);
391284194Sdelphij#endif
392284194Sdelphij
393284194Sdelphij	if (inname == NULL) {
394284194Sdelphij		if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode))
395284194Sdelphij			ispipe = 1;
396284194Sdelphij		else
397284194Sdelphij			pos = lseek(fd, (off_t)0, SEEK_CUR);
398284194Sdelphij	} else {
399284194Sdelphij		int flags = O_RDONLY|O_BINARY;
400284194Sdelphij		int okstat = stat(inname, &sb) == 0;
401284194Sdelphij
402284194Sdelphij		if (okstat && S_ISFIFO(sb.st_mode)) {
403284194Sdelphij#ifdef O_NONBLOCK
404284194Sdelphij			flags |= O_NONBLOCK;
405284194Sdelphij#endif
406284194Sdelphij			ispipe = 1;
407284194Sdelphij		}
408284194Sdelphij
409284194Sdelphij		errno = 0;
410284194Sdelphij		if ((fd = open(inname, flags)) < 0) {
411284194Sdelphij#ifdef WIN32
412284194Sdelphij			/*
413284194Sdelphij			 * Can't stat, can't open.  It may have been opened in
414284194Sdelphij			 * fsmagic, so if the user doesn't have read permission,
415284194Sdelphij			 * allow it to say so; otherwise an error was probably
416284194Sdelphij			 * displayed in fsmagic.
417284194Sdelphij			 */
418284194Sdelphij			if (!okstat && errno == EACCES) {
419284194Sdelphij				sb.st_mode = S_IFBLK;
420284194Sdelphij				okstat = 1;
421284194Sdelphij			}
422284194Sdelphij#endif
423284194Sdelphij			if (okstat &&
424284194Sdelphij			    unreadable_info(ms, sb.st_mode, inname) == -1)
425284194Sdelphij				goto done;
426284194Sdelphij			rv = 0;
427284194Sdelphij			goto done;
428284194Sdelphij		}
429284194Sdelphij#ifdef O_NONBLOCK
430284194Sdelphij		if ((flags = fcntl(fd, F_GETFL)) != -1) {
431284194Sdelphij			flags &= ~O_NONBLOCK;
432284194Sdelphij			(void)fcntl(fd, F_SETFL, flags);
433284194Sdelphij		}
434284194Sdelphij#endif
435284194Sdelphij	}
436284194Sdelphij
437284194Sdelphij	/*
438284194Sdelphij	 * try looking at the first HOWMANY bytes
439284194Sdelphij	 */
440284194Sdelphij	if (ispipe) {
441284194Sdelphij		ssize_t r = 0;
442284194Sdelphij
443284194Sdelphij		while ((r = sread(fd, (void *)&buf[nbytes],
444284194Sdelphij		    (size_t)(HOWMANY - nbytes), 1)) > 0) {
445284194Sdelphij			nbytes += r;
446284194Sdelphij			if (r < PIPE_BUF) break;
447284194Sdelphij		}
448284194Sdelphij
449284194Sdelphij		if (nbytes == 0) {
450284194Sdelphij			/* We can not read it, but we were able to stat it. */
451284194Sdelphij			if (unreadable_info(ms, sb.st_mode, inname) == -1)
452284194Sdelphij				goto done;
453284194Sdelphij			rv = 0;
454284194Sdelphij			goto done;
455284194Sdelphij		}
456284194Sdelphij
457284194Sdelphij	} else {
458284194Sdelphij		/* Windows refuses to read from a big console buffer. */
459284194Sdelphij		size_t howmany =
460284194Sdelphij#if defined(WIN32) && HOWMANY > 8 * 1024
461284194Sdelphij				_isatty(fd) ? 8 * 1024 :
462284194Sdelphij#endif
463284194Sdelphij				HOWMANY;
464284194Sdelphij		if ((nbytes = read(fd, (char *)buf, howmany)) == -1) {
465284194Sdelphij			if (inname == NULL && fd != STDIN_FILENO)
466284194Sdelphij				file_error(ms, errno, "cannot read fd %d", fd);
467284194Sdelphij			else
468284194Sdelphij				file_error(ms, errno, "cannot read `%s'",
469284194Sdelphij				    inname == NULL ? "/dev/stdin" : inname);
470284194Sdelphij			goto done;
471284194Sdelphij		}
472284194Sdelphij	}
473284194Sdelphij
474284194Sdelphij	(void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
475284194Sdelphij	if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1)
476284194Sdelphij		goto done;
477284194Sdelphij	rv = 0;
478284194Sdelphijdone:
479284194Sdelphij	free(buf);
480284194Sdelphij	if (pos != (off_t)-1)
481284194Sdelphij		(void)lseek(fd, pos, SEEK_SET);
482284194Sdelphij	close_and_restore(ms, inname, fd, &sb);
483284194Sdelphijout:
484284194Sdelphij	return rv == 0 ? file_getbuffer(ms) : NULL;
485284194Sdelphij}
486284194Sdelphij
487284194Sdelphij
488284194Sdelphijpublic const char *
489284194Sdelphijmagic_buffer(struct magic_set *ms, const void *buf, size_t nb)
490284194Sdelphij{
491284194Sdelphij	if (ms == NULL)
492284194Sdelphij		return NULL;
493284194Sdelphij	if (file_reset(ms) == -1)
494284194Sdelphij		return NULL;
495284194Sdelphij	/*
496284194Sdelphij	 * The main work is done here!
497284194Sdelphij	 * We have the file name and/or the data buffer to be identified.
498284194Sdelphij	 */
499284194Sdelphij	if (file_buffer(ms, -1, NULL, buf, nb) == -1) {
500284194Sdelphij		return NULL;
501284194Sdelphij	}
502284194Sdelphij	return file_getbuffer(ms);
503284194Sdelphij}
504284194Sdelphij#endif
505284194Sdelphij
506284194Sdelphijpublic const char *
507284194Sdelphijmagic_error(struct magic_set *ms)
508284194Sdelphij{
509284194Sdelphij	if (ms == NULL)
510284194Sdelphij		return "Magic database is not open";
511284194Sdelphij	return (ms->event_flags & EVENT_HAD_ERR) ? ms->o.buf : NULL;
512284194Sdelphij}
513284194Sdelphij
514284194Sdelphijpublic int
515284194Sdelphijmagic_errno(struct magic_set *ms)
516284194Sdelphij{
517284194Sdelphij	if (ms == NULL)
518284194Sdelphij		return EINVAL;
519284194Sdelphij	return (ms->event_flags & EVENT_HAD_ERR) ? ms->error : 0;
520284194Sdelphij}
521284194Sdelphij
522284194Sdelphijpublic int
523284194Sdelphijmagic_setflags(struct magic_set *ms, int flags)
524284194Sdelphij{
525284194Sdelphij	if (ms == NULL)
526284194Sdelphij		return -1;
527284194Sdelphij#if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
528284194Sdelphij	if (flags & MAGIC_PRESERVE_ATIME)
529284194Sdelphij		return -1;
530284194Sdelphij#endif
531284194Sdelphij	ms->flags = flags;
532284194Sdelphij	return 0;
533284194Sdelphij}
534284194Sdelphij
535284194Sdelphijpublic int
536284194Sdelphijmagic_version(void)
537284194Sdelphij{
538284194Sdelphij	return MAGIC_VERSION;
539284194Sdelphij}
540284194Sdelphij
541284194Sdelphijpublic int
542284194Sdelphijmagic_setparam(struct magic_set *ms, int param, const void *val)
543284194Sdelphij{
544284194Sdelphij	switch (param) {
545284194Sdelphij	case MAGIC_PARAM_INDIR_MAX:
546284194Sdelphij		ms->indir_max = *(const size_t *)val;
547284194Sdelphij		return 0;
548284194Sdelphij	case MAGIC_PARAM_NAME_MAX:
549284194Sdelphij		ms->name_max = *(const size_t *)val;
550284194Sdelphij		return 0;
551284194Sdelphij	case MAGIC_PARAM_ELF_PHNUM_MAX:
552284194Sdelphij		ms->elf_phnum_max = *(const size_t *)val;
553284194Sdelphij		return 0;
554284194Sdelphij	case MAGIC_PARAM_ELF_SHNUM_MAX:
555284194Sdelphij		ms->elf_shnum_max = *(const size_t *)val;
556284194Sdelphij		return 0;
557284194Sdelphij	case MAGIC_PARAM_ELF_NOTES_MAX:
558284194Sdelphij		ms->elf_notes_max = *(const size_t *)val;
559284194Sdelphij		return 0;
560284194Sdelphij	default:
561284194Sdelphij		errno = EINVAL;
562284194Sdelphij		return -1;
563284194Sdelphij	}
564284194Sdelphij}
565284194Sdelphij
566284194Sdelphijpublic int
567284194Sdelphijmagic_getparam(struct magic_set *ms, int param, void *val)
568284194Sdelphij{
569284194Sdelphij	switch (param) {
570284194Sdelphij	case MAGIC_PARAM_INDIR_MAX:
571284194Sdelphij		*(size_t *)val = ms->indir_max;
572284194Sdelphij		return 0;
573284194Sdelphij	case MAGIC_PARAM_NAME_MAX:
574284194Sdelphij		*(size_t *)val = ms->name_max;
575284194Sdelphij		return 0;
576284194Sdelphij	case MAGIC_PARAM_ELF_PHNUM_MAX:
577284194Sdelphij		*(size_t *)val = ms->elf_phnum_max;
578284194Sdelphij		return 0;
579284194Sdelphij	case MAGIC_PARAM_ELF_SHNUM_MAX:
580284194Sdelphij		*(size_t *)val = ms->elf_shnum_max;
581284194Sdelphij		return 0;
582284194Sdelphij	case MAGIC_PARAM_ELF_NOTES_MAX:
583284194Sdelphij		*(size_t *)val = ms->elf_notes_max;
584284194Sdelphij		return 0;
585284194Sdelphij	default:
586284194Sdelphij		errno = EINVAL;
587284194Sdelphij		return -1;
588284194Sdelphij	}
589284194Sdelphij}
590