+++ /dev/null
-$OpenBSD: LEGAL.NOTICE,v 1.8 2008/05/08 01:40:56 chl Exp $
-Copyright (c) Ian F. Darwin 1986, 1987, 1989, 1990, 1991, 1992, 1994, 1995.
-Software written by Ian F. Darwin and others;
-maintained 1994- Christos Zoulas.
-
-This software is not subject to any export provision of the United States
-Department of Commerce, and may be exported to any country or planet.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice immediately at the beginning of the file, without modification,
- this list of conditions, and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
+++ /dev/null
-$OpenBSD: MAINT,v 1.5 2009/04/24 18:54:34 chl Exp $
-
-Maintenance notes:
-
-I am continuing to maintain the file command. I welcome your help,
-but to make my life easier I'd like to request the following:
-
-- Do not distribute changed versions.
-
-People trying to be helpful occasionally put up their hacked versions
-of the file command for anonymous FTP, and people all over the
-world get copies of the hacked versions. Within a day or two I am
-getting email from around the world asking me why "my" file command
-won't compile!!! Needless to say this detracts from the limited
-time I have available to work on the actual software. Therefore I
-ask you again to please NOT distribute your changed version. If
-you need to make changes, please add a patch file next to the
-distribution tar, and a README file that clearly explains what you
-are trying to fix.
-
-Thank you for your assistance and cooperation.
-
-Code Overview
-
-This is a rough idea of the control flow from the main program:
-
-file.c main()
-file.c process (called for each file)
- printf file name
-magic.c magic_file()
-fsmagic.c file_fsmagic()
- (handles statbuf modes for DEV)
- (handles statbuf modes for executable &c.
- reads data from file.
-funcs.c: file_buffer()
-compress.c file_zmagic()
-is_tar.c file_is_tar()
-softmagic.c file_softmagic()
- match() - looks for match against main magic database
-ascmagic.c file_ascmagic()
-readelf.c file_tryelf()
- "unknown"
-
-Christos Zoulas (see README for email address)
-# $OpenBSD: Makefile,v 1.12 2009/04/14 21:28:10 chl Exp $
+# $OpenBSD: Makefile,v 1.13 2015/04/24 16:24:11 nicm Exp $
+
+PROG= file
+SRCS= file.c magic-dump.c magic-load.c magic-test.c magic-common.c text.c \
+ xmalloc.c
+MAN= file.1 magic.5
+
+CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
+CDIAGFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
+CDIAGFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
+CDIAGFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align
MAGIC= /etc/magic
MAGICOWN= root
MAGICGRP= bin
MAGICMODE= 444
-PROG= file
-SRCS= file.c apprentice.c fsmagic.c softmagic.c ascmagic.c is_tar.c \
- print.c compress.c readelf.c magic.c funcs.c
-CFLAGS+= -DMAGIC='"$(MAGIC)"' -DUSE_UTIMES -DHAVE_CONFIG_H
-MAN= file.1 magic.5
-
CLEANFILES+= magic post-magic
-all: file magic
-MAG1= $(.CURDIR)/magdir/Header\
- $(.CURDIR)/magdir/Localstuff\
+MAG1= $(.CURDIR)/magdir/Header \
+ $(.CURDIR)/magdir/Localstuff \
$(.CURDIR)/magdir/OpenBSD
MAGFILES= $(.CURDIR)/magdir/[0-9a-z]*
-post-magic: $(MAGFILES)
- for i in ${.ALLSRC:N*.orig}; \
- do \
+post-magic: $(MAGFILES)
+ for i in ${.ALLSRC:N*.orig}; do \
echo $$i; \
- done|sort|xargs -n 1024 cat > $(.TARGET)
-
-magic: $(MAG1) post-magic
- cat ${MAG1} post-magic > $(.TARGET)
+ done|sort|xargs -n 1024 cat >$(.TARGET)
+magic: $(MAG1) post-magic
+ cat ${MAG1} post-magic >$(.TARGET)
afterinstall:
- ${INSTALL} ${INSTALL_COPY} -o $(MAGICOWN) -g $(MAGICGRP) -m $(MAGICMODE) magic \
- $(DESTDIR)$(MAGIC)
+ ${INSTALL} ${INSTALL_COPY} -o $(MAGICOWN) -g $(MAGICGRP) \
+ -m $(MAGICMODE) magic $(DESTDIR)$(MAGIC)
+
+all: file magic
.include <bsd.prog.mk>
+++ /dev/null
-** README for file(1) Command **
-@(#) $OpenBSD: README,v 1.5 2009/04/24 18:54:34 chl Exp $
-
-E-mail: christos@astron.com
-Mailing List: file@mx.gw.com
-
-Phone: Do not even think of telephoning me about this program. Send cash first!
-
-This is Release 4.x of Ian Darwin's (copyright but distributable)
-file(1) command. This version is the standard "file" command for Linux,
-*BSD, and other systems. (See "patchlevel.h" for the exact release number).
-
-The major feature of 4.x is the refactoring of the code into a library,
-and the re-write of the file command in terms of that library. The library
-itself, libmagic can be used by 3rd party programs that wish to identify
-file types without having to fork() and exec() file. The prime contributor
-for 4.0 was M\xe5ns Rullg\xe5rd.
-
-UNIX is a trademark of UNIX System Laboratories.
-
-The prime contributor to Release 3.8 was Guy Harris, who put in megachanges
-including byte-order independence.
-
-The prime contributor to Release 3.0 was Christos Zoulas, who put
-in hundreds of lines of source code changes, including his own
-ANSIfication of the code (I liked my own ANSIfication better, but
-his (__P()) is the "Berkeley standard" way of doing it, and I wanted UCB
-to include the code...), his HP-like "indirection" (a feature of
-the HP file command, I think), and his mods that finally got the
-uncompress (-z) mode finished and working.
-
-This release has compiled in numerous environments; see PORTING
-for a list and problems.
-
-This fine freeware file(1) follows the USG (System V) model of the file
-command, rather than the Research (V7) version or the V7-derived 4.[23]
-Berkeley one. That is, the file /etc/magic contains much of the ritual
-information that is the source of this program's power. My version
-knows a little more magic (including tar archives) than System V; the
-/etc/magic parsing seems to be compatible with the (poorly documented)
-System V /etc/magic format (with one exception; see the man page).
-
-In addition, the /etc/magic file is built from a subdirectory
-for easier(?) maintenance. I will act as a clearinghouse for
-magic numbers assigned to all sorts of data files that
-are in reasonable circulation. Send your magic numbers,
-in magic(5) format please, to the maintainer, Christos Zoulas.
-
-LEGAL.NOTICE - read this first.
-README - read this second (you are currently reading this file).
-PORTING - read this only if the program won't compile.
-Makefile - read this next, adapt it as needed (particularly
- the location of the old existing file command and
- the man page layouts), type "make" to compile,
- "make try" to try it out against your old version.
- Expect some diffs, particularly since your original
- file(1) may not grok the embedded-space ("\ ") in
- the current magic file, or may even not use the
- magic file.
-apprentice.c - parses /etc/magic to learn magic
-ascmagic.c - third & last set of tests, based on hardwired assumptions.
-core - not included in distribution due to mailer limitations.
-debug.c - includes -c printout routine
-file.1 - man page for the command
-magic.4 - man page for the magic file, courtesy Guy Harris.
- Install as magic.4 on USG and magic.5 on V7 or Berkeley; cf Makefile.
-file.c - main program
-file.h - header file
-fsmagic.c - first set of tests the program runs, based on filesystem info
-is_tar.c, tar.h - knows about tarchives (courtesy John Gilmore).
-magdir - directory of /etc/magic pieces
- magdir/Makefile - ADJUST THIS FOR YOUR CONFIGURATION
-names.h - header file for ascmagic.c
-softmagic.c - 2nd set of tests, based on /etc/magic
-readelf.[ch] - Stand-alone elf parsing code.
-compress.c - on-the-fly decompression.
-print.c - print results, errors, warnings.
-
-You can download the latest version of file from:
-
- ftp://ftp.astron.com/pub/file/
-
-If your gzip sometimes fails to decompress things complaining about a short
-file, apply this patch [which is going to be in the next version of gzip]:
-*** - Tue Oct 29 02:06:35 1996
---- util.c Sun Jul 21 21:51:38 1996
-*** 106,111 ****
---- 108,114 ----
-
- if (insize == 0) {
- if (eof_ok) return EOF;
-+ flush_window();
- read_error();
- }
- bytes_in += (ulg)insize;
-
-Parts of this software were developed at SoftQuad Inc., developers
-of SGML/HTML/XML publishing software, in Toronto, Canada.
-SoftQuad was swallowed up by Corel in 2002
-and does not exist any longer.
-
-From: Kees Zeelenberg
-
-An MS-Windows (Win32) port of File-4.17 is available from
-http://gnuwin32.sourceforge.net/
-
-File is an implementation of the Unix File(1) command.
-It knows the 'magic number' of several thousands of file types.
+++ /dev/null
-/* $OpenBSD: apprentice.c,v 1.34 2015/01/16 18:08:15 millert Exp $ */
-/*
- * Copyright (c) Ian F. Darwin 1986-1995.
- * Software written by Ian F. Darwin and others;
- * maintained 1995-present by Christos Zoulas and others.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-/*
- * apprentice - make one pass through /etc/magic, learning its secrets.
- */
-
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "file.h"
-#include "magic.h"
-#include "patchlevel.h"
-#include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <limits.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-#include <fcntl.h>
-#ifdef QUICK
-#include <sys/mman.h>
-#endif
-#include <dirent.h>
-
-#define EATAB {while (isascii((unsigned char) *l) && \
- isspace((unsigned char) *l)) ++l;}
-#define LOWCASE(l) (isupper((unsigned char) (l)) ? \
- tolower((unsigned char) (l)) : (l))
-/*
- * Work around a bug in headers on Digital Unix.
- * At least confirmed for: OSF1 V4.0 878
- */
-#if defined(__osf__) && defined(__DECC)
-#ifdef MAP_FAILED
-#undef MAP_FAILED
-#endif
-#endif
-
-#ifndef MAP_FAILED
-#define MAP_FAILED (void *) -1
-#endif
-
-#ifndef MAP_FILE
-#define MAP_FILE 0
-#endif
-
-struct magic_entry {
- struct magic *mp;
- uint32_t cont_count;
- uint32_t max_count;
-};
-
-int file_formats[FILE_NAMES_SIZE];
-const size_t file_nformats = FILE_NAMES_SIZE;
-const char *file_names[FILE_NAMES_SIZE];
-const size_t file_nnames = FILE_NAMES_SIZE;
-
-private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
-private int hextoint(int);
-private const char *getstr(struct magic_set *, const char *, char *, int,
- int *, int);
-private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
- const char *, size_t, int);
-private int parse_mime(struct magic_set *, struct magic_entry **, uint32_t *,
- const char *);
-private void eatsize(const char **);
-private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
-private size_t apprentice_magic_strength(const struct magic *);
-private int apprentice_sort(const void *, const void *);
-private int apprentice_load(struct magic_set *, struct magic **, uint32_t *,
- const char *, int);
-private void byteswap(struct magic *, uint32_t);
-private void bs1(struct magic *);
-private uint16_t swap2(uint16_t);
-private uint32_t swap4(uint32_t);
-private uint64_t swap8(uint64_t);
-private void mkdbname(const char *, char **, int);
-private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
- const char *);
-private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
- const char *);
-private int check_format_type(const char *, int);
-private int check_format(struct magic_set *, struct magic *);
-private int get_op(char);
-
-private size_t maxmagic = 0;
-private size_t magicsize = sizeof(struct magic);
-
-private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
-private const char mime_marker[] = "!:mime";
-private const size_t mime_marker_len = sizeof(mime_marker) - 1;
-
-#ifdef COMPILE_ONLY
-
-int main(int, char *[]);
-
-int
-main(int argc, char *argv[])
-{
- int ret;
- struct magic_set *ms;
- char *progname;
-
- if ((progname = strrchr(argv[0], '/')) != NULL)
- progname++;
- else
- progname = argv[0];
-
- if (argc != 2) {
- (void)fprintf(stderr, "Usage: %s file\n", progname);
- return 1;
- }
-
- if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
- (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
- return 1;
- }
- ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
- if (ret == 1)
- (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
- magic_close(ms);
- return ret;
-}
-#endif /* COMPILE_ONLY */
-
-static const struct type_tbl_s {
- const char name[16];
- const size_t len;
- const int type;
- const int format;
-} type_tbl[] = {
-# define XX(s) s, (sizeof(s) - 1)
-# define XX_NULL "", 0
- { XX("byte"), FILE_BYTE, FILE_FMT_NUM },
- { XX("short"), FILE_SHORT, FILE_FMT_NUM },
- { XX("default"), FILE_DEFAULT, FILE_FMT_STR },
- { XX("long"), FILE_LONG, FILE_FMT_NUM },
- { XX("string"), FILE_STRING, FILE_FMT_STR },
- { XX("date"), FILE_DATE, FILE_FMT_STR },
- { XX("beshort"), FILE_BESHORT, FILE_FMT_NUM },
- { XX("belong"), FILE_BELONG, FILE_FMT_NUM },
- { XX("bedate"), FILE_BEDATE, FILE_FMT_STR },
- { XX("leshort"), FILE_LESHORT, FILE_FMT_NUM },
- { XX("lelong"), FILE_LELONG, FILE_FMT_NUM },
- { XX("ledate"), FILE_LEDATE, FILE_FMT_STR },
- { XX("pstring"), FILE_PSTRING, FILE_FMT_STR },
- { XX("ldate"), FILE_LDATE, FILE_FMT_STR },
- { XX("beldate"), FILE_BELDATE, FILE_FMT_STR },
- { XX("leldate"), FILE_LELDATE, FILE_FMT_STR },
- { XX("regex"), FILE_REGEX, FILE_FMT_STR },
- { XX("bestring16"), FILE_BESTRING16, FILE_FMT_STR },
- { XX("lestring16"), FILE_LESTRING16, FILE_FMT_STR },
- { XX("search"), FILE_SEARCH, FILE_FMT_STR },
- { XX("medate"), FILE_MEDATE, FILE_FMT_STR },
- { XX("meldate"), FILE_MELDATE, FILE_FMT_STR },
- { XX("melong"), FILE_MELONG, FILE_FMT_NUM },
- { XX("quad"), FILE_QUAD, FILE_FMT_QUAD },
- { XX("lequad"), FILE_LEQUAD, FILE_FMT_QUAD },
- { XX("bequad"), FILE_BEQUAD, FILE_FMT_QUAD },
- { XX("qdate"), FILE_QDATE, FILE_FMT_STR },
- { XX("leqdate"), FILE_LEQDATE, FILE_FMT_STR },
- { XX("beqdate"), FILE_BEQDATE, FILE_FMT_STR },
- { XX("qldate"), FILE_QLDATE, FILE_FMT_STR },
- { XX("leqldate"), FILE_LEQLDATE, FILE_FMT_STR },
- { XX("beqldate"), FILE_BEQLDATE, FILE_FMT_STR },
- { XX("float"), FILE_FLOAT, FILE_FMT_FLOAT },
- { XX("befloat"), FILE_BEFLOAT, FILE_FMT_FLOAT },
- { XX("lefloat"), FILE_LEFLOAT, FILE_FMT_FLOAT },
- { XX("double"), FILE_DOUBLE, FILE_FMT_DOUBLE },
- { XX("bedouble"), FILE_BEDOUBLE, FILE_FMT_DOUBLE },
- { XX("ledouble"), FILE_LEDOUBLE, FILE_FMT_DOUBLE },
- { XX_NULL, FILE_INVALID, FILE_FMT_NONE },
-# undef XX
-# undef XX_NULL
-};
-
-private int
-get_type(const char *l, const char **t)
-{
- const struct type_tbl_s *p;
-
- for (p = type_tbl; p->len; p++) {
- if (strncmp(l, p->name, p->len) == 0) {
- if (t)
- *t = l + p->len;
- break;
- }
- }
- return p->type;
-}
-
-private void
-init_file_tables(void)
-{
- static int done = 0;
- const struct type_tbl_s *p;
-
- if (done)
- return;
- done++;
-
- for (p = type_tbl; p->len; p++) {
- assert(p->type < FILE_NAMES_SIZE);
- file_names[p->type] = p->name;
- file_formats[p->type] = p->format;
- }
-}
-
-/*
- * Handle one file or directory.
- */
-private int
-apprentice_1(struct magic_set *ms, const char *fn, int action,
- struct mlist *mlist)
-{
- struct magic *magic = NULL;
- uint32_t nmagic = 0;
- struct mlist *ml;
- int rv = -1;
- int mapped;
-
- if (magicsize != FILE_MAGICSIZE) {
- file_error(ms, 0, "magic element size %lu != %lu",
- (unsigned long)sizeof(*magic),
- (unsigned long)FILE_MAGICSIZE);
- return -1;
- }
-
- if (action == FILE_COMPILE) {
- rv = apprentice_load(ms, &magic, &nmagic, fn, action);
- if (rv != 0)
- return -1;
- rv = apprentice_compile(ms, &magic, &nmagic, fn);
- free(magic);
- return rv;
- }
-
-#ifndef COMPILE_ONLY
- if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "using regular magic file `%s'", fn);
- rv = apprentice_load(ms, &magic, &nmagic, fn, action);
- if (rv != 0)
- return -1;
- }
-
- mapped = rv;
-
- if (magic == NULL) {
- file_delmagic(magic, mapped, nmagic);
- return -1;
- }
-
- if ((ml = malloc(sizeof(*ml))) == NULL) {
- file_delmagic(magic, mapped, nmagic);
- file_oomem(ms, sizeof(*ml));
- return -1;
- }
-
- ml->magic = magic;
- ml->nmagic = nmagic;
- ml->mapped = mapped;
-
- mlist->prev->next = ml;
- ml->prev = mlist->prev;
- ml->next = mlist;
- mlist->prev = ml;
-
- return 0;
-#endif /* COMPILE_ONLY */
-}
-
-protected void
-file_delmagic(struct magic *p, int type, size_t entries)
-{
- if (p == NULL)
- return;
- switch (type) {
-#ifdef QUICK
- case 2:
- p--;
- (void)munmap((void *)p, sizeof(*p) * (entries + 1));
- break;
-#endif
- case 1:
- p--;
- /*FALLTHROUGH*/
- case 0:
- free(p);
- break;
- default:
- abort();
- }
-}
-
-/* const char *fn: list of magic files and directories */
-protected struct mlist *
-file_apprentice(struct magic_set *ms, const char *fn, int action)
-{
- char *p, *mfn;
- int file_err, errs = -1;
- struct mlist *mlist;
-
- init_file_tables();
-
- if (fn == NULL)
- fn = getenv("MAGIC");
- if (fn == NULL)
- fn = MAGIC;
-
- if ((mfn = strdup(fn)) == NULL) {
- file_oomem(ms, strlen(fn));
- return NULL;
- }
- fn = mfn;
-
- if ((mlist = malloc(sizeof(*mlist))) == NULL) {
- free(mfn);
- file_oomem(ms, sizeof(*mlist));
- return NULL;
- }
- mlist->next = mlist->prev = mlist;
-
- while (fn) {
- p = strchr(fn, PATHSEP);
- if (p)
- *p++ = '\0';
- if (*fn == '\0')
- break;
- file_err = apprentice_1(ms, fn, action, mlist);
- errs = MAX(errs, file_err);
- fn = p;
- }
- if (errs == -1) {
- free(mfn);
- free(mlist);
- mlist = NULL;
- file_error(ms, 0, "could not find any magic files!");
- return NULL;
- }
- free(mfn);
- return mlist;
-}
-
-/*
- * Get weight of this magic entry, for sorting purposes.
- */
-private size_t
-apprentice_magic_strength(const struct magic *m)
-{
-#define MULT 10
- size_t val = 2 * MULT; /* baseline strength */
-
- switch (m->type) {
- case FILE_DEFAULT: /* make sure this sorts last */
- return 0;
-
- case FILE_BYTE:
- val += 1 * MULT;
- break;
-
- case FILE_SHORT:
- case FILE_LESHORT:
- case FILE_BESHORT:
- val += 2 * MULT;
- break;
-
- case FILE_LONG:
- case FILE_LELONG:
- case FILE_BELONG:
- case FILE_MELONG:
- val += 4 * MULT;
- break;
-
- case FILE_PSTRING:
- case FILE_STRING:
- val += m->vallen * MULT;
- break;
-
- case FILE_BESTRING16:
- case FILE_LESTRING16:
- val += m->vallen * MULT / 2;
- break;
-
- case FILE_SEARCH:
- case FILE_REGEX:
- val += m->vallen * MAX(MULT / m->vallen, 1);
- break;
-
- case FILE_DATE:
- case FILE_LEDATE:
- case FILE_BEDATE:
- case FILE_MEDATE:
- case FILE_LDATE:
- case FILE_LELDATE:
- case FILE_BELDATE:
- case FILE_MELDATE:
- case FILE_FLOAT:
- case FILE_BEFLOAT:
- case FILE_LEFLOAT:
- val += 4 * MULT;
- break;
-
- case FILE_QUAD:
- case FILE_BEQUAD:
- case FILE_LEQUAD:
- case FILE_QDATE:
- case FILE_LEQDATE:
- case FILE_BEQDATE:
- case FILE_QLDATE:
- case FILE_LEQLDATE:
- case FILE_BEQLDATE:
- case FILE_DOUBLE:
- case FILE_BEDOUBLE:
- case FILE_LEDOUBLE:
- val += 8 * MULT;
- break;
-
- default:
- val = 0;
- (void)fprintf(stderr, "Bad type %d\n", m->type);
- abort();
- }
-
- switch (m->reln) {
- case 'x': /* matches anything penalize */
- case '!': /* matches almost anything penalize */
- val = 0;
- break;
-
- case '=': /* Exact match, prefer */
- val += MULT;
- break;
-
- case '>':
- case '<': /* comparison match reduce strength */
- val -= 2 * MULT;
- break;
-
- case '^':
- case '&': /* masking bits, we could count them too */
- val -= MULT;
- break;
-
- default:
- (void)fprintf(stderr, "Bad relation %c\n", m->reln);
- abort();
- }
-
- if (val == 0) /* ensure we only return 0 for FILE_DEFAULT */
- val = 1;
-
- return val;
-}
-
-/*
- * Sort callback for sorting entries by "strength" (basically length)
- */
-private int
-apprentice_sort(const void *a, const void *b)
-{
- const struct magic_entry *ma = a;
- const struct magic_entry *mb = b;
- size_t sa = apprentice_magic_strength(ma->mp);
- size_t sb = apprentice_magic_strength(mb->mp);
- if (sa == sb)
- return 0;
- else if (sa > sb)
- return -1;
- else
- return 1;
-}
-
-private void
-set_test_type(struct magic *mstart, struct magic *m)
-{
- switch (m->type) {
- case FILE_BYTE:
- case FILE_SHORT:
- case FILE_LONG:
- case FILE_DATE:
- case FILE_BESHORT:
- case FILE_BELONG:
- case FILE_BEDATE:
- case FILE_LESHORT:
- case FILE_LELONG:
- case FILE_LEDATE:
- case FILE_LDATE:
- case FILE_BELDATE:
- case FILE_LELDATE:
- case FILE_MEDATE:
- case FILE_MELDATE:
- case FILE_MELONG:
- case FILE_QUAD:
- case FILE_LEQUAD:
- case FILE_BEQUAD:
- case FILE_QDATE:
- case FILE_LEQDATE:
- case FILE_BEQDATE:
- case FILE_QLDATE:
- case FILE_LEQLDATE:
- case FILE_BEQLDATE:
- case FILE_FLOAT:
- case FILE_BEFLOAT:
- case FILE_LEFLOAT:
- case FILE_DOUBLE:
- case FILE_BEDOUBLE:
- case FILE_LEDOUBLE:
- case FILE_STRING:
- case FILE_PSTRING:
- case FILE_BESTRING16:
- case FILE_LESTRING16:
- /* binary test, set flag */
- mstart->flag |= BINTEST;
- break;
- case FILE_REGEX:
- case FILE_SEARCH:
- /* binary test if pattern is not text */
- if (file_looks_utf8(m->value.s, m->vallen, NULL, NULL) == 0)
- mstart->flag |= BINTEST;
- break;
- case FILE_DEFAULT:
- /* can't deduce anything; we shouldn't see this at the
- top level anyway */
- break;
- case FILE_INVALID:
- default:
- /* invalid search type, but no need to complain here */
- break;
- }
-}
-
-/*
- * Load and parse one file.
- */
-private void
-load_1(struct magic_set *ms, int action, const char *fn, int *errs,
- struct magic_entry **marray, uint32_t *marraycount)
-{
- char line[BUFSIZ];
- size_t lineno = 0;
- FILE *f = fopen(ms->file = fn, "r");
- if (f == NULL) {
- if (errno != ENOENT)
- file_error(ms, errno, "cannot read magic file `%s'",
- fn);
- (*errs)++;
- } else {
- /* read and parse this file */
- for (ms->line = 1; fgets(line, sizeof(line), f) != NULL; ms->line++) {
- size_t len;
- len = strlen(line);
- if (len == 0) /* null line, garbage, etc */
- continue;
- if (line[len - 1] == '\n') {
- lineno++;
- line[len - 1] = '\0'; /* delete newline */
- }
- if (line[0] == '\0') /* empty, do not parse */
- continue;
- if (line[0] == '#') /* comment, do not parse */
- continue;
- if (len > mime_marker_len &&
- memcmp(line, mime_marker, mime_marker_len) == 0) {
- /* MIME type */
- if (parse_mime(ms, marray, marraycount,
- line + mime_marker_len) != 0)
- (*errs)++;
- continue;
- }
- if (parse(ms, marray, marraycount, line, lineno, action) != 0)
- (*errs)++;
- }
-
- (void)fclose(f);
- }
-}
-
-/*
- * parse a file or directory of files
- * const char *fn: name of magic file or directory
- */
-private int
-apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
- const char *fn, int action)
-{
- int errs = 0;
- struct magic_entry *marray;
- uint32_t marraycount, i, mentrycount = 0, starttest;
- char subfn[PATH_MAX];
- struct stat st;
- DIR *dir;
- struct dirent *d;
-
- ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */
-
- maxmagic = MAXMAGIS;
- if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) {
- file_oomem2(ms, maxmagic, sizeof(*marray));
- return -1;
- }
- marraycount = 0;
-
- /* print silly verbose header for USG compat. */
- if (action == FILE_CHECK)
- (void)fprintf(stderr, "%s\n", usg_hdr);
-
- /* load directory or file */
- if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
- dir = opendir(fn);
- if (dir) {
- while ((d = readdir(dir)) != NULL) {
- snprintf(subfn, sizeof(subfn), "%s/%s",
- fn, d->d_name);
- if (stat(subfn, &st) == 0 && S_ISREG(st.st_mode)) {
- load_1(ms, action, subfn, &errs,
- &marray, &marraycount);
- }
- }
- closedir(dir);
- } else
- errs++;
- } else
- load_1(ms, action, fn, &errs, &marray, &marraycount);
- if (errs)
- goto out;
-
- /* Set types of tests */
- for (i = 0; i < marraycount; ) {
- if (marray[i].mp->cont_level != 0) {
- i++;
- continue;
- }
-
- starttest = i;
- do {
- set_test_type(marray[starttest].mp, marray[i].mp);
- if (ms->flags & MAGIC_DEBUG) {
- (void)fprintf(stderr, "%s%s%s: %s\n",
- marray[i].mp->mimetype,
- marray[i].mp->mimetype[0] == '\0' ? "" : "; ",
- marray[i].mp->desc[0] ? marray[i].mp->desc : "(no description)",
- marray[i].mp->flag & BINTEST ? "binary" : "text");
- if (marray[i].mp->flag & BINTEST) {
-#define SYMBOL "text"
-#define SYMLEN sizeof(SYMBOL)
- char *p = strstr(marray[i].mp->desc, "text");
- if (p && (p == marray[i].mp->desc || isspace(p[-1])) &&
- (p + SYMLEN - marray[i].mp->desc == MAXstring ||
- (p[SYMLEN] == '\0' || isspace(p[SYMLEN])))) {
- (void)fprintf(stderr,
- "*** Possible binary test for text type\n");
- }
-#undef SYMBOL
-#undef SYMLEN
- }
- }
- } while (++i < marraycount && marray[i].mp->cont_level != 0);
- }
-
- qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
-
- /*
- * Make sure that any level 0 "default" line is last (if one exists).
- */
- for (i = 0; i < marraycount; i++) {
- if (marray[i].mp->cont_level == 0 &&
- marray[i].mp->type == FILE_DEFAULT) {
- while (++i < marraycount)
- if (marray[i].mp->cont_level == 0)
- break;
- if (i != marraycount) {
- ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
- file_magwarn(ms,
- "level 0 \"default\" did not sort last");
- }
- break;
- }
- }
-
- for (i = 0; i < marraycount; i++)
- mentrycount += marray[i].cont_count;
-
- if ((*magicp = reallocarray(NULL, mentrycount, sizeof(**magicp))) == NULL) {
- file_oomem2(ms, mentrycount, sizeof(**magicp));
- errs++;
- goto out;
- }
-
- mentrycount = 0;
- for (i = 0; i < marraycount; i++) {
- (void)memcpy(*magicp + mentrycount, marray[i].mp,
- marray[i].cont_count * sizeof(**magicp));
- mentrycount += marray[i].cont_count;
- }
-out:
- for (i = 0; i < marraycount; i++)
- free(marray[i].mp);
- free(marray);
- if (errs) {
- *magicp = NULL;
- *nmagicp = 0;
- return errs;
- } else {
- *nmagicp = mentrycount;
- return 0;
- }
-
-}
-
-/*
- * extend the sign bit if the comparison is to be signed
- */
-protected uint64_t
-file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
-{
- if (!(m->flag & UNSIGNED)) {
- switch(m->type) {
- /*
- * Do not remove the casts below. They are
- * vital. When later compared with the data,
- * the sign extension must have happened.
- */
- case FILE_BYTE:
- v = (char) v;
- break;
- case FILE_SHORT:
- case FILE_BESHORT:
- case FILE_LESHORT:
- v = (short) v;
- break;
- case FILE_DATE:
- case FILE_BEDATE:
- case FILE_LEDATE:
- case FILE_MEDATE:
- case FILE_LDATE:
- case FILE_BELDATE:
- case FILE_LELDATE:
- case FILE_MELDATE:
- case FILE_LONG:
- case FILE_BELONG:
- case FILE_LELONG:
- case FILE_MELONG:
- case FILE_FLOAT:
- case FILE_BEFLOAT:
- case FILE_LEFLOAT:
- v = (int32_t) v;
- break;
- case FILE_QUAD:
- case FILE_BEQUAD:
- case FILE_LEQUAD:
- case FILE_QDATE:
- case FILE_QLDATE:
- case FILE_BEQDATE:
- case FILE_BEQLDATE:
- case FILE_LEQDATE:
- case FILE_LEQLDATE:
- case FILE_DOUBLE:
- case FILE_BEDOUBLE:
- case FILE_LEDOUBLE:
- v = (int64_t) v;
- break;
- case FILE_STRING:
- case FILE_PSTRING:
- case FILE_BESTRING16:
- case FILE_LESTRING16:
- case FILE_REGEX:
- case FILE_SEARCH:
- case FILE_DEFAULT:
- break;
- default:
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "cannot happen: m->type=%d\n",
- m->type);
- return ~0U;
- }
- }
- return v;
-}
-
-private int
-string_modifier_check(struct magic_set *ms, struct magic *m)
-{
- if ((ms->flags & MAGIC_CHECK) == 0)
- return 0;
-
- switch (m->type) {
- case FILE_BESTRING16:
- case FILE_LESTRING16:
- if (m->str_flags != 0) {
- file_magwarn(ms,
- "no modifiers allowed for 16-bit strings\n");
- return -1;
- }
- break;
- case FILE_STRING:
- case FILE_PSTRING:
- if ((m->str_flags & REGEX_OFFSET_START) != 0) {
- file_magwarn(ms,
- "'/%c' only allowed on regex and search\n",
- CHAR_REGEX_OFFSET_START);
- return -1;
- }
- break;
- case FILE_SEARCH:
- if (m->str_range == 0) {
- file_magwarn(ms,
- "missing range; defaulting to %d\n",
- STRING_DEFAULT_RANGE);
- m->str_range = STRING_DEFAULT_RANGE;
- return -1;
- }
- break;
- case FILE_REGEX:
- if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
- file_magwarn(ms, "'/%c' not allowed on regex\n",
- CHAR_COMPACT_BLANK);
- return -1;
- }
- if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
- file_magwarn(ms, "'/%c' not allowed on regex\n",
- CHAR_COMPACT_OPTIONAL_BLANK);
- return -1;
- }
- break;
- default:
- file_magwarn(ms, "coding error: m->type=%d\n",
- m->type);
- return -1;
- }
- return 0;
-}
-
-private int
-get_op(char c)
-{
- switch (c) {
- case '&':
- return FILE_OPAND;
- case '|':
- return FILE_OPOR;
- case '^':
- return FILE_OPXOR;
- case '+':
- return FILE_OPADD;
- case '-':
- return FILE_OPMINUS;
- case '*':
- return FILE_OPMULTIPLY;
- case '/':
- return FILE_OPDIVIDE;
- case '%':
- return FILE_OPMODULO;
- default:
- return -1;
- }
-}
-
-#ifdef ENABLE_CONDITIONALS
-private int
-get_cond(const char *l, const char **t)
-{
- static const struct cond_tbl_s {
- char name[8];
- size_t len;
- int cond;
- } cond_tbl[] = {
- { "if", 2, COND_IF },
- { "elif", 4, COND_ELIF },
- { "else", 4, COND_ELSE },
- { "", 0, COND_NONE },
- };
- const struct cond_tbl_s *p;
-
- for (p = cond_tbl; p->len; p++) {
- if (strncmp(l, p->name, p->len) == 0 &&
- isspace((unsigned char)l[p->len])) {
- if (t)
- *t = l + p->len;
- break;
- }
- }
- return p->cond;
-}
-
-private int
-check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
-{
- int last_cond;
- last_cond = ms->c.li[cont_level].last_cond;
-
- switch (cond) {
- case COND_IF:
- if (last_cond != COND_NONE && last_cond != COND_ELIF) {
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "syntax error: `if'");
- return -1;
- }
- last_cond = COND_IF;
- break;
-
- case COND_ELIF:
- if (last_cond != COND_IF && last_cond != COND_ELIF) {
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "syntax error: `elif'");
- return -1;
- }
- last_cond = COND_ELIF;
- break;
-
- case COND_ELSE:
- if (last_cond != COND_IF && last_cond != COND_ELIF) {
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "syntax error: `else'");
- return -1;
- }
- last_cond = COND_NONE;
- break;
-
- case COND_NONE:
- last_cond = COND_NONE;
- break;
- }
-
- ms->c.li[cont_level].last_cond = last_cond;
- return 0;
-}
-#endif /* ENABLE_CONDITIONALS */
-
-/*
- * parse one line from magic file, put into magic[index++] if valid
- */
-private int
-parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp,
- const char *line, size_t lineno, int action)
-{
-#ifdef ENABLE_CONDITIONALS
- static uint32_t last_cont_level = 0;
-#endif
- size_t i;
- struct magic_entry *me;
- struct magic *m;
- const char *l = line;
- char *t;
- int op;
- uint32_t cont_level;
-
- cont_level = 0;
-
- while (*l == '>') {
- ++l; /* step over */
- cont_level++;
- }
-#ifdef ENABLE_CONDITIONALS
- if (cont_level == 0 || cont_level > last_cont_level)
- if (file_check_mem(ms, cont_level) == -1)
- return -1;
- last_cont_level = cont_level;
-#endif
-
-#define ALLOC_CHUNK (size_t)10
-#define ALLOC_INCR (size_t)200
-
- if (cont_level != 0) {
- if (*nmentryp == 0) {
- file_error(ms, 0, "No current entry for continuation");
- return -1;
- }
- me = &(*mentryp)[*nmentryp - 1];
- if (me->cont_count == me->max_count) {
- struct magic *nm;
- size_t cnt = me->max_count + ALLOC_CHUNK;
- if ((nm = reallocarray(me->mp, cnt, sizeof(*nm)))
- == NULL) {
- file_oomem2(ms, cnt, sizeof(*nm));
- return -1;
- }
- me->mp = m = nm;
- me->max_count = cnt;
- }
- m = &me->mp[me->cont_count++];
- (void)memset(m, 0, sizeof(*m));
- m->cont_level = cont_level;
- } else {
- if (*nmentryp == maxmagic) {
- struct magic_entry *mp;
-
- maxmagic += ALLOC_INCR;
- if ((mp = reallocarray(*mentryp, maxmagic,
- sizeof(*mp))) == NULL) {
- file_oomem2(ms, maxmagic, sizeof(*mp));
- return -1;
- }
- (void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
- ALLOC_INCR);
- *mentryp = mp;
- }
- me = &(*mentryp)[*nmentryp];
- if (me->mp == NULL) {
- if ((m = reallocarray(NULL, ALLOC_CHUNK, sizeof(*m))) == NULL) {
- file_oomem2(ms, ALLOC_CHUNK, sizeof(*m));
- return -1;
- }
- me->mp = m;
- me->max_count = ALLOC_CHUNK;
- } else
- m = me->mp;
- (void)memset(m, 0, sizeof(*m));
- m->cont_level = 0;
- me->cont_count = 1;
- }
- m->lineno = lineno;
-
- if (*l == '&') { /* m->cont_level == 0 checked below. */
- ++l; /* step over */
- m->flag |= OFFADD;
- }
- if (*l == '(') {
- ++l; /* step over */
- m->flag |= INDIR;
- if (m->flag & OFFADD)
- m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
-
- if (*l == '&') { /* m->cont_level == 0 checked below */
- ++l; /* step over */
- m->flag |= OFFADD;
- }
- }
- /* Indirect offsets are not valid at level 0. */
- if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "relative offset at level 0");
-
- /* get offset, then skip over it */
- m->offset = (uint32_t)strtoul(l, &t, 0);
- if (l == t)
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "offset `%s' invalid", l);
- l = t;
-
- if (m->flag & INDIR) {
- m->in_type = FILE_LONG;
- m->in_offset = 0;
- /*
- * read [.lbs][+-]nnnnn)
- */
- if (*l == '.') {
- l++;
- switch (*l) {
- case 'l':
- m->in_type = FILE_LELONG;
- break;
- case 'L':
- m->in_type = FILE_BELONG;
- break;
- case 'm':
- m->in_type = FILE_MELONG;
- break;
- case 'h':
- case 's':
- m->in_type = FILE_LESHORT;
- break;
- case 'H':
- case 'S':
- m->in_type = FILE_BESHORT;
- break;
- case 'c':
- case 'b':
- case 'C':
- case 'B':
- m->in_type = FILE_BYTE;
- break;
- case 'e':
- case 'f':
- case 'g':
- m->in_type = FILE_LEDOUBLE;
- break;
- case 'E':
- case 'F':
- case 'G':
- m->in_type = FILE_BEDOUBLE;
- break;
- default:
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms,
- "indirect offset type `%c' invalid",
- *l);
- break;
- }
- l++;
- }
-
- m->in_op = 0;
- if (*l == '~') {
- m->in_op |= FILE_OPINVERSE;
- l++;
- }
- if ((op = get_op(*l)) != -1) {
- m->in_op |= op;
- l++;
- }
- if (*l == '(') {
- m->in_op |= FILE_OPINDIRECT;
- l++;
- }
- if (isdigit((unsigned char)*l) || *l == '-') {
- m->in_offset = (int32_t)strtol(l, &t, 0);
- if (l == t)
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms,
- "in_offset `%s' invalid", l);
- l = t;
- }
- if (*l++ != ')' ||
- ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms,
- "missing ')' in indirect offset");
- }
- EATAB;
-
-#ifdef ENABLE_CONDITIONALS
- m->cond = get_cond(l, &l);
- if (check_cond(ms, m->cond, cont_level) == -1)
- return -1;
-
- EATAB;
-#endif
-
- if (*l == 'u') {
- ++l;
- m->flag |= UNSIGNED;
- }
-
- m->type = get_type(l, &l);
- if (m->type == FILE_INVALID) {
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "type `%s' invalid", l);
- return -1;
- }
-
- /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
- /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
-
- m->mask_op = 0;
- if (*l == '~') {
- if (!IS_STRING(m->type))
- m->mask_op |= FILE_OPINVERSE;
- else if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "'~' invalid for string types");
- ++l;
- }
- m->str_range = 0;
- m->str_flags = 0;
- m->num_mask = 0;
- if ((op = get_op(*l)) != -1) {
- if (!IS_STRING(m->type)) {
- uint64_t val;
- ++l;
- m->mask_op |= op;
- val = (uint64_t)strtoull(l, &t, 0);
- l = t;
- m->num_mask = file_signextend(ms, m, val);
- eatsize(&l);
- }
- else if (op == FILE_OPDIVIDE) {
- int have_range = 0;
- while (!isspace((unsigned char)*++l)) {
- switch (*l) {
- case '0': case '1': case '2':
- case '3': case '4': case '5':
- case '6': case '7': case '8':
- case '9':
- if (have_range &&
- (ms->flags & MAGIC_CHECK))
- file_magwarn(ms,
- "multiple ranges");
- have_range = 1;
- m->str_range = strtoul(l, &t, 0);
- if (m->str_range == 0)
- file_magwarn(ms,
- "zero range");
- l = t - 1;
- break;
- case CHAR_COMPACT_BLANK:
- m->str_flags |= STRING_COMPACT_BLANK;
- break;
- case CHAR_COMPACT_OPTIONAL_BLANK:
- m->str_flags |=
- STRING_COMPACT_OPTIONAL_BLANK;
- break;
- case CHAR_IGNORE_LOWERCASE:
- m->str_flags |= STRING_IGNORE_LOWERCASE;
- break;
- case CHAR_IGNORE_UPPERCASE:
- m->str_flags |= STRING_IGNORE_UPPERCASE;
- break;
- case CHAR_REGEX_OFFSET_START:
- m->str_flags |= REGEX_OFFSET_START;
- break;
- default:
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms,
- "string extension `%c' invalid",
- *l);
- return -1;
- }
- /* allow multiple '/' for readability */
- if (l[1] == '/' &&
- !isspace((unsigned char)l[2]))
- l++;
- }
- if (string_modifier_check(ms, m) == -1)
- return -1;
- }
- else {
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "invalid string op: %c", *t);
- return -1;
- }
- }
- /*
- * We used to set mask to all 1's here, instead let's just not do
- * anything if mask = 0 (unless you have a better idea)
- */
- EATAB;
-
- switch (*l) {
- case '>':
- case '<':
- /* Old-style anding: "0 byte &0x80 dynamically linked" */
- case '&':
- case '^':
- case '=':
- m->reln = *l;
- ++l;
- if (*l == '=') {
- /* HP compat: ignore &= etc. */
- ++l;
- }
- break;
- case '!':
- m->reln = *l;
- ++l;
- break;
- default:
- m->reln = '='; /* the default relation */
- if (*l == 'x' && ((isascii((unsigned char)l[1]) &&
- isspace((unsigned char)l[1])) || !l[1])) {
- m->reln = *l;
- ++l;
- }
- break;
- }
- /*
- * Grab the value part, except for an 'x' reln.
- */
- if (m->reln != 'x' && getvalue(ms, m, &l, action))
- return -1;
-
- /*
- * TODO finish this macro and start using it!
- * #define offsetcheck {if (offset > HOWMANY-1)
- * magwarn("offset too big"); }
- */
-
- /*
- * Now get last part - the description
- */
- EATAB;
- if (l[0] == '\b') {
- ++l;
- m->flag |= NOSPACE;
- } else if ((l[0] == '\\') && (l[1] == 'b')) {
- ++l;
- ++l;
- m->flag |= NOSPACE;
- }
- for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
- continue;
- if (i == sizeof(m->desc)) {
- m->desc[sizeof(m->desc) - 1] = '\0';
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "description `%s' truncated", m->desc);
- }
-
- /*
- * We only do this check while compiling, or if any of the magic
- * files were not compiled.
- */
- if (ms->flags & MAGIC_CHECK) {
- if (check_format(ms, m) == -1)
- return -1;
- }
-#ifndef COMPILE_ONLY
- if (action == FILE_CHECK) {
- file_mdump(m);
- }
-#endif
- m->mimetype[0] = '\0'; /* initialise MIME type to none */
- if (m->cont_level == 0)
- ++(*nmentryp); /* make room for next */
- return 0;
-}
-
-/*
- * parse a MIME annotation line from magic file, put into magic[index - 1]
- * if valid
- */
-private int
-parse_mime(struct magic_set *ms, struct magic_entry **mentryp,
- uint32_t *nmentryp, const char *line)
-{
- size_t i;
- const char *l = line;
- struct magic *m;
- struct magic_entry *me;
-
- if (*nmentryp == 0) {
- file_error(ms, 0, "No current entry for MIME type");
- return -1;
- }
-
- me = &(*mentryp)[*nmentryp - 1];
- m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
-
- if (m->mimetype[0] != '\0') {
- file_error(ms, 0, "Current entry already has a MIME type: %s\n"
- "Description: %s\nNew type: %s", m->mimetype, m->desc, l);
- return -1;
- }
-
- EATAB;
- for (i = 0;
- *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
- || strchr("-+/.", *l)) && i < sizeof(m->mimetype);
- m->mimetype[i++] = *l++)
- continue;
- if (i == sizeof(m->mimetype)) {
- m->desc[sizeof(m->mimetype) - 1] = '\0';
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "MIME type `%s' truncated %zu",
- m->mimetype, i);
- } else
- m->mimetype[i] = '\0';
-
- if (i > 0)
- return 0;
- else
- return -1;
-}
-
-private int
-check_format_type(const char *ptr, int type)
-{
- int quad = 0;
- if (*ptr == '\0') {
- /* Missing format string; bad */
- return -1;
- }
-
- switch (type) {
- case FILE_FMT_QUAD:
- quad = 1;
- /*FALLTHROUGH*/
- case FILE_FMT_NUM:
- if (*ptr == '-')
- ptr++;
- if (*ptr == '.')
- ptr++;
- while (isdigit((unsigned char)*ptr)) ptr++;
- if (*ptr == '.')
- ptr++;
- while (isdigit((unsigned char)*ptr)) ptr++;
- if (quad) {
- if (*ptr++ != 'l')
- return -1;
- if (*ptr++ != 'l')
- return -1;
- }
-
- switch (*ptr++) {
- case 'l':
- switch (*ptr++) {
- case 'i':
- case 'd':
- case 'u':
- case 'x':
- case 'X':
- return 0;
- default:
- return -1;
- }
-
- case 'h':
- switch (*ptr++) {
- case 'h':
- switch (*ptr++) {
- case 'i':
- case 'd':
- case 'u':
- case 'x':
- case 'X':
- return 0;
- default:
- return -1;
- }
- case 'd':
- return 0;
- default:
- return -1;
- }
-
- case 'i':
- case 'c':
- case 'd':
- case 'u':
- case 'x':
- case 'X':
- return 0;
-
- default:
- return -1;
- }
-
- case FILE_FMT_FLOAT:
- case FILE_FMT_DOUBLE:
- if (*ptr == '-')
- ptr++;
- if (*ptr == '.')
- ptr++;
- while (isdigit((unsigned char)*ptr)) ptr++;
- if (*ptr == '.')
- ptr++;
- while (isdigit((unsigned char)*ptr)) ptr++;
-
- switch (*ptr++) {
- case 'e':
- case 'E':
- case 'f':
- case 'F':
- case 'g':
- case 'G':
- return 0;
-
- default:
- return -1;
- }
-
-
- case FILE_FMT_STR:
- if (*ptr == '-')
- ptr++;
- while (isdigit((unsigned char )*ptr))
- ptr++;
- if (*ptr == '.') {
- ptr++;
- while (isdigit((unsigned char )*ptr))
- ptr++;
- }
-
- switch (*ptr++) {
- case 's':
- return 0;
- default:
- return -1;
- }
-
- default:
- /* internal error */
- abort();
- }
- /*NOTREACHED*/
- return -1;
-}
-
-/*
- * Check that the optional printf format in description matches
- * the type of the magic.
- */
-private int
-check_format(struct magic_set *ms, struct magic *m)
-{
- char *ptr;
-
- for (ptr = m->desc; *ptr; ptr++)
- if (*ptr == '%')
- break;
- if (*ptr == '\0') {
- /* No format string; ok */
- return 1;
- }
-
- assert(file_nformats == file_nnames);
-
- if (m->type >= file_nformats) {
- file_magwarn(ms, "Internal error inconsistency between "
- "m->type and format strings");
- return -1;
- }
- if (file_formats[m->type] == FILE_FMT_NONE) {
- file_magwarn(ms, "No format string for `%s' with description "
- "`%s'", m->desc, file_names[m->type]);
- return -1;
- }
-
- ptr++;
- if (check_format_type(ptr, file_formats[m->type]) == -1) {
- /*
- * TODO: this error message is unhelpful if the format
- * string is not one character long
- */
- file_magwarn(ms, "Printf format `%c' is not valid for type "
- "`%s' in description `%s'",
- ptr && *ptr ? *ptr : '?',
- file_names[m->type], m->desc);
- return -1;
- }
-
- for (; *ptr; ptr++) {
- if (*ptr == '%') {
- file_magwarn(ms,
- "Too many format strings (should have at most one) "
- "for `%s' with description `%s'",
- file_names[m->type], m->desc);
- return -1;
- }
- }
- return 0;
-}
-
-/*
- * Read a numeric value from a pointer, into the value union of a magic
- * pointer, according to the magic type. Update the string pointer to point
- * just after the number read. Return 0 for success, non-zero for failure.
- */
-private int
-getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
-{
- int slen;
-
- switch (m->type) {
- case FILE_BESTRING16:
- case FILE_LESTRING16:
- case FILE_STRING:
- case FILE_PSTRING:
- case FILE_REGEX:
- case FILE_SEARCH:
- *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen, action);
- if (*p == NULL) {
- if (ms->flags & MAGIC_CHECK)
- file_magwarn(ms, "cannot get string from `%s'",
- m->value.s);
- return -1;
- }
- m->vallen = slen;
- if (m->type == FILE_PSTRING)
- m->vallen++;
- return 0;
- case FILE_FLOAT:
- case FILE_BEFLOAT:
- case FILE_LEFLOAT:
- if (m->reln != 'x') {
- char *ep;
-#ifdef HAVE_STRTOF
- m->value.f = strtof(*p, &ep);
-#else
- m->value.f = (float)strtod(*p, &ep);
-#endif
- *p = ep;
- }
- return 0;
- case FILE_DOUBLE:
- case FILE_BEDOUBLE:
- case FILE_LEDOUBLE:
- if (m->reln != 'x') {
- char *ep;
- m->value.d = strtod(*p, &ep);
- *p = ep;
- }
- return 0;
- default:
- if (m->reln != 'x') {
- char *ep;
- m->value.q = file_signextend(ms, m,
- (uint64_t)strtoull(*p, &ep, 0));
- *p = ep;
- eatsize(p);
- }
- return 0;
- }
-}
-
-/*
- * Convert a string containing C character escapes. Stop at an unescaped
- * space or tab.
- * Copy the converted version to "p", returning its length in *slen.
- * Return updated scan pointer as function result.
- */
-private const char *
-getstr(struct magic_set *ms, const char *s, char *p, int plen, int *slen, int action)
-{
- const char *origs = s;
- char *origp = p;
- char *pmax = p + plen - 1;
- int c;
- int val;
-
- while ((c = *s++) != '\0') {
- if (isspace((unsigned char) c))
- break;
- if (p >= pmax) {
- file_error(ms, 0, "string too long: `%s'", origs);
- return NULL;
- }
- if (c == '\\') {
- switch(c = *s++) {
-
- case '\0':
- if (action == FILE_COMPILE)
- file_magwarn(ms, "incomplete escape");
- goto out;
-
- case '\t':
- if (action == FILE_COMPILE) {
- file_magwarn(ms,
- "escaped tab found, use \\t instead");
- action++;
- }
- /*FALLTHROUGH*/
- default:
- if (action == FILE_COMPILE) {
- if (isprint((unsigned char)c))
- file_magwarn(ms,
- "no need to escape `%c'", c);
- else
- file_magwarn(ms,
- "unknown escape sequence: \\%03o", c);
- }
- /*FALLTHROUGH*/
- /* space, perhaps force people to use \040? */
- case ' ':
-#if 0
- /*
- * Other things people escape, but shouldn't need to,
- * so we disallow them
- */
- case '\'':
- case '"':
- case '?':
-#endif
- /* Relations */
- case '>':
- case '<':
- case '&':
- case '^':
- case '=':
- case '!':
- /* and baskslash itself */
- case '\\':
- *p++ = (char) c;
- break;
-
- case 'a':
- *p++ = '\a';
- break;
-
- case 'b':
- *p++ = '\b';
- break;
-
- case 'f':
- *p++ = '\f';
- break;
-
- case 'n':
- *p++ = '\n';
- break;
-
- case 'r':
- *p++ = '\r';
- break;
-
- case 't':
- *p++ = '\t';
- break;
-
- case 'v':
- *p++ = '\v';
- break;
-
- /* \ and up to 3 octal digits */
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- val = c - '0';
- c = *s++; /* try for 2 */
- if (c >= '0' && c <= '7') {
- val = (val << 3) | (c - '0');
- c = *s++; /* try for 3 */
- if (c >= '0' && c <= '7')
- val = (val << 3) | (c-'0');
- else
- --s;
- }
- else
- --s;
- *p++ = (char)val;
- break;
-
- /* \x and up to 2 hex digits */
- case 'x':
- val = 'x'; /* Default if no digits */
- c = hextoint(*s++); /* Get next char */
- if (c >= 0) {
- val = c;
- c = hextoint(*s++);
- if (c >= 0)
- val = (val << 4) + c;
- else
- --s;
- } else
- --s;
- *p++ = (char)val;
- break;
- }
- } else
- *p++ = (char)c;
- }
-out:
- *p = '\0';
- *slen = p - origp;
- return s;
-}
-
-
-/* Single hex char to int; -1 if not a hex char. */
-private int
-hextoint(int c)
-{
- if (!isascii((unsigned char) c))
- return -1;
- if (isdigit((unsigned char) c))
- return c - '0';
- if ((c >= 'a') && (c <= 'f'))
- return c + 10 - 'a';
- if (( c>= 'A') && (c <= 'F'))
- return c + 10 - 'A';
- return -1;
-}
-
-
-/*
- * Print a string containing C character escapes.
- */
-protected void
-file_showstr(FILE *fp, const char *s, size_t len)
-{
- char c;
-
- for (;;) {
- c = *s++;
- if (len == ~0U) {
- if (c == '\0')
- break;
- }
- else {
- if (len-- == 0)
- break;
- }
- if (c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
- (void) fputc(c, fp);
- else {
- (void) fputc('\\', fp);
- switch (c) {
- case '\a':
- (void) fputc('a', fp);
- break;
-
- case '\b':
- (void) fputc('b', fp);
- break;
-
- case '\f':
- (void) fputc('f', fp);
- break;
-
- case '\n':
- (void) fputc('n', fp);
- break;
-
- case '\r':
- (void) fputc('r', fp);
- break;
-
- case '\t':
- (void) fputc('t', fp);
- break;
-
- case '\v':
- (void) fputc('v', fp);
- break;
-
- default:
- (void) fprintf(fp, "%.3o", c & 0377);
- break;
- }
- }
- }
-}
-
-/*
- * eatsize(): Eat the size spec from a number [eg. 10UL]
- */
-private void
-eatsize(const char **p)
-{
- const char *l = *p;
-
- if (LOWCASE(*l) == 'u')
- l++;
-
- switch (LOWCASE(*l)) {
- case 'l': /* long */
- case 's': /* short */
- case 'h': /* short */
- case 'b': /* char/byte */
- case 'c': /* char/byte */
- l++;
- /*FALLTHROUGH*/
- default:
- break;
- }
-
- *p = l;
-}
-
-/*
- * handle a compiled file.
- */
-private int
-apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
- const char *fn)
-{
- int fd;
- struct stat st;
- uint32_t *ptr;
- uint32_t version;
- int needsbyteswap;
- char *dbname = NULL;
- void *mm = NULL;
-
- mkdbname(fn, &dbname, 0);
- if (dbname == NULL)
- goto error2;
-
- if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
- goto error2;
-
- if (fstat(fd, &st) == -1) {
- file_error(ms, errno, "cannot stat `%s'", dbname);
- goto error1;
- }
- if (st.st_size < 8 || st.st_size > SIZE_MAX) {
- file_error(ms, 0, "file `%s' is too %s", dbname,
- st.st_size > SIZE_MAX ? "large" : "small");
- goto error1;
- }
-
-#ifdef QUICK
- if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
- file_error(ms, errno, "cannot map `%s'", dbname);
- goto error1;
- }
-#define RET 2
-#else
- if ((mm = malloc((size_t)st.st_size)) == NULL) {
- file_oomem(ms, (size_t)st.st_size);
- goto error1;
- }
- if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
- file_badread(ms);
- goto error1;
- }
-#define RET 1
-#endif
- *magicp = mm;
- (void)close(fd);
- fd = -1;
- ptr = (uint32_t *)(void *)*magicp;
- if (*ptr != MAGICNO) {
- if (swap4(*ptr) != MAGICNO) {
- file_error(ms, 0, "bad magic in `%s'");
- goto error1;
- }
- needsbyteswap = 1;
- } else
- needsbyteswap = 0;
- if (needsbyteswap)
- version = swap4(ptr[1]);
- else
- version = ptr[1];
- if (version != VERSIONNO) {
- file_error(ms, 0, "File %d.%d supports only %d version magic "
- "files. `%s' is version %d", FILE_VERSION_MAJOR, patchlevel,
- VERSIONNO, dbname, version);
- goto error1;
- }
- *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic));
- if (*nmagicp > 0)
- (*nmagicp)--;
- (*magicp)++;
- if (needsbyteswap)
- byteswap(*magicp, *nmagicp);
- free(dbname);
- return RET;
-
-error1:
- if (fd != -1)
- (void)close(fd);
- if (mm) {
-#ifdef QUICK
- (void)munmap((void *)mm, (size_t)st.st_size);
-#else
- free(mm);
-#endif
- } else {
- *magicp = NULL;
- *nmagicp = 0;
- }
-error2:
- free(dbname);
- return -1;
-}
-
-private const uint32_t ar[] = {
- MAGICNO, VERSIONNO
-};
-/*
- * handle an mmaped file.
- */
-private int
-apprentice_compile(struct magic_set *ms, struct magic **magicp,
- uint32_t *nmagicp, const char *fn)
-{
- int fd;
- char *dbname;
- int rv = -1;
-
- mkdbname(fn, &dbname, 1);
-
- if (dbname == NULL)
- goto out;
-
- if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
- file_error(ms, errno, "cannot open `%s'", dbname);
- goto out;
- }
-
- if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
- file_error(ms, errno, "error writing `%s'", dbname);
- goto out;
- }
-
- if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
- != sizeof(struct magic)) {
- file_error(ms, errno, "error seeking `%s'", dbname);
- goto out;
- }
-
- if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp))
- != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
- file_error(ms, errno, "error writing `%s'", dbname);
- goto out;
- }
-
- (void)close(fd);
- rv = 0;
-out:
- free(dbname);
- return rv;
-}
-
-private const char ext[] = ".mgc";
-/*
- * make a dbname
- */
-private void
-mkdbname(const char *fn, char **buf, int strip)
-{
- if (strip) {
- const char *p;
- if ((p = strrchr(fn, '/')) != NULL)
- fn = ++p;
- }
-
- (void)asprintf(buf, "%s%s", fn, ext);
- if (*buf && strlen(*buf) > PATH_MAX) {
- free(*buf);
- *buf = NULL;
- }
-}
-
-/*
- * Byteswap an mmap'ed file if needed
- */
-private void
-byteswap(struct magic *magic, uint32_t nmagic)
-{
- uint32_t i;
- for (i = 0; i < nmagic; i++)
- bs1(&magic[i]);
-}
-
-/*
- * swap a short
- */
-private uint16_t
-swap2(uint16_t sv)
-{
- uint16_t rv;
- uint8_t *s = (uint8_t *)(void *)&sv;
- uint8_t *d = (uint8_t *)(void *)&rv;
- d[0] = s[1];
- d[1] = s[0];
- return rv;
-}
-
-/*
- * swap an int
- */
-private uint32_t
-swap4(uint32_t sv)
-{
- uint32_t rv;
- uint8_t *s = (uint8_t *)(void *)&sv;
- uint8_t *d = (uint8_t *)(void *)&rv;
- d[0] = s[3];
- d[1] = s[2];
- d[2] = s[1];
- d[3] = s[0];
- return rv;
-}
-
-/*
- * swap a quad
- */
-private uint64_t
-swap8(uint64_t sv)
-{
- uint64_t rv;
- uint8_t *s = (uint8_t *)(void *)&sv;
- uint8_t *d = (uint8_t *)(void *)&rv;
-#if 0
- d[0] = s[3];
- d[1] = s[2];
- d[2] = s[1];
- d[3] = s[0];
- d[4] = s[7];
- d[5] = s[6];
- d[6] = s[5];
- d[7] = s[4];
-#else
- d[0] = s[7];
- d[1] = s[6];
- d[2] = s[5];
- d[3] = s[4];
- d[4] = s[3];
- d[5] = s[2];
- d[6] = s[1];
- d[7] = s[0];
-#endif
- return rv;
-}
-
-/*
- * byteswap a single magic entry
- */
-private void
-bs1(struct magic *m)
-{
- m->cont_level = swap2(m->cont_level);
- m->offset = swap4((uint32_t)m->offset);
- m->in_offset = swap4((uint32_t)m->in_offset);
- m->lineno = swap4((uint32_t)m->lineno);
- if (IS_STRING(m->type)) {
- m->str_range = swap4(m->str_range);
- m->str_flags = swap4(m->str_flags);
- }
- else {
- m->value.q = swap8(m->value.q);
- m->num_mask = swap8(m->num_mask);
- }
-}
+++ /dev/null
-/* $OpenBSD: ascmagic.c,v 1.12 2014/05/18 17:50:11 espie Exp $ */
-/*
- * Copyright (c) Ian F. Darwin 1986-1995.
- * Software written by Ian F. Darwin and others;
- * maintained 1995-present by Christos Zoulas and others.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-/*
- * ASCII magic -- file types that we know based on keywords
- * that can appear anywhere in the file.
- *
- * Extensively modified by Eric Fischer <enf@pobox.com> in July, 2000,
- * to handle character codes other than ASCII on a unified basis.
- *
- * Joerg Wunsch <joerg@freebsd.org> wrote the original support for 8-bit
- * international characters, now subsumed into this file.
- */
-
-#include "file.h"
-#include "magic.h"
-#include <stdio.h>
-#include <string.h>
-#include <memory.h>
-#include <ctype.h>
-#include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include "names.h"
-
-#define MAXLINELEN 300 /* longest sane line length */
-#define ISSPC(x) ((x) == ' ' || (x) == '\t' || (x) == '\r' || (x) == '\n' \
- || (x) == 0x85 || (x) == '\f')
-
-private int looks_ascii(const unsigned char *, size_t, unichar *, size_t *);
-private int looks_utf8_with_BOM(const unsigned char *, size_t, unichar *,
- size_t *);
-protected int file_looks_utf8(const unsigned char *, size_t, unichar *, size_t *);
-private int looks_ucs16(const unsigned char *, size_t, unichar *, size_t *);
-private int looks_latin1(const unsigned char *, size_t, unichar *, size_t *);
-private int looks_extended(const unsigned char *, size_t, unichar *, size_t *);
-private void from_ebcdic(const unsigned char *, size_t, unsigned char *);
-private int ascmatch(const unsigned char *, const unichar *, size_t);
-private unsigned char *encode_utf8(unsigned char *, size_t, unichar *, size_t);
-
-
-protected int
-file_ascmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes)
-{
- size_t i;
- unsigned char *nbuf = NULL, *utf8_buf = NULL, *utf8_end;
- unichar *ubuf = NULL;
- size_t ulen, mlen;
- const struct names *p;
- int rv = -1;
- int mime = ms->flags & MAGIC_MIME;
-
- const char *code = NULL;
- const char *code_mime = NULL;
- const char *type = NULL;
- const char *subtype = NULL;
- const char *subtype_mime = NULL;
-
- int has_escapes = 0;
- int has_backspace = 0;
- int seen_cr = 0;
-
- int n_crlf = 0;
- int n_lf = 0;
- int n_cr = 0;
- int n_nel = 0;
-
- size_t last_line_end = (size_t)-1;
- int has_long_lines = 0;
-
- /*
- * Undo the NUL-termination kindly provided by process()
- * but leave at least one byte to look at
- */
- while (nbytes > 1 && buf[nbytes - 1] == '\0')
- nbytes--;
-
- if ((nbuf = calloc((nbytes + 1), sizeof(nbuf[0]))) == NULL)
- goto done;
- if ((ubuf = calloc((nbytes + 1), sizeof(ubuf[0]))) == NULL)
- goto done;
-
- /*
- * Then try to determine whether it's any character code we can
- * identify. Each of these tests, if it succeeds, will leave
- * the text converted into one-unichar-per-character Unicode in
- * ubuf, and the number of characters converted in ulen.
- */
- if (looks_ascii(buf, nbytes, ubuf, &ulen)) {
- code = "ASCII";
- code_mime = "us-ascii";
- type = "text";
- } else if (looks_utf8_with_BOM(buf, nbytes, ubuf, &ulen) > 0) {
- code = "UTF-8 Unicode (with BOM)";
- code_mime = "utf-8";
- type = "text";
- } else if (file_looks_utf8(buf, nbytes, ubuf, &ulen) > 1) {
- code = "UTF-8 Unicode";
- code_mime = "utf-8";
- type = "text";
- } else if ((i = looks_ucs16(buf, nbytes, ubuf, &ulen)) != 0) {
- if (i == 1)
- code = "Little-endian UTF-16 Unicode";
- else
- code = "Big-endian UTF-16 Unicode";
-
- type = "character data";
- code_mime = "utf-16"; /* is this defined? */
- } else if (looks_latin1(buf, nbytes, ubuf, &ulen)) {
- code = "ISO-8859";
- type = "text";
- code_mime = "iso-8859-1";
- } else if (looks_extended(buf, nbytes, ubuf, &ulen)) {
- code = "Non-ISO extended-ASCII";
- type = "text";
- code_mime = "unknown";
- } else {
- from_ebcdic(buf, nbytes, nbuf);
-
- if (looks_ascii(nbuf, nbytes, ubuf, &ulen)) {
- code = "EBCDIC";
- type = "character data";
- code_mime = "ebcdic";
- } else if (looks_latin1(nbuf, nbytes, ubuf, &ulen)) {
- code = "International EBCDIC";
- type = "character data";
- code_mime = "ebcdic";
- } else {
- rv = 0;
- goto done; /* doesn't look like text at all */
- }
- }
-
- if (nbytes <= 1) {
- rv = 0;
- goto done;
- }
-
- /* Convert ubuf to UTF-8 and try text soft magic */
- /* If original was ASCII or UTF-8, could use nbuf instead of
- re-converting. */
- /* malloc size is a conservative overestimate; could be
- re-converting improved, or at least realloced after
- re-converting conversion. */
- mlen = ulen * 6;
- if ((utf8_buf = malloc(mlen)) == NULL) {
- file_oomem(ms, mlen);
- goto done;
- }
- if ((utf8_end = encode_utf8(utf8_buf, mlen, ubuf, ulen)) == NULL)
- goto done;
- if (file_softmagic(ms, utf8_buf, utf8_end - utf8_buf, TEXTTEST) != 0) {
- rv = 1;
- goto done;
- }
-
- /* look for tokens from names.h - this is expensive! */
- if ((ms->flags & MAGIC_NO_CHECK_TOKENS) != 0)
- goto subtype_identified;
-
- i = 0;
- while (i < ulen) {
- size_t end;
-
- /* skip past any leading space */
- while (i < ulen && ISSPC(ubuf[i]))
- i++;
- if (i >= ulen)
- break;
-
- /* find the next whitespace */
- for (end = i + 1; end < nbytes; end++)
- if (ISSPC(ubuf[end]))
- break;
-
- /* compare the word thus isolated against the token list */
- for (p = names; p < names + NNAMES; p++) {
- if (ascmatch((const unsigned char *)p->name, ubuf + i,
- end - i)) {
- subtype = types[p->type].human;
- subtype_mime = types[p->type].mime;
- goto subtype_identified;
- }
- }
-
- i = end;
- }
-
-subtype_identified:
-
- /* Now try to discover other details about the file. */
- for (i = 0; i < ulen; i++) {
- if (ubuf[i] == '\n') {
- if (seen_cr)
- n_crlf++;
- else
- n_lf++;
- last_line_end = i;
- } else if (seen_cr)
- n_cr++;
-
- seen_cr = (ubuf[i] == '\r');
- if (seen_cr)
- last_line_end = i;
-
- if (ubuf[i] == 0x85) { /* X3.64/ECMA-43 "next line" character */
- n_nel++;
- last_line_end = i;
- }
-
- /* If this line is _longer_ than MAXLINELEN, remember it. */
- if (i > last_line_end + MAXLINELEN)
- has_long_lines = 1;
-
- if (ubuf[i] == '\033')
- has_escapes = 1;
- if (ubuf[i] == '\b')
- has_backspace = 1;
- }
-
- /* Beware, if the data has been truncated, the final CR could have
- been followed by a LF. If we have HOWMANY bytes, it indicates
- that the data might have been truncated, probably even before
- this function was called. */
- if (seen_cr && nbytes < HOWMANY)
- n_cr++;
-
- if (mime) {
- if (mime & MAGIC_MIME_TYPE) {
- if (subtype_mime) {
- if (file_printf(ms, subtype_mime) == -1)
- goto done;
- } else {
- if (file_printf(ms, "text/plain") == -1)
- goto done;
- }
- }
-
- if ((mime == 0 || mime == MAGIC_MIME) && code_mime) {
- if ((mime & MAGIC_MIME_TYPE) &&
- file_printf(ms, " charset=") == -1)
- goto done;
- if (file_printf(ms, code_mime) == -1)
- goto done;
- }
-
- if (mime == MAGIC_MIME_ENCODING)
- file_printf(ms, "binary");
- } else {
- if (file_printf(ms, code) == -1)
- goto done;
-
- if (subtype) {
- if (file_printf(ms, " ") == -1)
- goto done;
- if (file_printf(ms, subtype) == -1)
- goto done;
- }
-
- if (file_printf(ms, " ") == -1)
- goto done;
- if (file_printf(ms, type) == -1)
- goto done;
-
- if (has_long_lines)
- if (file_printf(ms, ", with very long lines") == -1)
- goto done;
-
- /*
- * Only report line terminators if we find one other than LF,
- * or if we find none at all.
- */
- if ((n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) ||
- (n_crlf != 0 || n_cr != 0 || n_nel != 0)) {
- if (file_printf(ms, ", with") == -1)
- goto done;
-
- if (n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) {
- if (file_printf(ms, " no") == -1)
- goto done;
- } else {
- if (n_crlf) {
- if (file_printf(ms, " CRLF") == -1)
- goto done;
- if (n_cr || n_lf || n_nel)
- if (file_printf(ms, ",") == -1)
- goto done;
- }
- if (n_cr) {
- if (file_printf(ms, " CR") == -1)
- goto done;
- if (n_lf || n_nel)
- if (file_printf(ms, ",") == -1)
- goto done;
- }
- if (n_lf) {
- if (file_printf(ms, " LF") == -1)
- goto done;
- if (n_nel)
- if (file_printf(ms, ",") == -1)
- goto done;
- }
- if (n_nel)
- if (file_printf(ms, " NEL") == -1)
- goto done;
- }
-
- if (file_printf(ms, " line terminators") == -1)
- goto done;
- }
-
- if (has_escapes)
- if (file_printf(ms, ", with escape sequences") == -1)
- goto done;
- if (has_backspace)
- if (file_printf(ms, ", with overstriking") == -1)
- goto done;
- }
- rv = 1;
-done:
- if (nbuf)
- free(nbuf);
- if (ubuf)
- free(ubuf);
- if (utf8_buf)
- free(utf8_buf);
-
- return rv;
-}
-
-private int
-ascmatch(const unsigned char *s, const unichar *us, size_t ulen)
-{
- size_t i;
-
- for (i = 0; i < ulen; i++) {
- if (s[i] != us[i])
- return 0;
- }
-
- if (s[i])
- return 0;
- else
- return 1;
-}
-
-/*
- * This table reflects a particular philosophy about what constitutes
- * "text," and there is room for disagreement about it.
- *
- * Version 3.31 of the file command considered a file to be ASCII if
- * each of its characters was approved by either the isascii() or
- * isalpha() function. On most systems, this would mean that any
- * file consisting only of characters in the range 0x00 ... 0x7F
- * would be called ASCII text, but many systems might reasonably
- * consider some characters outside this range to be alphabetic,
- * so the file command would call such characters ASCII. It might
- * have been more accurate to call this "considered textual on the
- * local system" than "ASCII."
- *
- * It considered a file to be "International language text" if each
- * of its characters was either an ASCII printing character (according
- * to the real ASCII standard, not the above test), a character in
- * the range 0x80 ... 0xFF, or one of the following control characters:
- * backspace, tab, line feed, vertical tab, form feed, carriage return,
- * escape. No attempt was made to determine the language in which files
- * of this type were written.
- *
- *
- * The table below considers a file to be ASCII if all of its characters
- * are either ASCII printing characters (again, according to the X3.4
- * standard, not isascii()) or any of the following controls: bell,
- * backspace, tab, line feed, form feed, carriage return, esc, nextline.
- *
- * I include bell because some programs (particularly shell scripts)
- * use it literally, even though it is rare in normal text. I exclude
- * vertical tab because it never seems to be used in real text. I also
- * include, with hesitation, the X3.64/ECMA-43 control nextline (0x85),
- * because that's what the dd EBCDIC->ASCII table maps the EBCDIC newline
- * character to. It might be more appropriate to include it in the 8859
- * set instead of the ASCII set, but it's got to be included in *something*
- * we recognize or EBCDIC files aren't going to be considered textual.
- * Some old Unix source files use SO/SI (^N/^O) to shift between Greek
- * and Latin characters, so these should possibly be allowed. But they
- * make a real mess on VT100-style displays if they're not paired properly,
- * so we are probably better off not calling them text.
- *
- * A file is considered to be ISO-8859 text if its characters are all
- * either ASCII, according to the above definition, or printing characters
- * from the ISO-8859 8-bit extension, characters 0xA0 ... 0xFF.
- *
- * Finally, a file is considered to be international text from some other
- * character code if its characters are all either ISO-8859 (according to
- * the above definition) or characters in the range 0x80 ... 0x9F, which
- * ISO-8859 considers to be control characters but the IBM PC and Macintosh
- * consider to be printing characters.
- */
-
-#define F 0 /* character never appears in text */
-#define T 1 /* character appears in plain ASCII text */
-#define I 2 /* character appears in ISO-8859 text */
-#define X 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
-
-private char text_chars[256] = {
- /* BEL BS HT LF FF CR */
- F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F, /* 0x0X */
- /* ESC */
- F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */
- T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */
- T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */
- T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */
- T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */
- T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */
- T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */
- /* NEL */
- X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X, /* 0x8X */
- X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 0x9X */
- I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xaX */
- I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xbX */
- I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xcX */
- I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xdX */
- I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xeX */
- I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I /* 0xfX */
-};
-
-private int
-looks_ascii(const unsigned char *buf, size_t nbytes, unichar *ubuf,
- size_t *ulen)
-{
- size_t i;
-
- *ulen = 0;
-
- for (i = 0; i < nbytes; i++) {
- int t = text_chars[buf[i]];
-
- if (t != T)
- return 0;
-
- ubuf[(*ulen)++] = buf[i];
- }
-
- return 1;
-}
-
-private int
-looks_latin1(const unsigned char *buf, size_t nbytes, unichar *ubuf, size_t *ulen)
-{
- size_t i;
-
- *ulen = 0;
-
- for (i = 0; i < nbytes; i++) {
- int t = text_chars[buf[i]];
-
- if (t != T && t != I)
- return 0;
-
- ubuf[(*ulen)++] = buf[i];
- }
-
- return 1;
-}
-
-private int
-looks_extended(const unsigned char *buf, size_t nbytes, unichar *ubuf,
- size_t *ulen)
-{
- size_t i;
-
- *ulen = 0;
-
- for (i = 0; i < nbytes; i++) {
- int t = text_chars[buf[i]];
-
- if (t != T && t != I && t != X)
- return 0;
-
- ubuf[(*ulen)++] = buf[i];
- }
-
- return 1;
-}
-
-/*
- * Encode Unicode string as UTF-8, returning pointer to character
- * after end of string, or NULL if an invalid character is found.
- */
-private unsigned char *
-encode_utf8(unsigned char *buf, size_t len, unichar *ubuf, size_t ulen)
-{
- size_t i;
- unsigned char *end = buf + len;
-
- for (i = 0; i < ulen; i++) {
- if (ubuf[i] <= 0x7f) {
- if (end - buf < 1)
- return NULL;
- *buf++ = (unsigned char)ubuf[i];
- } else if (ubuf[i] <= 0x7ff) {
- if (end - buf < 2)
- return NULL;
- *buf++ = (unsigned char)((ubuf[i] >> 6) + 0xc0);
- *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
- } else if (ubuf[i] <= 0xffff) {
- if (end - buf < 3)
- return NULL;
- *buf++ = (unsigned char)((ubuf[i] >> 12) + 0xe0);
- *buf++ = (unsigned char)(((ubuf[i] >> 6) & 0x3f) + 0x80);
- *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
- } else if (ubuf[i] <= 0x1fffff) {
- if (end - buf < 4)
- return NULL;
- *buf++ = (unsigned char)((ubuf[i] >> 18) + 0xf0);
- *buf++ = (unsigned char)(((ubuf[i] >> 12) & 0x3f) + 0x80);
- *buf++ = (unsigned char)(((ubuf[i] >> 6) & 0x3f) + 0x80);
- *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
- } else if (ubuf[i] <= 0x3ffffff) {
- if (end - buf < 5)
- return NULL;
- *buf++ = (unsigned char)((ubuf[i] >> 24) + 0xf8);
- *buf++ = (unsigned char)(((ubuf[i] >> 18) & 0x3f) + 0x80);
- *buf++ = (unsigned char)(((ubuf[i] >> 12) & 0x3f) + 0x80);
- *buf++ = (unsigned char)(((ubuf[i] >> 6) & 0x3f) + 0x80);
- *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
- } else if (ubuf[i] <= 0x7fffffff) {
- if (end - buf < 6)
- return NULL;
- *buf++ = (unsigned char)((ubuf[i] >> 30) + 0xfc);
- *buf++ = (unsigned char)(((ubuf[i] >> 24) & 0x3f) + 0x80);
- *buf++ = (unsigned char)(((ubuf[i] >> 18) & 0x3f) + 0x80);
- *buf++ = (unsigned char)(((ubuf[i] >> 12) & 0x3f) + 0x80);
- *buf++ = (unsigned char)(((ubuf[i] >> 6) & 0x3f) + 0x80);
- *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
- } else /* Invalid character */
- return NULL;
- }
-
- return buf;
-}
-
-/*
- * Decide whether some text looks like UTF-8. Returns:
- *
- * -1: invalid UTF-8
- * 0: uses odd control characters, so doesn't look like text
- * 1: 7-bit text
- * 2: definitely UTF-8 text (valid high-bit set bytes)
- *
- * If ubuf is non-NULL on entry, text is decoded into ubuf, *ulen;
- * ubuf must be big enough!
- */
-protected int
-file_looks_utf8(const unsigned char *buf, size_t nbytes, unichar *ubuf, size_t *ulen)
-{
- size_t i;
- int n;
- unichar c;
- int gotone = 0, ctrl = 0;
-
- if (ubuf)
- *ulen = 0;
-
- for (i = 0; i < nbytes; i++) {
- if ((buf[i] & 0x80) == 0) { /* 0xxxxxxx is plain ASCII */
- /*
- * Even if the whole file is valid UTF-8 sequences,
- * still reject it if it uses weird control characters.
- */
-
- if (text_chars[buf[i]] != T)
- ctrl = 1;
-
- if (ubuf)
- ubuf[(*ulen)++] = buf[i];
- } else if ((buf[i] & 0x40) == 0) { /* 10xxxxxx never 1st byte */
- return -1;
- } else { /* 11xxxxxx begins UTF-8 */
- int following;
-
- if ((buf[i] & 0x20) == 0) { /* 110xxxxx */
- c = buf[i] & 0x1f;
- following = 1;
- } else if ((buf[i] & 0x10) == 0) { /* 1110xxxx */
- c = buf[i] & 0x0f;
- following = 2;
- } else if ((buf[i] & 0x08) == 0) { /* 11110xxx */
- c = buf[i] & 0x07;
- following = 3;
- } else if ((buf[i] & 0x04) == 0) { /* 111110xx */
- c = buf[i] & 0x03;
- following = 4;
- } else if ((buf[i] & 0x02) == 0) { /* 1111110x */
- c = buf[i] & 0x01;
- following = 5;
- } else
- return -1;
-
- for (n = 0; n < following; n++) {
- i++;
- if (i >= nbytes)
- goto done;
-
- if ((buf[i] & 0x80) == 0 || (buf[i] & 0x40))
- return -1;
-
- c = (c << 6) + (buf[i] & 0x3f);
- }
-
- if (ubuf)
- ubuf[(*ulen)++] = c;
- gotone = 1;
- }
- }
-done:
- return ctrl ? 0 : (gotone ? 2 : 1);
-}
-
-/*
- * Decide whether some text looks like UTF-8 with BOM. If there is no
- * BOM, return -1; otherwise return the result of looks_utf8 on the
- * rest of the text.
- */
-private int
-looks_utf8_with_BOM(const unsigned char *buf, size_t nbytes, unichar *ubuf,
- size_t *ulen)
-{
- if (nbytes > 3 && buf[0] == 0xef && buf[1] == 0xbb && buf[2] == 0xbf)
- return file_looks_utf8(buf + 3, nbytes - 3, ubuf, ulen);
- else
- return -1;
-}
-
-private int
-looks_ucs16(const unsigned char *buf, size_t nbytes, unichar *ubuf,
- size_t *ulen)
-{
- int bigend;
- size_t i;
-
- if (nbytes < 2)
- return 0;
-
- if (buf[0] == 0xff && buf[1] == 0xfe)
- bigend = 0;
- else if (buf[0] == 0xfe && buf[1] == 0xff)
- bigend = 1;
- else
- return 0;
-
- *ulen = 0;
-
- for (i = 2; i + 1 < nbytes; i += 2) {
- /* XXX fix to properly handle chars > 65536 */
-
- if (bigend)
- ubuf[(*ulen)++] = buf[i + 1] + 256 * buf[i];
- else
- ubuf[(*ulen)++] = buf[i] + 256 * buf[i + 1];
-
- if (ubuf[*ulen - 1] == 0xfffe)
- return 0;
- if (ubuf[*ulen - 1] < 128 &&
- text_chars[(size_t)ubuf[*ulen - 1]] != T)
- return 0;
- }
-
- return 1 + bigend;
-}
-
-#undef F
-#undef T
-#undef I
-#undef X
-
-/*
- * This table maps each EBCDIC character to an (8-bit extended) ASCII
- * character, as specified in the rationale for the dd(1) command in
- * draft 11.2 (September, 1991) of the POSIX P1003.2 standard.
- *
- * Unfortunately it does not seem to correspond exactly to any of the
- * five variants of EBCDIC documented in IBM's _Enterprise Systems
- * Architecture/390: Principles of Operation_, SA22-7201-06, Seventh
- * Edition, July, 1999, pp. I-1 - I-4.
- *
- * Fortunately, though, all versions of EBCDIC, including this one, agree
- * on most of the printing characters that also appear in (7-bit) ASCII.
- * Of these, only '|', '!', '~', '^', '[', and ']' are in question at all.
- *
- * Fortunately too, there is general agreement that codes 0x00 through
- * 0x3F represent control characters, 0x41 a nonbreaking space, and the
- * remainder printing characters.
- *
- * This is sufficient to allow us to identify EBCDIC text and to distinguish
- * between old-style and internationalized examples of text.
- */
-
-private unsigned char ebcdic_to_ascii[] = {
- 0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 157, 133, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31,
-128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7,
-144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26,
-' ', 160, 161, 162, 163, 164, 165, 166, 167, 168, 213, '.', '<', '(', '+', '|',
-'&', 169, 170, 171, 172, 173, 174, 175, 176, 177, '!', '$', '*', ')', ';', '~',
-'-', '/', 178, 179, 180, 181, 182, 183, 184, 185, 203, ',', '%', '_', '>', '?',
-186, 187, 188, 189, 190, 191, 192, 193, 194, '`', ':', '#', '@', '\'','=', '"',
-195, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 196, 197, 198, 199, 200, 201,
-202, 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', '^', 204, 205, 206, 207, 208,
-209, 229, 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 210, 211, 212, '[', 214, 215,
-216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, ']', 230, 231,
-'{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 232, 233, 234, 235, 236, 237,
-'}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 238, 239, 240, 241, 242, 243,
-'\\',159, 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 244, 245, 246, 247, 248, 249,
-'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 250, 251, 252, 253, 254, 255
-};
-
-#ifdef notdef
-/*
- * The following EBCDIC-to-ASCII table may relate more closely to reality,
- * or at least to modern reality. It comes from
- *
- * http://ftp.s390.ibm.com/products/oe/bpxqp9.html
- *
- * and maps the characters of EBCDIC code page 1047 (the code used for
- * Unix-derived software on IBM's 390 systems) to the corresponding
- * characters from ISO 8859-1.
- *
- * If this table is used instead of the above one, some of the special
- * cases for the NEL character can be taken out of the code.
- */
-
-private unsigned char ebcdic_1047_to_8859[] = {
-0x00,0x01,0x02,0x03,0x9C,0x09,0x86,0x7F,0x97,0x8D,0x8E,0x0B,0x0C,0x0D,0x0E,0x0F,
-0x10,0x11,0x12,0x13,0x9D,0x0A,0x08,0x87,0x18,0x19,0x92,0x8F,0x1C,0x1D,0x1E,0x1F,
-0x80,0x81,0x82,0x83,0x84,0x85,0x17,0x1B,0x88,0x89,0x8A,0x8B,0x8C,0x05,0x06,0x07,
-0x90,0x91,0x16,0x93,0x94,0x95,0x96,0x04,0x98,0x99,0x9A,0x9B,0x14,0x15,0x9E,0x1A,
-0x20,0xA0,0xE2,0xE4,0xE0,0xE1,0xE3,0xE5,0xE7,0xF1,0xA2,0x2E,0x3C,0x28,0x2B,0x7C,
-0x26,0xE9,0xEA,0xEB,0xE8,0xED,0xEE,0xEF,0xEC,0xDF,0x21,0x24,0x2A,0x29,0x3B,0x5E,
-0x2D,0x2F,0xC2,0xC4,0xC0,0xC1,0xC3,0xC5,0xC7,0xD1,0xA6,0x2C,0x25,0x5F,0x3E,0x3F,
-0xF8,0xC9,0xCA,0xCB,0xC8,0xCD,0xCE,0xCF,0xCC,0x60,0x3A,0x23,0x40,0x27,0x3D,0x22,
-0xD8,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0xAB,0xBB,0xF0,0xFD,0xFE,0xB1,
-0xB0,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0xAA,0xBA,0xE6,0xB8,0xC6,0xA4,
-0xB5,0x7E,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0xA1,0xBF,0xD0,0x5B,0xDE,0xAE,
-0xAC,0xA3,0xA5,0xB7,0xA9,0xA7,0xB6,0xBC,0xBD,0xBE,0xDD,0xA8,0xAF,0x5D,0xB4,0xD7,
-0x7B,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0xAD,0xF4,0xF6,0xF2,0xF3,0xF5,
-0x7D,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0xB9,0xFB,0xFC,0xF9,0xFA,0xFF,
-0x5C,0xF7,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xB2,0xD4,0xD6,0xD2,0xD3,0xD5,
-0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0xB3,0xDB,0xDC,0xD9,0xDA,0x9F
-};
-#endif
-
-/*
- * Copy buf[0 ... nbytes-1] into out[], translating EBCDIC to ASCII.
- */
-private void
-from_ebcdic(const unsigned char *buf, size_t nbytes, unsigned char *out)
-{
- size_t i;
-
- for (i = 0; i < nbytes; i++) {
- out[i] = ebcdic_to_ascii[buf[i]];
- }
-}
+++ /dev/null
-/* $OpenBSD: compress.c,v 1.16 2013/04/20 19:02:57 deraadt Exp $ */
-/*
- * Copyright (c) Ian F. Darwin 1986-1995.
- * Software written by Ian F. Darwin and others;
- * maintained 1995-present by Christos Zoulas and others.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-/*
- * compress routines:
- * zmagic() - returns 0 if not recognized, uncompresses and prints
- * information if recognized
- * uncompress(method, old, n, newch) - uncompress old into new,
- * using method, return sizeof new
- */
-#include "file.h"
-#include "magic.h"
-#include <stdio.h>
-#include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <string.h>
-#include <errno.h>
-#include <poll.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-#if defined(HAVE_SYS_TIME_H)
-#include <sys/time.h>
-#endif
-#if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ)
-#define BUILTIN_DECOMPRESS
-#include <zlib.h>
-#endif
-
-
-private const struct {
- const char magic[8];
- size_t maglen;
- const char *argv[3];
- int silent;
-} compr[] = {
- { "\037\235", 2, { "gzip", "-cdq", NULL }, 1 }, /* compressed */
- /* Uncompress can get stuck; so use gzip first if we have it
- * Idea from Damien Clark, thanks! */
- { "\037\235", 2, { "uncompress", "-c", NULL }, 1 }, /* compressed */
- { "\037\213", 2, { "gzip", "-cdq", NULL }, 1 }, /* gzipped */
- { "\037\236", 2, { "gzip", "-cdq", NULL }, 1 }, /* frozen */
- { "\037\240", 2, { "gzip", "-cdq", NULL }, 1 }, /* SCO LZH */
- /* the standard pack utilities do not accept standard input */
- { "\037\036", 2, { "gzip", "-cdq", NULL }, 0 }, /* packed */
- { "PK\3\4", 4, { "gzip", "-cdq", NULL }, 1 }, /* pkzipped, */
- /* ...only first file examined */
- { "BZh", 3, { "bzip2", "-cd", NULL }, 1 }, /* bzip2-ed */
-};
-
-private size_t ncompr = sizeof(compr) / sizeof(compr[0]);
-
-#define NODATA ((size_t)~0)
-
-
-private ssize_t swrite(int, const void *, size_t);
-private size_t uncompressbuf(struct magic_set *, int, size_t,
- const unsigned char *, unsigned char **, size_t);
-#ifdef BUILTIN_DECOMPRESS
-private size_t uncompressgzipped(struct magic_set *, const unsigned char *,
- unsigned char **, size_t);
-#endif
-
-protected int
-file_zmagic(struct magic_set *ms, int fd, const char *name,
- const unsigned char *buf, size_t nbytes)
-{
- unsigned char *newbuf = NULL;
- size_t i, nsz;
- int rv = 0;
- int mime = ms->flags & MAGIC_MIME;
-
- if ((ms->flags & MAGIC_COMPRESS) == 0)
- return 0;
-
- for (i = 0; i < ncompr; i++) {
- if (nbytes < compr[i].maglen)
- continue;
- if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 &&
- (nsz = uncompressbuf(ms, fd, i, buf, &newbuf,
- nbytes)) != NODATA) {
- ms->flags &= ~MAGIC_COMPRESS;
- rv = -1;
- if (file_buffer(ms, -1, name, newbuf, nsz) == -1)
- goto error;
-
- if (mime == MAGIC_MIME || mime == 0) {
- if (file_printf(ms, mime ?
- " compressed-encoding=" : " (") == -1)
- goto error;
- }
-
- if ((mime == 0 || mime & MAGIC_MIME_ENCODING) &&
- file_buffer(ms, -1, NULL, buf, nbytes) == -1)
- goto error;
-
- if (!mime && file_printf(ms, ")") == -1)
- goto error;
- rv = 1;
- break;
- }
- }
-error:
- if (newbuf)
- free(newbuf);
- ms->flags |= MAGIC_COMPRESS;
- return rv;
-}
-
-/*
- * `safe' write for sockets and pipes.
- */
-private ssize_t
-swrite(int fd, const void *buf, size_t n)
-{
- int rv;
- size_t rn = n;
-
- do
- switch (rv = write(fd, buf, n)) {
- case -1:
- if (errno == EINTR)
- continue;
- return -1;
- default:
- n -= rv;
- buf = ((const char *)buf) + rv;
- break;
- }
- while (n > 0);
- return rn;
-}
-
-
-/*
- * `safe' read for sockets and pipes.
- */
-protected ssize_t
-sread(int fd, void *buf, size_t n, int canbepipe)
-{
- int rv, cnt;
-#ifdef FIONREAD
- int t = 0;
-#endif
- size_t rn = n;
-
- if (fd == STDIN_FILENO)
- goto nocheck;
-
-#ifdef FIONREAD
- if ((canbepipe && (ioctl(fd, FIONREAD, &t) == -1)) || (t == 0)) {
-#ifdef FD_ZERO
- for (cnt = 0;; cnt++) {
- struct pollfd pfd[1];
- int rv;
-
- pfd[0].fd = fd;
- pfd[0].events = POLLIN;
-
- /*
- * Avoid soft deadlock: do not read if there
- * is nothing to read from sockets and pipes.
- */
- rv = poll(pfd, 1, 100);
- if (rv == -1) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- } else if (rv == 0 && cnt >= 5) {
- return 0;
- } else
- break;
- }
-#endif
- (void)ioctl(fd, FIONREAD, &t);
- }
-
- if (t > 0 && (size_t)t < n) {
- n = t;
- rn = n;
- }
-#endif
-
-nocheck:
- do
- switch ((rv = read(fd, buf, n))) {
- case -1:
- if (errno == EINTR)
- continue;
- return -1;
- case 0:
- return rn - n;
- default:
- n -= rv;
- buf = ((char *)buf) + rv;
- break;
- }
- while (n > 0);
- return rn;
-}
-
-protected int
-file_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
- size_t nbytes)
-{
- char buf[4096];
- int r, tfd;
-
- (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf);
- tfd = mkstemp(buf);
- r = errno;
- (void)unlink(buf);
- errno = r;
- if (tfd == -1) {
- file_error(ms, errno,
- "cannot create temporary file for pipe copy");
- return -1;
- }
-
- if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes)
- r = 1;
- else {
- while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
- if (swrite(tfd, buf, (size_t)r) != r)
- break;
- }
-
- switch (r) {
- case -1:
- file_error(ms, errno, "error copying from pipe to temp file");
- return -1;
- case 0:
- break;
- default:
- file_error(ms, errno, "error while writing to temp file");
- return -1;
- }
-
- /*
- * We duplicate the file descriptor, because fclose on a
- * tmpfile will delete the file, but any open descriptors
- * can still access the phantom inode.
- */
- if ((fd = dup2(tfd, fd)) == -1) {
- file_error(ms, errno, "could not dup descriptor for temp file");
- return -1;
- }
- (void)close(tfd);
- if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
- return fd;
-}
-
-#ifdef BUILTIN_DECOMPRESS
-
-#define FHCRC (1 << 1)
-#define FEXTRA (1 << 2)
-#define FNAME (1 << 3)
-#define FCOMMENT (1 << 4)
-
-private size_t
-uncompressgzipped(struct magic_set *ms, const unsigned char *old,
- unsigned char **newch, size_t n)
-{
- unsigned char flg = old[3];
- size_t data_start = 10;
- z_stream z;
- int rc;
-
- if (flg & FEXTRA) {
- if (data_start+1 >= n)
- return 0;
- data_start += 2 + old[data_start] + old[data_start + 1] * 256;
- }
- if (flg & FNAME) {
- while(data_start < n && old[data_start])
- data_start++;
- data_start++;
- }
- if(flg & FCOMMENT) {
- while(data_start < n && old[data_start])
- data_start++;
- data_start++;
- }
- if(flg & FHCRC)
- data_start += 2;
-
- if (data_start >= n)
- return 0;
- if ((*newch = (unsigned char *)malloc(HOWMANY + 1)) == NULL) {
- return 0;
- }
-
- /* XXX: const castaway, via strchr */
- z.next_in = (Bytef *)strchr((const char *)old + data_start,
- old[data_start]);
- z.avail_in = n - data_start;
- z.next_out = *newch;
- z.avail_out = HOWMANY;
- z.zalloc = Z_NULL;
- z.zfree = Z_NULL;
- z.opaque = Z_NULL;
-
- rc = inflateInit2(&z, -15);
- if (rc != Z_OK) {
- file_error(ms, 0, "zlib: %s", z.msg);
- return 0;
- }
-
- rc = inflate(&z, Z_SYNC_FLUSH);
- if (rc != Z_OK && rc != Z_STREAM_END) {
- file_error(ms, 0, "zlib: %s", z.msg);
- return 0;
- }
-
- n = (size_t)z.total_out;
- (void)inflateEnd(&z);
-
- /* let's keep the nul-terminate tradition */
- (*newch)[n] = '\0';
-
- return n;
-}
-#endif
-
-private size_t
-uncompressbuf(struct magic_set *ms, int fd, size_t method,
- const unsigned char *old, unsigned char **newch, size_t n)
-{
- int fdin[2], fdout[2];
- int r;
-
-#ifdef BUILTIN_DECOMPRESS
- /* FIXME: This doesn't cope with bzip2 */
- if (method == 2)
- return uncompressgzipped(ms, old, newch, n);
-#endif
- (void)fflush(stdout);
- (void)fflush(stderr);
-
- if ((fd != -1 && pipe(fdin) == -1) || pipe(fdout) == -1) {
- file_error(ms, errno, "cannot create pipe");
- return NODATA;
- }
- switch (fork()) {
- case 0: /* child */
- (void) close(0);
- if (fd != -1) {
- (void) dup(fd);
- (void) lseek(0, (off_t)0, SEEK_SET);
- } else {
- (void) dup(fdin[0]);
- (void) close(fdin[0]);
- (void) close(fdin[1]);
- }
-
- (void) close(1);
- (void) dup(fdout[1]);
- (void) close(fdout[0]);
- (void) close(fdout[1]);
-#ifndef DEBUG
- if (compr[method].silent)
- (void)close(2);
-#endif
-
- (void)execvp(compr[method].argv[0],
- (char *const *)(intptr_t)compr[method].argv);
-#ifdef DEBUG
- (void)fprintf(stderr, "exec `%s' failed (%s)\n",
- compr[method].argv[0], strerror(errno));
-#endif
- exit(1);
- /*NOTREACHED*/
- case -1:
- file_error(ms, errno, "could not fork");
- return NODATA;
-
- default: /* parent */
- (void) close(fdout[1]);
- if (fd == -1) {
- (void) close(fdin[0]);
- /*
- * fork again, to avoid blocking because both
- * pipes filled
- */
- switch (fork()) {
- case 0: /* child */
- (void)close(fdout[0]);
- if (swrite(fdin[1], old, n) != (ssize_t)n) {
-#ifdef DEBUG
- (void)fprintf(stderr,
- "Write failed (%s)\n",
- strerror(errno));
-#endif
- exit(1);
- }
- exit(0);
- /*NOTREACHED*/
-
- case -1:
-#ifdef DEBUG
- (void)fprintf(stderr, "Fork failed (%s)\n",
- strerror(errno));
-#endif
- exit(1);
- /*NOTREACHED*/
-
- default: /* parent */
- break;
- }
- (void) close(fdin[1]);
- fdin[1] = -1;
- }
-
- if ((*newch = (unsigned char *) malloc(HOWMANY + 1)) == NULL) {
-#ifdef DEBUG
- (void)fprintf(stderr, "Malloc failed (%s)\n",
- strerror(errno));
-#endif
- n = 0;
- goto err;
- }
- if ((r = sread(fdout[0], *newch, HOWMANY, 0)) <= 0) {
-#ifdef DEBUG
- (void)fprintf(stderr, "Read failed (%s)\n",
- strerror(errno));
-#endif
- free(*newch);
- n = 0;
- newch[0] = '\0';
- goto err;
- } else {
- n = r;
- }
- /* NUL terminate, as every buffer is handled here. */
- (*newch)[n] = '\0';
-err:
- if (fdin[1] != -1)
- (void) close(fdin[1]);
- (void) close(fdout[0]);
-#ifdef WNOHANG
- while (waitpid(-1, NULL, WNOHANG) != -1)
- continue;
-#else
- (void)wait(NULL);
-#endif
- return n;
- }
-}
+++ /dev/null
-/*
- * Hand-made config.h file for OpenBSD, so we don't have to run
- * the dratted configure script every time we build this puppy,
- * but can still carefully import stuff from Christos' version.
- *
- * This file is in the public domain. Original Author Ian F. Darwin.
- * $OpenBSD: config.h,v 1.7 2011/07/25 16:21:22 martynas Exp $
- */
-
-/* header file issues. */
-#define HAVE_UNISTD_H 1
-#define HAVE_FCNTL_H 1
-#define HAVE_SYS_WAIT_H 1
-#define HAVE_LOCALE_H 1
-#define HAVE_SYS_STAT_H 1
-#define HAVE_INTTYPES_H 1
-#define HAVE_GETOPT_H 1
-#define HAVE_LIMITS_H 1
-/* #define HAVE_ZLIB_H 1 DO NOT ENABLE YET -- chl */
-/* #define HAVE_LIBZ 1 DO NOT ENABLE YET -- ian */
-
-#define HAVE_STRTOUL
-#define HAVE_STRERROR
-#define HAVE_VSNPRINTF
-#define HAVE_SNPRINTF
-#define HAVE_STRNDUP
-#define HAVE_STRTOF
-
-/* Compiler issues */
-#define SIZEOF_LONG_LONG 8
-
-/* Library issues */
-#define HAVE_GETOPT_LONG 1 /* in-tree as of 3.2 */
-#define HAVE_ST_RDEV 1
-
-/* ELF support */
-#define BUILTIN_ELF 1
-#define ELFCORE 1
+++ /dev/null
-/* $OpenBSD: elfclass.h,v 1.2 2009/04/26 14:17:45 chl Exp $ */
-/*
- * Copyright (c) Christos Zoulas 2008.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- if (nbytes <= sizeof(elfhdr))
- return 0;
-
- u.l = 1;
- (void)memcpy(&elfhdr, buf, sizeof elfhdr);
- swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
-
- type = elf_getu16(swap, elfhdr.e_type);
- switch (type) {
-#ifdef ELFCORE
- case ET_CORE:
- if (dophn_core(ms, class, swap, fd,
- (off_t)elf_getu(swap, elfhdr.e_phoff),
- elf_getu16(swap, elfhdr.e_phnum),
- (size_t)elf_getu16(swap, elfhdr.e_phentsize),
- fsize, &flags) == -1)
- return -1;
- break;
-#endif
- case ET_EXEC:
- case ET_DYN:
- if (dophn_exec(ms, class, swap, fd,
- (off_t)elf_getu(swap, elfhdr.e_phoff),
- elf_getu16(swap, elfhdr.e_phnum),
- (size_t)elf_getu16(swap, elfhdr.e_phentsize),
- fsize, &flags) == -1)
- return -1;
- /*FALLTHROUGH*/
- case ET_REL:
- if (doshn(ms, class, swap, fd,
- (off_t)elf_getu(swap, elfhdr.e_shoff),
- elf_getu16(swap, elfhdr.e_shnum),
- (size_t)elf_getu16(swap, elfhdr.e_shentsize),
- &flags) == -1)
- return -1;
- break;
-
- default:
- break;
- }
- return 1;
-.\" $OpenBSD: file.1,v 1.35 2015/02/15 22:26:45 bentley Exp $
+.\" $OpenBSD: file.1,v 1.36 2015/04/24 16:24:11 nicm Exp $
.\" $FreeBSD: src/usr.bin/file/file.1,v 1.16 2000/03/01 12:19:39 sheldonh Exp $
.\"
+.\" Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
.\" Copyright (c) Ian F. Darwin 1986-1995.
.\" Software written by Ian F. Darwin and others;
.\" maintained 1995-present by Christos Zoulas and others.
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd $Mdocdate: February 15 2015 $
+.Dd $Mdocdate: April 24 2015 $
.Dt FILE 1
.Os
.Sh NAME
.Sh SYNOPSIS
.Nm
.Bk -words
-.Op Fl 0bCcehikLNnprsvz
-.Op Fl -help
-.Op Fl -mime-encoding
-.Op Fl -mime-type
-.Op Fl F Ar separator
-.Op Fl f Ar namefile
-.Op Fl m Ar magicfiles
-.Ar file
+.Op Fl bciLsW
+.Ar
.Ek
.Sh DESCRIPTION
The
.Nm
-utility tests each argument in an attempt to classify it.
-There are three sets of tests, performed in this order:
-filesystem tests, magic tests, and language tests.
-The first test that succeeds causes the file type to be printed.
+utility tests each argument and attempts to determine its type.
+Three sets of tests are performed:
+.Bl -enum -offset Ds
+.It
+Filesystem tests, for example if a file is empty, or a special file such as a
+socket or named pipe (FIFO).
+.It
+.Dq Magic
+tests for data in particular fixed formats.
+These are loaded from the
+.Pa /etc/magic
+file (or
+.Pa ~/.magic
+instead if it exists).
+The file format is described in
+.Xr magic 5 .
+.It
+Tests for text files such as plain ASCII or C programming language files.
+.El
.Pp
-The type printed will usually contain one of the words
+The first test which succeeds causes the file type to be printed.
+The type will often contain one of the words
.Em text
-(the file contains only
-printing characters and a few common control
-characters and is probably safe to read on an
-ASCII terminal),
+(contains only printing characters and is probably safe to read on an ASCII
+terminal),
.Em executable
-(the file contains the result of compiling a program
-in a form understandable to some
-.Ux
-kernel or another),
+(the file contains a compiled executable program)
or
.Em data
-meaning anything else (data is usually
-.Dq binary
-or non-printable).
-Exceptions are well-known file formats (core files, tar archives)
-that are known to contain binary data.
-When modifying magic files or the program itself, make sure to
-.Em preserve these keywords .
-Users depend on knowing that all the readable files in a directory
-have the word
-.Dq text
-printed.
-Don't do as Berkeley did and change
-.Dq shell commands text
-to
-.Dq shell script .
-.Pp
-The filesystem tests are based on examining the return from a
-.Xr stat 2
-system call.
-The program checks to see if the file is empty,
-or if it's some sort of special file.
-Any known file types,
-such as sockets, symbolic links, and named pipes (FIFOs),
-are intuited if they are defined in
-the system header file
-.In sys/stat.h .
-.Pp
-The magic tests are used to check for files with data in
-particular fixed formats.
-The canonical example of this is a binary executable (compiled program)
-a.out file, whose format is defined in
-.In elf.h ,
-.In a.out.h ,
-and possibly
-.In exec.h
-in the standard include directory.
-These files have a
-.Dq magic number
-stored in a particular place
-near the beginning of the file that tells the
-.Ux
-operating system
-that the file is a binary executable, and which of several types thereof.
-The concept of a
-.Dq magic
-has been applied by extension to data files.
-Any file with some invariant identifier at a small fixed
-offset into the file can usually be described in this way.
-The information identifying these files is read from the magic file
-.Pa /etc/magic .
-In addition, if
-.Pa $HOME/.magic.mgc
-or
-.Pa $HOME/.magic
-exists, it will be used in preference to the system magic files.
-.Pp
-If a file does not match any of the entries in the magic file,
-it is examined to see if it seems to be a text file.
-ASCII, ISO-8859-x, non-ISO 8-bit extended-ASCII character sets
-(such as those used on Macintosh and IBM PC systems),
-UTF-8-encoded Unicode, UTF-16-encoded Unicode, and EBCDIC
-character sets can be distinguished by the different
-ranges and sequences of bytes that constitute printable text
-in each set.
-If a file passes any of these tests, its character set is reported.
-ASCII, ISO-8859-x, UTF-8, and extended-ASCII files are identified
-as
-.Dq text
-because they will be mostly readable on nearly any terminal;
-UTF-16 and EBCDIC are only
-.Dq character data
-because, while
-they contain text, it is text that will require translation
-before it can be read.
-In addition,
-.Nm
-will attempt to determine other characteristics of text-type files.
-If the lines of a file are terminated by CR, CRLF, or NEL, instead
-of the Unix-standard LF, this will be reported.
-Files that contain embedded escape sequences or overstriking
-will also be identified.
-.Pp
-Once
-.Nm
-has determined the character set used in a text-type file,
-it will
-attempt to determine in what language the file is written.
-The language tests look for particular strings (cf.\&
-.In names.h )
-that can appear anywhere in the first few blocks of a file.
-For example, the keyword
-.Em .br
-indicates that the file is most likely a
-troff input file, just as the keyword
-.Em struct
-indicates a C program.
-These tests are less reliable than the previous
-two groups, so they are performed last.
-The language test routines also test for some miscellany
-(such as
-.Xr tar 1
-archives).
-.Pp
-Any file that cannot be identified as having been written
-in any of the character sets listed above is simply said to be
-.Dq data .
+meaning anything else.
.Sh OPTIONS
.Bl -tag -width indent
-.It Fl 0 , -print0
-Output a null character
-.Sq \e0
-after the end of the filename.
-Nice to
-.Xr cut 1
-the output.
-This does not affect the separator which is still printed.
-.It Fl b , -brief
-Do not prepend filenames to output lines (brief mode).
-.It Fl C , -compile
-Write a
-.Pa magic.mgc
-output file that contains a pre-parsed version of the magic file or directory.
-.It Fl c , -checking-printout
-Cause a checking printout of the parsed form of the magic file.
-This is usually used in conjunction with the
-.Fl m
-flag to debug a new magic file before installing it.
-.It Fl e , -exclude Ar testname
-Exclude the test named in
-.Ar testname
-from the list of tests made to determine the file type.
-Valid test names are:
-.Bl -tag -width compress
-.It apptype
-Check for
-.Dv EMX
-application type (only on EMX).
-.It ascii
-Check for various types of ASCII files.
-.It compress
-Don't look for, or inside, compressed files.
-.It elf
-Don't print elf details.
-.It fortran
-Don't look for fortran sequences inside ASCII files.
-.It soft
-Don't consult magic files.
-.It tar
-Don't examine tar files.
-.It token
-Don't look for known tokens inside ASCII files.
-.It troff
-Don't look for troff sequences inside ASCII files.
-.El
-.It Fl F , -separator Ar separator
-Use the specified string as the separator between the filename and the
-file result returned.
-Defaults to
-.Sq \&: .
-.It Fl f , -files-from Ar namefile
-Read the names of the files to be examined from
-.Ar namefile
-(one per line)
-before the argument list.
-Either
-.Ar namefile
-or at least one filename argument must be present;
-to test the standard input, use
-.Sq -
-as a filename argument.
-.It Fl h , -no-dereference
-Causes symlinks not to be followed.
-This is the default if the environment variable
-.Dv POSIXLY_CORRECT
-is not defined.
-.It Fl -help
-Print a help message and exit.
-.It Fl i , -mime
-Causes the file command to output mime type strings rather than the more
-traditional human readable ones.
+.It Fl b
+Do not prepend filenames to output lines.
+.It Fl c
+Print a summary of the parsed magic file, usually used for debugging.
+.It Fl i , -mime , -mime-type
+Causes the file command to output MIME type strings rather than the more
+traditional human-readable ones.
Thus it may say
-.Dq text/plain charset=us-ascii
+.Dq text/plain
rather than
.Dq ASCII text .
-In order for this option to work,
+.It Fl L
+Causes symlinks to be followed.
+.It Fl s
+Instructs
.Nm
-changes the way it handles files recognized by the command itself
-(such as many of the text file types, directories etc.),
-and makes use of an alternative
-.Dq magic
-file.
-See also
-.Sx FILES ,
-below.
-.It Fl -mime-encoding , -mime-type
-Like
-.Fl i ,
-but print only the specified element(s).
-.It Fl k , -keep-going
-Don't stop at the first match, keep going.
-Subsequent matches will have the string
-.Dq "\[rs]012\- "
-prepended.
-(If a newline is required, see the
-.Fl r
-option.)
-.It Fl L , -dereference
-Causes symlinks to be followed;
-analogous to the option of the same name in
-.Xr ls 1 .
-This is the default if the environment variable
-.Dv POSIXLY_CORRECT
-is defined.
-.It Fl m , -magic-file Ar magicfiles
-Specify an alternate list of files and directories containing magic.
-This can be a single item, or a colon-separated list.
-If a compiled magic file is found alongside a file or directory,
-it will be used instead.
-.It Fl N , -no-pad
-Don't pad filenames so that they align in the output.
-.It Fl n , -no-buffer
-Force stdout to be flushed after checking each file.
-This is only useful if checking a list of files.
-It is intended to be used by programs that want filetype output from a pipe.
-.It Fl p , -preserve-date
-On systems that support
-.Xr utime 3
-or
-.Xr utimes 2 ,
-attempt to preserve the access time of files analyzed, to pretend that
-.Nm
-never read them.
-.It Fl r , -raw
-Don't translate unprintable characters to \eooo.
-Normally
-.Nm
-translates unprintable characters to their octal representation.
-.It Fl s , -special-files
-Normally,
-.Nm
-only attempts to read and determine the type of argument files which
+to attempt to read all files, not only those which
.Xr stat 2
reports are ordinary files.
-This prevents problems, because reading special files may have peculiar
-consequences.
-Specifying the
-.Fl s
-option causes
-.Nm
-to also read argument files which are block or character special files.
-This is useful for determining the filesystem types of the data in raw
-disk partitions, which are block special files.
-This option also causes
-.Nm
-to disregard the file size as reported by
-.Xr stat 2
-since on some systems it reports a zero size for raw disk partitions.
-.It Fl v , -version
-Print the version of the program and exit.
-.It Fl z , -uncompress
-Try to look inside compressed files.
+.It Fl W
+Display warnings when parsing the magic file or applying its tests.
+Usually used for debugging.
.El
-.Sh ENVIRONMENT
-The environment variable
-.Dv MAGIC
-can be used to set the default magic file name.
-If that variable is set, then
-.Nm
-will not attempt to open
-.Pa $HOME/.magic .
-.Nm
-adds
-.Dq .mgc
-to the value of this variable as appropriate.
-The environment variable
-.Dv POSIXLY_CORRECT
-controls whether
-.Nm
-will attempt to follow symlinks or not.
-If set, then
-.Nm
-follows symlinks; otherwise it does not.
-This is also controlled by the
-.Fl L
-and
-.Fl h
-options.
.Sh FILES
.Bl -tag -width /etc/magic -compact
.It Pa /etc/magic
-default list of magic numbers
+default magic file
.El
.Sh EXIT STATUS
.Ex -std file
.Sh SEE ALSO
-.Xr hexdump 1 ,
-.Xr od 1 ,
-.Xr strings 1 ,
.Xr magic 5
-.Sh STANDARDS CONFORMANCE
-This program is believed to exceed the System V Interface Definition
-of FILE(CMD), as near as one can determine from the vague language
-contained therein.
-Its behavior is mostly compatible with the System V program of the same name.
-This version knows more magic, however, so it will produce
-different (albeit more accurate) output in many cases.
-.\" URL: http://www.opengroup.org/onlinepubs/009695399/utilities/file.html
-.Pp
-The one significant difference
-between this version and System V
-is that this version treats any whitespace
-as a delimiter, so that spaces in pattern strings must be escaped.
-For example,
-.Bd -literal -offset indent
-\*(Gt10 string language impress\ (imPRESS data)
-.Ed
-.Pp
-in an existing magic file would have to be changed to
-.Bd -literal -offset indent
-\*(Gt10 string language\e impress (imPRESS data)
-.Ed
-.Pp
-In addition, in this version, if a pattern string contains a backslash,
-it must be escaped.
-For example
-.Bd -literal -offset indent
-0 string \ebegindata Andrew Toolkit document
-.Ed
-.Pp
-in an existing magic file would have to be changed to
-.Bd -literal -offset indent
-0 string \e\ebegindata Andrew Toolkit document
-.Ed
-.Pp
-SunOS releases 3.2 and later from Sun Microsystems include a
+.Sh AUTHORS
.Nm
-command derived from the System V one, but with some extensions.
-This version differs from Sun's only in minor ways.
-It includes the extension of the
-.Sq &
-operator, used as,
-for example,
-.Bd -literal -offset indent
-\*(Gt16 long&0x7fffffff \*(Gt0 not stripped
-.Ed
-.Sh HISTORY
-There has been a
-.Nm
-command in every
-.Ux
-since at least Research Version 4
-(man page dated November, 1973).
-The System V version introduced one significant major change:
-the external list of magic types.
-This slowed the program down slightly but made it a lot more flexible.
-.Pp
-This program, based on the System V version,
-was written by Ian Darwin
-without looking at anybody else's source code.
-.Pp
-John Gilmore revised the code extensively, making it better than
-the first version.
-Geoff Collyer found several inadequacies
-and provided some magic file entries.
-Contributions by the `&' operator by Rob McMahon, 1989.
-.Pp
-Guy Harris, made many changes from 1993 to the present.
-.Pp
-Primary development and maintenance from 1990 to the present by
-Christos Zoulas.
-.Pp
-Altered by Chris Lowth, 2000:
-Handle the
-.Fl i
-option to output mime type strings, using an alternative
-magic file and internal logic.
-.Pp
-Altered by Eric Fischer, July, 2000,
-to identify character codes and attempt to identify the languages
-of non-ASCII files.
-.Pp
-Altered by Reuben Thomas, 2007 to 2008, to improve MIME
-support and merge MIME and non-MIME magic, support directories as well
-as files of magic, apply many bug fixes and improve the build system.
-.Pp
-The list of contributors to the
-.Dq magic
-directory (magic files)
-is too long to include here.
-You know who you are; thank you.
-Many contributors are listed in the source files.
-.Sh BUGS
-There must be a better way to automate the construction of the Magic
-file from all the glop in Magdir.
-What is it?
-.Pp
-.Nm
-uses several algorithms that favor speed over accuracy,
-thus it can be misled about the contents of
-text
-files.
-.Pp
-The support for text files (primarily for programming languages)
-is simplistic, inefficient and requires recompilation to update.
-.Pp
-The list of keywords in
-.Pa ascmagic
-probably belongs in the Magic file.
-This could be done by using some keyword like
-.Sq *
-for the offset value.
-.Pp
-Complain about conflicts in the magic file entries.
-Make a rule that the magic entries sort based on file offset rather
-than position within the magic file?
-.Pp
-The program should provide a way to give an estimate
-of
-.Dq how good
-a guess is.
-We end up removing guesses (e.g.
-.Dq From\
-as first 5 chars of file) because
-they are not as good as other guesses (e.g.\&
-.Dq Newsgroups:
-versus
-.Dq Return-Path: ) .
-Still, if the others don't pan out, it should be possible to use the
-first guess.
+commands have appeared in many previous versions of
+.Ux .
+This version was written by Nicholas Marriott for
+.Ox 5.8
+to replace the previous version originally written by Ian Darwin.
.Pp
-This manual page, and particularly this section, is too long.
+There is a large number of contributors to the magic files; many are listed in
+the source files.
-/* $OpenBSD: file.c,v 1.26 2015/01/16 18:08:15 millert Exp $ */
-/*
- * Copyright (c) Ian F. Darwin 1986-1995.
- * Software written by Ian F. Darwin and others;
- * maintained 1995-present by Christos Zoulas and others.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
+/* $OpenBSD: file.c,v 1.27 2015/04/24 16:24:11 nicm Exp $ */
+
/*
- * file - find type of a file or files - main program.
+ * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "file.h"
-#include "magic.h"
+#include <sys/ioctl.h>
+#include <sys/mman.h>
-#include <stdio.h>
+#include <errno.h>
+#include <libgen.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <pwd.h>
#include <stdlib.h>
#include <unistd.h>
-#include <limits.h>
-#include <string.h>
-#ifdef RESTORE_TIME
-# if (__COHERENT__ >= 0x420)
-# include <sys/utime.h>
-# else
-# ifdef USE_UTIMES
-# include <sys/time.h>
-# else
-# include <utime.h>
-# endif
-# endif
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for read() */
-#endif
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#endif
-#ifdef HAVE_WCHAR_H
-#include <wchar.h>
-#endif
-#include <getopt.h>
-#ifndef HAVE_GETOPT_LONG
-int getopt_long(int argc, char * const *argv, const char *optstring, const struct option *longopts, int *longindex);
-#endif
+#include "file.h"
+#include "magic.h"
+#include "xmalloc.h"
-#include <netinet/in.h> /* for byte swapping */
+struct input_file
+{
+ struct magic *m;
-#include "patchlevel.h"
+ const char *path;
+ const char *label;
+ int fd;
+ struct stat sb;
+ const char *error;
-#ifdef S_IFLNK
-#define SYMLINKFLAG "Lh"
-#else
-#define SYMLINKFLAG ""
-#endif
+ void *base;
+ size_t size;
+ int mapped;
+ char *result;
-# define USAGE "Usage: %s [-bcik" SYMLINKFLAG "nNprsvz0] [-e test] [-f namefile] [-F separator] [-m magicfiles] file...\n" \
- " %s -C -m magicfiles\n"
+ char link_path[PATH_MAX];
+ const char *link_error;
+ int link_target;
+};
-private int /* Global command-line options */
- bflag = 0, /* brief output format */
- nopad = 0, /* Don't pad output */
- nobuffer = 0, /* Do not buffer stdout */
- nulsep = 0; /* Append '\0' to the separator */
+extern char *__progname;
-private const char *magicfile = 0; /* where the magic is */
-private const char *default_magicfile = MAGIC;
-private const char *separator = ":"; /* Default field separator */
+__dead void usage(void);
-extern char *__progname; /* used throughout */
+static void open_file(struct input_file *, const char *, int *);
+static void read_link(struct input_file *);
+static void test_file(struct magic *, struct input_file *, int);
-private struct magic_set *magic;
+static int try_stat(struct input_file *);
+static int try_empty(struct input_file *);
+static int try_access(struct input_file *);
+static int try_text(struct input_file *);
+static int try_magic(struct input_file *);
+static int try_unknown(struct input_file *);
-private void unwrap(char *);
-private void usage(void);
-private void help(void);
+static int bflag;
+static int cflag;
+static int iflag;
+static int Lflag;
+static int sflag;
+static int Wflag;
-int main(int, char *[]);
-private void process(const char *, int);
-private void load(const char *, int);
+static struct option longopts[] = {
+ { "mime", no_argument, NULL, 'i' },
+ { "mime-type", no_argument, NULL, 'i' },
+ { NULL, 0, NULL, 0 }
+};
+__dead void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-bchiLsW] [file ...]\n", __progname);
+ exit(1);
+}
-/*
- * main - parse arguments and handle options
- */
int
-main(int argc, char *argv[])
+main(int argc, char **argv)
{
- int c;
- size_t i;
- int action = 0, didsomefiles = 0, errflg = 0;
- int flags = 0;
- char *home, *usermagic;
- struct stat sb;
- static const char hmagic[] = "/.magic";
-#define OPTSTRING "bcCde:f:F:hikLm:nNprsvz0"
- int longindex;
- static const struct option long_options[] =
- {
-#define OPT(shortname, longname, opt, doc) \
- {longname, opt, NULL, shortname},
-#define OPT_LONGONLY(longname, opt, doc) \
- {longname, opt, NULL, 0},
-#include "file_opts.h"
-#undef OPT
-#undef OPT_LONGONLY
- {0, 0, NULL, 0}
-};
-
- static const struct {
- const char *name;
- int value;
- } nv[] = {
- { "apptype", MAGIC_NO_CHECK_APPTYPE },
- { "ascii", MAGIC_NO_CHECK_ASCII },
- { "compress", MAGIC_NO_CHECK_COMPRESS },
- { "elf", MAGIC_NO_CHECK_ELF },
- { "soft", MAGIC_NO_CHECK_SOFT },
- { "tar", MAGIC_NO_CHECK_TAR },
- { "tokens", MAGIC_NO_CHECK_TOKENS },
- };
-
- /* makes islower etc work for other langs */
- (void)setlocale(LC_CTYPE, "");
-
-#ifdef __EMX__
- /* sh-like wildcard expansion! Shouldn't hurt at least ... */
- _wildcard(&argc, &argv);
-#endif
-
- magicfile = default_magicfile;
- if ((usermagic = getenv("MAGIC")) != NULL)
- magicfile = usermagic;
- else
- if ((home = getenv("HOME")) != NULL) {
- size_t len = strlen(home) + sizeof(hmagic);
- if ((usermagic = malloc(len)) != NULL) {
- (void)strlcpy(usermagic, home, len);
- (void)strlcat(usermagic, hmagic, len);
- if (stat(usermagic, &sb)<0)
- free(usermagic);
- else
- magicfile = usermagic;
- }
- }
-
-#ifdef S_IFLNK
- flags |= getenv("POSIXLY_CORRECT") ? MAGIC_SYMLINK : 0;
-#endif
- while ((c = getopt_long(argc, argv, OPTSTRING, long_options,
- &longindex)) != -1)
- switch (c) {
- case 0 :
- switch (longindex) {
- case 0:
- help();
- break;
- case 10:
- flags |= MAGIC_MIME_TYPE;
- break;
- case 11:
- flags |= MAGIC_MIME_ENCODING;
- break;
- }
- break;
- case '0':
- nulsep = 1;
+ struct input_file *files = NULL;
+ int nfiles, opt, i, width = 0;
+ FILE *f;
+ struct magic *m;
+ char *home, *path;
+ struct passwd *pw;
+
+ for (;;) {
+ opt = getopt_long(argc, argv, "bchiLsW", longopts, NULL);
+ if (opt == -1)
break;
+ switch (opt) {
case 'b':
- bflag++;
+ bflag = 1;
break;
case 'c':
- action = FILE_CHECK;
- break;
- case 'C':
- action = FILE_COMPILE;
- break;
- case 'd':
- flags |= MAGIC_DEBUG|MAGIC_CHECK;
- break;
- case 'e':
- for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++)
- if (strcmp(nv[i].name, optarg) == 0)
- break;
-
- if (i == sizeof(nv) / sizeof(nv[0]))
- errflg++;
- else
- flags |= nv[i].value;
- break;
-
- case 'f':
- if(action)
- usage();
- load(magicfile, flags);
- unwrap(optarg);
- ++didsomefiles;
+ cflag = 1;
break;
- case 'F':
- separator = optarg;
+ case 'h':
+ Lflag = 0;
break;
case 'i':
- flags |= MAGIC_MIME;
- break;
- case 'k':
- flags |= MAGIC_CONTINUE;
- break;
- case 'm':
- magicfile = optarg;
- break;
- case 'n':
- ++nobuffer;
+ iflag = 1;
break;
- case 'N':
- ++nopad;
- break;
-#if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
- case 'p':
- flags |= MAGIC_PRESERVE_ATIME;
- break;
-#endif
- case 'r':
- flags |= MAGIC_RAW;
+ case 'L':
+ Lflag = 1;
break;
case 's':
- flags |= MAGIC_DEVICES;
- break;
- case 'v':
- (void)fprintf(stderr, "%s-%d.%.2d\n", __progname,
- FILE_VERSION_MAJOR, patchlevel);
- (void)fprintf(stderr, "magic file from %s\n",
- magicfile);
- return 1;
- case 'z':
- flags |= MAGIC_COMPRESS;
+ sflag = 1;
break;
-#ifdef S_IFLNK
- case 'L':
- flags |= MAGIC_SYMLINK;
- break;
- case 'h':
- flags &= ~MAGIC_SYMLINK;
+ case 'W':
+ Wflag = 1;
break;
-#endif
- case '?':
default:
- errflg++;
- break;
+ usage();
}
-
- if (errflg) {
- usage();
}
+ argc -= optind;
+ argv += optind;
+ if (cflag) {
+ if (argc != 0)
+ usage();
+ } else if (argc == 0)
+ usage();
- switch(action) {
- case FILE_CHECK:
- case FILE_COMPILE:
- magic = magic_open(flags|MAGIC_CHECK);
- if (magic == NULL) {
- (void)fprintf(stderr, "%s: %s\n", __progname,
- strerror(errno));
- return 1;
- }
- c = action == FILE_CHECK ? magic_check(magic, magicfile) :
- magic_compile(magic, magicfile);
- if (c == -1) {
- (void)fprintf(stderr, "%s: %s\n", __progname,
- magic_error(magic));
- return -1;
- }
- return 0;
- default:
- load(magicfile, flags);
- break;
+ nfiles = argc;
+ if (nfiles != 0) {
+ files = xcalloc(nfiles, sizeof *files);
+ for (i = 0; i < argc; i++)
+ open_file(&files[i], argv[i], &width);
}
- if (optind == argc) {
- if (!didsomefiles) {
- usage();
- }
+ home = getenv("HOME");
+ if (home == NULL || *home == '\0') {
+ pw = getpwuid(getuid());
+ if (pw != NULL)
+ home = pw->pw_dir;
+ else
+ home = NULL;
}
- else {
- size_t j, wid, nw;
- for (wid = 0, j = (size_t)optind; j < (size_t)argc; j++) {
- nw = file_mbswidth(argv[j]);
- if (nw > wid)
- wid = nw;
- }
- /*
- * If bflag is only set twice, set it depending on
- * number of files [this is undocumented, and subject to change]
- */
- if (bflag == 2) {
- bflag = optind >= argc - 1;
- }
- for (; optind < argc; optind++)
- process(argv[optind], wid);
+ if (home != NULL) {
+ xasprintf(&path, "%s/.magic", home);
+ f = fopen(path, "r");
+ } else
+ f = NULL;
+ if (f == NULL) {
+ path = xstrdup("/etc/magic");
+ f = fopen(path, "r");
+ }
+ if (f == NULL)
+ err(1, "%s", path);
+
+ if (geteuid() == 0) {
+ pw = getpwnam(FILE_USER);
+ if (pw == NULL)
+ errx(1, "unknown user %s", FILE_USER);
+ if (setgroups(1, &pw->pw_gid) != 0)
+ err(1, "setgroups");
+ if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0)
+ err(1, "setresgid");
+ if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
+ err(1, "setresuid");
+ }
+
+ m = magic_load(f, path, cflag || Wflag);
+ if (cflag) {
+ magic_dump(m);
+ exit(0);
}
- c = magic->haderr ? 1 : 0;
- magic_close(magic);
- return c;
+ for (i = 0; i < nfiles; i++)
+ test_file(m, &files[i], width);
+ exit(0);
}
+static void
+open_file(struct input_file *inf, const char *path, int *width)
+{
+ char *label;
+ int n, retval;
+
+ inf->path = xstrdup(path);
-private void
-/*ARGSUSED*/
-load(const char *m, int flags)
+ n = xasprintf(&label, "%s:", inf->path);
+ if (n > *width)
+ *width = n;
+ inf->label = label;
+
+ retval = lstat(inf->path, &inf->sb);
+ if (retval == -1) {
+ inf->error = strerror(errno);
+ return;
+ }
+
+ if (S_ISLNK(inf->sb.st_mode))
+ read_link(inf);
+ inf->fd = open(inf->path, O_RDONLY|O_NONBLOCK);
+}
+
+static void
+read_link(struct input_file *inf)
{
- if (magic || m == NULL)
+ struct stat sb;
+ char path[PATH_MAX];
+ char *copy, *root;
+ int used;
+ ssize_t size;
+
+ size = readlink(inf->path, path, sizeof path);
+ if (size == -1) {
+ inf->link_error = strerror(errno);
return;
- magic = magic_open(flags);
- if (magic == NULL) {
- (void)fprintf(stderr, "%s: %s\n", __progname, strerror(errno));
- exit(1);
}
- if (magic_load(magic, magicfile) == -1) {
- (void)fprintf(stderr, "%s: %s\n",
- __progname, magic_error(magic));
- exit(1);
+ path[size] = '\0';
+
+ if (*path == '/')
+ strlcpy(inf->link_path, path, sizeof inf->link_path);
+ else {
+ copy = xstrdup(inf->path);
+
+ root = dirname(copy);
+ if (*root == '\0' || strcmp(root, ".") == 0 ||
+ strcmp (root, "/") == 0)
+ strlcpy(inf->link_path, path, sizeof inf->link_path);
+ else {
+ used = snprintf(inf->link_path, sizeof inf->link_path,
+ "%s/%s", root, path);
+ if (used < 0 || (size_t)used >= sizeof inf->link_path) {
+ inf->link_error = strerror(ENAMETOOLONG);
+ return;
+ }
+ }
+
+ free(copy);
+ }
+
+ if (Lflag) {
+ if (stat(inf->path, &inf->sb) == -1)
+ inf->error = strerror(errno);
+ } else {
+ if (stat(inf->link_path, &sb) == -1)
+ inf->link_target = errno;
}
}
-/*
- * unwrap -- read a file of filenames, do each one.
- */
-private void
-unwrap(char *fn)
+static void *
+fill_buffer(struct input_file *inf)
{
- char buf[PATH_MAX];
- FILE *f;
- int wid = 0, cwid;
+ static void *buffer;
+ ssize_t got;
+ size_t left;
+ void *next;
+
+ if (buffer == NULL)
+ buffer = xmalloc(FILE_READ_SIZE);
+
+ next = buffer;
+ left = inf->size;
+ while (left != 0) {
+ got = read(inf->fd, next, left);
+ if (got == -1) {
+ if (errno == EINTR)
+ continue;
+ return NULL;
+ }
+ if (got == 0)
+ break;
+ next = (char*)next + got;
+ left -= got;
+ }
- if (strcmp("-", fn) == 0) {
- f = stdin;
- wid = 1;
- } else {
- if ((f = fopen(fn, "r")) == NULL) {
- (void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n",
- __progname, fn, strerror(errno));
- exit(1);
+ return buffer;
+}
+
+static int
+load_file(struct input_file *inf)
+{
+ int available;
+
+ inf->size = inf->sb.st_size;
+ if (inf->size > FILE_READ_SIZE)
+ inf->size = FILE_READ_SIZE;
+ if (S_ISFIFO(inf->sb.st_mode)) {
+ if (ioctl(inf->fd, FIONREAD, &available) == -1) {
+ xasprintf(&inf->result, "cannot read '%s' (%s)",
+ inf->path, strerror(errno));
+ return (1);
+ }
+ inf->size = available;
+ } else if (!S_ISREG(inf->sb.st_mode) && inf->size == 0)
+ inf->size = FILE_READ_SIZE;
+ if (inf->size == 0)
+ return (0);
+
+ inf->base = mmap(NULL, inf->size, PROT_READ, MAP_PRIVATE, inf->fd, 0);
+ if (inf->base == MAP_FAILED) {
+ inf->base = fill_buffer(inf);
+ if (inf->base == NULL) {
+ xasprintf(&inf->result, "cannot read '%s' (%s)",
+ inf->path, strerror(errno));
+ return (1);
}
+ } else
+ inf->mapped = 1;
+ return (0);
+}
- while (fgets(buf, sizeof(buf), f) != NULL) {
- buf[strcspn(buf, "\n")] = '\0';
- cwid = file_mbswidth(buf);
- if (cwid > wid)
- wid = cwid;
+static int
+try_stat(struct input_file *inf)
+{
+ if (inf->error != NULL) {
+ xasprintf(&inf->result, "cannot stat '%s' (%s)", inf->path,
+ inf->error);
+ return (1);
+ }
+ if (sflag) {
+ switch (inf->sb.st_mode & S_IFMT) {
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFIFO:
+ case S_IFREG:
+ return (0);
}
+ }
- rewind(f);
+ if (iflag && (inf->sb.st_mode & S_IFMT) != S_IFREG) {
+ xasprintf(&inf->result, "application/x-not-regular-file");
+ return (1);
}
- while (fgets(buf, sizeof(buf), f) != NULL) {
- buf[strcspn(buf, "\n")] = '\0';
- process(buf, wid);
- if(nobuffer)
- (void)fflush(stdout);
+
+ switch (inf->sb.st_mode & S_IFMT) {
+ case S_IFDIR:
+ xasprintf(&inf->result, "directory");
+ return (1);
+ case S_IFLNK:
+ if (inf->link_error != NULL) {
+ xasprintf(&inf->result, "unreadable symlink '%s' (%s)",
+ inf->path, inf->link_error);
+ return (1);
+ }
+ if (inf->link_target == ELOOP)
+ xasprintf(&inf->result, "symbolic link in a loop");
+ else if (inf->link_target != 0) {
+ xasprintf(&inf->result, "broken symbolic link to '%s'",
+ inf->link_path);
+ } else {
+ xasprintf(&inf->result, "symbolic link to '%s'",
+ inf->link_path);
+ }
+ return (1);
+ case S_IFSOCK:
+ xasprintf(&inf->result, "socket");
+ return (1);
+ case S_IFBLK:
+ xasprintf(&inf->result, "block special (%ld/%ld)",
+ (long)major(inf->sb.st_rdev), (long)minor(inf->sb.st_rdev));
+ return (1);
+ case S_IFCHR:
+ xasprintf(&inf->result, "character special (%ld/%ld)",
+ (long)major(inf->sb.st_rdev), (long)minor(inf->sb.st_rdev));
+ return (1);
+ case S_IFIFO:
+ xasprintf(&inf->result, "fifo (named pipe)");
+ return (1);
}
+ return (0);
+}
+
+static int
+try_empty(struct input_file *inf)
+{
+ if (inf->size != 0)
+ return (0);
- (void)fclose(f);
+ if (iflag)
+ xasprintf(&inf->result, "application/x-empty");
+ else
+ xasprintf(&inf->result, "empty");
+ return (1);
}
-/*
- * Called for each input file on the command line (or in a list of files)
- */
-private void
-process(const char *inname, int wid)
+static int
+try_access(struct input_file *inf)
{
- const char *type;
- int std_in = strcmp(inname, "-") == 0;
+ char tmp[256] = "";
+
+ if (inf->fd != -1)
+ return (0);
+
+ if (inf->sb.st_mode & 0222)
+ strlcat(tmp, "writable, ", sizeof tmp);
+ if (inf->sb.st_mode & 0111)
+ strlcat(tmp, "executable, ", sizeof tmp);
+ if (S_ISREG(inf->sb.st_mode))
+ strlcat(tmp, "regular file, ", sizeof tmp);
+ strlcat(tmp, "no read permission", sizeof tmp);
+
+ inf->result = xstrdup(tmp);
+ return (1);
+}
+
+static int
+try_text(struct input_file *inf)
+{
+ const char *type, *s;
+ int flags;
+
+ flags = MAGIC_TEST_TEXT;
+ if (iflag)
+ flags |= MAGIC_TEST_MIME;
+
+ type = text_get_type(inf->base, inf->size);
+ if (type == NULL)
+ return (0);
+
+ s = magic_test(inf->m, inf->base, inf->size, flags);
+ if (s != NULL) {
+ inf->result = xstrdup(s);
+ return (1);
+ }
- if (wid > 0 && !bflag) {
- (void)printf("%s", std_in ? "/dev/stdin" : inname);
- if (nulsep)
- (void)putc('\0', stdout);
+ s = text_try_words(inf->base, inf->size, flags);
+ if (s != NULL) {
+ if (iflag)
+ inf->result = xstrdup(s);
else
- (void)printf("%s", separator);
- (void)printf("%*s ",
- (int) (nopad ? 0 : (wid - file_mbswidth(inname))), "");
+ xasprintf(&inf->result, "%s %s text", type, s);
+ return (1);
}
- type = magic_file(magic, std_in ? NULL : inname);
- if (type == NULL)
- (void)printf("ERROR: %s\n", magic_error(magic));
+ if (iflag)
+ inf->result = xstrdup("text/plain");
else
- (void)printf("%s\n", type);
+ xasprintf(&inf->result, "%s text", type);
+ return (1);
}
-size_t
-file_mbswidth(const char *s)
+static int
+try_magic(struct input_file *inf)
{
-#if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
- size_t bytesconsumed, old_n, n, width = 0;
- mbstate_t state;
- wchar_t nextchar;
- (void)memset(&state, 0, sizeof(mbstate_t));
- old_n = n = strlen(s);
- int w;
-
- while (n > 0) {
- bytesconsumed = mbrtowc(&nextchar, s, n, &state);
- if (bytesconsumed == (size_t)(-1) ||
- bytesconsumed == (size_t)(-2)) {
- /* Something went wrong, return something reasonable */
- return old_n;
- }
- if (s[0] == '\n') {
- /*
- * do what strlen() would do, so that caller
- * is always right
- */
- width++;
- } else {
- w = wcwidth(nextchar);
- if (w > 0)
- width += w;
- }
+ const char *s;
+ int flags;
+
+ flags = 0;
+ if (iflag)
+ flags |= MAGIC_TEST_MIME;
- s += bytesconsumed, n -= bytesconsumed;
+ s = magic_test(inf->m, inf->base, inf->size, flags);
+ if (s != NULL) {
+ inf->result = xstrdup(s);
+ return (1);
}
- return width;
-#else
- return strlen(s);
-#endif
+ return (0);
}
-private void
-usage(void)
+static int
+try_unknown(struct input_file *inf)
{
- (void)fprintf(stderr, USAGE, __progname, __progname);
- (void)fputs("Try `file --help' for more information.\n", stderr);
- exit(1);
+ if (iflag)
+ xasprintf(&inf->result, "application/x-not-regular-file");
+ else
+ xasprintf(&inf->result, "data");
+ return (1);
}
-private void
-help(void)
+static void
+test_file(struct magic *m, struct input_file *inf, int width)
{
- (void)fputs(
-"Usage: file [OPTION...] [FILE...]\n"
-"Determine type of FILEs.\n"
-"\n", stderr);
-#define OPT(shortname, longname, opt, doc) \
- fprintf(stderr, " -%c, --" longname doc, shortname);
-#define OPT_LONGONLY(longname, opt, doc) \
- fprintf(stderr, " --" longname doc);
-#include "file_opts.h"
-#undef OPT
-#undef OPT_LONGONLY
- exit(0);
+ int stop;
+
+ inf->m = m;
+
+ stop = 0;
+ if (!stop)
+ stop = try_stat(inf);
+ if (!stop)
+ stop = try_access(inf);
+ if (!stop)
+ stop = load_file(inf);
+ if (!stop)
+ stop = try_empty(inf);
+ if (!stop)
+ stop = try_magic(inf);
+ if (!stop)
+ stop = try_text(inf);
+ if (!stop)
+ stop = try_unknown(inf);
+
+ if (bflag)
+ printf("%s\n", inf->result);
+ else
+ printf("%-*s %s\n", width, inf->label, inf->result);
+
+ if (inf->mapped && inf->base != NULL)
+ munmap(inf->base, inf->size);
+ inf->base = NULL;
+
+ free(inf->result);
}
-/* $OpenBSD: file.h,v 1.24 2014/05/18 17:50:11 espie Exp $ */
-/*
- * Copyright (c) Ian F. Darwin 1986-1995.
- * Software written by Ian F. Darwin and others;
- * maintained 1995-present by Christos Zoulas and others.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
+/* $OpenBSD: file.h,v 1.25 2015/04/24 16:24:11 nicm Exp $ */
+
/*
- * file.h - definitions for file(1) program
- * @(#)$Id: file.h,v 1.24 2014/05/18 17:50:11 espie Exp $
+ * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef __file_h__
-#define __file_h__
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdio.h> /* Include that here, to make sure __P gets defined */
-#include <errno.h>
-#include <fcntl.h> /* For open and flags */
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-#include <regex.h>
-#include <sys/types.h>
-/* Do this here and now, because struct stat gets re-defined on solaris */
-#include <sys/stat.h>
-#include <stdarg.h>
-
-#define ENABLE_CONDITIONALS
-
-#ifndef MAGIC
-#define MAGIC "/etc/magic"
-#endif
-
-#ifdef __EMX__
-#define PATHSEP ';'
-#else
-#define PATHSEP ':'
-#endif
-
-#define private static
-#ifndef protected
-#define protected
-#endif
-#define public
-
-#ifndef __GNUC_PREREQ__
-#ifdef __GNUC__
-#define __GNUC_PREREQ__(x, y) \
- ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \
- (__GNUC__ > (x)))
-#else
-#define __GNUC_PREREQ__(x, y) 0
-#endif
-#endif
-
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#ifndef MAX
-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifndef HOWMANY
-# define HOWMANY (256 * 1024) /* how much of the file to look at */
-#endif
-#define MAXMAGIS 8192 /* max entries in any one magic file
- or directory */
-#define MAXDESC 64 /* max leng of text description/MIME type */
-#define MAXstring 32 /* max leng of "string" types */
-
-#define MAGICNO 0xF11E041C
-#define VERSIONNO 5
-#define FILE_MAGICSIZE (32 * 6)
-
-#define FILE_LOAD 0
-#define FILE_CHECK 1
-#define FILE_COMPILE 2
-
-struct magic {
- /* Word 1 */
- uint16_t cont_level; /* level of ">" */
- uint8_t flag;
-#define INDIR 0x01 /* if '(...)' appears */
-#define OFFADD 0x02 /* if '>&' or '>...(&' appears */
-#define INDIROFFADD 0x04 /* if '>&(' appears */
-#define UNSIGNED 0x08 /* comparison is unsigned */
-#define NOSPACE 0x10 /* suppress space character before output */
-#define BINTEST 0x20 /* test is for a binary type (set only
- for top-level tests) */
-#define TEXTTEST 0 /* for passing to file_softmagic */
-
- uint8_t dummy1;
-
- /* Word 2 */
- uint8_t reln; /* relation (0=eq, '>'=gt, etc) */
- uint8_t vallen; /* length of string value, if any */
- uint8_t type; /* comparison type (FILE_*) */
- uint8_t in_type; /* type of indirection */
-#define FILE_INVALID 0
-#define FILE_BYTE 1
-#define FILE_SHORT 2
-#define FILE_DEFAULT 3
-#define FILE_LONG 4
-#define FILE_STRING 5
-#define FILE_DATE 6
-#define FILE_BESHORT 7
-#define FILE_BELONG 8
-#define FILE_BEDATE 9
-#define FILE_LESHORT 10
-#define FILE_LELONG 11
-#define FILE_LEDATE 12
-#define FILE_PSTRING 13
-#define FILE_LDATE 14
-#define FILE_BELDATE 15
-#define FILE_LELDATE 16
-#define FILE_REGEX 17
-#define FILE_BESTRING16 18
-#define FILE_LESTRING16 19
-#define FILE_SEARCH 20
-#define FILE_MEDATE 21
-#define FILE_MELDATE 22
-#define FILE_MELONG 23
-#define FILE_QUAD 24
-#define FILE_LEQUAD 25
-#define FILE_BEQUAD 26
-#define FILE_QDATE 27
-#define FILE_LEQDATE 28
-#define FILE_BEQDATE 29
-#define FILE_QLDATE 30
-#define FILE_LEQLDATE 31
-#define FILE_BEQLDATE 32
-#define FILE_FLOAT 33
-#define FILE_BEFLOAT 34
-#define FILE_LEFLOAT 35
-#define FILE_DOUBLE 36
-#define FILE_BEDOUBLE 37
-#define FILE_LEDOUBLE 38
-#define FILE_NAMES_SIZE 39/* size of array to contain all names */
-
-#define IS_STRING(t) \
- ((t) == FILE_STRING || \
- (t) == FILE_PSTRING || \
- (t) == FILE_BESTRING16 || \
- (t) == FILE_LESTRING16 || \
- (t) == FILE_REGEX || \
- (t) == FILE_SEARCH || \
- (t) == FILE_DEFAULT)
-
-#define FILE_FMT_NONE 0
-#define FILE_FMT_NUM 1 /* "cduxXi" */
-#define FILE_FMT_STR 2 /* "s" */
-#define FILE_FMT_QUAD 3 /* "ll" */
-#define FILE_FMT_FLOAT 4 /* "eEfFgG" */
-#define FILE_FMT_DOUBLE 5 /* "eEfFgG" */
-
- /* Word 3 */
- uint8_t in_op; /* operator for indirection */
- uint8_t mask_op; /* operator for mask */
-#ifdef ENABLE_CONDITIONALS
- uint8_t cond; /* conditional type */
- uint8_t dummy2;
-#else
- uint8_t dummy2;
- uint8_t dummy3;
-#endif
-
-#define FILE_OPS "&|^+-*/%"
-#define FILE_OPAND 0
-#define FILE_OPOR 1
-#define FILE_OPXOR 2
-#define FILE_OPADD 3
-#define FILE_OPMINUS 4
-#define FILE_OPMULTIPLY 5
-#define FILE_OPDIVIDE 6
-#define FILE_OPMODULO 7
-#define FILE_OPS_MASK 0x07 /* mask for above ops */
-#define FILE_UNUSED_1 0x08
-#define FILE_UNUSED_2 0x10
-#define FILE_UNUSED_3 0x20
-#define FILE_OPINVERSE 0x40
-#define FILE_OPINDIRECT 0x80
-
-#ifdef ENABLE_CONDITIONALS
-#define COND_NONE 0
-#define COND_IF 1
-#define COND_ELIF 2
-#define COND_ELSE 3
-#endif /* ENABLE_CONDITIONALS */
-
- /* Word 4 */
- uint32_t offset; /* offset to magic number */
- /* Word 5 */
- int32_t in_offset; /* offset from indirection */
- /* Word 6 */
- uint32_t lineno; /* line number in magic file */
- /* Word 7,8 */
- union {
- uint64_t _mask; /* for use with numeric and date types */
- struct {
- uint32_t _count; /* repeat/line count */
- uint32_t _flags; /* modifier flags */
- } _s; /* for use with string types */
- } _u;
-#define num_mask _u._mask
-#define str_range _u._s._count
-#define str_flags _u._s._flags
-
- /* Words 9-16 */
- union VALUETYPE {
- uint8_t b;
- uint16_t h;
- uint32_t l;
- uint64_t q;
- uint8_t hs[2]; /* 2 bytes of a fixed-endian "short" */
- uint8_t hl[4]; /* 4 bytes of a fixed-endian "long" */
- uint8_t hq[8]; /* 8 bytes of a fixed-endian "quad" */
- char s[MAXstring]; /* the search string or regex pattern */
- float f;
- double d;
- } value; /* either number or string */
- /* Words 17..31 */
- char desc[MAXDESC]; /* description */
- /* Words 32..47 */
- char mimetype[MAXDESC]; /* MIME type */
-};
-
-#define BIT(A) (1 << (A))
-#define STRING_COMPACT_BLANK BIT(0)
-#define STRING_COMPACT_OPTIONAL_BLANK BIT(1)
-#define STRING_IGNORE_LOWERCASE BIT(2)
-#define STRING_IGNORE_UPPERCASE BIT(3)
-#define REGEX_OFFSET_START BIT(4)
-#define CHAR_COMPACT_BLANK 'B'
-#define CHAR_COMPACT_OPTIONAL_BLANK 'b'
-#define CHAR_IGNORE_LOWERCASE 'c'
-#define CHAR_IGNORE_UPPERCASE 'C'
-#define CHAR_REGEX_OFFSET_START 's'
-#define STRING_IGNORE_CASE (STRING_IGNORE_LOWERCASE|STRING_IGNORE_UPPERCASE)
-#define STRING_DEFAULT_RANGE 100
-
-
-/* list of magic entries */
-struct mlist {
- struct magic *magic; /* array of magic entries */
- uint32_t nmagic; /* number of entries in array */
- int mapped; /* allocation type: 0 => apprentice_file
- * 1 => apprentice_map + malloc
- * 2 => apprentice_map + mmap */
- struct mlist *next, *prev;
-};
-
-struct magic_set {
- struct mlist *mlist;
- struct cont {
- size_t len;
- struct level_info {
- int32_t off;
- int got_match;
-#ifdef ENABLE_CONDITIONALS
- int last_match;
- int last_cond; /* used for error checking by parse() */
-#endif
- } *li;
- } c;
- struct out {
- char *buf; /* Accumulation buffer */
- char *pbuf; /* Printable buffer */
- } o;
- uint32_t offset;
- int error;
- int flags;
- int haderr;
- const char *file;
- size_t line; /* current magic line number */
-
- /* data for searches */
- struct {
- const char *s; /* start of search in original source */
- size_t s_len; /* length of search region */
- size_t offset; /* starting offset in source: XXX - should this be off_t? */
- size_t rm_len; /* match length */
- } search;
-
- /* FIXME: Make the string dynamically allocated so that e.g.
- strings matched in files can be longer than MAXstring */
- union VALUETYPE ms_value; /* either number or string */
-};
-
-/* Type for Unicode characters */
-typedef unsigned long unichar;
-
-struct stat;
-protected const char *file_fmttime(uint64_t, int);
-protected int file_buffer(struct magic_set *, int, const char *, const void *,
- size_t);
-protected int file_fsmagic(struct magic_set *, const char *, struct stat *);
-protected int file_pipe2file(struct magic_set *, int, const void *, size_t);
-protected int file_printf(struct magic_set *, const char *, ...);
-protected int file_reset(struct magic_set *);
-protected int file_tryelf(struct magic_set *, int, const unsigned char *,
- size_t);
-protected int file_zmagic(struct magic_set *, int, const char *,
- const unsigned char *, size_t);
-protected int file_ascmagic(struct magic_set *, const unsigned char *, size_t);
-protected int file_is_tar(struct magic_set *, const unsigned char *, size_t);
-protected int file_softmagic(struct magic_set *, const unsigned char *, size_t, int);
-protected struct mlist *file_apprentice(struct magic_set *, const char *, int);
-protected uint64_t file_signextend(struct magic_set *, struct magic *,
- uint64_t);
-protected void file_delmagic(struct magic *, int type, size_t entries);
-protected void file_badread(struct magic_set *);
-protected void file_badseek(struct magic_set *);
-protected void file_oomem(struct magic_set *, size_t);
-protected void file_oomem2(struct magic_set *, size_t, size_t);
-protected void file_error(struct magic_set *, int, const char *, ...);
-protected void file_magerror(struct magic_set *, const char *, ...);
-protected void file_magwarn(struct magic_set *, const char *, ...);
-protected void file_mdump(struct magic *);
-protected void file_showstr(FILE *, const char *, size_t);
-protected size_t file_mbswidth(const char *);
-protected const char *file_getbuffer(struct magic_set *);
-protected ssize_t sread(int, void *, size_t, int);
-protected int file_check_mem(struct magic_set *, unsigned int);
-protected int file_looks_utf8(const unsigned char *, size_t, unichar *, size_t *);
-
-#ifndef COMPILE_ONLY
-extern const char *file_names[];
-extern const size_t file_nnames;
-#endif
-
-#ifndef HAVE_STRERROR
-extern int sys_nerr;
-extern char *sys_errlist[];
-#define strerror(e) \
- (((e) >= 0 && (e) < sys_nerr) ? sys_errlist[(e)] : "Unknown error")
-#endif
-
-#ifndef HAVE_STRTOUL
-#define strtoul(a, b, c) strtol(a, b, c)
-#endif
+#ifndef FILE_H
+#define FILE_H
-#ifndef HAVE_VASPRINTF
-int vasprintf(char **ptr, const char *format_string, va_list vargs);
-#endif
-#ifndef HAVE_ASPRINTF
-int asprintf(char **ptr, const char *format_string, ...);
-#endif
+/* Bytes to read if can't use the whole file. */
+#define FILE_READ_SIZE (256 * 1024)
-#if defined(HAVE_MMAP) && defined(HAVE_SYS_MMAN_H) && !defined(QUICK)
-#define QUICK
-#endif
+/* User to drop to if run as root. */
+#define FILE_USER "nobody"
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
+/* text.c */
+const char *text_get_type(const void *, size_t);
+const char *text_try_words(const void *, size_t, int);
-#endif /* __file_h__ */
+#endif /* FILE_H */
+++ /dev/null
-/* $OpenBSD: file_opts.h,v 1.2 2009/04/26 14:17:45 chl Exp $ */
-/*
- * Table of command-line options
- *
- * The first column specifies the short name, if any, or 0 if none.
- * The second column specifies the long name.
- * The third column specifies whether it takes a parameter.
- * The fourth column is the documentation.
- *
- * N.B. The long options' order must correspond to the code in file.c,
- * and OPTSTRING must be kept up-to-date with the short options.
- * Pay particular attention to the numbers of long-only options in the
- * switch statement!
- */
-
-OPT_LONGONLY("help", 0, " display this help and exit\n")
-OPT('v', "version", 0, " output version information and exit\n")
-OPT('m', "magic-file", 1, " LIST use LIST as a colon-separated list of magic\n"
- " number files\n")
-OPT('z', "uncompress", 0, " try to look inside compressed files\n")
-OPT('b', "brief", 0, " do not prepend filenames to output lines\n")
-OPT('c', "checking-printout", 0, " print the parsed form of the magic file, use in\n"
- " conjunction with -m to debug a new magic file\n"
- " before installing it\n")
-OPT('e', "exclude", 1, " TEST exclude TEST from the list of test to be\n"
- " performed for file. Valid tests are:\n"
- " ascii, apptype, compress, elf, soft, tar, tokens, troff\n")
-OPT('f', "files-from", 1, " FILE read the filenames to be examined from FILE\n")
-OPT('F', "separator", 1, " STRING use string as separator instead of `:'\n")
-OPT('i', "mime", 0, " output MIME type strings (--mime-type and\n"
- " --mime-encoding)\n")
-OPT_LONGONLY("mime-type", 0, " output the MIME type\n")
-OPT_LONGONLY("mime-encoding", 0, " output the MIME encoding\n")
-OPT('k', "keep-going", 0, " don't stop at the first match\n")
-#ifdef S_IFLNK
-OPT('L', "dereference", 0, " follow symlinks (default)\n")
-OPT('h', "no-dereference", 0, " don't follow symlinks\n")
-#endif
-OPT('n', "no-buffer", 0, " do not buffer output\n")
-OPT('N', "no-pad", 0, " do not pad output\n")
-OPT('0', "print0", 0, " terminate filenames with ASCII NUL\n")
-#if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
-OPT('p', "preserve-date", 0, " preserve access times on files\n")
-#endif
-OPT('r', "raw", 0, " don't translate unprintable chars to \\ooo\n")
-OPT('s', "special-files", 0, " treat special (block/char devices) files as\n"
- " ordinary ones\n")
-OPT('C', "compile", 0, " compile file specified by -m\n")
-OPT('d', "debug", 0, " print debugging messages\n")
+++ /dev/null
-/* $OpenBSD: fsmagic.c,v 1.14 2009/10/27 23:59:37 deraadt Exp $ */
-/*
- * Copyright (c) Ian F. Darwin 1986-1995.
- * Software written by Ian F. Darwin and others;
- * maintained 1995-present by Christos Zoulas and others.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-/*
- * fsmagic - magic based on filesystem info - directory, special files, etc.
- */
-
-#include "file.h"
-#include "magic.h"
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <stdlib.h>
-#include <sys/stat.h>
-/* Since major is a function on SVR4, we cannot use `ifndef major'. */
-#ifdef MAJOR_IN_MKDEV
-# include <sys/mkdev.h>
-# define HAVE_MAJOR
-#endif
-#ifdef MAJOR_IN_SYSMACROS
-# include <sys/sysmacros.h>
-# define HAVE_MAJOR
-#endif
-#ifdef major /* Might be defined in sys/types.h. */
-# define HAVE_MAJOR
-#endif
-
-#ifndef HAVE_MAJOR
-# define major(dev) (((dev) >> 8) & 0xff)
-# define minor(dev) ((dev) & 0xff)
-#endif
-#undef HAVE_MAJOR
-
-private int
-bad_link(struct magic_set *ms, int err, char *buf)
-{
- char *errfmt;
- if (err == ELOOP)
- errfmt = "symbolic link in a loop";
- else
- errfmt = "broken symbolic link to `%s'";
- if (ms->flags & MAGIC_ERROR) {
- file_error(ms, err, errfmt, buf);
- return -1;
- }
- if (file_printf(ms, errfmt, buf) == -1)
- return -1;
- return 1;
-}
-
-protected int
-file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb)
-{
- int ret = 0;
- int mime = ms->flags & MAGIC_MIME;
-#ifdef S_IFLNK
- char buf[BUFSIZ+4];
- int nch;
- struct stat tstatbuf;
-#endif
-
- if (fn == NULL)
- return 0;
-
- /*
- * Fstat is cheaper but fails for files you don't have read perms on.
- * On 4.2BSD and similar systems, use lstat() to identify symlinks.
- */
-#ifdef S_IFLNK
- if ((ms->flags & MAGIC_SYMLINK) == 0)
- ret = lstat(fn, sb);
- else
-#endif
- ret = stat(fn, sb); /* don't merge into if; see "ret =" above */
-
- if (ret) {
- if (ms->flags & MAGIC_ERROR) {
- file_error(ms, errno, "cannot stat `%s'", fn);
- return -1;
- }
- if (file_printf(ms, "cannot open `%s' (%s)",
- fn, strerror(errno)) == -1)
- return -1;
- return 1;
- }
-
- if (mime) {
- if ((sb->st_mode & S_IFMT) != S_IFREG) {
- if ((mime & MAGIC_MIME_TYPE) &&
- file_printf(ms, "application/x-not-regular-file")
- == -1)
- return -1;
- return 1;
- }
- }
- else {
-#ifdef S_ISUID
- if (sb->st_mode & S_ISUID)
- if (file_printf(ms, "setuid ") == -1)
- return -1;
-#endif
-#ifdef S_ISGID
- if (sb->st_mode & S_ISGID)
- if (file_printf(ms, "setgid ") == -1)
- return -1;
-#endif
-#ifdef S_ISVTX
- if (sb->st_mode & S_ISVTX)
- if (file_printf(ms, "sticky ") == -1)
- return -1;
-#endif
- }
-
- switch (sb->st_mode & S_IFMT) {
- case S_IFDIR:
- if (file_printf(ms, "directory") == -1)
- return -1;
- return 1;
-#ifdef S_IFCHR
- case S_IFCHR:
- /*
- * If -s has been specified, treat character special files
- * like ordinary files. Otherwise, just report that they
- * are block special files and go on to the next file.
- */
- if ((ms->flags & MAGIC_DEVICES) != 0)
- break;
-#ifdef HAVE_STAT_ST_RDEV
-# ifdef dv_unit
- if (file_printf(ms, "character special (%d/%d/%d)",
- major(sb->st_rdev), dv_unit(sb->st_rdev),
- dv_subunit(sb->st_rdev)) == -1)
- return -1;
-# else
- if (file_printf(ms, "character special (%ld/%ld)",
- (long) major(sb->st_rdev), (long) minor(sb->st_rdev)) == -1)
- return -1;
-# endif
-#else
- if (file_printf(ms, "character special") == -1)
- return -1;
-#endif
- return 1;
-#endif
-#ifdef S_IFBLK
- case S_IFBLK:
- /*
- * If -s has been specified, treat block special files
- * like ordinary files. Otherwise, just report that they
- * are block special files and go on to the next file.
- */
- if ((ms->flags & MAGIC_DEVICES) != 0)
- break;
-#ifdef HAVE_STAT_ST_RDEV
-# ifdef dv_unit
- if (file_printf(ms, "block special (%d/%d/%d)",
- major(sb->st_rdev), dv_unit(sb->st_rdev),
- dv_subunit(sb->st_rdev)) == -1)
- return -1;
-# else
- if (file_printf(ms, "block special (%ld/%ld)",
- (long)major(sb->st_rdev), (long)minor(sb->st_rdev)) == -1)
- return -1;
-# endif
-#else
- if (file_printf(ms, "block special") == -1)
- return -1;
-#endif
- return 1;
-#endif
- /* TODO add code to handle V7 MUX and Blit MUX files */
-#ifdef S_IFIFO
- case S_IFIFO:
- if((ms->flags & MAGIC_DEVICES) != 0)
- break;
- if (file_printf(ms, "fifo (named pipe)") == -1)
- return -1;
- return 1;
-#endif
-#ifdef S_IFDOOR
- case S_IFDOOR:
- if (file_printf(ms, "door") == -1)
- return -1;
- return 1;
-#endif
-#ifdef S_IFLNK
- case S_IFLNK:
- if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
- if (ms->flags & MAGIC_ERROR) {
- file_error(ms, errno, "unreadable symlink `%s'",
- fn);
- return -1;
- }
- if (file_printf(ms,
- "unreadable symlink `%s' (%s)", fn,
- strerror(errno)) == -1)
- return -1;
- return 1;
- }
- buf[nch] = '\0'; /* readlink(2) does not do this */
-
- /* If broken symlink, say so and quit early. */
- if (*buf == '/') {
- if (stat(buf, &tstatbuf) < 0)
- return bad_link(ms, errno, buf);
- } else {
- char *tmp;
- char buf2[BUFSIZ+BUFSIZ+4];
-
- if ((tmp = strrchr(fn, '/')) == NULL) {
- tmp = buf; /* in current directory anyway */
- } else {
- if (tmp - fn + 1 > BUFSIZ) {
- if (ms->flags & MAGIC_ERROR) {
- file_error(ms, 0,
- "path too long: `%s'", buf);
- return -1;
- }
- if (file_printf(ms,
- "path too long: `%s'", fn) == -1)
- return -1;
- return 1;
- }
- (void)strlcpy(buf2, fn, sizeof buf2); /* take dir part */
- buf2[tmp - fn + 1] = '\0';
- (void)strlcat(buf2, buf, sizeof buf2); /* plus (rel) link */
- tmp = buf2;
- }
- if (stat(tmp, &tstatbuf) < 0)
- return bad_link(ms, errno, buf);
- }
-
- /* Otherwise, handle it. */
- if ((ms->flags & MAGIC_SYMLINK) != 0) {
- const char *p;
- ms->flags &= MAGIC_SYMLINK;
- p = magic_file(ms, buf);
- ms->flags |= MAGIC_SYMLINK;
- return p != NULL ? 1 : -1;
- } else { /* just print what it points to */
- if (file_printf(ms, "symbolic link to `%s'",
- buf) == -1)
- return -1;
- }
- return 1;
-#endif
-#ifdef S_IFSOCK
-#ifndef __COHERENT__
- case S_IFSOCK:
- if (file_printf(ms, "socket") == -1)
- return -1;
- return 1;
-#endif
-#endif
- case S_IFREG:
- break;
- default:
- file_error(ms, 0, "invalid mode 0%o", sb->st_mode);
- return -1;
- /*NOTREACHED*/
- }
-
- /*
- * regular file, check next possibility
- *
- * If stat() tells us the file has zero length, report here that
- * the file is empty, so we can skip all the work of opening and
- * reading the file.
- * But if the -s option has been given, we skip this optimization,
- * since on some systems, stat() reports zero size for raw disk
- * partitions. (If the block special device really has zero length,
- * the fact that it is empty will be detected and reported correctly
- * when we read the file.)
- */
- if ((ms->flags & MAGIC_DEVICES) == 0 && sb->st_size == 0) {
- if ((!mime || (mime & MAGIC_MIME_TYPE)) &&
- file_printf(ms, mime ? "application/x-empty" :
- "empty") == -1)
- return -1;
- return 1;
- }
- return 0;
-}
+++ /dev/null
-/* $OpenBSD: funcs.c,v 1.8 2014/05/18 17:50:11 espie Exp $ */
-/*
- * Copyright (c) Christos Zoulas 2003.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include "file.h"
-#include "magic.h"
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#if defined(HAVE_WCHAR_H)
-#include <wchar.h>
-#endif
-#if defined(HAVE_WCTYPE_H)
-#include <wctype.h>
-#endif
-
-/*
- * Like printf, only we append to a buffer.
- */
-protected int
-file_printf(struct magic_set *ms, const char *fmt, ...)
-{
- va_list ap;
- int len;
- char *buf, *newstr;
-
- va_start(ap, fmt);
- len = vasprintf(&buf, fmt, ap);
- if (len < 0)
- goto out;
- va_end(ap);
-
- if (ms->o.buf != NULL) {
- len = asprintf(&newstr, "%s%s", ms->o.buf, buf);
- free(buf);
- if (len < 0)
- goto out;
- free(ms->o.buf);
- buf = newstr;
- }
- ms->o.buf = buf;
- return 0;
-out:
- file_error(ms, errno, "vasprintf failed");
- return -1;
-}
-
-/*
- * error - print best error message possible
- */
-/*VARARGS*/
-private void
-file_error_core(struct magic_set *ms, int error, const char *f, va_list va,
- uint32_t lineno)
-{
- /* Only the first error is ok */
- if (ms->haderr)
- return;
- if (lineno != 0) {
- free(ms->o.buf);
- ms->o.buf = NULL;
- file_printf(ms, "line %u: ", lineno);
- }
- file_printf(ms, f, va);
- if (error > 0)
- file_printf(ms, " (%s)", strerror(error));
- ms->haderr++;
- ms->error = error;
-}
-
-/*VARARGS*/
-protected void
-file_error(struct magic_set *ms, int error, const char *f, ...)
-{
- va_list va;
- va_start(va, f);
- file_error_core(ms, error, f, va, 0);
- va_end(va);
-}
-
-/*
- * Print an error with magic line number.
- */
-/*VARARGS*/
-protected void
-file_magerror(struct magic_set *ms, const char *f, ...)
-{
- va_list va;
- va_start(va, f);
- file_error_core(ms, 0, f, va, ms->line);
- va_end(va);
-}
-
-protected void
-file_oomem(struct magic_set *ms, size_t len)
-{
- file_error(ms, errno, "cannot allocate %zu bytes", len);
-}
-
-protected void
-file_oomem2(struct magic_set *ms, size_t len, size_t l2)
-{
- file_error(ms, errno, "cannot allocate %zu * %zu bytes", len, l2);
-}
-protected void
-file_badseek(struct magic_set *ms)
-{
- file_error(ms, errno, "error seeking");
-}
-
-protected void
-file_badread(struct magic_set *ms)
-{
- file_error(ms, errno, "error reading");
-}
-
-#ifndef COMPILE_ONLY
-protected int
-file_buffer(struct magic_set *ms, int fd, const char *inname, const void *buf,
- size_t nb)
-{
- int m;
- int mime = ms->flags & MAGIC_MIME;
-
- if (nb == 0) {
- if ((!mime || (mime & MAGIC_MIME_TYPE)) &&
- file_printf(ms, mime ? "application/x-empty" :
- "empty") == -1)
- return -1;
- return 1;
- } else if (nb == 1) {
- if ((!mime || (mime & MAGIC_MIME_TYPE)) &&
- file_printf(ms, mime ? "application/octet-stream" :
- "very short file (no magic)") == -1)
- return -1;
- return 1;
- }
-
-#ifdef __EMX__
- if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) {
- switch (file_os2_apptype(ms, inname, buf, nb)) {
- case -1:
- return -1;
- case 0:
- break;
- default:
- return 1;
- }
- }
-#endif
-
- /* try compression stuff */
- if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) != 0 ||
- (m = file_zmagic(ms, fd, inname, buf, nb)) == 0) {
- /* Check if we have a tar file */
- if ((ms->flags & MAGIC_NO_CHECK_TAR) != 0 ||
- (m = file_is_tar(ms, buf, nb)) == 0) {
- /* try tests in /etc/magic (or surrogate magic file) */
- if ((ms->flags & MAGIC_NO_CHECK_SOFT) != 0 ||
- (m = file_softmagic(ms, buf, nb, BINTEST)) == 0) {
- /* try known keywords, check whether it is ASCII */
- if ((ms->flags & MAGIC_NO_CHECK_ASCII) != 0 ||
- (m = file_ascmagic(ms, buf, nb)) == 0) {
- /* abandon hope, all ye who remain here */
- if ((!mime || (mime & MAGIC_MIME_TYPE)) &&
- file_printf(ms, mime ? "application/octet-stream" :
- "data") == -1)
- return -1;
- m = 1;
- }
- }
- }
- }
-#ifdef BUILTIN_ELF
- if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && m == 1 &&
- nb > 5 && fd != -1) {
- /*
- * We matched something in the file, so this *might*
- * be an ELF file, and the file is at least 5 bytes
- * long, so if it's an ELF file it has at least one
- * byte past the ELF magic number - try extracting
- * information from the ELF headers that cannot easily
- * be extracted with rules in the magic file.
- */
- (void)file_tryelf(ms, fd, buf, nb);
- }
-#endif
- return m;
-}
-#endif
-
-protected int
-file_reset(struct magic_set *ms)
-{
- if (ms->mlist == NULL) {
- file_error(ms, 0, "no magic files loaded");
- return -1;
- }
- ms->o.buf = NULL;
- ms->haderr = 0;
- ms->error = -1;
- return 0;
-}
-
-#define OCTALIFY(n, o) \
- /*LINTED*/ \
- (void)(*(n)++ = '\\', \
- *(n)++ = (((uint32_t)*(o) >> 6) & 3) + '0', \
- *(n)++ = (((uint32_t)*(o) >> 3) & 7) + '0', \
- *(n)++ = (((uint32_t)*(o) >> 0) & 7) + '0', \
- (o)++)
-
-protected const char *
-file_getbuffer(struct magic_set *ms)
-{
- char *pbuf, *op, *np;
- size_t psize, len;
-
- if (ms->haderr)
- return NULL;
-
- if (ms->flags & MAGIC_RAW)
- return ms->o.buf;
-
- /* * 4 is for octal representation, + 1 is for NUL */
- len = strlen(ms->o.buf);
- if (len > (SIZE_MAX - 1) / 4) {
- file_oomem(ms, len);
- return NULL;
- }
- psize = len * 4 + 1;
- if ((pbuf = realloc(ms->o.pbuf, psize)) == NULL) {
- file_oomem(ms, psize);
- return NULL;
- }
- ms->o.pbuf = pbuf;
-
-#if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
- {
- mbstate_t state;
- wchar_t nextchar;
- int mb_conv = 1;
- size_t bytesconsumed;
- char *eop;
- (void)memset(&state, 0, sizeof(mbstate_t));
-
- np = ms->o.pbuf;
- op = ms->o.buf;
- eop = op + len;
-
- while (op < eop) {
- bytesconsumed = mbrtowc(&nextchar, op,
- (size_t)(eop - op), &state);
- if (bytesconsumed == (size_t)(-1) ||
- bytesconsumed == (size_t)(-2)) {
- mb_conv = 0;
- break;
- }
-
- if (iswprint(nextchar)) {
- (void)memcpy(np, op, bytesconsumed);
- op += bytesconsumed;
- np += bytesconsumed;
- } else {
- while (bytesconsumed-- > 0)
- OCTALIFY(np, op);
- }
- }
- *np = '\0';
-
- /* Parsing succeeded as a multi-byte sequence */
- if (mb_conv != 0)
- return ms->o.pbuf;
- }
-#endif
-
- for (np = ms->o.pbuf, op = ms->o.buf; *op; op++) {
- if (isprint((unsigned char)*op)) {
- *np++ = *op;
- } else {
- OCTALIFY(np, op);
- }
- }
- *np = '\0';
- return ms->o.pbuf;
-}
-
-protected int
-file_check_mem(struct magic_set *ms, unsigned int level)
-{
- size_t len;
-
- if (level >= ms->c.len) {
- len = (ms->c.len += 20) * sizeof(*ms->c.li);
- ms->c.li = (ms->c.li == NULL) ? malloc(len) :
- realloc(ms->c.li, len);
- if (ms->c.li == NULL) {
- file_oomem(ms, len);
- return -1;
- }
- }
- ms->c.li[level].got_match = 0;
-#ifdef ENABLE_CONDITIONALS
- ms->c.li[level].last_match = 0;
- ms->c.li[level].last_cond = COND_NONE;
-#endif /* ENABLE_CONDITIONALS */
- return 0;
-}
+++ /dev/null
-/* $OpenBSD: is_tar.c,v 1.10 2009/10/27 23:59:37 deraadt Exp $ */
-/*
- * Copyright (c) Ian F. Darwin 1986-1995.
- * Software written by Ian F. Darwin and others;
- * maintained 1995-present by Christos Zoulas and others.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-/*
- * is_tar() -- figure out whether file is a tar archive.
- *
- * Stolen (by the author!) from the public domain tar program:
- * Public Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
- *
- * @(#)list.c 1.18 9/23/86 Public Domain - gnu
- *
- * Comments changed and some code/comments reformatted
- * for file command by Ian Darwin.
- */
-
-#include "file.h"
-#include "magic.h"
-#include <string.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include "tar.h"
-
-#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
-
-private int is_tar(const unsigned char *, size_t);
-private int from_oct(int, const char *); /* Decode octal number */
-
-static const char tartype[][32] = {
- "tar archive",
- "POSIX tar archive",
- "POSIX tar archive (GNU)",
-};
-
-protected int
-file_is_tar(struct magic_set *ms, const unsigned char *buf, size_t nbytes)
-{
- /*
- * Do the tar test first, because if the first file in the tar
- * archive starts with a dot, we can confuse it with an nroff file.
- */
- int tar = is_tar(buf, nbytes);
- int mime = ms->flags & MAGIC_MIME;
-
- if (tar < 1 || tar > 3)
- return 0;
-
- if (mime == MAGIC_MIME_ENCODING)
- return 0;
-
- if (file_printf(ms, mime ? "application/x-tar" :
- tartype[tar - 1]) == -1)
- return -1;
- return 1;
-}
-
-/*
- * Return
- * 0 if the checksum is bad (i.e., probably not a tar archive),
- * 1 for old UNIX tar file,
- * 2 for Unix Std (POSIX) tar file,
- * 3 for GNU tar file.
- */
-private int
-is_tar(const unsigned char *buf, size_t nbytes)
-{
- const union record *header = (const union record *)(const void *)buf;
- int i;
- int sum, recsum;
- const char *p;
-
- if (nbytes < sizeof(union record))
- return 0;
-
- recsum = from_oct(8, header->header.chksum);
-
- sum = 0;
- p = header->charptr;
- for (i = sizeof(union record); --i >= 0;) {
- /*
- * We cannot use unsigned char here because of old compilers,
- * e.g. V7.
- */
- sum += 0xFF & *p++;
- }
-
- /* Adjust checksum to count the "chksum" field as blanks. */
- for (i = sizeof(header->header.chksum); --i >= 0;)
- sum -= 0xFF & header->header.chksum[i];
- sum += ' '* sizeof header->header.chksum;
-
- if (sum != recsum)
- return 0; /* Not a tar archive */
-
- if (strcmp(header->header.magic, GNUTMAGIC) == 0)
- return 3; /* GNU Unix Standard tar archive */
- if (strcmp(header->header.magic, TMAGIC) == 0)
- return 2; /* Unix Standard tar archive */
-
- return 1; /* Old fashioned tar archive */
-}
-
-
-/*
- * Quick and dirty octal conversion.
- *
- * Result is -1 if the field is invalid (all blank, or nonoctal).
- */
-private int
-from_oct(int digs, const char *where)
-{
- int value;
-
- while (isspace((unsigned char)*where)) { /* Skip spaces */
- where++;
- if (--digs <= 0)
- return -1; /* All blank field */
- }
- value = 0;
- while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */
- value = (value << 3) | (*where++ - '0');
- --digs;
- }
-
- if (digs > 0 && *where && !isspace((unsigned char)*where))
- return -1; /* Ended on non-space/nul */
-
- return value;
-}
--- /dev/null
+/* $OpenBSD: magic-common.c,v 1.1 2015/04/24 16:24:11 nicm Exp $ */
+
+/*
+ * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "magic.h"
+
+char *
+magic_strtoull(const char *s, uint64_t *u)
+{
+ char *endptr;
+
+ if (*s == '-')
+ return (NULL);
+ errno = 0;
+ *u = strtoull(s, &endptr, 0);
+ if (*s == '\0')
+ return (NULL);
+ if (errno == ERANGE && *u == ULLONG_MAX)
+ return (NULL);
+ if (*endptr == 'L')
+ endptr++;
+ return (endptr);
+}
+
+char *
+magic_strtoll(const char *s, int64_t *i)
+{
+ char *endptr;
+
+ errno = 0;
+ *i = strtoll(s, &endptr, 0);
+ if (*s == '\0')
+ return (NULL);
+ if (errno == ERANGE && *i == LLONG_MAX)
+ return (NULL);
+ if (*endptr == 'L')
+ endptr++;
+ return (endptr);
+}
+
+void
+magic_warn(struct magic_line *ml, const char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+
+ if (!ml->root->warnings)
+ return;
+
+ va_start(ap, fmt);
+ if (vasprintf(&msg, fmt, ap) == -1) {
+ va_end(ap);
+ return;
+ }
+ va_end(ap);
+
+ fprintf(stderr, "%s:%u: %s\n", ml->root->path, ml->line, msg);
+ free(msg);
+}
--- /dev/null
+/* $OpenBSD: magic-dump.c,v 1.1 2015/04/24 16:24:11 nicm Exp $ */
+
+/*
+ * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#include "magic.h"
+
+static void
+magic_dump_line(struct magic_line *ml, u_int depth)
+{
+ struct magic_line *child;
+ u_int i;
+
+ printf("%u", ml->line);
+ for (i = 0; i < depth; i++)
+ printf(">");
+ printf(" %s/%s%s%s%s [%u]%s\n", ml->type_string,
+ ml->result == NULL ? "" : ml->result,
+ ml->mimetype == NULL ? "" : " (",
+ ml->mimetype == NULL ? "" : ml->mimetype,
+ ml->mimetype == NULL ? "" : ")",
+ ml->strength, ml->text ? " (text)" : "");
+
+ TAILQ_FOREACH(child, &ml->children, entry)
+ magic_dump_line(child, depth + 1);
+
+}
+
+void
+magic_dump(struct magic *m)
+{
+ struct magic_line *ml;
+
+ RB_FOREACH(ml, magic_tree, &m->tree)
+ magic_dump_line(ml, 0);
+}
--- /dev/null
+/* $OpenBSD: magic-load.c,v 1.1 2015/04/24 16:24:11 nicm Exp $ */
+
+/*
+ * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "magic.h"
+#include "xmalloc.h"
+
+static int
+magic_odigit(u_char c)
+{
+ if (c >= '0' && c <= '7')
+ return (c - '0');
+ return (-1);
+}
+
+static int
+magic_xdigit(u_char c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ if (c >= 'a' && c <= 'f')
+ return (10 + c - 'a');
+ if (c >= 'A' && c <= 'F')
+ return (10 + c - 'A');
+ return (-1);
+}
+
+static void
+magic_mark_text(struct magic_line *ml, int text)
+{
+ do {
+ ml->text = text;
+ ml = ml->parent;
+ } while (ml != NULL);
+}
+
+static int
+magic_make_pattern(struct magic_line *ml, const char *name, regex_t *re,
+ const char *p)
+{
+ int error;
+ char errbuf[256];
+
+ error = regcomp(re, p, REG_EXTENDED|REG_NOSUB);
+ if (error != 0) {
+ regerror(error, re, errbuf, sizeof errbuf);
+ magic_warn(ml, "bad %s pattern: %s", name, errbuf);
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+magic_set_result(struct magic_line *ml, const char *s)
+{
+ const char *fmt;
+ const char *endfmt;
+ const char *cp;
+ regex_t *re = NULL;
+ regmatch_t pmatch;
+ size_t fmtlen;
+
+ while (isspace((u_char)*s))
+ s++;
+ if (*s == '\0') {
+ ml->result = NULL;
+ return (0);
+ }
+ ml->result = xstrdup(s);
+
+ fmt = NULL;
+ for (cp = s; *cp != '\0'; cp++) {
+ if (cp[0] == '%' && cp[1] != '%') {
+ if (fmt != NULL) {
+ magic_warn(ml, "multiple formats");
+ return (-1);
+ }
+ fmt = cp;
+ }
+ }
+ if (fmt == NULL)
+ return (0);
+ fmt++;
+
+ for (endfmt = fmt; *endfmt != '\0'; endfmt++) {
+ if (strchr("diouxXeEfFgGsc", *endfmt) != NULL)
+ break;
+ }
+ if (*endfmt == '\0') {
+ magic_warn(ml, "unterminated format");
+ return (-1);
+ }
+ fmtlen = endfmt + 1 - fmt;
+ if (fmtlen > 32) {
+ magic_warn(ml, "format too long");
+ return (-1);
+ }
+
+ if (*endfmt == 's') {
+ switch (ml->type) {
+ case MAGIC_TYPE_DATE:
+ case MAGIC_TYPE_LDATE:
+ case MAGIC_TYPE_UDATE:
+ case MAGIC_TYPE_ULDATE:
+ case MAGIC_TYPE_BEDATE:
+ case MAGIC_TYPE_BELDATE:
+ case MAGIC_TYPE_UBEDATE:
+ case MAGIC_TYPE_UBELDATE:
+ case MAGIC_TYPE_QDATE:
+ case MAGIC_TYPE_QLDATE:
+ case MAGIC_TYPE_UQDATE:
+ case MAGIC_TYPE_UQLDATE:
+ case MAGIC_TYPE_BEQDATE:
+ case MAGIC_TYPE_BEQLDATE:
+ case MAGIC_TYPE_UBEQDATE:
+ case MAGIC_TYPE_UBEQLDATE:
+ case MAGIC_TYPE_LEQDATE:
+ case MAGIC_TYPE_LEQLDATE:
+ case MAGIC_TYPE_ULEQDATE:
+ case MAGIC_TYPE_ULEQLDATE:
+ case MAGIC_TYPE_LEDATE:
+ case MAGIC_TYPE_LELDATE:
+ case MAGIC_TYPE_ULEDATE:
+ case MAGIC_TYPE_ULELDATE:
+ case MAGIC_TYPE_MEDATE:
+ case MAGIC_TYPE_MELDATE:
+ case MAGIC_TYPE_STRING:
+ case MAGIC_TYPE_PSTRING:
+ case MAGIC_TYPE_BESTRING16:
+ case MAGIC_TYPE_LESTRING16:
+ case MAGIC_TYPE_REGEX:
+ case MAGIC_TYPE_SEARCH:
+ break;
+ default:
+ ml->stringify = 1;
+ break;
+ }
+ }
+
+ if (!ml->root->compiled) {
+ /*
+ * XXX %ld (and %lu and so on) is invalid on 64-bit platforms
+ * with byte, short, long. We get lucky because our first and
+ * only argument ends up in a register. Accept it for now.
+ */
+ if (magic_make_pattern(ml, "short", &ml->root->format_short,
+ "^-?[0-9]*(\\.[0-9]*)?(c|(l|h|hh)?[iduxX])$") != 0)
+ return (-1);
+ if (magic_make_pattern(ml, "long", &ml->root->format_long,
+ "^-?[0-9]*(\\.[0-9]*)?(c|(l|h|hh)?[iduxX])$") != 0)
+ return (-1);
+ if (magic_make_pattern(ml, "quad", &ml->root->format_quad,
+ "^-?[0-9]*(\\.[0-9]*)?ll[iduxX]$") != 0)
+ return (-1);
+ if (magic_make_pattern(ml, "float", &ml->root->format_float,
+ "^-?[0-9]*(\\.[0-9]*)?[eEfFgG]$") != 0)
+ return (-1);
+ if (magic_make_pattern(ml, "string", &ml->root->format_string,
+ "^-?[0-9]*(\\.[0-9]*)?s$") != 0)
+ return (-1);
+ ml->root->compiled = 1;
+ }
+
+ if (ml->stringify)
+ re = &ml->root->format_string;
+ else {
+ switch (ml->type) {
+ case MAGIC_TYPE_NONE:
+ case MAGIC_TYPE_DEFAULT:
+ return (0); /* don't use result */
+ case MAGIC_TYPE_BYTE:
+ case MAGIC_TYPE_UBYTE:
+ case MAGIC_TYPE_SHORT:
+ case MAGIC_TYPE_USHORT:
+ case MAGIC_TYPE_BESHORT:
+ case MAGIC_TYPE_UBESHORT:
+ case MAGIC_TYPE_LESHORT:
+ case MAGIC_TYPE_ULESHORT:
+ re = &ml->root->format_short;
+ break;
+ case MAGIC_TYPE_LONG:
+ case MAGIC_TYPE_ULONG:
+ case MAGIC_TYPE_BELONG:
+ case MAGIC_TYPE_UBELONG:
+ case MAGIC_TYPE_LELONG:
+ case MAGIC_TYPE_ULELONG:
+ case MAGIC_TYPE_MELONG:
+ re = &ml->root->format_long;
+ break;
+ case MAGIC_TYPE_QUAD:
+ case MAGIC_TYPE_UQUAD:
+ case MAGIC_TYPE_BEQUAD:
+ case MAGIC_TYPE_UBEQUAD:
+ case MAGIC_TYPE_LEQUAD:
+ case MAGIC_TYPE_ULEQUAD:
+ re = &ml->root->format_quad;
+ break;
+ case MAGIC_TYPE_FLOAT:
+ case MAGIC_TYPE_BEFLOAT:
+ case MAGIC_TYPE_LEFLOAT:
+ case MAGIC_TYPE_DOUBLE:
+ case MAGIC_TYPE_BEDOUBLE:
+ case MAGIC_TYPE_LEDOUBLE:
+ re = &ml->root->format_float;
+ break;
+ case MAGIC_TYPE_DATE:
+ case MAGIC_TYPE_LDATE:
+ case MAGIC_TYPE_UDATE:
+ case MAGIC_TYPE_ULDATE:
+ case MAGIC_TYPE_BEDATE:
+ case MAGIC_TYPE_BELDATE:
+ case MAGIC_TYPE_UBEDATE:
+ case MAGIC_TYPE_UBELDATE:
+ case MAGIC_TYPE_QDATE:
+ case MAGIC_TYPE_QLDATE:
+ case MAGIC_TYPE_UQDATE:
+ case MAGIC_TYPE_UQLDATE:
+ case MAGIC_TYPE_BEQDATE:
+ case MAGIC_TYPE_BEQLDATE:
+ case MAGIC_TYPE_UBEQDATE:
+ case MAGIC_TYPE_UBEQLDATE:
+ case MAGIC_TYPE_LEQDATE:
+ case MAGIC_TYPE_LEQLDATE:
+ case MAGIC_TYPE_ULEQDATE:
+ case MAGIC_TYPE_ULEQLDATE:
+ case MAGIC_TYPE_LEDATE:
+ case MAGIC_TYPE_LELDATE:
+ case MAGIC_TYPE_ULEDATE:
+ case MAGIC_TYPE_ULELDATE:
+ case MAGIC_TYPE_MEDATE:
+ case MAGIC_TYPE_MELDATE:
+ case MAGIC_TYPE_STRING:
+ case MAGIC_TYPE_PSTRING:
+ case MAGIC_TYPE_REGEX:
+ case MAGIC_TYPE_SEARCH:
+ re = &ml->root->format_string;
+ break;
+ case MAGIC_TYPE_BESTRING16:
+ case MAGIC_TYPE_LESTRING16:
+ magic_warn(ml, "unsupported type %s", ml->type_string);
+ return (-1);
+ }
+ }
+
+ pmatch.rm_so = 0;
+ pmatch.rm_eo = fmtlen;
+ if (regexec(re, fmt, 1, &pmatch, REG_STARTEND) != 0) {
+ magic_warn(ml, "bad format for %s: %%%.*s", ml->type_string,
+ (int)fmtlen, fmt);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static u_int
+magic_get_strength(struct magic_line *ml)
+{
+ int n;
+ size_t size;
+
+ if (ml->test_not || ml->test_operator == 'x')
+ return (1);
+
+ n = 20;
+ switch (ml->type) {
+ case MAGIC_TYPE_NONE:
+ case MAGIC_TYPE_DEFAULT:
+ return (0);
+ case MAGIC_TYPE_BYTE:
+ case MAGIC_TYPE_UBYTE:
+ n += 1 * MAGIC_STRENGTH_MULTIPLIER;
+ break;
+ case MAGIC_TYPE_SHORT:
+ case MAGIC_TYPE_USHORT:
+ case MAGIC_TYPE_BESHORT:
+ case MAGIC_TYPE_UBESHORT:
+ case MAGIC_TYPE_LESHORT:
+ case MAGIC_TYPE_ULESHORT:
+ n += 2 * MAGIC_STRENGTH_MULTIPLIER;
+ break;
+ case MAGIC_TYPE_LONG:
+ case MAGIC_TYPE_ULONG:
+ case MAGIC_TYPE_FLOAT:
+ case MAGIC_TYPE_DATE:
+ case MAGIC_TYPE_LDATE:
+ case MAGIC_TYPE_UDATE:
+ case MAGIC_TYPE_ULDATE:
+ case MAGIC_TYPE_BELONG:
+ case MAGIC_TYPE_UBELONG:
+ case MAGIC_TYPE_BEFLOAT:
+ case MAGIC_TYPE_BEDATE:
+ case MAGIC_TYPE_BELDATE:
+ case MAGIC_TYPE_UBEDATE:
+ case MAGIC_TYPE_UBELDATE:
+ n += 4 * MAGIC_STRENGTH_MULTIPLIER;
+ break;
+ case MAGIC_TYPE_QUAD:
+ case MAGIC_TYPE_UQUAD:
+ case MAGIC_TYPE_DOUBLE:
+ case MAGIC_TYPE_QDATE:
+ case MAGIC_TYPE_QLDATE:
+ case MAGIC_TYPE_UQDATE:
+ case MAGIC_TYPE_UQLDATE:
+ case MAGIC_TYPE_BEQUAD:
+ case MAGIC_TYPE_UBEQUAD:
+ case MAGIC_TYPE_BEDOUBLE:
+ case MAGIC_TYPE_BEQDATE:
+ case MAGIC_TYPE_BEQLDATE:
+ case MAGIC_TYPE_UBEQDATE:
+ case MAGIC_TYPE_UBEQLDATE:
+ case MAGIC_TYPE_LEQUAD:
+ case MAGIC_TYPE_ULEQUAD:
+ case MAGIC_TYPE_LEDOUBLE:
+ case MAGIC_TYPE_LEQDATE:
+ case MAGIC_TYPE_LEQLDATE:
+ case MAGIC_TYPE_ULEQDATE:
+ case MAGIC_TYPE_ULEQLDATE:
+ case MAGIC_TYPE_LELONG:
+ case MAGIC_TYPE_ULELONG:
+ case MAGIC_TYPE_LEFLOAT:
+ case MAGIC_TYPE_LEDATE:
+ case MAGIC_TYPE_LELDATE:
+ case MAGIC_TYPE_ULEDATE:
+ case MAGIC_TYPE_ULELDATE:
+ case MAGIC_TYPE_MELONG:
+ case MAGIC_TYPE_MEDATE:
+ case MAGIC_TYPE_MELDATE:
+ n += 8 * MAGIC_STRENGTH_MULTIPLIER;
+ break;
+ case MAGIC_TYPE_STRING:
+ case MAGIC_TYPE_PSTRING:
+ n += ml->test_string_size * MAGIC_STRENGTH_MULTIPLIER;
+ break;
+ case MAGIC_TYPE_BESTRING16:
+ case MAGIC_TYPE_LESTRING16:
+ n += ml->test_string_size * MAGIC_STRENGTH_MULTIPLIER / 2;
+ break;
+ case MAGIC_TYPE_REGEX:
+ case MAGIC_TYPE_SEARCH:
+ size = MAGIC_STRENGTH_MULTIPLIER / ml->test_string_size;
+ if (size < 1)
+ size = 1;
+ n += ml->test_string_size * size;
+ break;
+ }
+ switch (ml->test_operator) {
+ case '=':
+ n += MAGIC_STRENGTH_MULTIPLIER;
+ break;
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ n -= 2 * MAGIC_STRENGTH_MULTIPLIER;
+ break;
+ case '^':
+ case '&':
+ n -= MAGIC_STRENGTH_MULTIPLIER;
+ break;
+ }
+ return (n <= 0 ? 1 : n);
+}
+
+static int
+magic_get_string(char **line, char *out, size_t *outlen)
+{
+ char *start, *cp, c;
+ int d0, d1, d2;
+
+ start = out;
+ for (cp = *line; *cp != '\0' && !isspace((u_char)*cp); cp++) {
+ if (*cp != '\\') {
+ *out++ = *cp;
+ continue;
+ }
+
+ switch (c = *++cp) {
+ case ' ':
+ *out++ = ' ';
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ d0 = magic_odigit(cp[0]);
+ if (cp[0] != '\0')
+ d1 = magic_odigit(cp[1]);
+ else
+ d1 = -1;
+ if (cp[0] != '\0' && cp[1] != '\0')
+ d2 = magic_odigit(cp[2]);
+ else
+ d2 = -1;
+
+ if (d0 != -1 && d1 != -1 && d2 != -1) {
+ *out = d2 | (d1 << 3) | (d0 << 6);
+ cp += 2;
+ } else if (d0 != -1 && d1 != -1) {
+ *out = d1 | (d0 << 3);
+ cp++;
+ } else if (d0 != -1)
+ *out = d0;
+ else
+ return (-1);
+ out++;
+ break;
+ case 'x':
+ d0 = magic_xdigit(cp[1]);
+ if (cp[1] != '\0')
+ d1 = magic_xdigit(cp[2]);
+ else
+ d1 = -1;
+
+ if (d0 != -1 && d1 != -1) {
+ *out = d1 | (d0 << 4);
+ cp += 2;
+ } else if (d0 != -1) {
+ *out = d0;
+ cp++;
+ } else
+ return (-1);
+ out++;
+
+ break;
+ case 'a':
+ *out++ = '\a';
+ break;
+ case 'b':
+ *out++ = '\b';
+ break;
+ case 't':
+ *out++ = '\t';
+ break;
+ case 'f':
+ *out++ = '\f';
+ break;
+ case 'n':
+ *out++ = '\n';
+ break;
+ case 'r':
+ *out++ = '\r';
+ break;
+ case '\\':
+ *out++ = '\\';
+ break;
+ case '\'':
+ *out++ = '\'';
+ break;
+ case '\"':
+ *out++ = '\"';
+ break;
+ default:
+ *out++ = c;
+ break;
+ }
+ }
+ *out = '\0';
+ *outlen = out - start;
+
+ *line = cp;
+ return (0);
+}
+
+static int
+magic_parse_offset(struct magic_line *ml, char **line)
+{
+ char *copy, *s, *cp, *endptr;
+
+ while (isspace((u_char)**line))
+ (*line)++;
+ copy = s = cp = xmalloc(strlen(*line) + 1);
+ while (**line != '\0' && !isspace((u_char)**line))
+ *cp++ = *(*line)++;
+ *cp = '\0';
+
+ ml->offset = 0;
+ ml->offset_relative = 0;
+
+ ml->indirect_type = ' ';
+ ml->indirect_relative = 0;
+ ml->indirect_offset = 0;
+ ml->indirect_operator = ' ';
+ ml->indirect_operand = 0;
+
+ if (*s == '&') {
+ ml->offset_relative = 1;
+ s++;
+ }
+
+ if (*s != '(') {
+ endptr = magic_strtoll(s, &ml->offset);
+ if (endptr == NULL || *endptr != '\0') {
+ magic_warn(ml, "missing closing bracket");
+ goto fail;
+ }
+ if (ml->offset < 0 && !ml->offset_relative) {
+ magic_warn(ml, "negative absolute offset");
+ goto fail;
+ }
+ goto done;
+ }
+ s++;
+
+ if (*s == '&') {
+ ml->indirect_relative = 1;
+ s++;
+ }
+
+ endptr = magic_strtoll(s, &ml->indirect_offset);
+ if (endptr == NULL) {
+ magic_warn(ml, "can't parse offset");
+ goto fail;
+ }
+ s = endptr;
+ if (*s == ')')
+ goto done;
+
+ if (*s == '.') {
+ s++;
+ if (strchr("bslBSL", *s) == NULL) {
+ magic_warn(ml, "unknown offset type");
+ goto fail;
+ }
+ ml->indirect_type = *s;
+ s++;
+ if (*s == ')')
+ goto done;
+ }
+
+ if (strchr("+-*", *s) == NULL) {
+ magic_warn(ml, "unknown offset operator");
+ goto fail;
+ }
+ ml->indirect_operator = *s;
+ s++;
+ if (*s == ')')
+ goto done;
+
+ if (*s == '(') {
+ s++;
+ endptr = magic_strtoll(s, &ml->indirect_operand);
+ if (endptr == NULL || *endptr != ')') {
+ magic_warn(ml, "missing closing bracket");
+ goto fail;
+ }
+ if (*++endptr != ')') {
+ magic_warn(ml, "missing closing bracket");
+ goto fail;
+ }
+ } else {
+ endptr = magic_strtoll(s, &ml->indirect_operand);
+ if (endptr == NULL || *endptr != ')') {
+ magic_warn(ml, "missing closing bracket");
+ goto fail;
+ }
+ }
+
+done:
+ free(copy);
+ return (0);
+
+fail:
+ free(copy);
+ return (-1);
+}
+
+static int
+magic_parse_type(struct magic_line *ml, char **line)
+{
+ char *copy, *s, *cp, *endptr;
+
+ while (isspace((u_char)**line))
+ (*line)++;
+ copy = s = cp = xmalloc(strlen(*line) + 1);
+ while (**line != '\0' && !isspace((u_char)**line))
+ *cp++ = *(*line)++;
+ *cp = '\0';
+
+ ml->type = MAGIC_TYPE_NONE;
+ ml->type_string = xstrdup(s);
+
+ ml->type_operator = ' ';
+ ml->type_operand = 0;
+
+ if (strncmp(s, "string", (sizeof "string") - 1) == 0) {
+ ml->type = MAGIC_TYPE_STRING;
+ magic_mark_text(ml, 0);
+ goto done;
+ }
+ if (strncmp(s, "search", (sizeof "search") - 1) == 0) {
+ ml->type = MAGIC_TYPE_SEARCH;
+ goto done;
+ }
+ if (strncmp(s, "regex", (sizeof "regex") - 1) == 0) {
+ ml->type = MAGIC_TYPE_REGEX;
+ goto done;
+ }
+
+ cp = &s[strcspn(s, "-&")];
+ if (*cp != '\0') {
+ ml->type_operator = *cp;
+ endptr = magic_strtoull(cp + 1, &ml->type_operand);
+ if (endptr == NULL || *endptr != '\0') {
+ magic_warn(ml, "can't parse operand");
+ goto fail;
+ }
+ *cp = '\0';
+ }
+
+ if (strcmp(s, "byte") == 0)
+ ml->type = MAGIC_TYPE_BYTE;
+ else if (strcmp(s, "short") == 0)
+ ml->type = MAGIC_TYPE_SHORT;
+ else if (strcmp(s, "long") == 0)
+ ml->type = MAGIC_TYPE_LONG;
+ else if (strcmp(s, "quad") == 0)
+ ml->type = MAGIC_TYPE_QUAD;
+ else if (strcmp(s, "ubyte") == 0)
+ ml->type = MAGIC_TYPE_UBYTE;
+ else if (strcmp(s, "ushort") == 0)
+ ml->type = MAGIC_TYPE_USHORT;
+ else if (strcmp(s, "ulong") == 0)
+ ml->type = MAGIC_TYPE_ULONG;
+ else if (strcmp(s, "uquad") == 0)
+ ml->type = MAGIC_TYPE_UQUAD;
+ else if (strcmp(s, "float") == 0)
+ ml->type = MAGIC_TYPE_FLOAT;
+ else if (strcmp(s, "double") == 0)
+ ml->type = MAGIC_TYPE_DOUBLE;
+ else if (strcmp(s, "pstring") == 0)
+ ml->type = MAGIC_TYPE_PSTRING;
+ else if (strcmp(s, "date") == 0)
+ ml->type = MAGIC_TYPE_DATE;
+ else if (strcmp(s, "qdate") == 0)
+ ml->type = MAGIC_TYPE_QDATE;
+ else if (strcmp(s, "ldate") == 0)
+ ml->type = MAGIC_TYPE_LDATE;
+ else if (strcmp(s, "qldate") == 0)
+ ml->type = MAGIC_TYPE_QLDATE;
+ else if (strcmp(s, "udate") == 0)
+ ml->type = MAGIC_TYPE_UDATE;
+ else if (strcmp(s, "uqdate") == 0)
+ ml->type = MAGIC_TYPE_UQDATE;
+ else if (strcmp(s, "uldate") == 0)
+ ml->type = MAGIC_TYPE_ULDATE;
+ else if (strcmp(s, "uqldate") == 0)
+ ml->type = MAGIC_TYPE_UQLDATE;
+ else if (strcmp(s, "beshort") == 0)
+ ml->type = MAGIC_TYPE_BESHORT;
+ else if (strcmp(s, "belong") == 0)
+ ml->type = MAGIC_TYPE_BELONG;
+ else if (strcmp(s, "bequad") == 0)
+ ml->type = MAGIC_TYPE_BEQUAD;
+ else if (strcmp(s, "ubeshort") == 0)
+ ml->type = MAGIC_TYPE_UBESHORT;
+ else if (strcmp(s, "ubelong") == 0)
+ ml->type = MAGIC_TYPE_UBELONG;
+ else if (strcmp(s, "ubequad") == 0)
+ ml->type = MAGIC_TYPE_UBEQUAD;
+ else if (strcmp(s, "befloat") == 0)
+ ml->type = MAGIC_TYPE_BEFLOAT;
+ else if (strcmp(s, "bedouble") == 0)
+ ml->type = MAGIC_TYPE_BEDOUBLE;
+ else if (strcmp(s, "bedate") == 0)
+ ml->type = MAGIC_TYPE_BEDATE;
+ else if (strcmp(s, "beqdate") == 0)
+ ml->type = MAGIC_TYPE_BEQDATE;
+ else if (strcmp(s, "beldate") == 0)
+ ml->type = MAGIC_TYPE_BELDATE;
+ else if (strcmp(s, "beqldate") == 0)
+ ml->type = MAGIC_TYPE_BEQLDATE;
+ else if (strcmp(s, "ubedate") == 0)
+ ml->type = MAGIC_TYPE_UBEDATE;
+ else if (strcmp(s, "ubeqdate") == 0)
+ ml->type = MAGIC_TYPE_UBEQDATE;
+ else if (strcmp(s, "ubeldate") == 0)
+ ml->type = MAGIC_TYPE_UBELDATE;
+ else if (strcmp(s, "ubeqldate") == 0)
+ ml->type = MAGIC_TYPE_UBEQLDATE;
+ else if (strcmp(s, "bestring16") == 0)
+ ml->type = MAGIC_TYPE_BESTRING16;
+ else if (strcmp(s, "leshort") == 0)
+ ml->type = MAGIC_TYPE_LESHORT;
+ else if (strcmp(s, "lelong") == 0)
+ ml->type = MAGIC_TYPE_LELONG;
+ else if (strcmp(s, "lequad") == 0)
+ ml->type = MAGIC_TYPE_LEQUAD;
+ else if (strcmp(s, "uleshort") == 0)
+ ml->type = MAGIC_TYPE_ULESHORT;
+ else if (strcmp(s, "ulelong") == 0)
+ ml->type = MAGIC_TYPE_ULELONG;
+ else if (strcmp(s, "ulequad") == 0)
+ ml->type = MAGIC_TYPE_ULEQUAD;
+ else if (strcmp(s, "lefloat") == 0)
+ ml->type = MAGIC_TYPE_LEFLOAT;
+ else if (strcmp(s, "ledouble") == 0)
+ ml->type = MAGIC_TYPE_LEDOUBLE;
+ else if (strcmp(s, "ledate") == 0)
+ ml->type = MAGIC_TYPE_LEDATE;
+ else if (strcmp(s, "leqdate") == 0)
+ ml->type = MAGIC_TYPE_LEQDATE;
+ else if (strcmp(s, "leldate") == 0)
+ ml->type = MAGIC_TYPE_LELDATE;
+ else if (strcmp(s, "leqldate") == 0)
+ ml->type = MAGIC_TYPE_LEQLDATE;
+ else if (strcmp(s, "uledate") == 0)
+ ml->type = MAGIC_TYPE_ULEDATE;
+ else if (strcmp(s, "uleqdate") == 0)
+ ml->type = MAGIC_TYPE_ULEQDATE;
+ else if (strcmp(s, "uleldate") == 0)
+ ml->type = MAGIC_TYPE_ULELDATE;
+ else if (strcmp(s, "uleqldate") == 0)
+ ml->type = MAGIC_TYPE_ULEQLDATE;
+ else if (strcmp(s, "lestring16") == 0)
+ ml->type = MAGIC_TYPE_LESTRING16;
+ else if (strcmp(s, "melong") == 0)
+ ml->type = MAGIC_TYPE_MELONG;
+ else if (strcmp(s, "medate") == 0)
+ ml->type = MAGIC_TYPE_MEDATE;
+ else if (strcmp(s, "meldate") == 0)
+ ml->type = MAGIC_TYPE_MELDATE;
+ else if (strcmp(s, "default") == 0)
+ ml->type = MAGIC_TYPE_DEFAULT;
+ else {
+ magic_warn(ml, "unknown type");
+ goto fail;
+ }
+ magic_mark_text(ml, 0);
+
+done:
+ free(copy);
+ return (0);
+
+fail:
+ free(copy);
+ return (-1);
+}
+
+static int
+magic_parse_value(struct magic_line *ml, char **line)
+{
+ char *copy, *s, *cp, *endptr;
+ size_t slen;
+
+ while (isspace((u_char)**line))
+ (*line)++;
+
+ ml->test_operator = '=';
+ ml->test_not = 0;
+ ml->test_string = NULL;
+ ml->test_string_size = 0;
+ ml->test_unsigned = 0;
+ ml->test_signed = 0;
+
+ s = *line;
+ if (s[0] == 'x' && (s[1] == '\0' || isspace((u_char)s[1]))) {
+ (*line)++;
+ ml->test_operator = 'x';
+ return (0);
+ }
+
+ if (**line == '!') {
+ ml->test_not = 1;
+ (*line)++;
+ }
+
+ switch (ml->type) {
+ case MAGIC_TYPE_STRING:
+ case MAGIC_TYPE_PSTRING:
+ case MAGIC_TYPE_SEARCH:
+ if (**line == '>' || **line == '<' || **line == '=') {
+ ml->test_operator = **line;
+ (*line)++;
+ }
+ /* FALLTHROUGH */
+ case MAGIC_TYPE_REGEX:
+ copy = s = xmalloc(strlen(*line) + 1);
+ if (magic_get_string(line, s, &slen) != 0) {
+ magic_warn(ml, "can't parse string");
+ goto fail;
+ }
+ ml->test_string_size = slen;
+ ml->test_string = s;
+ return (0); /* do not free */
+ default:
+ break;
+ }
+
+ copy = s = cp = xmalloc(strlen(*line) + 1);
+ if ((*line)[0] == '=' && (*line)[1] == ' ') {
+ /*
+ * Extra spaces such as "byte&7 = 0" are accepted, which is
+ * annoying. But it seems to be only for =, so special case it.
+ */
+ *cp++ = '=';
+ (*line) += 2;
+ }
+ while (**line != '\0' && !isspace((u_char)**line))
+ *cp++ = *(*line)++;
+ *cp = '\0';
+
+ if (*s == '\0')
+ goto done;
+
+ if (s[0] == '<' && s[1] == '=') {
+ ml->test_operator = '[';
+ s += 2;
+ } else if (s[0] == '>' && s[1] == '=') {
+ ml->test_operator = ']';
+ s += 2;
+ } else if (strchr("=<>&^", *s) != NULL) {
+ ml->test_operator = *s;
+ s++;
+ }
+
+ if (*ml->type_string == 'u')
+ endptr = magic_strtoull(s, &ml->test_unsigned);
+ else
+ endptr = magic_strtoll(s, &ml->test_signed);
+ if (endptr == NULL || *endptr != '\0') {
+ magic_warn(ml, "can't parse number");
+ goto fail;
+ }
+
+done:
+ free(copy);
+ return (0);
+
+fail:
+ free(copy);
+ return (-1);
+}
+
+static void
+magic_free_line(struct magic_line *ml)
+{
+ free((void*)ml->type_string);
+
+ free((void*)ml->mimetype);
+ free((void*)ml->result);
+
+ free(ml);
+}
+
+int
+magic_compare(struct magic_line *ml1, struct magic_line *ml2)
+{
+ if (ml1->strength < ml2->strength)
+ return (1);
+ if (ml1->strength > ml2->strength)
+ return (-1);
+
+ /*
+ * The original file depends on the (undefined!) qsort(3) behaviour
+ * when the strength is equal. This is impossible to reproduce with an
+ * RB tree so just use the line number and hope for the best.
+ */
+ if (ml1->line < ml2->line)
+ return (-1);
+ if (ml1->line > ml2->line)
+ return (1);
+
+ return (0);
+}
+RB_GENERATE(magic_tree, magic_line, node, magic_compare);
+
+static void
+magic_set_mimetype(struct magic *m, u_int at, struct magic_line *ml, char *line)
+{
+ char *mimetype, *cp;
+
+ mimetype = line + (sizeof "!:mime") - 1;
+ while (isspace((u_char)*mimetype))
+ mimetype++;
+
+ cp = strchr(mimetype, '#');
+ if (cp != NULL)
+ *cp = '\0';
+
+ if (*mimetype != '\0') {
+ cp = mimetype + strlen(mimetype) - 1;
+ while (cp != mimetype && isspace((u_char)*cp))
+ *cp-- = '\0';
+ }
+
+ cp = mimetype;
+ while (*cp != '\0') {
+ if (!isalnum((u_char)*cp) && strchr("/-.+", *cp) == NULL)
+ break;
+ cp++;
+ }
+ if (*mimetype == '\0' || *cp != '\0') {
+ fprintf(stderr, "%s:%u: invalid MIME type: %s\n", m->path, at,
+ mimetype);
+ return;
+ }
+ if (ml == NULL) {
+ fprintf(stderr, "%s:%u: stray MIME type: %s\n", m->path, at,
+ mimetype);
+ return;
+ }
+ ml->mimetype = xstrdup(mimetype);
+}
+
+struct magic *
+magic_load(FILE *f, const char *path, int warnings)
+{
+ struct magic *m;
+ struct magic_line *ml = NULL, *parent, *parent0;
+ char *line, *tmp;
+ size_t size;
+ u_int at, level, n, i;
+
+ m = xcalloc(1, sizeof *m);
+ m->path = xstrdup(path);
+ m->warnings = warnings;
+ RB_INIT(&m->tree);
+
+ parent = NULL;
+ parent0 = NULL;
+ level = 0;
+
+ at = 0;
+ tmp = NULL;
+ while ((line = fgetln(f, &size))) {
+ if (line[size - 1] == '\n')
+ line[size - 1] = '\0';
+ else {
+ tmp = xmalloc(size + 1);
+ memcpy(tmp, line, size);
+ tmp[size] = '\0';
+ line = tmp;
+ }
+ at++;
+
+ while (isspace((u_char)*line))
+ line++;
+ if (*line == '\0' || *line == '#')
+ continue;
+
+ if (strncmp (line, "!:mime", (sizeof "!:mime") - 1) == 0) {
+ magic_set_mimetype(m, at, ml, line);
+ continue;
+ }
+
+ n = 0;
+ for (; *line == '>'; line++)
+ n++;
+
+ ml = xcalloc(1, sizeof *ml);
+ ml->root = m;
+ ml->line = at;
+ ml->type = MAGIC_TYPE_NONE;
+ TAILQ_INIT(&ml->children);
+ ml->text = 1;
+
+ if (n == level + 1) {
+ parent = parent0;
+ } else if (n < level) {
+ for (i = n; i < level && parent != NULL; i++)
+ parent = parent->parent;
+ } else if (n != level) {
+ magic_warn(ml, "level skipped (%u->%u)", level, n);
+ free(ml);
+ continue;
+ }
+ ml->parent = parent;
+ level = n;
+
+ if (magic_parse_offset(ml, &line) != 0 ||
+ magic_parse_type(ml, &line) != 0 ||
+ magic_parse_value(ml, &line) != 0 ||
+ magic_set_result(ml, line) != 0) {
+ magic_free_line(ml);
+ ml = NULL;
+ continue;
+ }
+
+ ml->strength = magic_get_strength(ml);
+ if (ml->parent == NULL)
+ RB_INSERT(magic_tree, &m->tree, ml);
+ else
+ TAILQ_INSERT_TAIL(&ml->parent->children, ml, entry);
+ parent0 = ml;
+ }
+ free(tmp);
+
+ fclose(f);
+ return (m);
+}
--- /dev/null
+/* $OpenBSD: magic-test.c,v 1.1 2015/04/24 16:24:11 nicm Exp $ */
+
+/*
+ * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <vis.h>
+
+#include "magic.h"
+#include "xmalloc.h"
+
+static int
+magic_one_eq(char a, char b, int cflag)
+{
+ if (a == b)
+ return (1);
+ if (cflag && tolower((u_char)a) == tolower((u_char)b))
+ return (1);
+ return (0);
+}
+
+static int
+magic_test_eq(const char *ap, size_t asize, const char *bp, size_t bsize,
+ int cflag, int bflag, int Bflag)
+{
+ size_t aoff, boff, aspaces, bspaces;
+
+ aoff = boff = 0;
+ while (aoff != asize && boff != bsize) {
+ if (Bflag && isspace((u_char)ap[aoff])) {
+ aspaces = 0;
+ while (aoff != asize && isspace((u_char)ap[aoff])) {
+ aspaces++;
+ aoff++;
+ }
+ bspaces = 0;
+ while (boff != bsize && isspace((u_char)bp[boff])) {
+ bspaces++;
+ boff++;
+ }
+ if (bspaces >= aspaces)
+ continue;
+ return (1);
+ }
+ if (magic_one_eq(ap[aoff], bp[boff], cflag)) {
+ aoff++;
+ boff++;
+ continue;
+ }
+ if (bflag && isspace((u_char)bp[boff])) {
+ boff++;
+ continue;
+ }
+ if (ap[aoff] < bp[boff])
+ return (-1);
+ return (1);
+ }
+ return (0);
+}
+
+static int
+magic_copy_from(struct magic_state *ms, ssize_t offset, void *dst, size_t size)
+{
+ if (offset < 0)
+ offset = ms->offset;
+ if (offset + size > ms->size)
+ return (-1);
+ memcpy(dst, ms->base + offset, size);
+ return (0);
+}
+
+static void
+magic_add_result(struct magic_state *ms, struct magic_line *ml,
+ const char *fmt, ...)
+{
+ va_list ap;
+ int separate;
+ char *s, *tmp, *add;
+
+ va_start(ap, fmt);
+ if (ml->stringify) {
+ if (vasprintf(&s, fmt, ap) == -1) {
+ va_end(ap);
+ return;
+ }
+ va_end(ap);
+ if (asprintf(&tmp, ml->result, s) == -1) {
+ free(s);
+ return;
+ }
+ free(s);
+ } else {
+ if (vasprintf(&tmp, ml->result, ap) == -1) {
+ va_end(ap);
+ return;
+ }
+ va_end(ap);
+ }
+
+ separate = 1;
+ if (tmp[0] == '\\' && tmp[1] == 'b') {
+ separate = 0;
+ add = tmp + 2;
+ } else
+ add = tmp;
+
+ if (separate && *ms->out != '\0')
+ strlcat(ms->out, " ", sizeof ms->out);
+ strlcat(ms->out, add, sizeof ms->out);
+
+ free(tmp);
+}
+
+static void
+magic_add_string(struct magic_state *ms, struct magic_line *ml,
+ const char* s, size_t slen)
+{
+ char *out;
+ size_t outlen, offset;
+
+ outlen = MAGIC_STRING_SIZE;
+ if (outlen > slen)
+ outlen = slen;
+ for (offset = 0; offset < outlen; offset++) {
+ if (s[offset] == '\0' || !isprint((u_char)s[offset])) {
+ outlen = offset;
+ break;
+ }
+ }
+ out = xreallocarray(NULL, 4, outlen + 1);
+ strvisx(out, s, outlen, VIS_TAB|VIS_NL|VIS_CSTYLE|VIS_OCTAL);
+ magic_add_result(ms, ml, "%s", out);
+ free(out);
+}
+
+static int
+magic_test_signed(struct magic_line *ml, int64_t value, int64_t wanted)
+{
+ switch (ml->test_operator) {
+ case 'x':
+ return (1);
+ case '<':
+ return (value < wanted);
+ case '[':
+ return (value <= wanted);
+ case '>':
+ return (value > wanted);
+ case ']':
+ return (value >= wanted);
+ case '=':
+ return (value == wanted);
+ case '&':
+ return ((value & wanted) == wanted);
+ case '^':
+ return ((~value & wanted) == wanted);
+ }
+ return (-1);
+}
+
+static int
+magic_test_unsigned(struct magic_line *ml, uint64_t value, uint64_t wanted)
+{
+ switch (ml->test_operator) {
+ case 'x':
+ return (1);
+ case '<':
+ return (value < wanted);
+ case '[':
+ return (value <= wanted);
+ case '>':
+ return (value > wanted);
+ case ']':
+ return (value >= wanted);
+ case '=':
+ return (value == wanted);
+ case '&':
+ return ((value & wanted) == wanted);
+ case '^':
+ return ((~value & wanted) == wanted);
+ }
+ return (-1);
+}
+
+static int
+magic_test_type_none(__unused struct magic_line *ml,
+ __unused struct magic_state *ms)
+{
+ return (0);
+}
+
+static int
+magic_test_type_byte(struct magic_line *ml, struct magic_state *ms)
+{
+ int8_t value;
+ int result;
+
+ if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
+ return (0);
+
+ if (ml->type_operator == '&')
+ value &= (int8_t)ml->type_operand;
+ else if (ml->type_operator != ' ')
+ return (-1);
+
+ result = magic_test_signed(ml, value, (int8_t)ml->test_signed);
+ if (result == !ml->test_not && ml->result != NULL) {
+ magic_add_result(ms, ml, "%c", (int)value);
+ ms->offset += sizeof value;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_short(struct magic_line *ml, struct magic_state *ms)
+{
+ int16_t value;
+ int result;
+
+ if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
+ return (0);
+ if (ml->type == MAGIC_TYPE_BESHORT)
+ value = betoh16(value);
+ if (ml->type == MAGIC_TYPE_LESHORT)
+ value = letoh16(value);
+
+ if (ml->type_operator == '&')
+ value &= (int16_t)ml->type_operand;
+ else if (ml->type_operator != ' ')
+ return (-1);
+
+ result = magic_test_signed(ml, value, (int16_t)ml->test_signed);
+ if (result == !ml->test_not && ml->result != NULL) {
+ magic_add_result(ms, ml, "%hd", (int)value);
+ ms->offset += sizeof value;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_long(struct magic_line *ml, struct magic_state *ms)
+{
+ int32_t value;
+ int result;
+
+ if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
+ return (0);
+ if (ml->type == MAGIC_TYPE_BELONG)
+ value = betoh32(value);
+ if (ml->type == MAGIC_TYPE_LELONG)
+ value = letoh32(value);
+
+ if (ml->type_operator == '&')
+ value &= (int32_t)ml->type_operand;
+ else if (ml->type_operator != ' ')
+ return (-1);
+
+ result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
+ if (result == !ml->test_not && ml->result != NULL) {
+ magic_add_result(ms, ml, "%d", (int)value);
+ ms->offset += sizeof value;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_quad(struct magic_line *ml, struct magic_state *ms)
+{
+ int64_t value;
+ int result;
+
+ if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
+ return (0);
+ if (ml->type == MAGIC_TYPE_BEQUAD)
+ value = betoh64(value);
+ if (ml->type == MAGIC_TYPE_LEQUAD)
+ value = letoh64(value);
+
+ if (ml->type_operator == '&')
+ value &= (int64_t)ml->type_operand;
+ else if (ml->type_operator != ' ')
+ return (-1);
+
+ result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
+ if (result == !ml->test_not && ml->result != NULL) {
+ magic_add_result(ms, ml, "%lld", (long long)value);
+ ms->offset += sizeof value;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_ubyte(struct magic_line *ml, struct magic_state *ms)
+{
+ uint8_t value;
+ int result;
+
+ if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
+ return (0);
+
+ if (ml->type_operator == '&')
+ value &= (uint8_t)ml->type_operand;
+ else if (ml->type_operator != ' ')
+ return (-1);
+
+ result = magic_test_unsigned(ml, value, (uint8_t)ml->test_unsigned);
+ if (result == !ml->test_not && ml->result != NULL) {
+ magic_add_result(ms, ml, "%c", (unsigned int)value);
+ ms->offset += sizeof value;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_ushort(struct magic_line *ml, struct magic_state *ms)
+{
+ uint16_t value;
+ int result;
+
+ if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
+ return (0);
+ if (ml->type == MAGIC_TYPE_UBESHORT)
+ value = betoh16(value);
+ if (ml->type == MAGIC_TYPE_ULESHORT)
+ value = letoh16(value);
+
+ if (ml->type_operator == '&')
+ value &= (uint16_t)ml->type_operand;
+ else if (ml->type_operator != ' ')
+ return (-1);
+
+ result = magic_test_unsigned(ml, value, (uint16_t)ml->test_unsigned);
+ if (result == !ml->test_not && ml->result != NULL) {
+ magic_add_result(ms, ml, "%hu", (unsigned int)value);
+ ms->offset += sizeof value;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_ulong(struct magic_line *ml, struct magic_state *ms)
+{
+ uint32_t value;
+ int result;
+
+ if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
+ return (0);
+ if (ml->type == MAGIC_TYPE_UBELONG)
+ value = betoh32(value);
+ if (ml->type == MAGIC_TYPE_ULELONG)
+ value = letoh32(value);
+
+ if (ml->type_operator == '&')
+ value &= (uint32_t)ml->type_operand;
+ else if (ml->type_operator != ' ')
+ return (-1);
+
+ result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
+ if (result == !ml->test_not && ml->result != NULL) {
+ magic_add_result(ms, ml, "%u", (unsigned int)value);
+ ms->offset += sizeof value;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_uquad(struct magic_line *ml, struct magic_state *ms)
+{
+ uint64_t value;
+ int result;
+
+ if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
+ return (0);
+ if (ml->type == MAGIC_TYPE_UBEQUAD)
+ value = betoh64(value);
+ if (ml->type == MAGIC_TYPE_ULEQUAD)
+ value = letoh64(value);
+
+ if (ml->type_operator == '&')
+ value &= (uint64_t)ml->type_operand;
+ else if (ml->type_operator != ' ')
+ return (-1);
+
+ result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
+ if (result == !ml->test_not && ml->result != NULL) {
+ magic_add_result(ms, ml, "%llu", (unsigned long long)value);
+ ms->offset += sizeof value;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_float(struct magic_line *ml, struct magic_state *ms)
+{
+ uint32_t value0;
+ double value;
+
+ if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
+ return (0);
+ if (ml->type == MAGIC_TYPE_BEFLOAT)
+ value0 = betoh32(value0);
+ if (ml->type == MAGIC_TYPE_LEFLOAT)
+ value0 = letoh32(value0);
+ memcpy(&value, &value0, sizeof value);
+
+ if (ml->type_operator != ' ')
+ return (-1);
+
+ if (ml->test_operator != 'x')
+ return (-1);
+
+ magic_add_result(ms, ml, "%g", value);
+ ms->offset += sizeof value0;
+ return (1);
+}
+
+static int
+magic_test_type_double(struct magic_line *ml, struct magic_state *ms)
+{
+ uint64_t value0;
+ double value;
+
+ if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
+ return (0);
+ if (ml->type == MAGIC_TYPE_BEDOUBLE)
+ value0 = betoh64(value0);
+ if (ml->type == MAGIC_TYPE_LEDOUBLE)
+ value0 = letoh64(value0);
+ memcpy(&value, &value0, sizeof value);
+
+ if (ml->type_operator != ' ')
+ return (-1);
+
+ if (ml->test_operator != 'x')
+ return (-1);
+
+ magic_add_result(ms, ml, "%g", value);
+ ms->offset += sizeof value0;
+ return (1);
+}
+
+static int
+magic_test_type_string(struct magic_line *ml, struct magic_state *ms)
+{
+ const char *s, *cp;
+ size_t slen;
+ int result, cflag = 0, bflag = 0, Bflag = 0;
+
+ cp = &ml->type_string[(sizeof "string") - 1];
+ if (*cp != '\0') {
+ if (*cp != '/')
+ return (-1);
+ cp++;
+ for (; *cp != '\0'; cp++) {
+ switch (*cp) {
+ case 'B':
+ Bflag = 1;
+ break;
+ case 'b':
+ bflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ default:
+ return (-1);
+ }
+ }
+ }
+
+ s = ms->base + ms->offset;
+ slen = ms->size - ms->offset;
+ if (slen < ml->test_string_size)
+ return (0);
+
+ result = magic_test_eq(s, slen, ml->test_string, ml->test_string_size,
+ cflag, bflag, Bflag);
+ switch (ml->test_operator) {
+ case 'x':
+ result = 1;
+ break;
+ case '<':
+ result = result < 0;
+ break;
+ case '>':
+ result = result > 0;
+ break;
+ case '=':
+ result = result == 0;
+ break;
+ default:
+ result = -1;
+ break;
+ }
+ if (result == !ml->test_not) {
+ if (ml->result != NULL)
+ magic_add_string(ms, ml, s, slen);
+ if (result && ml->test_operator == '=')
+ ms->offset = s - ms->base + ml->test_string_size;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_pstring(struct magic_line *ml, struct magic_state *ms)
+{
+ const char *s;
+ size_t slen;
+ int result;
+
+ s = ms->base + ms->offset;
+ if (ms->size - ms->offset < 1)
+ return (-1);
+ slen = *(u_char *)s;
+ if (slen > ms->size - ms->offset)
+ return (-1);
+ s++;
+
+ if (slen < ml->test_string_size)
+ result = -1;
+ else if (slen > ml->test_string_size)
+ result = 1;
+ else
+ result = memcmp(s, ml->test_string, ml->test_string_size);
+ switch (ml->test_operator) {
+ case 'x':
+ result = 1;
+ break;
+ case '<':
+ result = result < 0;
+ break;
+ case '>':
+ result = result > 0;
+ break;
+ case '=':
+ result = result == 0;
+ break;
+ default:
+ result = -1;
+ break;
+ }
+ if (result == !ml->test_not) {
+ if (ml->result != NULL)
+ magic_add_string(ms, ml, s, slen);
+ if (result)
+ ms->offset += slen + 1;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_date(struct magic_line *ml, struct magic_state *ms)
+{
+ int32_t value;
+ int result;
+ time_t t;
+ char s[64];
+
+ if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
+ return (0);
+ if (ml->type == MAGIC_TYPE_BEDATE ||
+ ml->type == MAGIC_TYPE_BELDATE)
+ value = betoh32(value);
+ if (ml->type == MAGIC_TYPE_LEDATE ||
+ ml->type == MAGIC_TYPE_LELDATE)
+ value = letoh32(value);
+
+ if (ml->type_operator == '&')
+ value &= (int32_t)ml->type_operand;
+ else if (ml->type_operator != ' ')
+ return (-1);
+
+ result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
+ if (result == !ml->test_not && ml->result != NULL) {
+ t = value;
+ switch (ml->type) {
+ case MAGIC_TYPE_LDATE:
+ case MAGIC_TYPE_LELDATE:
+ case MAGIC_TYPE_BELDATE:
+ ctime_r(&t, s);
+ break;
+ default:
+ asctime_r(localtime(&t), s);
+ break;
+ }
+ s[strcspn(s, "\n")] = '\0';
+ magic_add_result(ms, ml, "%s", s);
+ ms->offset += sizeof value;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_qdate(struct magic_line *ml, struct magic_state *ms)
+{
+ int64_t value;
+ int result;
+ time_t t;
+ char s[64];
+
+ if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
+ return (0);
+ if (ml->type == MAGIC_TYPE_BEQDATE ||
+ ml->type == MAGIC_TYPE_BEQLDATE)
+ value = betoh64(value);
+ if (ml->type == MAGIC_TYPE_LEQDATE ||
+ ml->type == MAGIC_TYPE_LEQLDATE)
+ value = letoh64(value);
+
+ if (ml->type_operator == '&')
+ value &= (int64_t)ml->type_operand;
+ else if (ml->type_operator != ' ')
+ return (-1);
+
+ result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
+ if (result == !ml->test_not && ml->result != NULL) {
+ t = value;
+ switch (ml->type) {
+ case MAGIC_TYPE_QLDATE:
+ case MAGIC_TYPE_LEQLDATE:
+ case MAGIC_TYPE_BEQLDATE:
+ ctime_r(&t, s);
+ break;
+ default:
+ asctime_r(localtime(&t), s);
+ break;
+ }
+ s[strcspn(s, "\n")] = '\0';
+ magic_add_result(ms, ml, "%s", s);
+ ms->offset += sizeof value;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_udate(struct magic_line *ml, struct magic_state *ms)
+{
+ uint32_t value;
+ int result;
+ time_t t;
+ char s[64];
+
+ if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
+ return (0);
+ if (ml->type == MAGIC_TYPE_BEDATE ||
+ ml->type == MAGIC_TYPE_BELDATE)
+ value = betoh32(value);
+ if (ml->type == MAGIC_TYPE_LEDATE ||
+ ml->type == MAGIC_TYPE_LELDATE)
+ value = letoh32(value);
+
+ if (ml->type_operator == '&')
+ value &= (uint32_t)ml->type_operand;
+ else if (ml->type_operator != ' ')
+ return (-1);
+
+ result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
+ if (result == !ml->test_not && ml->result != NULL) {
+ t = value;
+ switch (ml->type) {
+ case MAGIC_TYPE_LDATE:
+ case MAGIC_TYPE_LELDATE:
+ case MAGIC_TYPE_BELDATE:
+ ctime_r(&t, s);
+ break;
+ default:
+ asctime_r(gmtime(&t), s);
+ break;
+ }
+ s[strcspn(s, "\n")] = '\0';
+ magic_add_result(ms, ml, "%s", s);
+ ms->offset += sizeof value;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_uqdate(struct magic_line *ml, struct magic_state *ms)
+{
+ uint64_t value;
+ int result;
+ time_t t;
+ char s[64];
+
+ if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
+ return (0);
+ if (ml->type == MAGIC_TYPE_UBEQDATE ||
+ ml->type == MAGIC_TYPE_UBEQLDATE)
+ value = betoh64(value);
+ if (ml->type == MAGIC_TYPE_ULEQDATE ||
+ ml->type == MAGIC_TYPE_ULEQLDATE)
+ value = letoh64(value);
+
+ if (ml->type_operator == '&')
+ value &= (uint64_t)ml->type_operand;
+ else if (ml->type_operator != ' ')
+ return (-1);
+
+ result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
+ if (result == !ml->test_not && ml->result != NULL) {
+ t = value;
+ switch (ml->type) {
+ case MAGIC_TYPE_UQLDATE:
+ case MAGIC_TYPE_ULEQLDATE:
+ case MAGIC_TYPE_UBEQLDATE:
+ ctime_r(&t, s);
+ break;
+ default:
+ asctime_r(gmtime(&t), s);
+ break;
+ }
+ s[strcspn(s, "\n")] = '\0';
+ magic_add_result(ms, ml, "%s", s);
+ ms->offset += sizeof value;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_bestring16(__unused struct magic_line *ml,
+ __unused struct magic_state *ms)
+{
+ return (-2);
+}
+
+static int
+magic_test_type_lestring16(__unused struct magic_line *ml,
+ __unused struct magic_state *ms)
+{
+ return (-2);
+}
+
+static int
+magic_test_type_melong(__unused struct magic_line *ml,
+ __unused struct magic_state *ms)
+{
+ return (-2);
+}
+
+static int
+magic_test_type_medate(__unused struct magic_line *ml,
+ __unused struct magic_state *ms)
+{
+ return (-2);
+}
+
+static int
+magic_test_type_meldate(__unused struct magic_line *ml,
+ __unused struct magic_state *ms)
+{
+ return (-2);
+}
+
+static int
+magic_test_type_regex(struct magic_line *ml, struct magic_state *ms)
+{
+ const char *cp;
+ regex_t re;
+ regmatch_t m;
+ int result, flags = 0, sflag = 0;
+
+ cp = &ml->type_string[(sizeof "regex") - 1];
+ if (*cp != '\0') {
+ if (*cp != '/')
+ return (-1);
+ cp++;
+ for (; *cp != '\0'; cp++) {
+ switch (*cp) {
+ case 's':
+ sflag = 1;
+ break;
+ case 'c':
+ flags |= REG_ICASE;
+ break;
+ default:
+ return (-1);
+ }
+ }
+ }
+
+ if (regcomp(&re, ml->test_string, REG_EXTENDED) != 0)
+ return (-1);
+ m.rm_so = ms->offset;
+ m.rm_eo = ms->size;
+
+ result = (regexec(&re, ms->base, 1, &m, REG_STARTEND) == 0);
+ if (result == !ml->test_not && ml->result != NULL) {
+ magic_add_result(ms, ml, "%s", "");
+ if (result) {
+ if (sflag)
+ ms->offset = m.rm_so;
+ else
+ ms->offset = m.rm_eo;
+ }
+ }
+ regfree(&re);
+ return (result);
+}
+
+static int
+magic_test_type_search(struct magic_line *ml, struct magic_state *ms)
+{
+ const char *cp, *endptr, *start, *found;
+ size_t size, end, i;
+ uint64_t range;
+ int result, n, cflag = 0, bflag = 0, Bflag = 0;
+
+ cp = &ml->type_string[(sizeof "search") - 1];
+ if (*cp != '\0') {
+ if (*cp != '/')
+ return (-1);
+ cp++;
+
+ endptr = magic_strtoull(cp, &range);
+ if (endptr == NULL || (*endptr != '/' && *endptr != '\0'))
+ return (-1);
+
+ if (*endptr == '/') {
+ for (cp = endptr + 1; *cp != '\0'; cp++) {
+ switch (*cp) {
+ case 'B':
+ Bflag = 1;
+ break;
+ case 'b':
+ bflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ default:
+ return (-1);
+ }
+ }
+ }
+ } else
+ range = UINT64_MAX;
+ if (range > (uint64_t)ms->size - ms->offset)
+ range = ms->size - ms->offset;
+ size = ml->test_string_size;
+
+ /* Want to search every starting position from up to range + size. */
+ end = range + size;
+ if (end > ms->size - ms->offset) {
+ if (size > ms->size - ms->offset)
+ end = 0;
+ else
+ end = ms->size - ms->offset - size;
+ }
+
+ /*
+ * < and > and the flags are only in /etc/magic with search/1 so don't
+ * support them with anything else.
+ */
+ start = ms->base + ms->offset;
+ if (end == 0)
+ found = NULL;
+ else if (ml->test_operator == 'x')
+ found = start;
+ else if (range == 1) {
+ n = magic_test_eq(start, ms->size - ms->offset, ml->test_string,
+ size, cflag, bflag, Bflag);
+ if (n == -1 && ml->test_operator == '<')
+ found = start;
+ else if (n == 1 && ml->test_operator == '>')
+ found = start;
+ else if (n == 0 && ml->test_operator == '=')
+ found = start;
+ else
+ found = NULL;
+ } else {
+ if (ml->test_operator != '=')
+ return (-2);
+ for (i = 0; i < end; i++) {
+ n = magic_test_eq(start + i, ms->size - ms->offset - i,
+ ml->test_string, size, cflag, bflag, Bflag);
+ if (n == 0) {
+ found = start + i;
+ break;
+ }
+ }
+ if (i == end)
+ found = NULL;
+ }
+ result = (found != NULL);
+
+ if (result == !ml->test_not && ml->result != NULL && found != NULL) {
+ magic_add_string(ms, ml, found, ms->size - ms->offset);
+ ms->offset = found - start + size;
+ }
+ return (result);
+}
+
+static int
+magic_test_type_default(__unused struct magic_line *ml,
+ __unused struct magic_state *ms)
+{
+ return (1);
+}
+
+static int (*magic_test_functions[])(struct magic_line *,
+ struct magic_state *) = {
+ magic_test_type_none,
+ magic_test_type_byte,
+ magic_test_type_short,
+ magic_test_type_long,
+ magic_test_type_quad,
+ magic_test_type_ubyte,
+ magic_test_type_ushort,
+ magic_test_type_ulong,
+ magic_test_type_uquad,
+ magic_test_type_float,
+ magic_test_type_double,
+ magic_test_type_string,
+ magic_test_type_pstring,
+ magic_test_type_date,
+ magic_test_type_qdate,
+ magic_test_type_date,
+ magic_test_type_qdate,
+ magic_test_type_udate,
+ magic_test_type_uqdate,
+ magic_test_type_udate,
+ magic_test_type_qdate,
+ magic_test_type_short,
+ magic_test_type_long,
+ magic_test_type_quad,
+ magic_test_type_ushort,
+ magic_test_type_ulong,
+ magic_test_type_uquad,
+ magic_test_type_float,
+ magic_test_type_double,
+ magic_test_type_date,
+ magic_test_type_qdate,
+ magic_test_type_date,
+ magic_test_type_qdate,
+ magic_test_type_udate,
+ magic_test_type_uqdate,
+ magic_test_type_udate,
+ magic_test_type_uqdate,
+ magic_test_type_bestring16,
+ magic_test_type_short,
+ magic_test_type_long,
+ magic_test_type_quad,
+ magic_test_type_ushort,
+ magic_test_type_ulong,
+ magic_test_type_uquad,
+ magic_test_type_float,
+ magic_test_type_double,
+ magic_test_type_date,
+ magic_test_type_qdate,
+ magic_test_type_date,
+ magic_test_type_qdate,
+ magic_test_type_udate,
+ magic_test_type_uqdate,
+ magic_test_type_udate,
+ magic_test_type_uqdate,
+ magic_test_type_lestring16,
+ magic_test_type_melong,
+ magic_test_type_medate,
+ magic_test_type_meldate,
+ magic_test_type_regex,
+ magic_test_type_search,
+ magic_test_type_default,
+};
+
+static int
+magic_test_line(struct magic_line *ml, struct magic_state *ms)
+{
+ struct magic_line *child;
+ int64_t offset, wanted, next;
+ int result;
+ uint8_t b;
+ uint16_t s;
+ uint32_t l;
+
+ if (ml->indirect_type == ' ')
+ wanted = ml->offset;
+ else {
+ wanted = ml->indirect_offset;
+ if (ml->indirect_relative) {
+ if (wanted < 0 && -wanted > ms->offset)
+ return (0);
+ if (wanted > 0 && ms->offset + wanted > ms->size)
+ return (0);
+ next = ms->offset + ml->indirect_offset;
+ } else
+ next = wanted;
+
+ switch (ml->indirect_type) {
+ case 'b':
+ case 'B':
+ if (magic_copy_from(ms, next, &b, sizeof b) != 0)
+ return (0);
+ wanted = b;
+ break;
+ case 's':
+ if (magic_copy_from(ms, next, &s, sizeof s) != 0)
+ return (0);
+ wanted = letoh16(s);
+ break;
+ case 'S':
+ if (magic_copy_from(ms, next, &s, sizeof s) != 0)
+ return (0);
+ wanted = betoh16(s);
+ break;
+ case 'l':
+ if (magic_copy_from(ms, next, &l, sizeof l) != 0)
+ return (0);
+ wanted = letoh16(l);
+ break;
+ case 'L':
+ if (magic_copy_from(ms, next, &l, sizeof l) != 0)
+ return (0);
+ wanted = betoh16(l);
+ break;
+ }
+
+ switch (ml->indirect_operator) {
+ case '+':
+ wanted += ml->indirect_operand;
+ break;
+ case '-':
+ wanted -= ml->indirect_operand;
+ break;
+ case '*':
+ wanted *= ml->indirect_operand;
+ break;
+ }
+ }
+
+ if (ml->offset_relative) {
+ if (wanted < 0 && -wanted > ms->offset)
+ return (0);
+ if (wanted > 0 && ms->offset + wanted > ms->size)
+ return (0);
+ offset = ms->offset + wanted;
+ } else
+ offset = wanted;
+ if (offset < 0 || offset > ms->size)
+ return (0);
+ ms->offset = offset;
+
+ result = magic_test_functions[ml->type](ml, ms);
+ if (result == -1) {
+ magic_warn(ml, "test %s/%c failed", ml->type_string,
+ ml->test_operator);
+ return (0);
+ }
+ if (result == -2) {
+ magic_warn(ml, "test %s/%c not implemented", ml->type_string,
+ ml->test_operator);
+ return (0);
+ }
+ if (result == ml->test_not)
+ return (0);
+ if (ml->mimetype != NULL)
+ ms->mimetype = ml->mimetype;
+
+ magic_warn(ml, "test %s/%c matched at offset %llu: '%s'",
+ ml->type_string, ml->test_operator, ms->offset,
+ ml->result == NULL ? "" : ml->result);
+
+ offset = ms->offset;
+ TAILQ_FOREACH(child, &ml->children, entry) {
+ ms->offset = offset;
+ magic_test_line(child, ms);
+ }
+ return (1);
+}
+
+const char *
+magic_test(struct magic *m, const void *base, size_t size, int flags)
+{
+ struct magic_line *ml;
+ static struct magic_state ms;
+
+ memset(&ms, 0, sizeof ms);
+
+ ms.base = base;
+ ms.size = size;
+
+ ms.text = !!(flags & MAGIC_TEST_TEXT);
+
+ RB_FOREACH(ml, magic_tree, &m->tree) {
+ ms.offset = 0;
+ if (ml->text == ms.text && magic_test_line(ml, &ms))
+ break;
+ }
+
+ if (*ms.out != '\0') {
+ if (flags & MAGIC_TEST_MIME) {
+ if (ms.mimetype)
+ return (xstrdup(ms.mimetype));
+ return (NULL);
+ }
+ return (xstrdup(ms.out));
+ }
+ return (NULL);
+}
+++ /dev/null
-/* $OpenBSD: magic.c,v 1.10 2015/01/16 08:24:04 doug Exp $ */
-/*
- * Copyright (c) Christos Zoulas 2003.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "file.h"
-#include "magic.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#ifdef QUICK
-#include <sys/mman.h>
-#endif
-#include <limits.h> /* for PIPE_BUF */
-
-#if defined(HAVE_UTIMES)
-# include <sys/time.h>
-#elif defined(HAVE_UTIME)
-# if defined(HAVE_SYS_UTIME_H)
-# include <sys/utime.h>
-# elif defined(HAVE_UTIME_H)
-# include <utime.h>
-# endif
-#endif
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for read() */
-#endif
-
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#endif
-
-#include <netinet/in.h> /* for byte swapping */
-
-#include "patchlevel.h"
-
-#ifndef PIPE_BUF
-/* Get the PIPE_BUF from pathconf */
-#ifdef _PC_PIPE_BUF
-#define PIPE_BUF pathconf(".", _PC_PIPE_BUF)
-#else
-#define PIPE_BUF 512
-#endif
-#endif
-
-#ifdef __EMX__
-private char *apptypeName = NULL;
-protected int file_os2_apptype(struct magic_set *ms, const char *fn,
- const void *buf, size_t nb);
-#endif /* __EMX__ */
-
-private void free_mlist(struct mlist *);
-private void close_and_restore(const struct magic_set *, const char *, int,
- const struct stat *);
-private int info_from_stat(struct magic_set *, mode_t);
-#ifndef COMPILE_ONLY
-private const char *file_or_fd(struct magic_set *, const char *, int);
-#endif
-
-#ifndef STDIN_FILENO
-#define STDIN_FILENO 0
-#endif
-
-public struct magic_set *
-magic_open(int flags)
-{
- struct magic_set *ms;
-
- if ((ms = calloc((size_t)1, sizeof(struct magic_set))) == NULL)
- return NULL;
-
- if (magic_setflags(ms, flags) == -1) {
- errno = EINVAL;
- goto free;
- }
-
- ms->o.buf = ms->o.pbuf = NULL;
-
- ms->c.len = 10;
- ms->c.li = reallocarray(NULL, ms->c.len, sizeof(*ms->c.li));
- if (ms->c.li == NULL)
- goto free;
-
- ms->haderr = 0;
- ms->error = -1;
- ms->mlist = NULL;
- ms->file = "unknown";
- ms->line = 0;
- return ms;
-free:
- free(ms);
- return NULL;
-}
-
-private void
-free_mlist(struct mlist *mlist)
-{
- struct mlist *ml;
-
- if (mlist == NULL)
- return;
-
- for (ml = mlist->next; ml != mlist;) {
- struct mlist *next = ml->next;
- struct magic *mg = ml->magic;
- file_delmagic(mg, ml->mapped, ml->nmagic);
- free(ml);
- ml = next;
- }
- free(ml);
-}
-
-private int
-info_from_stat(struct magic_set *ms, mode_t md)
-{
- /* We cannot open it, but we were able to stat it. */
- if (md & 0222)
- if (file_printf(ms, "writable, ") == -1)
- return -1;
- if (md & 0111)
- if (file_printf(ms, "executable, ") == -1)
- return -1;
- if (S_ISREG(md))
- if (file_printf(ms, "regular file, ") == -1)
- return -1;
- if (file_printf(ms, "no read permission") == -1)
- return -1;
- return 0;
-}
-
-public void
-magic_close(struct magic_set *ms)
-{
- free_mlist(ms->mlist);
- free(ms->o.pbuf);
- free(ms->o.buf);
- free(ms->c.li);
- free(ms);
-}
-
-/*
- * load a magic file
- */
-public int
-magic_load(struct magic_set *ms, const char *magicfile)
-{
- struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD);
- if (ml) {
- free_mlist(ms->mlist);
- ms->mlist = ml;
- return 0;
- }
- return -1;
-}
-
-public int
-magic_compile(struct magic_set *ms, const char *magicfile)
-{
- struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE);
- free_mlist(ml);
- return ml ? 0 : -1;
-}
-
-public int
-magic_check(struct magic_set *ms, const char *magicfile)
-{
- struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK);
- free_mlist(ml);
- return ml ? 0 : -1;
-}
-
-private void
-close_and_restore(const struct magic_set *ms, const char *name, int fd,
- const struct stat *sb)
-{
- if (fd == STDIN_FILENO)
- return;
- (void) close(fd);
-
- if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
- /*
- * Try to restore access, modification times if read it.
- * This is really *bad* because it will modify the status
- * time of the file... And of course this will affect
- * backup programs
- */
-#ifdef HAVE_UTIMES
- struct timeval utsbuf[2];
- (void)memset(utsbuf, 0, sizeof(utsbuf));
- utsbuf[0].tv_sec = sb->st_atime;
- utsbuf[1].tv_sec = sb->st_mtime;
-
- (void) utimes(name, utsbuf); /* don't care if loses */
-#elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
- struct utimbuf utbuf;
-
- (void)memset(utbuf, 0, sizeof(utbuf));
- utbuf.actime = sb->st_atime;
- utbuf.modtime = sb->st_mtime;
- (void) utime(name, &utbuf); /* don't care if loses */
-#endif
- }
-}
-
-#ifndef COMPILE_ONLY
-
-/*
- * find type of descriptor
- */
-public const char *
-magic_descriptor(struct magic_set *ms, int fd)
-{
- return file_or_fd(ms, NULL, fd);
-}
-
-/*
- * find type of named file
- */
-public const char *
-magic_file(struct magic_set *ms, const char *inname)
-{
- return file_or_fd(ms, inname, STDIN_FILENO);
-}
-
-private const char *
-file_or_fd(struct magic_set *ms, const char *inname, int fd)
-{
- int rv = -1;
- unsigned char *buf;
- struct stat sb;
- ssize_t nbytes = 0; /* number of bytes read from a datafile */
- int ispipe = 0;
-
- /*
- * one extra for terminating '\0', and
- * some overlapping space for matches near EOF
- */
-#define SLOP (1 + sizeof(union VALUETYPE))
- if ((buf = malloc(HOWMANY + SLOP)) == NULL)
- return NULL;
-
- if (file_reset(ms) == -1)
- goto done;
-
- switch (file_fsmagic(ms, inname, &sb)) {
- case -1: /* error */
- goto done;
- case 0: /* nothing found */
- break;
- default: /* matched it and printed type */
- rv = 0;
- goto done;
- }
-
- if (inname == NULL) {
- if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode))
- ispipe = 1;
- } else {
- int flags = O_RDONLY|O_BINARY;
-
- if (stat(inname, &sb) == 0 && S_ISFIFO(sb.st_mode)) {
- flags |= O_NONBLOCK;
- ispipe = 1;
- }
-
- errno = 0;
- if ((fd = open(inname, flags)) < 0) {
-#ifdef __CYGWIN__
- /* FIXME: Do this with EXEEXT from autotools */
- char *tmp = alloca(strlen(inname) + 5);
- (void)strcat(strcpy(tmp, inname), ".exe");
- if ((fd = open(tmp, flags)) < 0) {
-#endif
- fprintf(stderr, "couldn't open file\n");
- if (info_from_stat(ms, sb.st_mode) == -1)
- goto done;
- rv = 0;
- goto done;
-#ifdef __CYGWIN__
- }
-#endif
- }
-#ifdef O_NONBLOCK
- if ((flags = fcntl(fd, F_GETFL)) != -1) {
- flags &= ~O_NONBLOCK;
- (void)fcntl(fd, F_SETFL, flags);
- }
-#endif
- }
-
- /*
- * try looking at the first HOWMANY bytes
- */
- if (ispipe) {
- ssize_t r = 0;
-
- while ((r = sread(fd, (void *)&buf[nbytes],
- (size_t)(HOWMANY - nbytes), 1)) > 0) {
- nbytes += r;
- if (r < PIPE_BUF) break;
- }
-
- if (nbytes == 0) {
- /* We can not read it, but we were able to stat it. */
- if (info_from_stat(ms, sb.st_mode) == -1)
- goto done;
- rv = 0;
- goto done;
- }
-
- } else {
- if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
- file_error(ms, errno, "cannot read `%s'", inname);
- goto done;
- }
- }
-
- (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
- if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1)
- goto done;
- rv = 0;
-done:
- free(buf);
- close_and_restore(ms, inname, fd, &sb);
- return rv == 0 ? file_getbuffer(ms) : NULL;
-}
-
-
-public const char *
-magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
-{
- if (file_reset(ms) == -1)
- return NULL;
- /*
- * The main work is done here!
- * We have the file name and/or the data buffer to be identified.
- */
- if (file_buffer(ms, -1, NULL, buf, nb) == -1) {
- return NULL;
- }
- return file_getbuffer(ms);
-}
-#endif
-
-public const char *
-magic_error(struct magic_set *ms)
-{
- return ms->haderr ? ms->o.buf : NULL;
-}
-
-public int
-magic_errno(struct magic_set *ms)
-{
- return ms->haderr ? ms->error : 0;
-}
-
-public int
-magic_setflags(struct magic_set *ms, int flags)
-{
-#if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
- if (flags & MAGIC_PRESERVE_ATIME)
- return -1;
-#endif
- ms->flags = flags;
- return 0;
-}
-/* $OpenBSD: magic.h,v 1.4 2009/04/24 18:54:34 chl Exp $ */
+/* $OpenBSD: magic.h,v 1.5 2015/04/24 16:24:11 nicm Exp $ */
+
/*
- * Copyright (c) Christos Zoulas 2003.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef _MAGIC_H
-#define _MAGIC_H
-
-#include <sys/types.h>
-
-#define MAGIC_NONE 0x000000 /* No flags */
-#define MAGIC_DEBUG 0x000001 /* Turn on debugging */
-#define MAGIC_SYMLINK 0x000002 /* Follow symlinks */
-#define MAGIC_COMPRESS 0x000004 /* Check inside compressed files */
-#define MAGIC_DEVICES 0x000008 /* Look at the contents of devices */
-#define MAGIC_MIME_TYPE 0x000010 /* Return only the MIME type */
-#define MAGIC_CONTINUE 0x000020 /* Return all matches */
-#define MAGIC_CHECK 0x000040 /* Print warnings to stderr */
-#define MAGIC_PRESERVE_ATIME 0x000080 /* Restore access time on exit */
-#define MAGIC_RAW 0x000100 /* Don't translate unprint chars */
-#define MAGIC_ERROR 0x000200 /* Handle ENOENT etc as real errors */
-#define MAGIC_MIME_ENCODING 0x000400 /* Return only the MIME encoding */
-#define MAGIC_MIME (MAGIC_MIME_TYPE|MAGIC_MIME_ENCODING)
-#define MAGIC_NO_CHECK_COMPRESS 0x001000 /* Don't check for compressed files */
-#define MAGIC_NO_CHECK_TAR 0x002000 /* Don't check for tar files */
-#define MAGIC_NO_CHECK_SOFT 0x004000 /* Don't check magic entries */
-#define MAGIC_NO_CHECK_APPTYPE 0x008000 /* Don't check application type */
-#define MAGIC_NO_CHECK_ELF 0x010000 /* Don't check for elf details */
-#define MAGIC_NO_CHECK_ASCII 0x020000 /* Don't check for ascii files */
-#define MAGIC_NO_CHECK_TOKENS 0x100000 /* Don't check ascii/tokens */
-
-/* Defined for backwards compatibility; do nothing */
-#define MAGIC_NO_CHECK_FORTRAN 0x000000 /* Don't check ascii/fortran */
-#define MAGIC_NO_CHECK_TROFF 0x000000 /* Don't check ascii/troff */
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct magic_set *magic_t;
-magic_t magic_open(int);
-void magic_close(magic_t);
-
-const char *magic_file(magic_t, const char *);
-const char *magic_descriptor(magic_t, int);
-const char *magic_buffer(magic_t, const void *, size_t);
-
-const char *magic_error(magic_t);
-int magic_setflags(magic_t, int);
-
-int magic_load(magic_t, const char *);
-int magic_compile(magic_t, const char *);
-int magic_check(magic_t, const char *);
-int magic_errno(magic_t);
-
-#ifdef __cplusplus
+
+#ifndef MAGIC_H
+#define MAGIC_H
+
+#include <sys/param.h>
+#include <sys/tree.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAGIC_STRING_SIZE 31
+#define MAGIC_STRENGTH_MULTIPLIER 20
+
+enum magic_type {
+ MAGIC_TYPE_NONE = 0,
+ MAGIC_TYPE_BYTE,
+ MAGIC_TYPE_SHORT,
+ MAGIC_TYPE_LONG,
+ MAGIC_TYPE_QUAD,
+ MAGIC_TYPE_UBYTE,
+ MAGIC_TYPE_USHORT,
+ MAGIC_TYPE_ULONG,
+ MAGIC_TYPE_UQUAD,
+ MAGIC_TYPE_FLOAT,
+ MAGIC_TYPE_DOUBLE,
+ MAGIC_TYPE_STRING,
+ MAGIC_TYPE_PSTRING,
+ MAGIC_TYPE_DATE,
+ MAGIC_TYPE_QDATE,
+ MAGIC_TYPE_LDATE,
+ MAGIC_TYPE_QLDATE,
+ MAGIC_TYPE_UDATE,
+ MAGIC_TYPE_UQDATE,
+ MAGIC_TYPE_ULDATE,
+ MAGIC_TYPE_UQLDATE,
+ MAGIC_TYPE_BESHORT,
+ MAGIC_TYPE_BELONG,
+ MAGIC_TYPE_BEQUAD,
+ MAGIC_TYPE_UBESHORT,
+ MAGIC_TYPE_UBELONG,
+ MAGIC_TYPE_UBEQUAD,
+ MAGIC_TYPE_BEFLOAT,
+ MAGIC_TYPE_BEDOUBLE,
+ MAGIC_TYPE_BEDATE,
+ MAGIC_TYPE_BEQDATE,
+ MAGIC_TYPE_BELDATE,
+ MAGIC_TYPE_BEQLDATE,
+ MAGIC_TYPE_UBEDATE,
+ MAGIC_TYPE_UBEQDATE,
+ MAGIC_TYPE_UBELDATE,
+ MAGIC_TYPE_UBEQLDATE,
+ MAGIC_TYPE_BESTRING16,
+ MAGIC_TYPE_LESHORT,
+ MAGIC_TYPE_LELONG,
+ MAGIC_TYPE_LEQUAD,
+ MAGIC_TYPE_ULESHORT,
+ MAGIC_TYPE_ULELONG,
+ MAGIC_TYPE_ULEQUAD,
+ MAGIC_TYPE_LEFLOAT,
+ MAGIC_TYPE_LEDOUBLE,
+ MAGIC_TYPE_LEDATE,
+ MAGIC_TYPE_LEQDATE,
+ MAGIC_TYPE_LELDATE,
+ MAGIC_TYPE_LEQLDATE,
+ MAGIC_TYPE_ULEDATE,
+ MAGIC_TYPE_ULEQDATE,
+ MAGIC_TYPE_ULELDATE,
+ MAGIC_TYPE_ULEQLDATE,
+ MAGIC_TYPE_LESTRING16,
+ MAGIC_TYPE_MELONG,
+ MAGIC_TYPE_MEDATE,
+ MAGIC_TYPE_MELDATE,
+ MAGIC_TYPE_REGEX,
+ MAGIC_TYPE_SEARCH,
+ MAGIC_TYPE_DEFAULT,
};
-#endif
-#endif /* _MAGIC_H */
+TAILQ_HEAD(magic_lines, magic_line);
+RB_HEAD(magic_tree, magic_line);
+
+struct magic_line {
+ struct magic *root;
+ u_int line;
+ u_int strength;
+ struct magic_line *parent;
+
+ int text;
+
+ int64_t offset;
+ int offset_relative;
+
+ char indirect_type;
+ int indirect_relative;
+ int64_t indirect_offset;
+ char indirect_operator;
+ int64_t indirect_operand;
+
+ enum magic_type type;
+ const char *type_string;
+ char type_operator;
+ int64_t type_operand;
+
+ char test_operator;
+ int test_not;
+ const char *test_string;
+ size_t test_string_size;
+ uint64_t test_unsigned;
+ int64_t test_signed;
+
+ int stringify;
+ const char *result;
+ const char *mimetype;
+
+ struct magic_lines children;
+ TAILQ_ENTRY(magic_line) entry;
+ RB_ENTRY(magic_line) node;
+};
+
+struct magic {
+ const char *path;
+ int warnings;
+
+ struct magic_tree tree;
+
+ int compiled;
+ regex_t format_short;
+ regex_t format_long;
+ regex_t format_quad;
+ regex_t format_float;
+ regex_t format_string;
+};
+
+struct magic_state {
+ char out[4096];
+ const char *mimetype;
+ int text;
+
+ const char *base;
+ size_t size;
+ int64_t offset;
+};
+
+#define MAGIC_TEST_TEXT 0x1
+#define MAGIC_TEST_MIME 0x2
+
+int magic_compare(struct magic_line *, struct magic_line *);
+RB_PROTOTYPE(magic_tree, magic_line, node, magic_compare);
+
+char *magic_strtoull(const char *, uint64_t *);
+char *magic_strtoll(const char *, int64_t *);
+void magic_warn(struct magic_line *, const char *, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+void magic_dump(struct magic *);
+struct magic *magic_load(FILE *, const char *, int);
+const char *magic_test(struct magic *, const void *, size_t, int);
+
+#endif /* MAGIC_H */
+++ /dev/null
-/* $OpenBSD: names.h,v 1.8 2009/04/24 18:54:34 chl Exp $ */
-/*
- * Copyright (c) Ian F. Darwin 1986-1995.
- * Software written by Ian F. Darwin and others;
- * maintained 1995-present by Christos Zoulas and others.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-/*
- * Names.h - names and types used by ascmagic in file(1).
- * These tokens are here because they can appear anywhere in
- * the first HOWMANY bytes, while tokens in MAGIC must
- * appear at fixed offsets into the file. Don't make HOWMANY
- * too high unless you have a very fast CPU.
- *
- * $Id: names.h,v 1.8 2009/04/24 18:54:34 chl Exp $
- */
-
-/*
- modified by Chris Lowth - 9 April 2000
- to add mime type strings to the types table.
-*/
-
-/* these types are used to index the table 'types': keep em in sync! */
-#define L_C 0 /* first and foremost on UNIX */
-#define L_CC 1 /* Bjarne's postincrement */
-#define L_MAKE 2 /* Makefiles */
-#define L_PLI 3 /* PL/1 */
-#define L_MACH 4 /* some kinda assembler */
-#define L_ENG 5 /* English */
-#define L_PAS 6 /* Pascal */
-#define L_MAIL 7 /* Electronic mail */
-#define L_NEWS 8 /* Usenet Netnews */
-#define L_JAVA 9 /* Java code */
-#define L_HTML 10 /* HTML */
-#define L_BCPL 11 /* BCPL */
-#define L_M4 12 /* M4 */
-#define L_PO 13 /* PO */
-
-static const struct {
- char human[48];
- char mime[16];
-} types[] = {
- { "C program", "text/x-c", },
- { "C++ program", "text/x-c++" },
- { "make commands", "text/x-makefile" },
- { "PL/1 program", "text/x-pl1" },
- { "assembler program", "text/x-asm" },
- { "English", "text/plain" },
- { "Pascal program", "text/x-pascal" },
- { "mail", "text/x-mail" },
- { "news", "text/x-news" },
- { "Java program", "text/x-java" },
- { "HTML document", "text/html", },
- { "BCPL program", "text/x-bcpl" },
- { "M4 macro language pre-processor", "text/x-m4" },
- { "PO (gettext message catalogue)", "text/x-po" },
- { "cannot happen error on names.h/types", "error/x-error" }
-};
-
-/*
- * XXX - how should we distinguish Java from C++?
- * The trick used in a Debian snapshot, of having "extends" or "implements"
- * as tags for Java, doesn't work very well, given that those keywords
- * are often preceded by "class", which flags it as C++.
- *
- * Perhaps we need to be able to say
- *
- * If "class" then
- *
- * if "extends" or "implements" then
- * Java
- * else
- * C++
- * endif
- *
- * Or should we use other keywords, such as "package" or "import"?
- * Unfortunately, Ada95 uses "package", and Modula-3 uses "import",
- * although I infer from the language spec at
- *
- * http://www.research.digital.com/SRC/m3defn/html/m3.html
- *
- * that Modula-3 uses "IMPORT" rather than "import", i.e. it must be
- * in all caps.
- *
- * So, for now, we go with "import". We must put it before the C++
- * stuff, so that we don't misidentify Java as C++. Not using "package"
- * means we won't identify stuff that defines a package but imports
- * nothing; hopefully, very little Java code imports nothing (one of the
- * reasons for doing OO programming is to import as much as possible
- * and write only what you need to, right?).
- *
- * Unfortunately, "import" may cause us to misidentify English text
- * as Java, as it comes after "the" and "The". Perhaps we need a fancier
- * heuristic to identify Java?
- */
-static const struct names {
- char name[14];
- short type;
-} names[] = {
- /* These must be sorted by eye for optimal hit rate */
- /* Add to this list only after substantial meditation */
- {"msgid", L_PO},
- {"dnl", L_M4},
- {"import", L_JAVA},
- {"\"libhdr\"", L_BCPL},
- {"\"LIBHDR\"", L_BCPL},
- {"//", L_CC},
- {"template", L_CC},
- {"virtual", L_CC},
- {"class", L_CC},
- {"public:", L_CC},
- {"private:", L_CC},
- {"/*", L_C}, /* must precede "The", "the", etc. */
- {"#include", L_C},
- {"char", L_C},
- {"The", L_ENG},
- {"the", L_ENG},
- {"double", L_C},
- {"extern", L_C},
- {"float", L_C},
- {"struct", L_C},
- {"union", L_C},
- {"CFLAGS", L_MAKE},
- {"LDFLAGS", L_MAKE},
- {"all:", L_MAKE},
- {".PRECIOUS", L_MAKE},
- {".ascii", L_MACH},
- {".asciiz", L_MACH},
- {".byte", L_MACH},
- {".even", L_MACH},
- {".globl", L_MACH},
- {".text", L_MACH},
- {"clr", L_MACH},
- {"(input,", L_PAS},
- {"program", L_PAS},
- {"record", L_PAS},
- {"dcl", L_PLI},
- {"Received:", L_MAIL},
- {">From", L_MAIL},
- {"Return-Path:",L_MAIL},
- {"Cc:", L_MAIL},
- {"Newsgroups:", L_NEWS},
- {"Path:", L_NEWS},
- {"Organization:",L_NEWS},
- {"href=", L_HTML},
- {"HREF=", L_HTML},
- {"<body", L_HTML},
- {"<BODY", L_HTML},
- {"<html", L_HTML},
- {"<HTML", L_HTML},
- {"<!--", L_HTML},
-};
-#define NNAMES (sizeof(names)/sizeof(struct names))
+++ /dev/null
-/* $OpenBSD: patchlevel.h,v 1.9 2009/04/24 18:54:34 chl Exp $ */
-
-#define FILE_VERSION_MAJOR 4
-#define patchlevel 24
-
-/*
- * Patchlevel file for Ian Darwin's MAGIC command.
- * $File: patchlevel.h,v 1.68 2008/03/22 21:39:43 christos Exp $
- *
- * $Log: patchlevel.h,v $
- * Revision 1.9 2009/04/24 18:54:34 chl
- * file update to 4.24
- *
- * The '-i' switch is now enabled so file(1) can output mime type strings.
- *
- * ok ian@
- * builk ports build test on amd64 by jasper@
- *
- * ok ray@ gilles@ on a almost identical diff
- * builk ports build test on sparc64 on this almost identical diff by ajacoutot@
- * also tested by landry@
- *
- * Revision 1.68 2008/03/22 21:39:43 christos
- * file 4.24
- *
- * Revision 1.67 2007/12/28 20:08:40 christos
- * welcome to 4.23.
- *
- * Revision 1.66 2007/12/27 16:38:24 christos
- * welcome to 4.22
- *
- * Revision 1.65 2007/05/24 17:22:27 christos
- * Welcome to 4.21
- *
- * Revision 1.64 2007/03/01 22:14:55 christos
- * welcome to 4.20
- *
- * Revision 1.63 2007/01/12 17:38:28 christos
- * Use File id.
- *
- * Revision 1.62 2006/12/11 21:49:58 christos
- * time for 4.19
- *
- * Revision 1.61 2006/10/31 21:18:09 christos
- * bump
- *
- * Revision 1.60 2006/03/02 22:15:12 christos
- * welcome to 4.17
- *
- * Revision 1.59 2005/10/17 17:15:21 christos
- * welcome to 4.16
- *
- * Revision 1.58 2005/08/18 15:52:56 christos
- * welcome to 4.15
- *
- * Revision 1.57 2005/06/25 15:52:14 christos
- * Welcome to 4.14
- *
- * Revision 1.56 2005/02/09 19:25:13 christos
- * Welcome to 4.13
- *
- * Revision 1.55 2004/11/24 18:57:47 christos
- * Re-do the autoconf stuff once more; passes make dist now.
- *
- * Revision 1.54 2004/11/21 05:52:05 christos
- * ready for 4.11
- *
- * Revision 1.53 2004/07/24 20:40:46 christos
- * welcome to 4.10
- *
- * Revision 1.52 2004/04/07 00:32:25 christos
- * welcome to 4.09
- *
- * Revision 1.51 2004/03/22 21:17:11 christos
- * welcome to 4.08.
- *
- * Revision 1.50 2003/12/23 17:34:04 christos
- * 4.07
- *
- * Revision 1.49 2003/10/15 02:08:27 christos
- * welcome to 4.06
- *
- * Revision 1.48 2003/09/12 19:41:14 christos
- * this is 4.04
- *
- * Revision 1.47 2003/05/23 21:38:21 christos
- * welcome to 4.03
- *
- * Revision 1.46 2003/04/02 18:57:43 christos
- * prepare for 4.02
- *
- * Revision 1.45 2003/03/26 15:37:25 christos
- * - Pass lint
- * - make NULL in magic_file mean stdin
- * - Fix "-" argument to file to pass NULL to magic_file
- * - avoid pointer casts by using memcpy
- * - rename magic_buf -> magic_buffer
- * - keep only the first error
- * - manual page: new sentence, new line
- * - fix typo in api function (magic_buf -> magic_buffer)
- *
- * Revision 1.44 2003/03/23 22:23:31 christos
- * finish librarification.
- *
- * Revision 1.43 2003/03/23 21:16:26 christos
- * update copyrights.
- *
- * Revision 1.42 2003/03/23 04:06:05 christos
- * Library re-organization
- *
- * Revision 1.41 2003/02/27 20:53:45 christos
- * - fix memory allocation problem (Jeff Johnson)
- * - fix stack overflow corruption (David Endler)
- * - fixes from NetBSD source (Antti Kantee)
- * - magic fixes
- *
- * Revision 1.40 2003/02/08 18:33:53 christos
- * - detect inttypes.h too (Dave Love <d.love@dl.ac.uk>)
- * - eliminate unsigned char warnings (Petter Reinholdtsen <pere@hungry.com>)
- * - better elf PT_NOTE handling (Nalin Dahyabhai <nalin@redhat.com>)
- * - add options to format the output differently
- * - much more magic.
- *
- * Revision 1.39 2002/07/03 18:57:52 christos
- * - ansify/c99ize
- * - more magic
- * - better COMPILE_ONLY support.
- * - new magic files.
- * - fix solaris compilation problems.
- *
- * Revision 1.38 2002/05/16 18:45:56 christos
- * - pt_note elf additions from NetBSD
- * - EMX os specific changes (Alexander Mai)
- * - stdint.h detection, acconfig.h fixes (Maciej W. Rozycki, Franz Korntner)
- * - regex file additions (Kim Cromie)
- * - getopt_long support and misc cleanups (Michael Piefel)
- * - many magic fixes and additions
- *
- * Revision 1.37 2001/09/03 14:44:22 christos
- * daylight/tm_isdst detection
- * magic fixes
- * don't eat the whole file if it has only nulls
- *
- * Revision 1.36 2001/07/22 21:04:15 christos
- * - magic fixes
- * - add new operators, pascal strings, UTC date printing, $HOME/.magic
- * [from "Tom N Harris" <telliamed@mac.com>]
- *
- * Revision 1.35 2001/04/24 14:40:25 christos
- * - rename magic file sgi to mips and fix it
- * - add support for building magic.mgc
- * - portability fixes for mmap()
- * - try gzip before uncompress, because uncompress sometimes hangs
- * - be more conservative about pipe reads and writes
- * - many magic fixes
- *
- * Revision 1.34 2001/03/12 05:05:57 christos
- * - new compiled magic format
- * - lots of magic additions
- *
- * Revision 1.33 2000/11/13 00:30:50 christos
- * - wordperfect magic fix: freebsd pr 9388
- * - more msdos fixes from freebsd pr's 20131 and 20812
- * - sas and spss magic [Bruce Foster]
- * - mkinstalldirs [John Fremlin]
- * - sgi opengl fixes [Michael Pruett]
- * - netbsd magic fixes [Ignatios Souvatzis]
- * - audio additions [Michael Pruett]
- * - fix problem with non ansi RCSID [Andreas Ley]
- * - oggs magic [Felix von Leitner]
- * - gmon magic [Eugen Dedu]
- * - TNEF magic [Joomy]
- * - netpbm magic and misc other image stuff [Bryan Henderson]
- *
- * Revision 1.32 2000/08/05 18:24:18 christos
- * Correct indianness detection in elf (Charles Hannum)
- * FreeBSD elf core support (Guy Harris)
- * Use gzip in systems that don't have uncompress (Anthon van der Neut)
- * Internationalization/EBCDIC support (Eric Fisher)
- * Many many magic changes
- *
- * Revision 1.31 2000/05/14 17:58:36 christos
- * - new magic for claris files
- * - new magic for mathematica and maple files
- * - new magic for msvc files
- * - new -k flag to keep going matching all possible entries
- * - add the word executable on #! magic files, and fix the usage of
- * the word script
- * - lots of other magic fixes
- * - fix typo test -> text
- *
- * Revision 1.30 2000/04/11 02:41:17 christos
- * - add support for mime output (-i)
- * - make sure we free memory in case realloc fails
- * - magic fixes
- *
- * Revision 1.29 1999/11/28 20:02:29 christos
- * new string/[Bcb] magic from anthon, and adjustments to the magic files to
- * use it.
- *
- * Revision 1.28 1999/10/31 22:11:48 christos
- * - add "char" type for compatibility with HP/UX
- * - recognize HP/UX syntax &=n etc.
- * - include errno.h for CYGWIN
- * - conditionalize the S_IS* macros
- * - revert the SHT_DYNSYM test that broke the linux stripped binaries test
- * - lots of Magdir changes
- *
- * Revision 1.27 1999/02/14 17:21:41 christos
- * Automake support and misc cleanups from Rainer Orth
- * Enable reading character and block special files from Dale R. Worley
- *
- * Revision 1.26 1998/09/12 13:19:39 christos
- * - add support for bi-endian indirect offsets (Richard Verhoeven)
- * - add recognition for bcpl (Joseph Myers)
- * - remove non magic files from Magdir to avoid difficulties building
- * on os2 where files are case independent
- * - magic fixes.
- *
- * Revision 1.25 1998/06/27 14:04:04 christos
- * OLF patch Guy Harris
- * Recognize java/html (debian linux)
- * Const poisoning (debian linux)
- * More magic!
- *
- * Revision 1.24 1998/02/15 23:20:38 christos
- * Autoconf patch: Felix von Leitner <leitner@math.fu-berlin.de>
- * More magic fixes
- * Elf64 fixes
- *
- * Revision 1.23 1997/11/05 16:03:37 christos
- * - correct elf prps offset for SunOS-2.5.1 [guy@netapp.com]
- * - handle 64 bit time_t's correctly [ewt@redhat.com]
- * - new mime style magic [clarosse@netvista.net]
- * - new TI calculator magic [rmcguire@freenet.columbus.oh.us]
- * - new figlet fonts [obrien@freebsd.org]
- * - new cisco magic, and elf fixes [jhawk@bbnplanet.com]
- * - -b flag addition, and x86 filesystem magic [vax@linkhead.paranoia.com]
- * - s/Mpeg/MPEG, header and elf typo fixes [guy@netapp.com]
- * - Windows/NT registry files, audio code [guy@netapp.com]
- * - libGrx graphics lib fonts [guy@netapp.com]
- * - PNG fixes [guy@netapp.com]
- * - more m$ document magic [guy@netapp.com]
- * - PPD files [guy@netapp.com]
- * - archive magic cleanup [guy@netapp.com]
- * - linux kernel magic cleanup [guy@netapp.com]
- * - lecter magic [guy@netapp.com]
- * - vgetty magic [guy@netapp.com]
- * - sniffer additions [guy@netapp.com]
- *
- * Revision 1.22 1997/01/15 17:23:24 christos
- * - add support for elf core files: find the program name under SVR4 [Ken Pizzini]
- * - print strings only up to the first carriage return [various]
- * - freebsd international ascii support [J Wunsch]
- * - magic fixes and additions [Guy Harris]
- * - 64 bit fixes [Larry Schwimmer]
- * - support for both utime and utimes, but don't restore file access times
- * by default [various]
- * - \xXX only takes 2 hex digits, not 3.
- * - re-implement support for core files [Guy Harris]
- *
- * Revision 1.21 1996/10/05 18:15:29 christos
- * Segregate elf stuff and conditionally enable it with -DBUILTIN_ELF
- * More magic fixes
- *
- * Revision 1.20 1996/06/22 22:15:52 christos
- * - support relative offsets of the form >&
- * - fix bug with truncating magic strings that contain \n
- * - file -f - did not read from stdin as documented
- * - support elf file parsing using our own elf support.
- * - as always magdir fixes and additions.
- *
- * Revision 1.19 1995/10/27 23:14:46 christos
- * Ability to parse colon separated list of magic files
- * New LEGAL.NOTICE
- * Various magic file changes
- *
- * Revision 1.18 1995/05/20 22:09:21 christos
- * Passed incorrect argument to eatsize().
- * Use %ld and %lx where appropriate.
- * Remove unused variables
- * ELF support for both big and little endian
- * Fixes for small files again.
- *
- * Revision 1.17 1995/04/28 17:29:13 christos
- * - Incorrect nroff detection fix from der Mouse
- * - Lost and incorrect magic entries.
- * - Added ELF stripped binary detection [in C; ugh]
- * - Look for $MAGIC to find the magic file.
- * - Eat trailing size specifications from numbers i.e. ignore 10L
- * - More fixes for very short files
- *
- * Revision 1.16 1995/03/25 22:06:45 christos
- * - use strtoul() where it exists.
- * - fix sign-extend bug
- * - try to detect tar archives before nroff files, otherwise
- * tar files where the first file starts with a . will not work
- *
- * Revision 1.15 1995/01/21 21:03:35 christos
- * Added CSECTION for the file man page
- * Added version flag -v
- * Fixed bug with -f input flag (from iorio@violet.berkeley.edu)
- * Lots of magic fixes and reorganization...
- *
- * Revision 1.14 1994/05/03 17:58:23 christos
- * changes from mycroft@gnu.ai.mit.edu (Charles Hannum) for unsigned
- *
- * Revision 1.13 1994/01/21 01:27:01 christos
- * Fixed null termination bug from Don Seeley at BSDI in ascmagic.c
- *
- * Revision 1.12 1993/10/27 20:59:05 christos
- * Changed -z flag to understand gzip format too.
- * Moved builtin compression detection to a table, and move
- * the compress magic entry out of the source.
- * Made printing of numbers unsigned, and added the mask to it.
- * Changed the buffer size to 8k, because gzip will refuse to
- * unzip just a few bytes.
- *
- * Revision 1.11 1993/09/24 18:49:06 christos
- * Fixed small bug in softmagic.c introduced by
- * copying the data to be examined out of the input
- * buffer. Changed the Makefile to use sed to create
- * the correct man pages.
- *
- * Revision 1.10 1993/09/23 21:56:23 christos
- * Passed purify. Fixed indirections. Fixed byte order printing.
- * Fixed segmentation faults caused by referencing past the end
- * of the magic buffer. Fixed bus errors caused by referencing
- * unaligned shorts or longs.
- *
- * Revision 1.9 1993/03/24 14:23:40 ian
- * Batch of minor changes from several contributors.
- *
- * Revision 1.8 93/02/19 15:01:26 ian
- * Numerous changes from Guy Harris too numerous to mention but including
- * byte-order independance, fixing "old-style masking", etc. etc. A bugfix
- * for broken symlinks from martin@@d255s004.zfe.siemens.de.
- *
- * Revision 1.7 93/01/05 14:57:27 ian
- * Couple of nits picked by Christos (again, thanks).
- *
- * Revision 1.6 93/01/05 13:51:09 ian
- * Lotsa work on the Magic directory.
- *
- * Revision 1.5 92/09/14 14:54:51 ian
- * Fix a tiny null-pointer bug in previous fix for tar archive + uncompress.
- *
- */
+++ /dev/null
-/* $OpenBSD: print.c,v 1.17 2013/04/17 15:01:26 deraadt Exp $ */
-/*
- * Copyright (c) Ian F. Darwin 1986-1995.
- * Software written by Ian F. Darwin and others;
- * maintained 1995-present by Christos Zoulas and others.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-/*
- * print.c - debugging printout routines
- */
-
-#include "file.h"
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <time.h>
-
-#define SZOF(a) (sizeof(a) / sizeof(a[0]))
-
-#ifndef COMPILE_ONLY
-protected void
-file_mdump(struct magic *m)
-{
- private const char optyp[] = { FILE_OPS };
-
- (void) fprintf(stderr, "[%u", m->lineno);
- (void) fprintf(stderr, ">>>>>>>> %u" + 8 - (m->cont_level & 7),
- m->offset);
-
- if (m->flag & INDIR) {
- (void) fprintf(stderr, "(%s,",
- /* Note: type is unsigned */
- (m->in_type < file_nnames) ?
- file_names[m->in_type] : "*bad*");
- if (m->in_op & FILE_OPINVERSE)
- (void) fputc('~', stderr);
- (void) fprintf(stderr, "%c%u),",
- ((m->in_op & FILE_OPS_MASK) < SZOF(optyp)) ?
- optyp[m->in_op & FILE_OPS_MASK] : '?',
- m->in_offset);
- }
- (void) fprintf(stderr, " %s%s", (m->flag & UNSIGNED) ? "u" : "",
- /* Note: type is unsigned */
- (m->type < file_nnames) ? file_names[m->type] : "*bad*");
- if (m->mask_op & FILE_OPINVERSE)
- (void) fputc('~', stderr);
-
- if (IS_STRING(m->type)) {
- if (m->str_flags) {
- (void) fputc('/', stderr);
- if (m->str_flags & STRING_COMPACT_BLANK)
- (void) fputc(CHAR_COMPACT_BLANK, stderr);
- if (m->str_flags & STRING_COMPACT_OPTIONAL_BLANK)
- (void) fputc(CHAR_COMPACT_OPTIONAL_BLANK,
- stderr);
- if (m->str_flags & STRING_IGNORE_LOWERCASE)
- (void) fputc(CHAR_IGNORE_LOWERCASE, stderr);
- if (m->str_flags & STRING_IGNORE_UPPERCASE)
- (void) fputc(CHAR_IGNORE_UPPERCASE, stderr);
- if (m->str_flags & REGEX_OFFSET_START)
- (void) fputc(CHAR_REGEX_OFFSET_START, stderr);
- }
- if (m->str_range)
- (void) fprintf(stderr, "/%u", m->str_range);
- }
- else {
- if ((m->mask_op & FILE_OPS_MASK) < SZOF(optyp))
- (void) fputc(optyp[m->mask_op & FILE_OPS_MASK], stderr);
- else
- (void) fputc('?', stderr);
-
- if (m->num_mask) {
- (void) fprintf(stderr, "%.8llx",
- (unsigned long long)m->num_mask);
- }
- }
- (void) fprintf(stderr, ",%c", m->reln);
-
- if (m->reln != 'x') {
- switch (m->type) {
- case FILE_BYTE:
- case FILE_SHORT:
- case FILE_LONG:
- case FILE_LESHORT:
- case FILE_LELONG:
- case FILE_MELONG:
- case FILE_BESHORT:
- case FILE_BELONG:
- (void) fprintf(stderr, "%d", m->value.l);
- break;
- case FILE_BEQUAD:
- case FILE_LEQUAD:
- case FILE_QUAD:
- (void) fprintf(stderr, "%lld",
- (unsigned long long)m->value.q);
- break;
- case FILE_PSTRING:
- case FILE_STRING:
- case FILE_REGEX:
- case FILE_BESTRING16:
- case FILE_LESTRING16:
- case FILE_SEARCH:
- file_showstr(stderr, m->value.s, (size_t)m->vallen);
- break;
- case FILE_DATE:
- case FILE_LEDATE:
- case FILE_BEDATE:
- case FILE_MEDATE:
- (void)fprintf(stderr, "%s,",
- file_fmttime(m->value.l, 1));
- break;
- case FILE_LDATE:
- case FILE_LELDATE:
- case FILE_BELDATE:
- case FILE_MELDATE:
- (void)fprintf(stderr, "%s,",
- file_fmttime(m->value.l, 0));
- break;
- case FILE_QDATE:
- case FILE_LEQDATE:
- case FILE_BEQDATE:
- (void)fprintf(stderr, "%s,",
- file_fmttime(m->value.q, 1));
- break;
- case FILE_QLDATE:
- case FILE_LEQLDATE:
- case FILE_BEQLDATE:
- (void)fprintf(stderr, "%s,",
- file_fmttime(m->value.q, 0));
- break;
- case FILE_FLOAT:
- case FILE_BEFLOAT:
- case FILE_LEFLOAT:
- (void) fprintf(stderr, "%G", m->value.f);
- break;
- case FILE_DOUBLE:
- case FILE_BEDOUBLE:
- case FILE_LEDOUBLE:
- (void) fprintf(stderr, "%G", m->value.d);
- break;
- case FILE_DEFAULT:
- /* XXX - do anything here? */
- break;
- default:
- (void) fputs("*bad*", stderr);
- break;
- }
- }
- (void) fprintf(stderr, ",\"%s\"]\n", m->desc);
-}
-#endif
-
-/*VARARGS*/
-protected void
-file_magwarn(struct magic_set *ms, const char *f, ...)
-{
- va_list va;
-
- /* cuz we use stdout for most, stderr here */
- (void) fflush(stdout);
-
- if (ms->file)
- (void) fprintf(stderr, "%s, %lu: ", ms->file,
- (unsigned long)ms->line);
- (void) fprintf(stderr, "Warning: ");
- va_start(va, f);
- (void) vfprintf(stderr, f, va);
- va_end(va);
- (void) fputc('\n', stderr);
-}
-
-protected const char *
-file_fmttime(uint64_t v, int local)
-{
- char *pp;
- time_t t = (time_t)v;
- struct tm *tm;
-
- if (local) {
- pp = ctime(&t);
- } else {
-#ifndef HAVE_DAYLIGHT
- private int daylight = 0;
-#ifdef HAVE_TM_ISDST
- private time_t now = (time_t)0;
-
- if (now == (time_t)0) {
- struct tm *tm1;
- (void)time(&now);
- tm1 = localtime(&now);
- if (tm1 == NULL)
- return "*Invalid time*";
- daylight = tm1->tm_isdst;
- }
-#endif /* HAVE_TM_ISDST */
-#endif /* HAVE_DAYLIGHT */
- if (daylight)
- t += 3600;
- tm = gmtime(&t);
- if (tm == NULL)
- return "*Invalid time*";
- pp = asctime(tm);
- }
-
- pp[strcspn(pp, "\n")] = '\0';
- return pp;
-}
+++ /dev/null
-/* $OpenBSD: readelf.c,v 1.12 2014/11/04 16:18:54 deraadt Exp $ */
-/*
- * Copyright (c) Christos Zoulas 2003.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include "file.h"
-
-#ifdef BUILTIN_ELF
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "readelf.h"
-#include "magic.h"
-
-#ifdef ELFCORE
-private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
- off_t, int *);
-#endif
-private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
- off_t, int *);
-private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, int *);
-private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int,
- int, size_t, int *);
-
-#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align)
-
-#define isquote(c) (strchr("'\"`", (c)) != NULL)
-
-private uint16_t getu16(int, uint16_t);
-private uint32_t getu32(int, uint32_t);
-private uint64_t getu64(int, uint64_t);
-
-private uint16_t
-getu16(int swap, uint16_t value)
-{
- union {
- uint16_t ui;
- char c[2];
- } retval, tmpval;
-
- if (swap) {
- tmpval.ui = value;
-
- retval.c[0] = tmpval.c[1];
- retval.c[1] = tmpval.c[0];
-
- return retval.ui;
- } else
- return value;
-}
-
-private uint32_t
-getu32(int swap, uint32_t value)
-{
- union {
- uint32_t ui;
- char c[4];
- } retval, tmpval;
-
- if (swap) {
- tmpval.ui = value;
-
- retval.c[0] = tmpval.c[3];
- retval.c[1] = tmpval.c[2];
- retval.c[2] = tmpval.c[1];
- retval.c[3] = tmpval.c[0];
-
- return retval.ui;
- } else
- return value;
-}
-
-private uint64_t
-getu64(int swap, uint64_t value)
-{
- union {
- uint64_t ui;
- char c[8];
- } retval, tmpval;
-
- if (swap) {
- tmpval.ui = value;
-
- retval.c[0] = tmpval.c[7];
- retval.c[1] = tmpval.c[6];
- retval.c[2] = tmpval.c[5];
- retval.c[3] = tmpval.c[4];
- retval.c[4] = tmpval.c[3];
- retval.c[5] = tmpval.c[2];
- retval.c[6] = tmpval.c[1];
- retval.c[7] = tmpval.c[0];
-
- return retval.ui;
- } else
- return value;
-}
-
-#define elf_getu16(swap, value) getu16(swap, value)
-#define elf_getu32(swap, value) getu32(swap, value)
-#ifdef USE_ARRAY_FOR_64BIT_TYPES
-# define elf_getu64(swap, array) \
- ((swap ? ((uint64_t)elf_getu32(swap, array[0])) << 32 : elf_getu32(swap, array[0])) + \
- (swap ? elf_getu32(swap, array[1]) : ((uint64_t)elf_getu32(swap, array[1]) << 32)))
-#else
-# define elf_getu64(swap, value) getu64(swap, value)
-#endif
-
-#define xsh_addr (class == ELFCLASS32 \
- ? (void *) &sh32 \
- : (void *) &sh64)
-#define xsh_sizeof (class == ELFCLASS32 \
- ? sizeof sh32 \
- : sizeof sh64)
-#define xsh_size (class == ELFCLASS32 \
- ? elf_getu32(swap, sh32.sh_size) \
- : elf_getu64(swap, sh64.sh_size))
-#define xsh_offset (class == ELFCLASS32 \
- ? elf_getu32(swap, sh32.sh_offset) \
- : elf_getu64(swap, sh64.sh_offset))
-#define xsh_type (class == ELFCLASS32 \
- ? elf_getu32(swap, sh32.sh_type) \
- : elf_getu32(swap, sh64.sh_type))
-#define xph_addr (class == ELFCLASS32 \
- ? (void *) &ph32 \
- : (void *) &ph64)
-#define xph_sizeof (class == ELFCLASS32 \
- ? sizeof ph32 \
- : sizeof ph64)
-#define xph_type (class == ELFCLASS32 \
- ? elf_getu32(swap, ph32.p_type) \
- : elf_getu32(swap, ph64.p_type))
-#define xph_offset (off_t)(class == ELFCLASS32 \
- ? elf_getu32(swap, ph32.p_offset) \
- : elf_getu64(swap, ph64.p_offset))
-#define xph_align (size_t)((class == ELFCLASS32 \
- ? (off_t) (ph32.p_align ? \
- elf_getu32(swap, ph32.p_align) : 4) \
- : (off_t) (ph64.p_align ? \
- elf_getu64(swap, ph64.p_align) : 4)))
-#define xph_filesz (size_t)((class == ELFCLASS32 \
- ? elf_getu32(swap, ph32.p_filesz) \
- : elf_getu64(swap, ph64.p_filesz)))
-#define xnh_addr (class == ELFCLASS32 \
- ? (void *) &nh32 \
- : (void *) &nh64)
-#define xph_memsz (size_t)((class == ELFCLASS32 \
- ? elf_getu32(swap, ph32.p_memsz) \
- : elf_getu64(swap, ph64.p_memsz)))
-#define xnh_sizeof (class == ELFCLASS32 \
- ? sizeof nh32 \
- : sizeof nh64)
-#define xnh_type (class == ELFCLASS32 \
- ? elf_getu32(swap, nh32.n_type) \
- : elf_getu32(swap, nh64.n_type))
-#define xnh_namesz (class == ELFCLASS32 \
- ? elf_getu32(swap, nh32.n_namesz) \
- : elf_getu32(swap, nh64.n_namesz))
-#define xnh_descsz (class == ELFCLASS32 \
- ? elf_getu32(swap, nh32.n_descsz) \
- : elf_getu32(swap, nh64.n_descsz))
-#define prpsoffsets(i) (class == ELFCLASS32 \
- ? prpsoffsets32[i] \
- : prpsoffsets64[i])
-
-#ifdef ELFCORE
-/*
- * Try larger offsets first to avoid false matches
- * from earlier data that happen to look like strings.
- */
-static const size_t prpsoffsets32[] = {
-#ifdef USE_NT_PSINFO
- 104, /* SunOS 5.x (command line) */
- 88, /* SunOS 5.x (short name) */
-#endif /* USE_NT_PSINFO */
-
- 100, /* SunOS 5.x (command line) */
- 84, /* SunOS 5.x (short name) */
-
- 44, /* Linux (command line) */
- 28, /* Linux 2.0.36 (short name) */
-
- 8, /* FreeBSD */
-};
-
-static const size_t prpsoffsets64[] = {
-#ifdef USE_NT_PSINFO
- 152, /* SunOS 5.x (command line) */
- 136, /* SunOS 5.x (short name) */
-#endif /* USE_NT_PSINFO */
-
- 136, /* SunOS 5.x, 64-bit (command line) */
- 120, /* SunOS 5.x, 64-bit (short name) */
-
- 56, /* Linux (command line) */
- 40, /* Linux (tested on core from 2.4.x, short name) */
-
- 16, /* FreeBSD, 64-bit */
-};
-
-#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
-#define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
-
-#define NOFFSETS (class == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
-
-/*
- * Look through the program headers of an executable image, searching
- * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
- * "FreeBSD"; if one is found, try looking in various places in its
- * contents for a 16-character string containing only printable
- * characters - if found, that string should be the name of the program
- * that dropped core. Note: right after that 16-character string is,
- * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
- * Linux, a longer string (80 characters, in 5.x, probably other
- * SVR4-flavored systems, and Linux) containing the start of the
- * command line for that program.
- *
- * SunOS 5.x core files contain two PT_NOTE sections, with the types
- * NT_PRPSINFO (old) and NT_PSINFO (new). These structs contain the
- * same info about the command name and command line, so it probably
- * isn't worthwhile to look for NT_PSINFO, but the offsets are provided
- * above (see USE_NT_PSINFO), in case we ever decide to do so. The
- * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent;
- * the SunOS 5.x file command relies on this (and prefers the latter).
- *
- * The signal number probably appears in a section of type NT_PRSTATUS,
- * but that's also rather OS-dependent, in ways that are harder to
- * dissect with heuristics, so I'm not bothering with the signal number.
- * (I suppose the signal number could be of interest in situations where
- * you don't have the binary of the program that dropped core; if you
- * *do* have that binary, the debugger will probably tell you what
- * signal it was.)
- */
-
-#define OS_STYLE_SVR4 0
-#define OS_STYLE_FREEBSD 1
-#define OS_STYLE_NETBSD 2
-
-private const char os_style_names[][8] = {
- "SVR4",
- "FreeBSD",
- "NetBSD",
-};
-
-#define FLAGS_DID_CORE 1
-#define FLAGS_DID_NOTE 2
-#define FLAGS_DID_CORE_STYLE 4
-
-private int
-dophn_core(struct magic_set *ms, int class, int swap, int fd, off_t off,
- int num, size_t size, off_t fsize, int *flags)
-{
- Elf32_Phdr ph32;
- Elf64_Phdr ph64;
- size_t offset;
- unsigned char nbuf[BUFSIZ];
- ssize_t bufsize;
- off_t savedoffset;
- struct stat st;
-
- if (fstat(fd, &st) < 0) {
- file_badread(ms);
- return -1;
- }
-
- if (size != xph_sizeof) {
- if (file_printf(ms, ", corrupted program header size") == -1)
- return -1;
- return 0;
- }
-
- /*
- * Loop through all the program headers.
- */
- for ( ; num; num--) {
- if ((savedoffset = lseek(fd, off, SEEK_SET)) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
- if (read(fd, xph_addr, xph_sizeof) == -1) {
- file_badread(ms);
- return -1;
- }
- if (xph_offset > fsize) {
- if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
- continue;
- }
-
- off += size;
- if (xph_type != PT_NOTE)
- continue;
-
- /*
- * This is a PT_NOTE section; loop through all the notes
- * in the section.
- */
- if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
- bufsize = read(fd, nbuf,
- ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf)));
- if (bufsize == -1) {
- file_badread(ms);
- return -1;
- }
- offset = 0;
- for (;;) {
- if (offset >= (size_t)bufsize)
- break;
- offset = donote(ms, nbuf, offset, (size_t)bufsize,
- class, swap, 4, flags);
- if (offset == 0)
- break;
-
- }
- }
- return 0;
-}
-#endif
-
-private size_t
-donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size,
- int class, int swap, size_t align, int *flags)
-{
- Elf32_Nhdr nh32;
- Elf64_Nhdr nh64;
- size_t noff, doff;
-#ifdef ELFCORE
- int os_style = -1;
-#endif
- uint32_t namesz, descsz;
-
- if (xnh_sizeof + offset > size) {
- /*
- * We're out of note headers.
- */
- return xnh_sizeof + offset;
- }
-
- (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
- offset += xnh_sizeof;
-
- namesz = xnh_namesz;
- descsz = xnh_descsz;
- if ((namesz == 0) && (descsz == 0)) {
- /*
- * We're out of note headers.
- */
- return (offset >= size) ? offset : size;
- }
-
- if (namesz & 0x80000000) {
- (void)file_printf(ms, ", bad note name size 0x%lx",
- (unsigned long)namesz);
- return offset;
- }
-
- if (descsz & 0x80000000) {
- (void)file_printf(ms, ", bad note description size 0x%lx",
- (unsigned long)descsz);
- return offset;
- }
-
-
- noff = offset;
- doff = ELF_ALIGN(offset + namesz);
-
- if (offset + namesz > size) {
- /*
- * We're past the end of the buffer.
- */
- return doff;
- }
-
- offset = ELF_ALIGN(doff + descsz);
- if (doff + descsz > size) {
- /*
- * We're past the end of the buffer.
- */
- return (offset >= size) ? offset : size;
- }
-
- if (*flags & FLAGS_DID_NOTE)
- goto core;
-
- if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
- xnh_type == NT_GNU_VERSION && descsz == 16) {
- uint32_t desc[4];
- (void)memcpy(desc, &nbuf[doff], sizeof(desc));
-
- if (file_printf(ms, ", for GNU/") == -1)
- return size;
- switch (elf_getu32(swap, desc[0])) {
- case GNU_OS_LINUX:
- if (file_printf(ms, "Linux") == -1)
- return size;
- break;
- case GNU_OS_HURD:
- if (file_printf(ms, "Hurd") == -1)
- return size;
- break;
- case GNU_OS_SOLARIS:
- if (file_printf(ms, "Solaris") == -1)
- return size;
- break;
- case GNU_OS_KFREEBSD:
- if (file_printf(ms, "kFreeBSD") == -1)
- return size;
- break;
- case GNU_OS_KNETBSD:
- if (file_printf(ms, "kNetBSD") == -1)
- return size;
- break;
- default:
- if (file_printf(ms, "<unknown>") == -1)
- return size;
- }
- if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
- elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
- return size;
- *flags |= FLAGS_DID_NOTE;
- return size;
- }
-
- if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 &&
- xnh_type == NT_NETBSD_VERSION && descsz == 4) {
- uint32_t desc;
- (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
- desc = elf_getu32(swap, desc);
-
- if (file_printf(ms, ", for NetBSD") == -1)
- return size;
- /*
- * The version number used to be stuck as 199905, and was thus
- * basically content-free. Newer versions of NetBSD have fixed
- * this and now use the encoding of __NetBSD_Version__:
- *
- * MMmmrrpp00
- *
- * M = major version
- * m = minor version
- * r = release ["",A-Z,Z[A-Z] but numeric]
- * p = patchlevel
- */
- if (desc > 100000000U) {
- uint32_t ver_patch = (desc / 100) % 100;
- uint32_t ver_rel = (desc / 10000) % 100;
- uint32_t ver_min = (desc / 1000000) % 100;
- uint32_t ver_maj = desc / 100000000;
-
- if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
- return size;
- if (ver_rel == 0 && ver_patch != 0) {
- if (file_printf(ms, ".%u", ver_patch) == -1)
- return size;
- } else if (ver_rel != 0) {
- while (ver_rel > 26) {
- if (file_printf(ms, "Z") == -1)
- return size;
- ver_rel -= 26;
- }
- if (file_printf(ms, "%c", 'A' + ver_rel - 1)
- == -1)
- return size;
- }
- }
- *flags |= FLAGS_DID_NOTE;
- return size;
- }
-
- if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 &&
- xnh_type == NT_FREEBSD_VERSION && descsz == 4) {
- uint32_t desc;
- (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
- desc = elf_getu32(swap, desc);
- if (file_printf(ms, ", for FreeBSD") == -1)
- return size;
-
- /*
- * Contents is __FreeBSD_version, whose relation to OS
- * versions is defined by a huge table in the Porter's
- * Handbook. This is the general scheme:
- *
- * Releases:
- * Mmp000 (before 4.10)
- * Mmi0p0 (before 5.0)
- * Mmm0p0
- *
- * Development branches:
- * Mmpxxx (before 4.6)
- * Mmp1xx (before 4.10)
- * Mmi1xx (before 5.0)
- * M000xx (pre-M.0)
- * Mmm1xx
- *
- * M = major version
- * m = minor version
- * i = minor version increment (491000 -> 4.10)
- * p = patchlevel
- * x = revision
- *
- * The first release of FreeBSD to use ELF by default
- * was version 3.0.
- */
- if (desc == 460002) {
- if (file_printf(ms, " 4.6.2") == -1)
- return size;
- } else if (desc < 460100) {
- if (file_printf(ms, " %d.%d", desc / 100000,
- desc / 10000 % 10) == -1)
- return size;
- if (desc / 1000 % 10 > 0)
- if (file_printf(ms, ".%d", desc / 1000 % 10)
- == -1)
- return size;
- if ((desc % 1000 > 0) || (desc % 100000 == 0))
- if (file_printf(ms, " (%d)", desc) == -1)
- return size;
- } else if (desc < 500000) {
- if (file_printf(ms, " %d.%d", desc / 100000,
- desc / 10000 % 10 + desc / 1000 % 10) == -1)
- return size;
- if (desc / 100 % 10 > 0) {
- if (file_printf(ms, " (%d)", desc) == -1)
- return size;
- } else if (desc / 10 % 10 > 0) {
- if (file_printf(ms, ".%d", desc / 10 % 10)
- == -1)
- return size;
- }
- } else {
- if (file_printf(ms, " %d.%d", desc / 100000,
- desc / 1000 % 100) == -1)
- return size;
- if ((desc / 100 % 10 > 0) ||
- (desc % 100000 / 100 == 0)) {
- if (file_printf(ms, " (%d)", desc) == -1)
- return size;
- } else if (desc / 10 % 10 > 0) {
- if (file_printf(ms, ".%d", desc / 10 % 10)
- == -1)
- return size;
- }
- }
- *flags |= FLAGS_DID_NOTE;
- return size;
- }
-
- if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
- xnh_type == NT_OPENBSD_VERSION && descsz == 4) {
- if (file_printf(ms, ", for OpenBSD") == -1)
- return size;
- /* Content of note is always 0 */
- *flags |= FLAGS_DID_NOTE;
- return size;
- }
-
- if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
- xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) {
- uint32_t desc;
- if (file_printf(ms, ", for DragonFly") == -1)
- return size;
- (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
- desc = elf_getu32(swap, desc);
- if (file_printf(ms, " %d.%d.%d", desc / 100000,
- desc / 10000 % 10, desc % 10000) == -1)
- return size;
- *flags |= FLAGS_DID_NOTE;
- return size;
- }
-
-core:
- /*
- * Sigh. The 2.0.36 kernel in Debian 2.1, at
- * least, doesn't correctly implement name
- * sections, in core dumps, as specified by
- * the "Program Linking" section of "UNIX(R) System
- * V Release 4 Programmer's Guide: ANSI C and
- * Programming Support Tools", because my copy
- * clearly says "The first 'namesz' bytes in 'name'
- * contain a *null-terminated* [emphasis mine]
- * character representation of the entry's owner
- * or originator", but the 2.0.36 kernel code
- * doesn't include the terminating null in the
- * name....
- */
- if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) ||
- (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) {
- os_style = OS_STYLE_SVR4;
- }
-
- if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) {
- os_style = OS_STYLE_FREEBSD;
- }
-
- if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11)
- == 0)) {
- os_style = OS_STYLE_NETBSD;
- }
-
-#ifdef ELFCORE
- if ((*flags & FLAGS_DID_CORE) != 0)
- return size;
-
- if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
- if (file_printf(ms, ", %s-style", os_style_names[os_style])
- == -1)
- return size;
- *flags |= FLAGS_DID_CORE_STYLE;
- }
-
- switch (os_style) {
- case OS_STYLE_NETBSD:
- if (xnh_type == NT_NETBSD_CORE_PROCINFO) {
- uint32_t signo;
- /*
- * Extract the program name. It is at
- * offset 0x7c, and is up to 32-bytes,
- * including the terminating NUL.
- */
- if (file_printf(ms, ", from '%.31s'",
- &nbuf[doff + 0x7c]) == -1)
- return size;
-
- /*
- * Extract the signal number. It is at
- * offset 0x08.
- */
- (void)memcpy(&signo, &nbuf[doff + 0x08],
- sizeof(signo));
- if (file_printf(ms, " (signal %u)",
- elf_getu32(swap, signo)) == -1)
- return size;
- *flags |= FLAGS_DID_CORE;
- return size;
- }
- break;
-
- default:
- if (xnh_type == NT_PRPSINFO) {
- size_t i, j;
- unsigned char c;
- /*
- * Extract the program name. We assume
- * it to be 16 characters (that's what it
- * is in SunOS 5.x and Linux).
- *
- * Unfortunately, it's at a different offset
- * in various OSes, so try multiple offsets.
- * If the characters aren't all printable,
- * reject it.
- */
- for (i = 0; i < NOFFSETS; i++) {
- unsigned char *cname, *cp;
- size_t reloffset = prpsoffsets(i);
- size_t noffset = doff + reloffset;
- for (j = 0; j < 16; j++, noffset++,
- reloffset++) {
- /*
- * Make sure we're not past
- * the end of the buffer; if
- * we are, just give up.
- */
- if (noffset >= size)
- goto tryanother;
-
- /*
- * Make sure we're not past
- * the end of the contents;
- * if we are, this obviously
- * isn't the right offset.
- */
- if (reloffset >= descsz)
- goto tryanother;
-
- c = nbuf[noffset];
- if (c == '\0') {
- /*
- * A '\0' at the
- * beginning is
- * obviously wrong.
- * Any other '\0'
- * means we're done.
- */
- if (j == 0)
- goto tryanother;
- else
- break;
- } else {
- /*
- * A nonprintable
- * character is also
- * wrong.
- */
- if (!isprint(c) || isquote(c))
- goto tryanother;
- }
- }
- /*
- * Well, that worked.
- */
- cname = (unsigned char *)
- &nbuf[doff + prpsoffsets(i)];
- for (cp = cname; *cp && isprint(*cp); cp++)
- continue;
- /*
- * Linux apparently appends a space at the end
- * of the command line: remove it.
- */
- while (cp > cname && isspace(cp[-1]))
- cp--;
- if (file_printf(ms, ", from '%.*s'",
- (int)(cp - cname), cname) == -1)
- return size;
- *flags |= FLAGS_DID_CORE;
- return size;
-
- tryanother:
- ;
- }
- }
- break;
- }
-#endif
- return offset;
-}
-
-private int
-doshn(struct magic_set *ms, int class, int swap, int fd, off_t off, int num,
- size_t size, int *flags)
-{
- Elf32_Shdr sh32;
- Elf64_Shdr sh64;
- int stripped = 1;
- void *nbuf;
- off_t noff;
-
- if (size != xsh_sizeof) {
- if (file_printf(ms, ", corrupted section header size") == -1)
- return -1;
- return 0;
- }
-
- if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
-
- for ( ; num; num--) {
- if (read(fd, xsh_addr, xsh_sizeof) == -1) {
- file_badread(ms);
- return -1;
- }
- switch (xsh_type) {
- case SHT_SYMTAB:
-#if 0
- case SHT_DYNSYM:
-#endif
- stripped = 0;
- break;
- case SHT_NOTE:
- if ((off = lseek(fd, (off_t)0, SEEK_CUR)) ==
- (off_t)-1) {
- file_badread(ms);
- return -1;
- }
- if ((nbuf = malloc((size_t)xsh_size)) == NULL) {
- file_error(ms, errno, "Cannot allocate memory"
- " for note");
- return -1;
- }
- if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) ==
- (off_t)-1) {
- file_badread(ms);
- free(nbuf);
- return -1;
- }
- if (read(fd, nbuf, (size_t)xsh_size) !=
- (ssize_t)xsh_size) {
- free(nbuf);
- file_badread(ms);
- return -1;
- }
-
- noff = 0;
- for (;;) {
- if (noff >= (size_t)xsh_size)
- break;
- noff = donote(ms, nbuf, (size_t)noff,
- (size_t)xsh_size, class, swap, 4,
- flags);
- if (noff == 0)
- break;
- }
- if ((lseek(fd, off, SEEK_SET)) == (off_t)-1) {
- free(nbuf);
- file_badread(ms);
- return -1;
- }
- free(nbuf);
- break;
- }
- }
- if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
- return -1;
- return 0;
-}
-
-/*
- * Look through the program headers of an executable image, searching
- * for a PT_INTERP section; if one is found, it's dynamically linked,
- * otherwise it's statically linked.
- */
-private int
-dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off,
- int num, size_t size, off_t fsize, int *flags)
-{
- Elf32_Phdr ph32;
- Elf64_Phdr ph64;
- const char *linking_style = "statically";
- const char *shared_libraries = "";
- unsigned char nbuf[BUFSIZ];
- int bufsize;
- size_t offset, align;
- off_t savedoffset = (off_t)-1;
- struct stat st;
-
- if (fstat(fd, &st) < 0) {
- file_badread(ms);
- return -1;
- }
-
- if (size != xph_sizeof) {
- if (file_printf(ms, ", corrupted program header size") == -1)
- return -1;
- return 0;
- }
-
- if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
-
- for ( ; num; num--) {
- if (read(fd, xph_addr, xph_sizeof) == -1) {
- file_badread(ms);
- return -1;
- }
- if (xph_offset > st.st_size && savedoffset != (off_t)-1) {
- if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
- continue;
- }
-
- if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
-
- if (xph_offset > fsize) {
- if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
- continue;
- }
-
- switch (xph_type) {
- case PT_DYNAMIC:
- linking_style = "dynamically";
- break;
- case PT_INTERP:
- shared_libraries = " (uses shared libs)";
- break;
- case PT_NOTE:
- if ((align = xph_align) & 0x80000000) {
- if (file_printf(ms,
- ", invalid note alignment 0x%lx",
- (unsigned long)align) == -1)
- return -1;
- align = 4;
- }
- /*
- * This is a PT_NOTE section; loop through all the notes
- * in the section.
- */
- if (lseek(fd, xph_offset, SEEK_SET)
- == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
- bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ?
- xph_filesz : sizeof(nbuf)));
- if (bufsize == -1) {
- file_badread(ms);
- return -1;
- }
- offset = 0;
- for (;;) {
- if (offset >= (size_t)bufsize)
- break;
- offset = donote(ms, nbuf, offset,
- (size_t)bufsize, class, swap, align,
- flags);
- if (offset == 0)
- break;
- }
- if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
- file_badseek(ms);
- return -1;
- }
- break;
- default:
- break;
- }
- }
- if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries)
- == -1)
- return -1;
- return 0;
-}
-
-
-protected int
-file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
- size_t nbytes)
-{
- union {
- int32_t l;
- char c[sizeof (int32_t)];
- } u;
- int class;
- int swap;
- struct stat st;
- off_t fsize;
- int flags = 0;
- Elf32_Ehdr elf32hdr;
- Elf64_Ehdr elf64hdr;
- uint16_t type;
-
- if (ms->flags & MAGIC_MIME)
- return 0;
- /*
- * ELF executables have multiple section headers in arbitrary
- * file locations and thus file(1) cannot determine it from easily.
- * Instead we traverse thru all section headers until a symbol table
- * one is found or else the binary is stripped.
- * Return immediately if it's not ELF (so we avoid pipe2file unless needed).
- */
- if (buf[EI_MAG0] != ELFMAG0
- || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
- || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
- return 0;
-
- /*
- * If we cannot seek, it must be a pipe, socket or fifo.
- */
- if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
- fd = file_pipe2file(ms, fd, buf, nbytes);
-
- if (fstat(fd, &st) == -1) {
- file_badread(ms);
- return -1;
- }
- fsize = st.st_size;
-
- class = buf[EI_CLASS];
-
- switch (class) {
- case ELFCLASS32:
-#undef elf_getu
-#define elf_getu(a, b) elf_getu32(a, b)
-#undef elfhdr
-#define elfhdr elf32hdr
-#include "elfclass.h"
- case ELFCLASS64:
-#undef elf_getu
-#define elf_getu(a, b) elf_getu64(a, b)
-#undef elfhdr
-#define elfhdr elf64hdr
-#include "elfclass.h"
- default:
- if (file_printf(ms, ", unknown class %d", class) == -1)
- return -1;
- break;
- }
- return 0;
-}
-#endif
+++ /dev/null
-/* $OpenBSD: readelf.h,v 1.7 2009/04/24 18:54:34 chl Exp $ */
-/*
- * Copyright (c) Christos Zoulas 2003.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-/*
- * @(#)Id: readelf.h,v 1.9 2002/05/16 18:45:56 christos Exp
- *
- * Provide elf data structures for non-elf machines, allowing file
- * non-elf hosts to determine if an elf binary is stripped.
- * Note: cobbled from the linux header file, with modifications
- */
-#ifndef __fake_elf_h__
-#define __fake_elf_h__
-
-#if HAVE_STDINT_H
-#include <stdint.h>
-#endif
-
-typedef uint32_t Elf32_Addr;
-typedef uint32_t Elf32_Off;
-typedef uint16_t Elf32_Half;
-typedef uint32_t Elf32_Word;
-typedef uint8_t Elf32_Char;
-
-#if SIZEOF_LONG_LONG != 8
-#define USE_ARRAY_FOR_64BIT_TYPES
-typedef uint32_t Elf64_Addr[2];
-typedef uint32_t Elf64_Off[2];
-typedef uint32_t Elf64_Xword[2];
-#else
-#undef USE_ARRAY_FOR_64BIT_TYPES
-typedef uint64_t Elf64_Addr;
-typedef uint64_t Elf64_Off;
-typedef uint64_t Elf64_Xword;
-#endif
-typedef uint16_t Elf64_Half;
-typedef uint32_t Elf64_Word;
-typedef uint8_t Elf64_Char;
-
-#define EI_NIDENT 16
-
-typedef struct {
- Elf32_Char e_ident[EI_NIDENT];
- Elf32_Half e_type;
- Elf32_Half e_machine;
- Elf32_Word e_version;
- Elf32_Addr e_entry; /* Entry point */
- Elf32_Off e_phoff;
- Elf32_Off e_shoff;
- Elf32_Word e_flags;
- Elf32_Half e_ehsize;
- Elf32_Half e_phentsize;
- Elf32_Half e_phnum;
- Elf32_Half e_shentsize;
- Elf32_Half e_shnum;
- Elf32_Half e_shstrndx;
-} Elf32_Ehdr;
-
-typedef struct {
- Elf64_Char e_ident[EI_NIDENT];
- Elf64_Half e_type;
- Elf64_Half e_machine;
- Elf64_Word e_version;
- Elf64_Addr e_entry; /* Entry point */
- Elf64_Off e_phoff;
- Elf64_Off e_shoff;
- Elf64_Word e_flags;
- Elf64_Half e_ehsize;
- Elf64_Half e_phentsize;
- Elf64_Half e_phnum;
- Elf64_Half e_shentsize;
- Elf64_Half e_shnum;
- Elf64_Half e_shstrndx;
-} Elf64_Ehdr;
-
-/* e_type */
-#define ET_REL 1
-#define ET_EXEC 2
-#define ET_DYN 3
-#define ET_CORE 4
-
-/* sh_type */
-#define SHT_SYMTAB 2
-#define SHT_NOTE 7
-#define SHT_DYNSYM 11
-
-/* elf type */
-#define ELFDATANONE 0 /* e_ident[EI_DATA] */
-#define ELFDATA2LSB 1
-#define ELFDATA2MSB 2
-
-/* elf class */
-#define ELFCLASSNONE 0
-#define ELFCLASS32 1
-#define ELFCLASS64 2
-
-/* magic number */
-#define EI_MAG0 0 /* e_ident[] indexes */
-#define EI_MAG1 1
-#define EI_MAG2 2
-#define EI_MAG3 3
-#define EI_CLASS 4
-#define EI_DATA 5
-#define EI_VERSION 6
-#define EI_PAD 7
-
-#define ELFMAG0 0x7f /* EI_MAG */
-#define ELFMAG1 'E'
-#define ELFMAG2 'L'
-#define ELFMAG3 'F'
-#define ELFMAG "\177ELF"
-
-#define OLFMAG1 'O'
-#define OLFMAG "\177OLF"
-
-typedef struct {
- Elf32_Word p_type;
- Elf32_Off p_offset;
- Elf32_Addr p_vaddr;
- Elf32_Addr p_paddr;
- Elf32_Word p_filesz;
- Elf32_Word p_memsz;
- Elf32_Word p_flags;
- Elf32_Word p_align;
-} Elf32_Phdr;
-
-typedef struct {
- Elf64_Word p_type;
- Elf64_Word p_flags;
- Elf64_Off p_offset;
- Elf64_Addr p_vaddr;
- Elf64_Addr p_paddr;
- Elf64_Xword p_filesz;
- Elf64_Xword p_memsz;
- Elf64_Xword p_align;
-} Elf64_Phdr;
-
-#define PT_NULL 0 /* p_type */
-#define PT_LOAD 1
-#define PT_DYNAMIC 2
-#define PT_INTERP 3
-#define PT_NOTE 4
-#define PT_SHLIB 5
-#define PT_PHDR 6
-#define PT_NUM 7
-
-typedef struct {
- Elf32_Word sh_name;
- Elf32_Word sh_type;
- Elf32_Word sh_flags;
- Elf32_Addr sh_addr;
- Elf32_Off sh_offset;
- Elf32_Word sh_size;
- Elf32_Word sh_link;
- Elf32_Word sh_info;
- Elf32_Word sh_addralign;
- Elf32_Word sh_entsize;
-} Elf32_Shdr;
-
-typedef struct {
- Elf64_Word sh_name;
- Elf64_Word sh_type;
- Elf64_Off sh_flags;
- Elf64_Addr sh_addr;
- Elf64_Off sh_offset;
- Elf64_Off sh_size;
- Elf64_Word sh_link;
- Elf64_Word sh_info;
- Elf64_Off sh_addralign;
- Elf64_Off sh_entsize;
-} Elf64_Shdr;
-
-#define NT_NETBSD_CORE_PROCINFO 1
-
-/* Note header in a PT_NOTE section */
-typedef struct elf_note {
- Elf32_Word n_namesz; /* Name size */
- Elf32_Word n_descsz; /* Content size */
- Elf32_Word n_type; /* Content type */
-} Elf32_Nhdr;
-
-typedef struct {
- Elf64_Word n_namesz;
- Elf64_Word n_descsz;
- Elf64_Word n_type;
-} Elf64_Nhdr;
-
-/* Notes used in ET_CORE */
-#define NT_PRSTATUS 1
-#define NT_PRFPREG 2
-#define NT_PRPSINFO 3
-#define NT_PRXREG 4
-#define NT_TASKSTRUCT 4
-#define NT_PLATFORM 5
-#define NT_AUXV 6
-
-/* Note types used in executables */
-/* NetBSD executables (name = "NetBSD") */
-#define NT_NETBSD_VERSION 1
-#define NT_NETBSD_EMULATION 2
-#define NT_FREEBSD_VERSION 1
-#define NT_OPENBSD_VERSION 1
-#define NT_DRAGONFLY_VERSION 1
-/* GNU executables (name = "GNU") */
-#define NT_GNU_VERSION 1
-
-/* GNU OS tags */
-#define GNU_OS_LINUX 0
-#define GNU_OS_HURD 1
-#define GNU_OS_SOLARIS 2
-#define GNU_OS_KFREEBSD 3
-#define GNU_OS_KNETBSD 4
-
-#endif
+++ /dev/null
-/* $OpenBSD: softmagic.c,v 1.17 2013/04/17 15:01:26 deraadt Exp $ */
-/*
- * Copyright (c) Ian F. Darwin 1986-1995.
- * Software written by Ian F. Darwin and others;
- * maintained 1995-present by Christos Zoulas and others.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-/*
- * softmagic - interpret variable magic from MAGIC
- */
-
-#include "file.h"
-#include "magic.h"
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <time.h>
-
-
-private int match(struct magic_set *, struct magic *, uint32_t,
- const unsigned char *, size_t, int);
-private int mget(struct magic_set *, const unsigned char *,
- struct magic *, size_t, unsigned int);
-private int magiccheck(struct magic_set *, struct magic *);
-private int32_t mprint(struct magic_set *, struct magic *);
-private void mdebug(uint32_t, const char *, size_t);
-private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
- const unsigned char *, uint32_t, size_t, size_t);
-private int mconvert(struct magic_set *, struct magic *);
-private int print_sep(struct magic_set *, int);
-private void cvt_8(union VALUETYPE *, const struct magic *);
-private void cvt_16(union VALUETYPE *, const struct magic *);
-private void cvt_32(union VALUETYPE *, const struct magic *);
-private void cvt_64(union VALUETYPE *, const struct magic *);
-
-/*
- * Macro to give description string according to whether we want plain
- * text or MIME type
- */
-#define MAGIC_DESC ((ms->flags & MAGIC_MIME) ? m->mimetype : m->desc)
-
-/*
- * softmagic - lookup one file in parsed, in-memory copy of database
- * Passed the name and FILE * of one file to be typed.
- */
-/*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
-protected int
-file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, int mode)
-{
- struct mlist *ml;
- int rv;
- for (ml = ms->mlist->next; ml != ms->mlist; ml = ml->next)
- if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, mode)) != 0)
- return rv;
-
- return 0;
-}
-
-/*
- * Go through the whole list, stopping if you find a match. Process all
- * the continuations of that match before returning.
- *
- * We support multi-level continuations:
- *
- * At any time when processing a successful top-level match, there is a
- * current continuation level; it represents the level of the last
- * successfully matched continuation.
- *
- * Continuations above that level are skipped as, if we see one, it
- * means that the continuation that controls them - i.e, the
- * lower-level continuation preceding them - failed to match.
- *
- * Continuations below that level are processed as, if we see one,
- * it means we've finished processing or skipping higher-level
- * continuations under the control of a successful or unsuccessful
- * lower-level continuation, and are now seeing the next lower-level
- * continuation and should process it. The current continuation
- * level reverts to the level of the one we're seeing.
- *
- * Continuations at the current level are processed as, if we see
- * one, there's no lower-level continuation that may have failed.
- *
- * If a continuation matches, we bump the current continuation level
- * so that higher-level continuations are processed.
- */
-private int
-match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
- const unsigned char *s, size_t nbytes, int mode)
-{
- uint32_t magindex = 0;
- unsigned int cont_level = 0;
- int need_separator = 0;
- int returnval = 0; /* if a match is found it is set to 1*/
- int firstline = 1; /* a flag to print X\n X\n- X */
- int printed_something = 0;
-
- if (file_check_mem(ms, cont_level) == -1)
- return -1;
-
- for (magindex = 0; magindex < nmagic; magindex++) {
- int flush;
- struct magic *m = &magic[magindex];
-
- if ((m->flag & BINTEST) != mode) {
- /* Skip sub-tests */
- while (magic[magindex + 1].cont_level != 0 &&
- ++magindex < nmagic)
- continue;
- continue; /* Skip to next top-level test*/
- }
-
- ms->offset = m->offset;
- ms->line = m->lineno;
-
- /* if main entry matches, print it... */
- flush = !mget(ms, s, m, nbytes, cont_level);
- if (flush) {
- if (m->reln == '!')
- flush = 0;
- } else {
- switch (magiccheck(ms, m)) {
- case -1:
- return -1;
- case 0:
- flush++;
- break;
- default:
- break;
- }
- }
- if (flush) {
- /*
- * main entry didn't match,
- * flush its continuations
- */
- while (magindex < nmagic - 1 &&
- magic[magindex + 1].cont_level != 0)
- magindex++;
- continue;
- }
-
- /*
- * If we are going to print something, we'll need to print
- * a blank before we print something else.
- */
- if (*MAGIC_DESC) {
- need_separator = 1;
- printed_something = 1;
- if (print_sep(ms, firstline) == -1)
- return -1;
- }
-
- if ((ms->c.li[cont_level].off = mprint(ms, m)) == -1)
- return -1;
-
- /* and any continuations that match */
- if (file_check_mem(ms, ++cont_level) == -1)
- return -1;
-
- while (magic[magindex+1].cont_level != 0 &&
- ++magindex < nmagic) {
- m = &magic[magindex];
- ms->line = m->lineno; /* for messages */
-
- if (cont_level < m->cont_level)
- continue;
- if (cont_level > m->cont_level) {
- /*
- * We're at the end of the level
- * "cont_level" continuations.
- */
- cont_level = m->cont_level;
- }
- ms->offset = m->offset;
- if (m->flag & OFFADD) {
- ms->offset +=
- ms->c.li[cont_level - 1].off;
- }
-
-#ifdef ENABLE_CONDITIONALS
- if (m->cond == COND_ELSE ||
- m->cond == COND_ELIF) {
- if (ms->c.li[cont_level].last_match == 1)
- continue;
- }
-#endif
- flush = !mget(ms, s, m, nbytes, cont_level);
- if (flush && m->reln != '!')
- continue;
-
- switch (flush ? 1 : magiccheck(ms, m)) {
- case -1:
- return -1;
- case 0:
-#ifdef ENABLE_CONDITIONALS
- ms->c.li[cont_level].last_match = 0;
-#endif
- break;
- default:
-#ifdef ENABLE_CONDITIONALS
- ms->c.li[cont_level].last_match = 1;
-#endif
- if (m->type != FILE_DEFAULT)
- ms->c.li[cont_level].got_match = 1;
- else if (ms->c.li[cont_level].got_match) {
- ms->c.li[cont_level].got_match = 0;
- break;
- }
- /*
- * If we are going to print something,
- * make sure that we have a separator first.
- */
- if (*MAGIC_DESC) {
- printed_something = 1;
- if (print_sep(ms, firstline) == -1)
- return -1;
- }
- /*
- * This continuation matched. Print
- * its message, with a blank before it
- * if the previous item printed and
- * this item isn't empty.
- */
- /* space if previous printed */
- if (need_separator
- && ((m->flag & NOSPACE) == 0)
- && *MAGIC_DESC) {
- if (file_printf(ms, " ") == -1)
- return -1;
- need_separator = 0;
- }
- if ((ms->c.li[cont_level].off = mprint(ms, m)) == -1)
- return -1;
- if (*MAGIC_DESC)
- need_separator = 1;
-
- /*
- * If we see any continuations
- * at a higher level,
- * process them.
- */
- if (file_check_mem(ms, ++cont_level) == -1)
- return -1;
- break;
- }
- }
- if (printed_something) {
- firstline = 0;
- returnval = 1;
- }
- if ((ms->flags & MAGIC_CONTINUE) == 0 && printed_something) {
- return 1; /* don't keep searching */
- }
- }
- return returnval; /* This is hit if -k is set or there is no match */
-}
-
-private int
-check_fmt(struct magic_set *ms, struct magic *m)
-{
- regex_t rx;
- int rc;
-
- if (strchr(MAGIC_DESC, '%') == NULL)
- return 0;
-
- rc = regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
- if (rc) {
- char errmsg[512];
- (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
- file_magerror(ms, "regex error %d, (%s)", rc, errmsg);
- return -1;
- } else {
- rc = regexec(&rx, MAGIC_DESC, 0, 0, 0);
- regfree(&rx);
- return !rc;
- }
-}
-
-#ifndef HAVE_STRNDUP
-char * strndup(const char *, size_t);
-
-char *
-strndup(const char *str, size_t n)
-{
- size_t len;
- char *copy;
-
- for (len = 0; len < n && str[len]; len++)
- continue;
- if ((copy = malloc(len + 1)) == NULL)
- return NULL;
- (void)memcpy(copy, str, len);
- copy[len] = '\0';
- return copy;
-}
-#endif /* HAVE_STRNDUP */
-
-private int32_t
-mprint(struct magic_set *ms, struct magic *m)
-{
- uint64_t v;
- float vf;
- double vd;
- int64_t t = 0;
- char *buf;
- union VALUETYPE *p = &ms->ms_value;
-
- switch (m->type) {
- case FILE_BYTE:
- v = file_signextend(ms, m, (uint64_t)p->b);
- switch (check_fmt(ms, m)) {
- case -1:
- return -1;
- case 1:
- if (asprintf(&buf, "%c", (unsigned char)v) < 0)
- return -1;
- if (file_printf(ms, MAGIC_DESC, buf) == -1)
- return -1;
- break;
- default:
- if (file_printf(ms, MAGIC_DESC, (unsigned char) v) == -1)
- return -1;
- break;
- }
- t = ms->offset + sizeof(char);
- break;
-
- case FILE_SHORT:
- case FILE_BESHORT:
- case FILE_LESHORT:
- v = file_signextend(ms, m, (uint64_t)p->h);
- switch (check_fmt(ms, m)) {
- case -1:
- return -1;
- case 1:
- if (asprintf(&buf, "%hu", (unsigned short)v) < 0)
- return -1;
- if (file_printf(ms, MAGIC_DESC, buf) == -1)
- return -1;
- break;
- default:
- if (file_printf(ms, MAGIC_DESC, (unsigned short) v) == -1)
- return -1;
- break;
- }
- t = ms->offset + sizeof(short);
- break;
-
- case FILE_LONG:
- case FILE_BELONG:
- case FILE_LELONG:
- case FILE_MELONG:
- v = file_signextend(ms, m, (uint64_t)p->l);
- switch (check_fmt(ms, m)) {
- case -1:
- return -1;
- case 1:
- if (asprintf(&buf, "%u", (uint32_t)v) < 0)
- return -1;
- if (file_printf(ms, MAGIC_DESC, buf) == -1)
- return -1;
- break;
- default:
- if (file_printf(ms, MAGIC_DESC, (uint32_t) v) == -1)
- return -1;
- break;
- }
- t = ms->offset + sizeof(int32_t);
- break;
-
- case FILE_QUAD:
- case FILE_BEQUAD:
- case FILE_LEQUAD:
- v = file_signextend(ms, m, p->q);
- if (file_printf(ms, MAGIC_DESC, (uint64_t) v) == -1)
- return -1;
- t = ms->offset + sizeof(int64_t);
- break;
-
- case FILE_STRING:
- case FILE_PSTRING:
- case FILE_BESTRING16:
- case FILE_LESTRING16:
- if (m->reln == '=' || m->reln == '!') {
- if (file_printf(ms, MAGIC_DESC, m->value.s) == -1)
- return -1;
- t = ms->offset + m->vallen;
- }
- else {
- if (*m->value.s == '\0')
- p->s[strcspn(p->s, "\n")] = '\0';
- if (file_printf(ms, MAGIC_DESC, p->s) == -1)
- return -1;
- t = ms->offset + strlen(p->s);
- if (m->type == FILE_PSTRING)
- t++;
- }
- break;
-
- case FILE_DATE:
- case FILE_BEDATE:
- case FILE_LEDATE:
- case FILE_MEDATE:
- if (file_printf(ms, MAGIC_DESC, file_fmttime(p->l, 1)) == -1)
- return -1;
- t = ms->offset + sizeof(int32_t);
- break;
-
- case FILE_LDATE:
- case FILE_BELDATE:
- case FILE_LELDATE:
- case FILE_MELDATE:
- if (file_printf(ms, MAGIC_DESC, file_fmttime(p->l, 0)) == -1)
- return -1;
- t = ms->offset + sizeof(int32_t);
- break;
-
- case FILE_QDATE:
- case FILE_BEQDATE:
- case FILE_LEQDATE:
- if (file_printf(ms, MAGIC_DESC, file_fmttime(p->q, 1))
- == -1)
- return -1;
- t = ms->offset + sizeof(uint64_t);
- break;
-
- case FILE_QLDATE:
- case FILE_BEQLDATE:
- case FILE_LEQLDATE:
- if (file_printf(ms, MAGIC_DESC, file_fmttime(p->q, 0))
- == -1)
- return -1;
- t = ms->offset + sizeof(uint64_t);
- break;
-
- case FILE_FLOAT:
- case FILE_BEFLOAT:
- case FILE_LEFLOAT:
- vf = p->f;
- switch (check_fmt(ms, m)) {
- case -1:
- return -1;
- case 1:
- if (asprintf(&buf, "%g", vf) < 0)
- return -1;
- if (file_printf(ms, MAGIC_DESC, buf) == -1)
- return -1;
- break;
- default:
- if (file_printf(ms, MAGIC_DESC, vf) == -1)
- return -1;
- break;
- }
- t = ms->offset + sizeof(float);
- break;
-
- case FILE_DOUBLE:
- case FILE_BEDOUBLE:
- case FILE_LEDOUBLE:
- vd = p->d;
- switch (check_fmt(ms, m)) {
- case -1:
- return -1;
- case 1:
- if (asprintf(&buf, "%g", vd) < 0)
- return -1;
- if (file_printf(ms, MAGIC_DESC, buf) == -1)
- return -1;
- break;
- default:
- if (file_printf(ms, MAGIC_DESC, vd) == -1)
- return -1;
- break;
- }
- t = ms->offset + sizeof(double);
- break;
-
- case FILE_REGEX: {
- char *cp;
- int rval;
-
- cp = strndup((const char *)ms->search.s, ms->search.rm_len);
- if (cp == NULL) {
- file_oomem(ms, ms->search.rm_len);
- return -1;
- }
- rval = file_printf(ms, MAGIC_DESC, cp);
- free(cp);
-
- if (rval == -1)
- return -1;
-
- if ((m->str_flags & REGEX_OFFSET_START))
- t = ms->search.offset;
- else
- t = ms->search.offset + ms->search.rm_len;
- break;
- }
-
- case FILE_SEARCH:
- if (file_printf(ms, MAGIC_DESC, m->value.s) == -1)
- return -1;
- if ((m->str_flags & REGEX_OFFSET_START))
- t = ms->search.offset;
- else
- t = ms->search.offset + m->vallen;
- break;
-
- case FILE_DEFAULT:
- if (file_printf(ms, MAGIC_DESC, m->value.s) == -1)
- return -1;
- t = ms->offset;
- break;
-
- default:
- file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
- return -1;
- }
- return(t);
-}
-
-
-#define DO_CVT(fld, cast) \
- if (m->num_mask) \
- switch (m->mask_op & FILE_OPS_MASK) { \
- case FILE_OPAND: \
- p->fld &= cast m->num_mask; \
- break; \
- case FILE_OPOR: \
- p->fld |= cast m->num_mask; \
- break; \
- case FILE_OPXOR: \
- p->fld ^= cast m->num_mask; \
- break; \
- case FILE_OPADD: \
- p->fld += cast m->num_mask; \
- break; \
- case FILE_OPMINUS: \
- p->fld -= cast m->num_mask; \
- break; \
- case FILE_OPMULTIPLY: \
- p->fld *= cast m->num_mask; \
- break; \
- case FILE_OPDIVIDE: \
- p->fld /= cast m->num_mask; \
- break; \
- case FILE_OPMODULO: \
- p->fld %= cast m->num_mask; \
- break; \
- } \
- if (m->mask_op & FILE_OPINVERSE) \
- p->fld = ~p->fld \
-
-private void
-cvt_8(union VALUETYPE *p, const struct magic *m)
-{
- DO_CVT(b, (uint8_t));
-}
-
-private void
-cvt_16(union VALUETYPE *p, const struct magic *m)
-{
- DO_CVT(h, (uint16_t));
-}
-
-private void
-cvt_32(union VALUETYPE *p, const struct magic *m)
-{
- DO_CVT(l, (uint32_t));
-}
-
-private void
-cvt_64(union VALUETYPE *p, const struct magic *m)
-{
- DO_CVT(q, (uint64_t));
-}
-
-#define DO_CVT2(fld, cast) \
- if (m->num_mask) \
- switch (m->mask_op & FILE_OPS_MASK) { \
- case FILE_OPADD: \
- p->fld += cast m->num_mask; \
- break; \
- case FILE_OPMINUS: \
- p->fld -= cast m->num_mask; \
- break; \
- case FILE_OPMULTIPLY: \
- p->fld *= cast m->num_mask; \
- break; \
- case FILE_OPDIVIDE: \
- p->fld /= cast m->num_mask; \
- break; \
- } \
-
-private void
-cvt_float(union VALUETYPE *p, const struct magic *m)
-{
- DO_CVT2(f, (float));
-}
-
-private void
-cvt_double(union VALUETYPE *p, const struct magic *m)
-{
- DO_CVT2(d, (double));
-}
-
-/*
- * Convert the byte order of the data we are looking at
- * While we're here, let's apply the mask operation
- * (unless you have a better idea)
- */
-private int
-mconvert(struct magic_set *ms, struct magic *m)
-{
- union VALUETYPE *p = &ms->ms_value;
-
- switch (m->type) {
- case FILE_BYTE:
- cvt_8(p, m);
- return 1;
- case FILE_SHORT:
- cvt_16(p, m);
- return 1;
- case FILE_LONG:
- case FILE_DATE:
- case FILE_LDATE:
- cvt_32(p, m);
- return 1;
- case FILE_QUAD:
- case FILE_QDATE:
- case FILE_QLDATE:
- cvt_64(p, m);
- return 1;
- case FILE_STRING:
- case FILE_BESTRING16:
- case FILE_LESTRING16: {
- size_t len;
-
- /* Null terminate and eat *trailing* return */
- p->s[sizeof(p->s) - 1] = '\0';
- len = strlen(p->s);
- if (len-- && p->s[len] == '\n')
- p->s[len] = '\0';
- return 1;
- }
- case FILE_PSTRING: {
- char *ptr1 = p->s, *ptr2 = ptr1 + 1;
- size_t len = *p->s;
- if (len >= sizeof(p->s))
- len = sizeof(p->s) - 1;
- while (len--)
- *ptr1++ = *ptr2++;
- *ptr1 = '\0';
- len = strlen(p->s);
- if (len-- && p->s[len] == '\n')
- p->s[len] = '\0';
- return 1;
- }
- case FILE_BESHORT:
- p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
- cvt_16(p, m);
- return 1;
- case FILE_BELONG:
- case FILE_BEDATE:
- case FILE_BELDATE:
- p->l = (int32_t)
- ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
- cvt_32(p, m);
- return 1;
- case FILE_BEQUAD:
- case FILE_BEQDATE:
- case FILE_BEQLDATE:
- p->q = (uint64_t)
- (((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
- ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
- ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
- ((uint64_t)p->hq[6]<<8)|((uint64_t)p->hq[7]));
- cvt_64(p, m);
- return 1;
- case FILE_LESHORT:
- p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
- cvt_16(p, m);
- return 1;
- case FILE_LELONG:
- case FILE_LEDATE:
- case FILE_LELDATE:
- p->l = (int32_t)
- ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
- cvt_32(p, m);
- return 1;
- case FILE_LEQUAD:
- case FILE_LEQDATE:
- case FILE_LEQLDATE:
- p->q = (uint64_t)
- (((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
- ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
- ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
- ((uint64_t)p->hq[1]<<8)|((uint64_t)p->hq[0]));
- cvt_64(p, m);
- return 1;
- case FILE_MELONG:
- case FILE_MEDATE:
- case FILE_MELDATE:
- p->l = (int32_t)
- ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2]));
- cvt_32(p, m);
- return 1;
- case FILE_FLOAT:
- cvt_float(p, m);
- return 1;
- case FILE_BEFLOAT:
- p->l = ((uint32_t)p->hl[0]<<24)|((uint32_t)p->hl[1]<<16)|
- ((uint32_t)p->hl[2]<<8) |((uint32_t)p->hl[3]);
- cvt_float(p, m);
- return 1;
- case FILE_LEFLOAT:
- p->l = ((uint32_t)p->hl[3]<<24)|((uint32_t)p->hl[2]<<16)|
- ((uint32_t)p->hl[1]<<8) |((uint32_t)p->hl[0]);
- cvt_float(p, m);
- return 1;
- case FILE_DOUBLE:
- cvt_double(p, m);
- return 1;
- case FILE_BEDOUBLE:
- p->q = ((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
- ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
- ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
- ((uint64_t)p->hq[6]<<8) |((uint64_t)p->hq[7]);
- cvt_double(p, m);
- return 1;
- case FILE_LEDOUBLE:
- p->q = ((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
- ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
- ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
- ((uint64_t)p->hq[1]<<8) |((uint64_t)p->hq[0]);
- cvt_double(p, m);
- return 1;
- case FILE_REGEX:
- case FILE_SEARCH:
- case FILE_DEFAULT:
- return 1;
- default:
- file_magerror(ms, "invalid type %d in mconvert()", m->type);
- return 0;
- }
-}
-
-
-private void
-mdebug(uint32_t offset, const char *str, size_t len)
-{
- (void) fprintf(stderr, "mget @%d: ", offset);
- file_showstr(stderr, str, len);
- (void) fputc('\n', stderr);
- (void) fputc('\n', stderr);
-}
-
-private int
-mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
- const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt)
-{
- /*
- * Note: FILE_SEARCH and FILE_REGEX do not actually copy
- * anything, but setup pointers into the source
- */
- if (indir == 0) {
- switch (type) {
- case FILE_SEARCH:
- ms->search.s = (const char *)s + offset;
- ms->search.s_len = nbytes - offset;
- ms->search.offset = offset;
- return 0;
-
- case FILE_REGEX: {
- const char *b;
- const char *c;
- const char *last; /* end of search region */
- const char *buf; /* start of search region */
- size_t lines;
-
- if (s == NULL) {
- ms->search.s_len = 0;
- ms->search.s = NULL;
- return 0;
- }
- buf = (const char *)s + offset;
- last = (const char *)s + nbytes;
- /* mget() guarantees buf <= last */
- for (lines = linecnt, b = buf;
- lines && ((b = strchr(c = b, '\n')) || (b = strchr(c, '\r')));
- lines--, b++) {
- last = b;
- if (b[0] == '\r' && b[1] == '\n')
- b++;
- }
- if (lines)
- last = (const char *)s + nbytes;
-
- ms->search.s = buf;
- ms->search.s_len = last - buf;
- ms->search.offset = offset;
- ms->search.rm_len = 0;
- return 0;
- }
- case FILE_BESTRING16:
- case FILE_LESTRING16: {
- const unsigned char *src = s + offset;
- const unsigned char *esrc = s + nbytes;
- char *dst = p->s;
- char *edst = &p->s[sizeof(p->s) - 1];
-
- if (type == FILE_BESTRING16)
- src++;
-
- /* check for pointer overflow */
- if (src < s) {
- file_magerror(ms, "invalid offset %zu in mcopy()",
- offset);
- return -1;
- }
- for (/*EMPTY*/; src < esrc; src += 2, dst++) {
- if (dst < edst)
- *dst = *src;
- else
- break;
- if (*dst == '\0') {
- if (type == FILE_BESTRING16 ?
- *(src - 1) != '\0' :
- *(src + 1) != '\0')
- *dst = ' ';
- }
- }
- *edst = '\0';
- return 0;
- }
- case FILE_STRING: /* XXX - these two should not need */
- case FILE_PSTRING: /* to copy anything, but do anyway. */
- default:
- break;
- }
- }
-
- if (offset >= nbytes) {
- (void)memset(p, '\0', sizeof(*p));
- return 0;
- }
- if (nbytes - offset < sizeof(*p))
- nbytes = nbytes - offset;
- else
- nbytes = sizeof(*p);
-
- (void)memcpy(p, s + offset, nbytes);
-
- /*
- * the usefulness of padding with zeroes eludes me, it
- * might even cause problems
- */
- if (nbytes < sizeof(*p))
- (void)memset(((char *)(void *)p) + nbytes, '\0',
- sizeof(*p) - nbytes);
- return 0;
-}
-
-private int
-mget(struct magic_set *ms, const unsigned char *s,
- struct magic *m, size_t nbytes, unsigned int cont_level)
-{
- uint32_t offset = ms->offset;
- uint32_t count = m->str_range;
- union VALUETYPE *p = &ms->ms_value;
-
- if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1)
- return -1;
-
- if ((ms->flags & MAGIC_DEBUG) != 0) {
- mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
- file_mdump(m);
- }
-
- if (m->flag & INDIR) {
- int off = m->in_offset;
- if (m->in_op & FILE_OPINDIRECT) {
- const union VALUETYPE *q =
- ((const void *)(s + offset + off));
- switch (m->in_type) {
- case FILE_BYTE:
- off = q->b;
- break;
- case FILE_SHORT:
- off = q->h;
- break;
- case FILE_BESHORT:
- off = (short)((q->hs[0]<<8)|(q->hs[1]));
- break;
- case FILE_LESHORT:
- off = (short)((q->hs[1]<<8)|(q->hs[0]));
- break;
- case FILE_LONG:
- off = q->l;
- break;
- case FILE_BELONG:
- off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)|
- (q->hl[2]<<8)|(q->hl[3]));
- break;
- case FILE_LELONG:
- off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)|
- (q->hl[1]<<8)|(q->hl[0]));
- break;
- case FILE_MELONG:
- off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)|
- (q->hl[3]<<8)|(q->hl[2]));
- break;
- }
- }
- switch (m->in_type) {
- case FILE_BYTE:
- if (nbytes < (offset + 1))
- return 0;
- if (off) {
- switch (m->in_op & FILE_OPS_MASK) {
- case FILE_OPAND:
- offset = p->b & off;
- break;
- case FILE_OPOR:
- offset = p->b | off;
- break;
- case FILE_OPXOR:
- offset = p->b ^ off;
- break;
- case FILE_OPADD:
- offset = p->b + off;
- break;
- case FILE_OPMINUS:
- offset = p->b - off;
- break;
- case FILE_OPMULTIPLY:
- offset = p->b * off;
- break;
- case FILE_OPDIVIDE:
- offset = p->b / off;
- break;
- case FILE_OPMODULO:
- offset = p->b % off;
- break;
- }
- } else
- offset = p->b;
- if (m->in_op & FILE_OPINVERSE)
- offset = ~offset;
- break;
- case FILE_BESHORT:
- if (nbytes < (offset + 2))
- return 0;
- if (off) {
- switch (m->in_op & FILE_OPS_MASK) {
- case FILE_OPAND:
- offset = (short)((p->hs[0]<<8)|
- (p->hs[1])) &
- off;
- break;
- case FILE_OPOR:
- offset = (short)((p->hs[0]<<8)|
- (p->hs[1])) |
- off;
- break;
- case FILE_OPXOR:
- offset = (short)((p->hs[0]<<8)|
- (p->hs[1])) ^
- off;
- break;
- case FILE_OPADD:
- offset = (short)((p->hs[0]<<8)|
- (p->hs[1])) +
- off;
- break;
- case FILE_OPMINUS:
- offset = (short)((p->hs[0]<<8)|
- (p->hs[1])) -
- off;
- break;
- case FILE_OPMULTIPLY:
- offset = (short)((p->hs[0]<<8)|
- (p->hs[1])) *
- off;
- break;
- case FILE_OPDIVIDE:
- offset = (short)((p->hs[0]<<8)|
- (p->hs[1])) /
- off;
- break;
- case FILE_OPMODULO:
- offset = (short)((p->hs[0]<<8)|
- (p->hs[1])) %
- off;
- break;
- }
- } else
- offset = (short)((p->hs[0]<<8)|
- (p->hs[1]));
- if (m->in_op & FILE_OPINVERSE)
- offset = ~offset;
- break;
- case FILE_LESHORT:
- if (nbytes < (offset + 2))
- return 0;
- if (off) {
- switch (m->in_op & FILE_OPS_MASK) {
- case FILE_OPAND:
- offset = (short)((p->hs[1]<<8)|
- (p->hs[0])) &
- off;
- break;
- case FILE_OPOR:
- offset = (short)((p->hs[1]<<8)|
- (p->hs[0])) |
- off;
- break;
- case FILE_OPXOR:
- offset = (short)((p->hs[1]<<8)|
- (p->hs[0])) ^
- off;
- break;
- case FILE_OPADD:
- offset = (short)((p->hs[1]<<8)|
- (p->hs[0])) +
- off;
- break;
- case FILE_OPMINUS:
- offset = (short)((p->hs[1]<<8)|
- (p->hs[0])) -
- off;
- break;
- case FILE_OPMULTIPLY:
- offset = (short)((p->hs[1]<<8)|
- (p->hs[0])) *
- off;
- break;
- case FILE_OPDIVIDE:
- offset = (short)((p->hs[1]<<8)|
- (p->hs[0])) /
- off;
- break;
- case FILE_OPMODULO:
- offset = (short)((p->hs[1]<<8)|
- (p->hs[0])) %
- off;
- break;
- }
- } else
- offset = (short)((p->hs[1]<<8)|
- (p->hs[0]));
- if (m->in_op & FILE_OPINVERSE)
- offset = ~offset;
- break;
- case FILE_SHORT:
- if (nbytes < (offset + 2))
- return 0;
- if (off) {
- switch (m->in_op & FILE_OPS_MASK) {
- case FILE_OPAND:
- offset = p->h & off;
- break;
- case FILE_OPOR:
- offset = p->h | off;
- break;
- case FILE_OPXOR:
- offset = p->h ^ off;
- break;
- case FILE_OPADD:
- offset = p->h + off;
- break;
- case FILE_OPMINUS:
- offset = p->h - off;
- break;
- case FILE_OPMULTIPLY:
- offset = p->h * off;
- break;
- case FILE_OPDIVIDE:
- offset = p->h / off;
- break;
- case FILE_OPMODULO:
- offset = p->h % off;
- break;
- }
- }
- else
- offset = p->h;
- if (m->in_op & FILE_OPINVERSE)
- offset = ~offset;
- break;
- case FILE_BELONG:
- if (nbytes < (offset + 4))
- return 0;
- if (off) {
- switch (m->in_op & FILE_OPS_MASK) {
- case FILE_OPAND:
- offset = (int32_t)((p->hl[0]<<24)|
- (p->hl[1]<<16)|
- (p->hl[2]<<8)|
- (p->hl[3])) &
- off;
- break;
- case FILE_OPOR:
- offset = (int32_t)((p->hl[0]<<24)|
- (p->hl[1]<<16)|
- (p->hl[2]<<8)|
- (p->hl[3])) |
- off;
- break;
- case FILE_OPXOR:
- offset = (int32_t)((p->hl[0]<<24)|
- (p->hl[1]<<16)|
- (p->hl[2]<<8)|
- (p->hl[3])) ^
- off;
- break;
- case FILE_OPADD:
- offset = (int32_t)((p->hl[0]<<24)|
- (p->hl[1]<<16)|
- (p->hl[2]<<8)|
- (p->hl[3])) +
- off;
- break;
- case FILE_OPMINUS:
- offset = (int32_t)((p->hl[0]<<24)|
- (p->hl[1]<<16)|
- (p->hl[2]<<8)|
- (p->hl[3])) -
- off;
- break;
- case FILE_OPMULTIPLY:
- offset = (int32_t)((p->hl[0]<<24)|
- (p->hl[1]<<16)|
- (p->hl[2]<<8)|
- (p->hl[3])) *
- off;
- break;
- case FILE_OPDIVIDE:
- offset = (int32_t)((p->hl[0]<<24)|
- (p->hl[1]<<16)|
- (p->hl[2]<<8)|
- (p->hl[3])) /
- off;
- break;
- case FILE_OPMODULO:
- offset = (int32_t)((p->hl[0]<<24)|
- (p->hl[1]<<16)|
- (p->hl[2]<<8)|
- (p->hl[3])) %
- off;
- break;
- }
- } else
- offset = (int32_t)((p->hl[0]<<24)|
- (p->hl[1]<<16)|
- (p->hl[2]<<8)|
- (p->hl[3]));
- if (m->in_op & FILE_OPINVERSE)
- offset = ~offset;
- break;
- case FILE_LELONG:
- if (nbytes < (offset + 4))
- return 0;
- if (off) {
- switch (m->in_op & FILE_OPS_MASK) {
- case FILE_OPAND:
- offset = (int32_t)((p->hl[3]<<24)|
- (p->hl[2]<<16)|
- (p->hl[1]<<8)|
- (p->hl[0])) &
- off;
- break;
- case FILE_OPOR:
- offset = (int32_t)((p->hl[3]<<24)|
- (p->hl[2]<<16)|
- (p->hl[1]<<8)|
- (p->hl[0])) |
- off;
- break;
- case FILE_OPXOR:
- offset = (int32_t)((p->hl[3]<<24)|
- (p->hl[2]<<16)|
- (p->hl[1]<<8)|
- (p->hl[0])) ^
- off;
- break;
- case FILE_OPADD:
- offset = (int32_t)((p->hl[3]<<24)|
- (p->hl[2]<<16)|
- (p->hl[1]<<8)|
- (p->hl[0])) +
- off;
- break;
- case FILE_OPMINUS:
- offset = (int32_t)((p->hl[3]<<24)|
- (p->hl[2]<<16)|
- (p->hl[1]<<8)|
- (p->hl[0])) -
- off;
- break;
- case FILE_OPMULTIPLY:
- offset = (int32_t)((p->hl[3]<<24)|
- (p->hl[2]<<16)|
- (p->hl[1]<<8)|
- (p->hl[0])) *
- off;
- break;
- case FILE_OPDIVIDE:
- offset = (int32_t)((p->hl[3]<<24)|
- (p->hl[2]<<16)|
- (p->hl[1]<<8)|
- (p->hl[0])) /
- off;
- break;
- case FILE_OPMODULO:
- offset = (int32_t)((p->hl[3]<<24)|
- (p->hl[2]<<16)|
- (p->hl[1]<<8)|
- (p->hl[0])) %
- off;
- break;
- }
- } else
- offset = (int32_t)((p->hl[3]<<24)|
- (p->hl[2]<<16)|
- (p->hl[1]<<8)|
- (p->hl[0]));
- if (m->in_op & FILE_OPINVERSE)
- offset = ~offset;
- break;
- case FILE_MELONG:
- if (nbytes < (offset + 4))
- return 0;
- if (off) {
- switch (m->in_op & FILE_OPS_MASK) {
- case FILE_OPAND:
- offset = (int32_t)((p->hl[1]<<24)|
- (p->hl[0]<<16)|
- (p->hl[3]<<8)|
- (p->hl[2])) &
- off;
- break;
- case FILE_OPOR:
- offset = (int32_t)((p->hl[1]<<24)|
- (p->hl[0]<<16)|
- (p->hl[3]<<8)|
- (p->hl[2])) |
- off;
- break;
- case FILE_OPXOR:
- offset = (int32_t)((p->hl[1]<<24)|
- (p->hl[0]<<16)|
- (p->hl[3]<<8)|
- (p->hl[2])) ^
- off;
- break;
- case FILE_OPADD:
- offset = (int32_t)((p->hl[1]<<24)|
- (p->hl[0]<<16)|
- (p->hl[3]<<8)|
- (p->hl[2])) +
- off;
- break;
- case FILE_OPMINUS:
- offset = (int32_t)((p->hl[1]<<24)|
- (p->hl[0]<<16)|
- (p->hl[3]<<8)|
- (p->hl[2])) -
- off;
- break;
- case FILE_OPMULTIPLY:
- offset = (int32_t)((p->hl[1]<<24)|
- (p->hl[0]<<16)|
- (p->hl[3]<<8)|
- (p->hl[2])) *
- off;
- break;
- case FILE_OPDIVIDE:
- offset = (int32_t)((p->hl[1]<<24)|
- (p->hl[0]<<16)|
- (p->hl[3]<<8)|
- (p->hl[2])) /
- off;
- break;
- case FILE_OPMODULO:
- offset = (int32_t)((p->hl[1]<<24)|
- (p->hl[0]<<16)|
- (p->hl[3]<<8)|
- (p->hl[2])) %
- off;
- break;
- }
- } else
- offset = (int32_t)((p->hl[1]<<24)|
- (p->hl[0]<<16)|
- (p->hl[3]<<8)|
- (p->hl[2]));
- if (m->in_op & FILE_OPINVERSE)
- offset = ~offset;
- break;
- case FILE_LONG:
- if (nbytes < (offset + 4))
- return 0;
- if (off) {
- switch (m->in_op & FILE_OPS_MASK) {
- case FILE_OPAND:
- offset = p->l & off;
- break;
- case FILE_OPOR:
- offset = p->l | off;
- break;
- case FILE_OPXOR:
- offset = p->l ^ off;
- break;
- case FILE_OPADD:
- offset = p->l + off;
- break;
- case FILE_OPMINUS:
- offset = p->l - off;
- break;
- case FILE_OPMULTIPLY:
- offset = p->l * off;
- break;
- case FILE_OPDIVIDE:
- offset = p->l / off;
- break;
- case FILE_OPMODULO:
- offset = p->l % off;
- break;
- }
- } else
- offset = p->l;
- if (m->in_op & FILE_OPINVERSE)
- offset = ~offset;
- break;
- }
-
- if (m->flag & INDIROFFADD)
- offset += ms->c.li[cont_level-1].off;
- if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1)
- return -1;
- ms->offset = offset;
-
- if ((ms->flags & MAGIC_DEBUG) != 0) {
- mdebug(offset, (char *)(void *)p,
- sizeof(union VALUETYPE));
- file_mdump(m);
- }
- }
-
- /* Verify we have enough data to match magic type */
- switch (m->type) {
- case FILE_BYTE:
- if (nbytes < (offset + 1)) /* should alway be true */
- return 0;
- break;
-
- case FILE_SHORT:
- case FILE_BESHORT:
- case FILE_LESHORT:
- if (nbytes < (offset + 2))
- return 0;
- break;
-
- case FILE_LONG:
- case FILE_BELONG:
- case FILE_LELONG:
- case FILE_MELONG:
- case FILE_DATE:
- case FILE_BEDATE:
- case FILE_LEDATE:
- case FILE_MEDATE:
- case FILE_LDATE:
- case FILE_BELDATE:
- case FILE_LELDATE:
- case FILE_MELDATE:
- case FILE_FLOAT:
- case FILE_BEFLOAT:
- case FILE_LEFLOAT:
- if (nbytes < (offset + 4))
- return 0;
- break;
-
- case FILE_DOUBLE:
- case FILE_BEDOUBLE:
- case FILE_LEDOUBLE:
- if (nbytes < (offset + 8))
- return 0;
- break;
-
- case FILE_STRING:
- case FILE_PSTRING:
- case FILE_SEARCH:
- if (nbytes < (offset + m->vallen))
- return 0;
- break;
-
- case FILE_REGEX:
- if (nbytes < offset)
- return 0;
- break;
-
- case FILE_DEFAULT: /* nothing to check */
- default:
- break;
- }
- if (!mconvert(ms, m))
- return 0;
- return 1;
-}
-
-private uint64_t
-file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
-{
- /*
- * Convert the source args to unsigned here so that (1) the
- * compare will be unsigned as it is in strncmp() and (2) so
- * the ctype functions will work correctly without extra
- * casting.
- */
- const unsigned char *a = (const unsigned char *)s1;
- const unsigned char *b = (const unsigned char *)s2;
- uint64_t v;
-
- /*
- * What we want here is v = strncmp(s1, s2, len),
- * but ignoring any nulls.
- */
- v = 0;
- if (0L == flags) { /* normal string: do it fast */
- while (len-- > 0)
- if ((v = *b++ - *a++) != '\0')
- break;
- }
- else { /* combine the others */
- while (len-- > 0) {
- if ((flags & STRING_IGNORE_LOWERCASE) &&
- islower(*a)) {
- if ((v = tolower(*b++) - *a++) != '\0')
- break;
- }
- else if ((flags & STRING_IGNORE_UPPERCASE) &&
- isupper(*a)) {
- if ((v = toupper(*b++) - *a++) != '\0')
- break;
- }
- else if ((flags & STRING_COMPACT_BLANK) &&
- isspace(*a)) {
- a++;
- if (isspace(*b++)) {
- while (isspace(*b))
- b++;
- }
- else {
- v = 1;
- break;
- }
- }
- else if ((flags & STRING_COMPACT_OPTIONAL_BLANK) &&
- isspace(*a)) {
- a++;
- while (isspace(*b))
- b++;
- }
- else {
- if ((v = *b++ - *a++) != '\0')
- break;
- }
- }
- }
- return v;
-}
-
-private uint64_t
-file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
-{
- /*
- * XXX - The 16-bit string compare probably needs to be done
- * differently, especially if the flags are to be supported.
- * At the moment, I am unsure.
- */
- flags = 0;
- return file_strncmp(a, b, len, flags);
-}
-
-private int
-magiccheck(struct magic_set *ms, struct magic *m)
-{
- uint64_t l = m->value.q;
- uint64_t v;
- float fl, fv;
- double dl, dv;
- int matched;
- union VALUETYPE *p = &ms->ms_value;
-
- switch (m->type) {
- case FILE_BYTE:
- v = p->b;
- break;
-
- case FILE_SHORT:
- case FILE_BESHORT:
- case FILE_LESHORT:
- v = p->h;
- break;
-
- case FILE_LONG:
- case FILE_BELONG:
- case FILE_LELONG:
- case FILE_MELONG:
- case FILE_DATE:
- case FILE_BEDATE:
- case FILE_LEDATE:
- case FILE_MEDATE:
- case FILE_LDATE:
- case FILE_BELDATE:
- case FILE_LELDATE:
- case FILE_MELDATE:
- v = p->l;
- break;
-
- case FILE_QUAD:
- case FILE_LEQUAD:
- case FILE_BEQUAD:
- case FILE_QDATE:
- case FILE_BEQDATE:
- case FILE_LEQDATE:
- case FILE_QLDATE:
- case FILE_BEQLDATE:
- case FILE_LEQLDATE:
- v = p->q;
- break;
-
- case FILE_FLOAT:
- case FILE_BEFLOAT:
- case FILE_LEFLOAT:
- fl = m->value.f;
- fv = p->f;
- switch (m->reln) {
- case 'x':
- matched = 1;
- break;
-
- case '!':
- matched = fv != fl;
- break;
-
- case '=':
- matched = fv == fl;
- break;
-
- case '>':
- matched = fv > fl;
- break;
-
- case '<':
- matched = fv < fl;
- break;
-
- default:
- matched = 0;
- file_magerror(ms, "cannot happen with float: invalid relation `%c'", m->reln);
- return -1;
- }
- return matched;
-
- case FILE_DOUBLE:
- case FILE_BEDOUBLE:
- case FILE_LEDOUBLE:
- dl = m->value.d;
- dv = p->d;
- switch (m->reln) {
- case 'x':
- matched = 1;
- break;
-
- case '!':
- matched = dv != dl;
- break;
-
- case '=':
- matched = dv == dl;
- break;
-
- case '>':
- matched = dv > dl;
- break;
-
- case '<':
- matched = dv < dl;
- break;
-
- default:
- matched = 0;
- file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
- return -1;
- }
- return matched;
-
- case FILE_DEFAULT:
- l = 0;
- v = 0;
- break;
-
- case FILE_STRING:
- case FILE_PSTRING:
- l = 0;
- v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
- break;
-
- case FILE_BESTRING16:
- case FILE_LESTRING16:
- l = 0;
- v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
- break;
-
- case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
- size_t slen;
- size_t idx;
-
- if (ms->search.s == NULL)
- return 0;
-
- slen = MIN(m->vallen, sizeof(m->value.s));
- l = 0;
- v = 0;
-
- for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
- if (slen + idx > ms->search.s_len)
- break;
-
- v = file_strncmp(m->value.s, ms->search.s + idx, slen, m->str_flags);
- if (v == 0) { /* found match */
- ms->search.offset += idx;
- break;
- }
- }
- break;
- }
- case FILE_REGEX: {
- int rc;
- regex_t rx;
- char errmsg[512];
-
- if (ms->search.s == NULL)
- return 0;
-
- l = 0;
- rc = regcomp(&rx, m->value.s,
- REG_EXTENDED|REG_NEWLINE|
- ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
- if (rc) {
- (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
- file_magerror(ms, "regex error %d, (%s)",
- rc, errmsg);
- v = (uint64_t)-1;
- }
- else {
- regmatch_t pmatch[1];
-#ifndef REG_STARTEND
-#define REG_STARTEND 0
- size_t l = ms->search.s_len - 1;
- char c = ms->search.s[l];
- ((char *)(intptr_t)ms->search.s)[l] = '\0';
-#else
- pmatch[0].rm_so = 0;
- pmatch[0].rm_eo = ms->search.s_len;
-#endif
- rc = regexec(&rx, (const char *)ms->search.s,
- 1, pmatch, REG_STARTEND);
-#if REG_STARTEND == 0
- ((char *)(intptr_t)ms->search.s)[l] = c;
-#endif
- switch (rc) {
- case 0:
- ms->search.s += (int)pmatch[0].rm_so;
- ms->search.offset += (size_t)pmatch[0].rm_so;
- ms->search.rm_len =
- (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so);
- v = 0;
- break;
-
- case REG_NOMATCH:
- v = 1;
- break;
-
- default:
- (void)regerror(rc, &rx, errmsg, sizeof(errmsg));
- file_magerror(ms, "regexec error %d, (%s)",
- rc, errmsg);
- v = (uint64_t)-1;
- break;
- }
- regfree(&rx);
- }
- if (v == (uint64_t)-1)
- return -1;
- break;
- }
- default:
- file_magerror(ms, "invalid type %d in magiccheck()", m->type);
- return -1;
- }
-
- v = file_signextend(ms, m, v);
-
- switch (m->reln) {
- case 'x':
- if ((ms->flags & MAGIC_DEBUG) != 0)
- (void) fprintf(stderr, "%llu == *any* = 1\n",
- (unsigned long long)v);
- matched = 1;
- break;
-
- case '!':
- matched = v != l;
- if ((ms->flags & MAGIC_DEBUG) != 0)
- (void) fprintf(stderr, "%llu != %llu = %d\n",
- (unsigned long long)v, (unsigned long long)l,
- matched);
- break;
-
- case '=':
- matched = v == l;
- if ((ms->flags & MAGIC_DEBUG) != 0)
- (void) fprintf(stderr, "%llu == %llu = %d\n",
- (unsigned long long)v, (unsigned long long)l,
- matched);
- break;
-
- case '>':
- if (m->flag & UNSIGNED) {
- matched = v > l;
- if ((ms->flags & MAGIC_DEBUG) != 0)
- (void) fprintf(stderr, "%llu > %llu = %d\n",
- (unsigned long long)v,
- (unsigned long long)l, matched);
- }
- else {
- matched = (int64_t) v > (int64_t) l;
- if ((ms->flags & MAGIC_DEBUG) != 0)
- (void) fprintf(stderr, "%lld > %lld = %d\n",
- (long long)v, (long long)l, matched);
- }
- break;
-
- case '<':
- if (m->flag & UNSIGNED) {
- matched = v < l;
- if ((ms->flags & MAGIC_DEBUG) != 0)
- (void) fprintf(stderr, "%llu < %llu = %d\n",
- (unsigned long long)v,
- (unsigned long long)l, matched);
- }
- else {
- matched = (int64_t) v < (int64_t) l;
- if ((ms->flags & MAGIC_DEBUG) != 0)
- (void) fprintf(stderr, "%lld < %lld = %d\n",
- (long long)v, (long long)l, matched);
- }
- break;
-
- case '&':
- matched = (v & l) == l;
- if ((ms->flags & MAGIC_DEBUG) != 0)
- (void) fprintf(stderr, "((%llx & %llx) == %llx) = %d\n",
- (unsigned long long)v, (unsigned long long)l,
- (unsigned long long)l, matched);
- break;
-
- case '^':
- matched = (v & l) != l;
- if ((ms->flags & MAGIC_DEBUG) != 0)
- (void) fprintf(stderr, "((%llx & %llx) != %llx) = %d\n",
- (unsigned long long)v, (unsigned long long)l,
- (unsigned long long)l, matched);
- break;
-
- default:
- matched = 0;
- file_magerror(ms, "cannot happen: invalid relation `%c'",
- m->reln);
- return -1;
- }
-
- return matched;
-}
-
-private int
-print_sep(struct magic_set *ms, int firstline)
-{
- if (firstline)
- return 0;
- /*
- * we found another match
- * put a newline and '-' to do some simple formatting
- */
- return file_printf(ms, "\n- ");
-}
+++ /dev/null
-/* $OpenBSD: tar.h,v 1.7 2009/04/24 18:54:34 chl Exp $ */
-/*
- * Copyright (c) Ian F. Darwin 1986-1995.
- * Software written by Ian F. Darwin and others;
- * maintained 1995-present by Christos Zoulas and others.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-/*
- * Header file for public domain tar (tape archive) program.
- *
- * @(#)tar.h 1.20 86/10/29 Public Domain.
- *
- * Created 25 August 1985 by John Gilmore, ihnp4!hoptoad!gnu.
- *
- * $Id: tar.h,v 1.7 2009/04/24 18:54:34 chl Exp $ # checkin only
- */
-
-/*
- * Header block on tape.
- *
- * I'm going to use traditional DP naming conventions here.
- * A "block" is a big chunk of stuff that we do I/O on.
- * A "record" is a piece of info that we care about.
- * Typically many "record"s fit into a "block".
- */
-#define RECORDSIZE 512
-#define NAMSIZ 100
-#define TUNMLEN 32
-#define TGNMLEN 32
-
-union record {
- char charptr[RECORDSIZE];
- struct header {
- char name[NAMSIZ];
- char mode[8];
- char uid[8];
- char gid[8];
- char size[12];
- char mtime[12];
- char chksum[8];
- char linkflag;
- char linkname[NAMSIZ];
- char magic[8];
- char uname[TUNMLEN];
- char gname[TGNMLEN];
- char devmajor[8];
- char devminor[8];
- } header;
-};
-
-/* The magic field is filled with this if uname and gname are valid. */
-#define TMAGIC "ustar" /* 5 chars and a null */
-#define GNUTMAGIC "ustar " /* 7 chars and a null */
--- /dev/null
+/* $OpenBSD: text.c,v 1.1 2015/04/24 16:24:11 nicm Exp $ */
+
+/*
+ * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <string.h>
+
+#include "file.h"
+#include "magic.h"
+#include "xmalloc.h"
+
+static const char *text_words[][3] = {
+ { "msgid", "PO (gettext message catalogue)", "text/x-po" },
+ { "dnl", "M4 macro language pre-processor", "text/x-m4" },
+ { "import", "Java program", "text/x-java" },
+ { "\"libhdr\"", "BCPL program", "text/x-bcpl" },
+ { "\"LIBHDR\"", "BCPL program", "text/x-bcpl" },
+ { "//", "C++ program", "text/x-c++" },
+ { "virtual", "C++ program", "text/x-c++" },
+ { "class", "C++ program", "text/x-c++" },
+ { "public:", "C++ program", "text/x-c++" },
+ { "private:", "C++ program", "text/x-c++" },
+ { "/*", "C program", "text/x-c" },
+ { "#include", "C program", "text/x-c" },
+ { "char", "C program", "text/x-c" },
+ { "The", "English", "text/plain" },
+ { "the", "English", "text/plain" },
+ { "double", "C program", "text/x-c" },
+ { "extern", "C program", "text/x-c" },
+ { "float", "C program", "text/x-c" },
+ { "struct", "C program", "text/x-c" },
+ { "union", "C program", "text/x-c" },
+ { "CFLAGS", "make commands", "text/x-makefile" },
+ { "LDFLAGS", "make commands", "text/x-makefile" },
+ { "all:", "make commands", "text/x-makefile" },
+ { ".PRECIOUS", "make commands", "text/x-makefile" },
+ { ".ascii", "assembler program", "text/x-asm" },
+ { ".asciiz", "assembler program", "text/x-asm" },
+ { ".byte", "assembler program", "text/x-asm" },
+ { ".even", "assembler program", "text/x-asm" },
+ { ".globl", "assembler program", "text/x-asm" },
+ { ".text", "assembler program", "text/x-asm" },
+ { "clr", "assembler program", "text/x-asm" },
+ { "(input", "Pascal program", "text/x-pascal" },
+ { "program", "Pascal program", "text/x-pascal" },
+ { "record", "Pascal program", "text/x-pascal" },
+ { "dcl", "PL/1 program", "text/x-pl1" },
+ { "Received:", "mail", "text/x-mail" },
+ { ">From", "mail", "text/x-mail" },
+ { "Return-Path:", "mail", "text/x-mail" },
+ { "Cc:", "mail", "text/x-mail" },
+ { "Newsgroups:", "news", "text/x-news" },
+ { "Path:", "news", "text/x-news" },
+ { "Organization:", "news", "text/x-news" },
+ { "href=", "HTML document", "text/html" },
+ { "HREF=", "HTML document", "text/html" },
+ { "<body", "HTML document", "text/html" },
+ { "<BODY", "HTML document", "text/html" },
+ { "<html", "HTML document", "text/html" },
+ { "<HTML", "HTML document", "text/html" },
+ { "<!--", "HTML document", "text/html" },
+ { NULL, NULL, NULL }
+};
+
+static int
+text_is_ascii(u_char c)
+{
+ const char cc[] = "\007\010\011\012\014\015\033";
+
+ if (c == '\0')
+ return (0);
+ if (strchr(cc, c) != NULL)
+ return (1);
+ return (c > 31 && c < 127);
+}
+
+static int
+text_is_latin1(u_char c)
+{
+ if (c >= 160)
+ return (1);
+ return (text_is_ascii(c));
+}
+
+static int
+text_is_extended(u_char c)
+{
+ if (c >= 128)
+ return (1);
+ return (text_is_ascii(c));
+}
+
+static int
+text_try_test(const void *base, size_t size, int (*f)(u_char))
+{
+ const u_char *data = base;
+ size_t offset;
+
+ for (offset = 0; offset < size; offset++) {
+ if (!f(data[offset]))
+ return (0);
+ }
+ return (1);
+}
+
+const char *
+text_get_type(const void *base, size_t size)
+{
+ if (text_try_test(base, size, text_is_ascii))
+ return ("ASCII");
+ if (text_try_test(base, size, text_is_latin1))
+ return ("ISO-8859");
+ if (text_try_test(base, size, text_is_extended))
+ return ("Non-ISO extended-ASCII");
+ return (NULL);
+}
+
+const char *
+text_try_words(const void *base, size_t size, int flags)
+{
+ const char *cp, *end, *next, *word;
+ size_t wordlen;
+ u_int i;
+
+ end = (char*)base + size;
+ for (cp = base; cp != end; /* nothing */) {
+ while (cp != end && isspace((u_char)*cp))
+ cp++;
+
+ next = cp;
+ while (next != end && !isspace((u_char)*next))
+ next++;
+
+ for (i = 0; /* nothing */; i++) {
+ word = text_words[i][0];
+ if (word == NULL)
+ break;
+ wordlen = strlen(word);
+
+ if ((size_t)(next - cp) != wordlen)
+ continue;
+ if (memcmp(cp, word, wordlen) != 0)
+ continue;
+ if (flags & MAGIC_TEST_MIME)
+ return (text_words[i][2]);
+ return (text_words[i][1]);
+ }
+
+ cp = next;
+ }
+ return (NULL);
+}
--- /dev/null
+/* $OpenBSD: xmalloc.c,v 1.1 2015/04/24 16:24:11 nicm Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ * Versions of malloc and friends that check their results, and never return
+ * failure (they call fatal if they encounter an error).
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#include <err.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xmalloc.h"
+
+void *
+xmalloc(size_t size)
+{
+ void *ptr;
+
+ if (size == 0)
+ errx(1, "xmalloc: zero size");
+ ptr = malloc(size);
+ if (ptr == NULL)
+ errx(1,
+ "xmalloc: out of memory (allocating %zu bytes)",
+ size);
+ return ptr;
+}
+
+void *
+xcalloc(size_t nmemb, size_t size)
+{
+ void *ptr;
+
+ if (size == 0 || nmemb == 0)
+ errx(1, "xcalloc: zero size");
+ if (SIZE_MAX / nmemb < size)
+ errx(1, "xcalloc: nmemb * size > SIZE_MAX");
+ ptr = calloc(nmemb, size);
+ if (ptr == NULL)
+ errx(1, "xcalloc: out of memory (allocating %zu bytes)",
+ (size * nmemb));
+ return ptr;
+}
+
+void *
+xreallocarray(void *ptr, size_t nmemb, size_t size)
+{
+ void *new_ptr;
+
+ new_ptr = reallocarray(ptr, nmemb, size);
+ if (new_ptr == NULL)
+ errx(1, "xreallocarray: out of memory (new_size %zu bytes)",
+ nmemb * size);
+ return new_ptr;
+}
+
+void
+xfree(void *ptr)
+{
+ if (ptr == NULL)
+ errx(1, "xfree: NULL pointer given as argument");
+ free(ptr);
+}
+
+char *
+xstrdup(const char *str)
+{
+ size_t len;
+ char *cp;
+
+ len = strlen(str) + 1;
+ cp = xmalloc(len);
+ if (strlcpy(cp, str, len) >= len)
+ errx(1, "xstrdup: string truncated");
+ return cp;
+}
+
+int
+xasprintf(char **ret, const char *fmt, ...)
+{
+ va_list ap;
+ int i;
+
+ va_start(ap, fmt);
+ i = vasprintf(ret, fmt, ap);
+ va_end(ap);
+
+ if (i < 0 || *ret == NULL)
+ errx(1, "xasprintf: could not allocate memory");
+
+ return (i);
+}
--- /dev/null
+/* $OpenBSD: xmalloc.h,v 1.1 2015/04/24 16:24:11 nicm Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ * Created: Mon Mar 20 22:09:17 1995 ylo
+ *
+ * Versions of malloc and friends that check their results, and never return
+ * failure (they call fatal if they encounter an error).
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+#ifndef XMALLOC_H
+#define XMALLOC_H
+
+void *xmalloc(size_t);
+void *xcalloc(size_t, size_t);
+void *xreallocarray(void *, size_t, size_t);
+void xfree(void *);
+char *xstrdup(const char *);
+int xasprintf(char **, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)))
+ __attribute__((__nonnull__ (2)));
+
+#endif /* XMALLOC_H */