From e627b28e7c33b3e42253c2f98c4f1d1e4c84c762 Mon Sep 17 00:00:00 2001 From: Christos Zoulas Date: Sun, 23 Mar 2003 04:06:04 +0000 Subject: [PATCH] reorg --- src/apprentice.c | 352 ++++++++++++++++++++++++----------------------- src/ascmagic.c | 171 +++++++++++++---------- src/compress.c | 106 +++++++------- src/file.c | 283 +++++++++++++------------------------ src/file.h | 93 +++++++------ src/fsmagic.c | 127 ++++++++++------- src/is_tar.c | 12 +- src/names.h | 6 +- src/patchlevel.h | 27 +--- src/print.c | 82 +++-------- src/readelf.c | 328 +++++++++++++++++++++++++------------------ src/readelf.h | 4 +- src/softmagic.c | 333 +++++++++++++++++++++++++------------------- 13 files changed, 978 insertions(+), 946 deletions(-) diff --git a/src/apprentice.c b/src/apprentice.c index ba93fc28..260449be 100644 --- a/src/apprentice.c +++ b/src/apprentice.c @@ -26,6 +26,7 @@ */ #include "file.h" +#include "magic.h" #include #ifdef HAVE_UNISTD_H #include @@ -33,12 +34,14 @@ #include #include #include +#include +#include #ifdef QUICK #include #endif #ifndef lint -FILE_RCSID("@(#)$Id: apprentice.c,v 1.51 2003/03/11 14:52:56 christos Exp $") +FILE_RCSID("@(#)$Id: apprentice.c,v 1.52 2003/03/23 04:06:04 christos Exp $") #endif /* lint */ #define EATAB {while (isascii((unsigned char) *l) && \ @@ -70,24 +73,25 @@ FILE_RCSID("@(#)$Id: apprentice.c,v 1.51 2003/03/11 14:52:56 christos Exp $") #endif -static int getvalue(struct magic *, char **); -static int hextoint(int); -static char *getstr(char *, char *, int, int *); -static int parse(struct magic **, uint32_t *, char *, int); -static void eatsize(char **); -static int apprentice_1(const char *, int); -static int apprentice_file(struct magic **, uint32_t *, const char *, int); -static void byteswap(struct magic *, uint32_t); -static void bs1(struct magic *); -static uint16_t swap2(uint16_t); -static uint32_t swap4(uint32_t); -static char *mkdbname(const char *); -static int apprentice_map(struct magic **, uint32_t *, const char *, int); -static int apprentice_compile(struct magic **, uint32_t *, const char *, int); - -static int maxmagic = 0; - -struct mlist mlist; +private int getvalue(struct magic_set *ms, struct magic *, char **); +private int hextoint(int); +private char *getstr(struct magic_set *, char *, char *, int, int *); +private int parse(struct magic_set *, struct magic **, uint32_t *, char *, int); +private void eatsize(char **); +private int apprentice_1(struct magic_set *, const char *, int, struct mlist *); +private int apprentice_file(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 char *mkdbname(struct magic_set *, const char *, char *, size_t); +private int apprentice_map(struct magic_set *, struct magic **, uint32_t *, + const char *, int); +private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *, + const char *, int); + +private int maxmagic = 0; #ifdef COMPILE_ONLY const char *magicfile; @@ -112,7 +116,7 @@ main(int argc, char *argv[]) } magicfile = argv[1]; - exit(apprentice(magicfile, COMPILE)); + exit(apprentice(magicfile, COMPILE, MAGIC_CHECK)); } #endif /* COMPILE_ONLY */ @@ -120,140 +124,144 @@ main(int argc, char *argv[]) /* * Handle one file. */ -static int -apprentice_1(const char *fn, int action) +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 (action == COMPILE) { - rv = apprentice_file(&magic, &nmagic, fn, action); - if (rv == 0) - return apprentice_compile(&magic, &nmagic, fn, action); - else - return rv; + rv = apprentice_file(ms, &magic, &nmagic, fn, action); + if (rv == 0) { + rv = apprentice_compile(ms, &magic, &nmagic, fn, + action); + free(magic); + } + return rv; } #ifndef COMPILE_ONLY - if ((rv = apprentice_map(&magic, &nmagic, fn, action)) != 0) - (void)fprintf(stderr, "%s: Using regular magic file `%s'\n", - progname, fn); - - if (rv != 0) - rv = apprentice_file(&magic, &nmagic, fn, action); - - if (rv != 0) + if ((rv = apprentice_map(ms, &magic, &nmagic, fn, action)) == -1) { + if (ms->flags & MAGIC_CHECK) + file_magwarn("Using regular magic file `%s'", fn); + rv = apprentice_file(ms, &magic, &nmagic, fn, action); + mapped = 0; + } + + if (rv == -1) return rv; + mapped = rv; if ((ml = malloc(sizeof(*ml))) == NULL) { - (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname, - strerror(errno)); - if (action == CHECK) - return -1; + file_oomem(ms); + return -1; } if (magic == NULL || nmagic == 0) - return rv; + 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; + mlist->prev->next = ml; + ml->prev = mlist->prev; + ml->next = mlist; + mlist->prev = ml; - return rv; + return 0; #endif /* COMPILE_ONLY */ } /* const char *fn: list of magic files */ -int -apprentice(const char *fn, int action) +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; - mlist.next = mlist.prev = &mlist; - mfn = malloc(strlen(fn)+1); - if (mfn == NULL) { - (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname, - strerror(errno)); - if (action == CHECK) - return -1; - else - exit(1); + if ((fn = mfn = strdup(fn)) == NULL) { + file_oomem(ms); + return NULL; } - fn = strcpy(mfn, fn); - + if ((mlist = malloc(sizeof(*mlist))) == NULL) { + free(mfn); + file_oomem(ms); + return NULL; + } + mlist->next = mlist->prev = mlist; + while (fn) { p = strchr(fn, PATHSEP); if (p) *p++ = '\0'; - file_err = apprentice_1(fn, action); + file_err = apprentice_1(ms, fn, action, mlist); if (file_err > errs) errs = file_err; fn = p; } - if (errs == -1) - (void) fprintf(stderr, "%s: couldn't find any magic files!\n", - progname); - if (action == CHECK && errs) - exit(1); - + if (errs == -1) { + free(mfn); + free(mlist); + mlist = NULL; + file_error(ms, "Couldn't find any magic files!"); + return NULL; + } free(mfn); - return errs; + return mlist; } /* * parse from a file * const char *fn: name of magic file */ -static int -apprentice_file(struct magic **magicp, uint32_t *nmagicp, const char *fn, - int action) +private int +apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, + const char *fn, int action) { - static const char hdr[] = + private const char hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; FILE *f; char line[BUFSIZ+1]; + int lineno; int errs = 0; f = fopen(fn, "r"); if (f == NULL) { if (errno != ENOENT) - (void) fprintf(stderr, - "%s: can't read magic file %s (%s)\n", - progname, fn, strerror(errno)); + file_error(ms, "Can't read magic file %s (%s)", + fn, strerror(errno)); return -1; } maxmagic = MAXMAGIS; *magicp = (struct magic *) calloc(maxmagic, sizeof(struct magic)); if (*magicp == NULL) { - (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname, - strerror(errno)); - if (action == CHECK) - return -1; + (void)fclose(f); + file_oomem(ms); + return -1; } /* parse it */ if (action == CHECK) /* print silly verbose header for USG compat. */ (void) printf("%s\n", hdr); - for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) { + for (lineno = 1; fgets(line, BUFSIZ, f) != NULL; lineno++) { if (line[0]=='#') /* comment, do not parse */ continue; if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */ continue; line[strlen(line)-1] = '\0'; /* delete newline */ - if (parse(magicp, nmagicp, line, action) != 0) + if (parse(ms, magicp, nmagicp, line, action) != 0) errs = 1; } - (void) fclose(f); + (void)fclose(f); if (errs) { free(*magicp); *magicp = NULL; @@ -265,8 +273,8 @@ apprentice_file(struct magic **magicp, uint32_t *nmagicp, const char *fn, /* * extend the sign bit if the comparison is to be signed */ -uint32_t -signextend(struct magic *m, uint32_t v) +protected uint32_t +file_signextend(struct magic_set *ms, struct magic *m, uint32_t v) { if (!(m->flag & UNSIGNED)) switch(m->type) { @@ -300,8 +308,9 @@ signextend(struct magic *m, uint32_t v) case REGEX: break; default: - magwarn("can't happen: m->type=%d\n", - m->type); + if (ms->flags & MAGIC_CHECK) + file_magwarn("can't happen: m->type=%d\n", + m->type); return -1; } return v; @@ -310,8 +319,9 @@ signextend(struct magic *m, uint32_t v) /* * parse one line from magic file, put into magic[index++] if valid */ -static int -parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) +private int +parse(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, char *l, + int action) { int i = 0; struct magic *m; @@ -322,14 +332,10 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) maxmagic += ALLOC_INCR; if ((m = (struct magic *) realloc(*magicp, sizeof(struct magic) * maxmagic)) == NULL) { - (void) fprintf(stderr, "%s: Out of memory (%s).\n", - progname, strerror(errno)); + file_oomem(ms); if (*magicp) free(*magicp); - if (action == CHECK) - return -1; - else - exit(1); + return -1; } *magicp = m; memset(&(*magicp)[*nmagicp], 0, sizeof(struct magic) @@ -356,7 +362,8 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) /* get offset, then skip over it */ m->offset = (int) strtoul(l,&t,0); if (l == t) - magwarn("offset %s invalid", l); + if (ms->flags & MAGIC_CHECK) + file_magwarn("offset %s invalid", l); l = t; if (m->flag & INDIR) { @@ -389,7 +396,10 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) m->in_type = BYTE; break; default: - magwarn("indirect offset type %c invalid", *l); + if (ms->flags & MAGIC_CHECK) + file_magwarn( + "indirect offset type %c invalid", + *l); break; } l++; @@ -437,7 +447,8 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) else t = l; if (*t++ != ')') - magwarn("missing ')' in indirect offset"); + if (ms->flags & MAGIC_CHECK) + file_magwarn("missing ')' in indirect offset"); l = t; } @@ -521,7 +532,8 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) m->type = REGEX; l += sizeof("regex"); } else { - magwarn("type %s invalid", l); + if (ms->flags & MAGIC_CHECK) + file_magwarn("type %s invalid", l); return -1; } /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */ @@ -535,50 +547,50 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) case '&': m->mask_op |= OPAND; ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); + m->mask = file_signextend(ms, m, strtoul(l, &l, 0)); eatsize(&l); break; case '|': m->mask_op |= OPOR; ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); + m->mask = file_signextend(ms, m, strtoul(l, &l, 0)); eatsize(&l); break; case '^': m->mask_op |= OPXOR; ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); + m->mask = file_signextend(ms, m, strtoul(l, &l, 0)); eatsize(&l); break; case '+': m->mask_op |= OPADD; ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); + m->mask = file_signextend(ms, m, strtoul(l, &l, 0)); eatsize(&l); break; case '-': m->mask_op |= OPMINUS; ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); + m->mask = file_signextend(ms, m, strtoul(l, &l, 0)); eatsize(&l); break; case '*': m->mask_op |= OPMULTIPLY; ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); + m->mask = file_signextend(ms, m, strtoul(l, &l, 0)); eatsize(&l); break; case '%': m->mask_op |= OPMODULO; ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); + m->mask = file_signextend(ms, m, strtoul(l, &l, 0)); eatsize(&l); break; case '/': if (STRING != m->type && PSTRING != m->type) { m->mask_op |= OPDIVIDE; ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); + m->mask = file_signextend(ms, m, strtoul(l, &l, 0)); eatsize(&l); } else { m->mask = 0L; @@ -595,8 +607,10 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) STRING_COMPACT_OPTIONAL_BLANK; break; default: - magwarn("string extension %c invalid", - *l); + if (ms->flags & MAGIC_CHECK) + file_magwarn( + "string extension %c invalid", + *l); return -1; } } @@ -640,7 +654,7 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) } EATAB; - if (getvalue(m, &l)) + if (getvalue(ms, m, &l)) return -1; /* * TODO finish this macro and start using it! @@ -667,7 +681,7 @@ GetDesc: #ifndef COMPILE_ONLY if (action == CHECK) { - mdump(m); + file_mdump(m); } #endif ++(*nmagicp); /* make room for next */ @@ -679,17 +693,19 @@ GetDesc: * 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. */ -static int -getvalue(struct magic *m, char **p) +private int +getvalue(struct magic_set *ms, struct magic *m, char **p) { int slen; if (m->type == STRING || m->type == PSTRING || m->type == REGEX) { - *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen); + *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen); + if (*p == NULL) + return -1; m->vallen = slen; } else if (m->reln != 'x') { - m->value.l = signextend(m, strtoul(*p, p, 0)); + m->value.l = file_signextend(ms, m, strtoul(*p, p, 0)); eatsize(p); } return 0; @@ -701,8 +717,8 @@ getvalue(struct magic *m, char **p) * Copy the converted version to "p", returning its length in *slen. * Return updated scan pointer as function result. */ -static char * -getstr(char *s, char *p, int plen, int *slen) +private char * +getstr(struct magic_set *ms, char *s, char *p, int plen, int *slen) { char *origs = s, *origp = p; char *pmax = p + plen - 1; @@ -713,8 +729,8 @@ getstr(char *s, char *p, int plen, int *slen) if (isspace((unsigned char) c)) break; if (p >= pmax) { - fprintf(stderr, "String too long: %s\n", origs); - break; + file_error(ms, "String too long: `%s'", origs); + return NULL; } if(c == '\\') { switch(c = *s++) { @@ -801,7 +817,7 @@ out: /* Single hex char to int; -1 if not a hex char. */ -static int +private int hextoint(int c) { if (!isascii((unsigned char) c)) @@ -819,8 +835,8 @@ hextoint(int c) /* * Print a string containing C character escapes. */ -void -showstr(FILE *fp, const char *s, int len) +protected void +file_showstr(FILE *fp, const char *s, int len) { char c; @@ -875,7 +891,7 @@ showstr(FILE *fp, const char *s, int len) /* * eatsize(): Eat the size spec from a number [eg. 10UL] */ -static void +private void eatsize(char **p) { char *l = *p; @@ -901,16 +917,17 @@ eatsize(char **p) /* * handle a compiled file. */ -static int -apprentice_map(struct magic **magicp, uint32_t *nmagicp, const char *fn, - int action) +private int +apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, + const char *fn, int action) { int fd; struct stat st; uint32_t *ptr; uint32_t version; int needsbyteswap; - char *dbname = mkdbname(fn); + char buf[MAXPATHLEN]; + char *dbname = mkdbname(ms, fn, buf, sizeof(buf)); void *mm; if (dbname == NULL) @@ -920,27 +937,24 @@ apprentice_map(struct magic **magicp, uint32_t *nmagicp, const char *fn, return -1; if (fstat(fd, &st) == -1) { - (void)fprintf(stderr, "%s: Cannot stat `%s' (%s)\n", - progname, dbname, strerror(errno)); + file_error(ms, "Cannot stat `%s' (%s)", dbname, + strerror(errno)); goto error; } #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) { - (void)fprintf(stderr, "%s: Cannot map `%s' (%s)\n", - progname, dbname, strerror(errno)); + file_error(ms, "Cannot map `%s' (%s)", dbname, strerror(errno)); goto error; } #else if ((mm = malloc((size_t)st.st_size)) == NULL) { - (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname, - strerror(errno)); + file_oomem(ms); goto error; } if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) { - (void) fprintf(stderr, "%s: Read failed (%s).\n", progname, - strerror(errno)); + file_error(ms, "Read failed (%s)", strerror(errno)); goto error; } #endif @@ -950,8 +964,7 @@ apprentice_map(struct magic **magicp, uint32_t *nmagicp, const char *fn, ptr = (uint32_t *) *magicp; if (*ptr != MAGICNO) { if (swap4(*ptr) != MAGICNO) { - (void)fprintf(stderr, "%s: Bad magic in `%s'\n", - progname, dbname); + file_error(ms, "Bad magic in `%s'", dbname); goto error; } needsbyteswap = 1; @@ -962,9 +975,8 @@ apprentice_map(struct magic **magicp, uint32_t *nmagicp, const char *fn, else version = ptr[1]; if (version != VERSIONNO) { - (void)fprintf(stderr, - "%s: version mismatch (%d != %d) in `%s'\n", - progname, version, VERSIONNO, dbname); + file_error(ms, "version mismatch (%d != %d) in `%s'", + version, VERSIONNO, dbname); goto error; } *nmagicp = (st.st_size / sizeof(struct magic)) - 1; @@ -989,44 +1001,44 @@ error: return -1; } +private const uint32_t ar[] = { + MAGICNO, VERSIONNO +}; /* * handle an mmaped file. */ -static int -apprentice_compile(struct magic **magicp, uint32_t *nmagicp, const char *fn, - int action) +private int +apprentice_compile(struct magic_set *ms, struct magic **magicp, + uint32_t *nmagicp, const char *fn, int action) { int fd; - char *dbname = mkdbname(fn); - static const uint32_t ar[] = { - MAGICNO, VERSIONNO - }; + char buf[MAXPATHLEN]; + char *dbname = mkdbname(ms, fn, buf, sizeof(buf)); if (dbname == NULL) return -1; if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) { - (void)fprintf(stderr, "%s: Cannot open `%s' (%s)\n", - progname, dbname, strerror(errno)); + file_error(ms, "Cannot open `%s' (%s)", dbname, strerror(errno)); return -1; } if (write(fd, ar, sizeof(ar)) != sizeof(ar)) { - (void)fprintf(stderr, "%s: error writing `%s' (%s)\n", - progname, dbname, strerror(errno)); + file_error(ms, "Error writing `%s' (%s)", dbname, + strerror(errno)); return -1; } if (lseek(fd, sizeof(struct magic), SEEK_SET) != sizeof(struct magic)) { - (void)fprintf(stderr, "%s: error seeking `%s' (%s)\n", - progname, dbname, strerror(errno)); + file_error(ms, "Error seeking `%s' (%s)", dbname, + strerror(errno)); return -1; } if (write(fd, *magicp, sizeof(struct magic) * *nmagicp) != sizeof(struct magic) * *nmagicp) { - (void)fprintf(stderr, "%s: error writing `%s' (%s)\n", - progname, dbname, strerror(errno)); + file_error(ms, "Error writing `%s' (%s)", dbname, + strerror(errno)); return -1; } @@ -1034,36 +1046,26 @@ apprentice_compile(struct magic **magicp, uint32_t *nmagicp, const char *fn, return 0; } +private const char ext[] = ".mgc"; /* * make a dbname */ -char * -mkdbname(const char *fn) +private char * +mkdbname(struct magic_set *ms, const char *fn, char *buf, size_t bufsiz) { - static const char ext[] = ".mgc"; - static char *buf = NULL; - const char *tail = strrchr(fn, '/'); - size_t len; - tail = tail == NULL ? fn : ++tail; - len = strlen(tail) + sizeof(ext) + 1; - if (buf == NULL) - buf = malloc(len); + const char *p; + if ((p = strrchr(fn, '/')) != NULL) + p++; else - buf = realloc(buf, len); - if (buf == NULL) { - (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname, - strerror(errno)); - return NULL; - } - (void)strcpy(buf, tail); - (void)strcat(buf, ext); + p = fn; + snprintf(buf, bufsiz, "%s%s", p, ext); return buf; } /* * Byteswap an mmap'ed file if needed */ -static void +private void byteswap(struct magic *magic, uint32_t nmagic) { uint32_t i; @@ -1074,7 +1076,7 @@ byteswap(struct magic *magic, uint32_t nmagic) /* * swap a short */ -static uint16_t +private uint16_t swap2(uint16_t sv) { uint16_t rv; @@ -1088,7 +1090,7 @@ swap2(uint16_t sv) /* * swap an int */ -static uint32_t +private uint32_t swap4(uint32_t sv) { uint32_t rv; @@ -1104,8 +1106,8 @@ swap4(uint32_t sv) /* * byteswap a single magic entry */ -static -void bs1(struct magic *m) +private void +bs1(struct magic *m) { m->cont_level = swap2(m->cont_level); m->offset = swap4(m->offset); diff --git a/src/ascmagic.c b/src/ascmagic.c index 8217f194..e8b8e121 100644 --- a/src/ascmagic.c +++ b/src/ascmagic.c @@ -34,7 +34,9 @@ * 4. This notice may not be removed or altered. */ +#include "magic.h" #include "file.h" +#include #include #include #include @@ -45,7 +47,7 @@ #include "names.h" #ifndef lint -FILE_RCSID("@(#)$Id: ascmagic.c,v 1.33 2003/02/08 18:33:53 christos Exp $") +FILE_RCSID("@(#)$Id: ascmagic.c,v 1.34 2003/03/23 04:06:04 christos Exp $") #endif /* lint */ typedef unsigned long unichar; @@ -54,29 +56,29 @@ typedef unsigned long unichar; #define ISSPC(x) ((x) == ' ' || (x) == '\t' || (x) == '\r' || (x) == '\n' \ || (x) == 0x85 || (x) == '\f') -static int looks_ascii(const unsigned char *, int, unichar *, int *); -static int looks_utf8(const unsigned char *, int, unichar *, int *); -static int looks_unicode(const unsigned char *, int, unichar *, int *); -static int looks_latin1(const unsigned char *, int, unichar *, int *); -static int looks_extended(const unsigned char *, int, unichar *, int *); -static void from_ebcdic(const unsigned char *, int, unsigned char *); -static int ascmatch(const unsigned char *, const unichar *, int); - -/* int nbytes: size actually read */ -int -ascmagic(unsigned char *buf, int nbytes) +private int looks_ascii(const unsigned char *, size_t, unichar *, size_t *); +private int looks_utf8(const unsigned char *, size_t, unichar *, size_t *); +private int looks_unicode(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); + + +protected int +file_ascmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes) { - int i; + size_t i; unsigned char nbuf[HOWMANY+1]; /* one extra for terminating '\0' */ unichar ubuf[HOWMANY+1]; /* one extra for terminating '\0' */ - int ulen; + size_t ulen; struct names *p; - char *code = NULL; - char *code_mime = NULL; - char *type = NULL; - char *subtype = NULL; - char *subtype_mime = NULL; + 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; @@ -93,13 +95,16 @@ ascmagic(unsigned char *buf, int 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. */ - switch (is_tar(buf, nbytes)) { + switch (file_is_tar(buf, nbytes)) { case 1: - ckfputs(iflag ? "application/x-tar" : "tar archive", stdout); + if (file_printf(ms, (ms->flags & MAGIC_MIME) ? + "application/x-tar" : "tar archive") == -1) + return -1; return 1; case 2: - ckfputs(iflag ? "application/x-tar, POSIX" - : "POSIX tar archive", stdout); + if (file_printf(ms, (ms->flags & MAGIC_MIME) ? + "application/x-tar, POSIX" : "POSIX tar archive") == -1) + return -1; return 1; } @@ -190,7 +195,7 @@ ascmagic(unsigned char *buf, int nbytes) i = 0; while (i < ulen) { - int end; + size_t end; /* * skip past any leading space @@ -211,7 +216,7 @@ ascmagic(unsigned char *buf, int nbytes) * compare the word thus isolated against the token list */ for (p = names; p < names + NNAMES; p++) { - if (ascmatch((unsigned char *)p->name, ubuf + i, + if (ascmatch((const unsigned char *)p->name, ubuf + i, end - i)) { subtype = types[p->type].human; subtype_mime = types[p->type].mime; @@ -254,29 +259,40 @@ subtype_identified: } } - if (iflag) { - if (subtype_mime) - ckfputs(subtype_mime, stdout); - else - ckfputs("text/plain", stdout); + if ((ms->flags & MAGIC_MIME)) { + if (subtype_mime) { + if (file_printf(ms, subtype_mime) == -1) + return -1; + } else { + if (file_printf(ms, "text/plain") == -1) + return -1; + } if (code_mime) { - ckfputs("; charset=", stdout); - ckfputs(code_mime, stdout); + if (file_printf(ms, "; charset=") == -1) + return -1; + if (file_printf(ms, code_mime) == -1) + return -1; } } else { - ckfputs(code, stdout); + if (file_printf(ms, code) == -1) + return -1; if (subtype) { - ckfputs(" ", stdout); - ckfputs(subtype, stdout); + if (file_printf(ms, " ") == -1) + return -1; + if (file_printf(ms, subtype) == -1) + return -1; } - ckfputs(" ", stdout); - ckfputs(type, stdout); + if (file_printf(ms, " ") == -1) + return -1; + if (file_printf(ms, type) == -1) + return -1; if (has_long_lines) - ckfputs(", with very long lines", stdout); + if (file_printf(ms, ", with very long lines") == -1) + return -1; /* * Only report line terminators if we find one other than LF, @@ -284,44 +300,56 @@ subtype_identified: */ if ((n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) || (n_crlf != 0 || n_cr != 0 || n_nel != 0)) { - ckfputs(", with", stdout); + if (file_printf(ms, ", with") == -1) + return -1; - if (n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) - ckfputs(" no", stdout); - else { + if (n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) { + if (file_printf(ms, " no") == -1) + return -1; + } else { if (n_crlf) { - ckfputs(" CRLF", stdout); + if (file_printf(ms, " CRLF") == -1) + return -1; if (n_cr || n_lf || n_nel) - ckfputs(",", stdout); + if (file_printf(ms, ",") == -1) + return -1; } if (n_cr) { - ckfputs(" CR", stdout); + if (file_printf(ms, " CR") == -1) + return -1; if (n_lf || n_nel) - ckfputs(",", stdout); + if (file_printf(ms, ",") == -1) + return -1; } if (n_lf) { - ckfputs(" LF", stdout); + if (file_printf(ms, " LF") == -1) + return -1; if (n_nel) - ckfputs(",", stdout); + if (file_printf(ms, ",") == -1) + return -1; } if (n_nel) - ckfputs(" NEL", stdout); + if (file_printf(ms, " NEL") == -1) + return -1; } - ckfputs(" line terminators", stdout); + if (file_printf(ms, " line terminators") == -1) + return -1; } if (has_escapes) - ckfputs(", with escape sequences", stdout); + if (file_printf(ms, ", with escape sequences") == -1) + return -1; if (has_backspace) - ckfputs(", with overstriking", stdout); + if (file_printf(ms, ", with overstriking") == -1) + return -1; } return 1; } -static int -ascmatch(const unsigned char *s, const unichar *us, int ulen) +private int +ascmatch(const unsigned char *s, const unichar *us, size_t ulen) { size_t i; @@ -393,7 +421,7 @@ ascmatch(const unsigned char *s, const unichar *us, int ulen) #define I 2 /* character appears in ISO-8859 text */ #define X 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */ -static char text_chars[256] = { +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 */ @@ -415,8 +443,9 @@ static char text_chars[256] = { I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I /* 0xfX */ }; -static int -looks_ascii(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen) +private int +looks_ascii(const unsigned char *buf, size_t nbytes, unichar *ubuf, + size_t *ulen) { int i; @@ -434,8 +463,8 @@ looks_ascii(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen) return 1; } -static int -looks_latin1(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen) +private int +looks_latin1(const unsigned char *buf, size_t nbytes, unichar *ubuf, size_t *ulen) { int i; @@ -453,8 +482,9 @@ looks_latin1(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen) return 1; } -static int -looks_extended(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen) +private int +looks_extended(const unsigned char *buf, size_t nbytes, unichar *ubuf, + size_t *ulen) { int i; @@ -472,8 +502,8 @@ looks_extended(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen) return 1; } -int -looks_utf8(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen) +private int +looks_utf8(const unsigned char *buf, size_t nbytes, unichar *ubuf, size_t *ulen) { int i, n; unichar c; @@ -534,8 +564,9 @@ done: return gotone; /* don't claim it's UTF-8 if it's all 7-bit */ } -static int -looks_unicode(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen) +private int +looks_unicode(const unsigned char *buf, size_t nbytes, unichar *ubuf, + size_t *ulen) { int bigend; int i; @@ -596,7 +627,7 @@ looks_unicode(const unsigned char *buf, int nbytes, unichar *ubuf, int *ulen) * between old-style and internationalized examples of text. */ -unsigned char ebcdic_to_ascii[] = { +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, @@ -615,6 +646,7 @@ unsigned char ebcdic_to_ascii[] = { '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 @@ -629,7 +661,7 @@ unsigned char ebcdic_to_ascii[] = { * cases for the NEL character can be taken out of the code. */ -unsigned char ebcdic_1047_to_8859[] = { +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, @@ -647,12 +679,13 @@ unsigned char ebcdic_1047_to_8859[] = { 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. */ -static void -from_ebcdic(const unsigned char *buf, int nbytes, unsigned char *out) +private void +from_ebcdic(const unsigned char *buf, size_t nbytes, unsigned char *out) { int i; diff --git a/src/compress.c b/src/compress.c index 4e1219c9..185d4221 100644 --- a/src/compress.c +++ b/src/compress.c @@ -5,12 +5,16 @@ * uncompress(method, old, n, newch) - uncompress old into new, * using method, return sizeof new */ +#include "magic.h" #include "file.h" +#include #include #ifdef HAVE_UNISTD_H #include #endif #include +#include +#include #ifdef HAVE_SYS_WAIT_H #include #endif @@ -19,11 +23,11 @@ #endif #ifndef lint -FILE_RCSID("@(#)$Id: compress.c,v 1.25 2002/07/03 18:26:37 christos Exp $") +FILE_RCSID("@(#)$Id: compress.c,v 1.26 2003/03/23 04:06:05 christos Exp $") #endif -static struct { +private struct { const char *magic; int maglen; const char *const argv[3]; @@ -41,47 +45,52 @@ static struct { { "BZh", 3, { "bzip2", "-cd", NULL }, 1 }, /* bzip2-ed */ }; -static int ncompr = sizeof(compr) / sizeof(compr[0]); +private int ncompr = sizeof(compr) / sizeof(compr[0]); -static int swrite(int, const void *, size_t); -static int sread(int, void *, size_t); -static int uncompressbuf(int, const unsigned char *, unsigned char **, int); +private int swrite(int, const void *, size_t); +private int sread(int, void *, size_t); +private size_t uncompressbuf(struct magic_set *ms, int, const unsigned char *, + unsigned char **, size_t); #ifdef HAVE_LIBZ -static int uncompressgzipped(const unsigned char *, unsigned char **, int); +private size_t uncompressgzipped(struct magic_set *ms, const unsigned char *, + unsigned char **, size_t); #endif -int -zmagic(const char *fname, unsigned char *buf, int nbytes) +protected int +file_zmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes) { unsigned char *newbuf; - int newsize; - int i; + size_t nsz; + size_t i; + + 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 && - (newsize = uncompressbuf(i, buf, &newbuf, nbytes)) != 0) { - tryit(fname, newbuf, newsize, 1); + (nsz = uncompressbuf(ms, i, buf, &newbuf, nbytes)) != 0) { free(newbuf); - printf(" ("); - tryit(fname, buf, nbytes, 0); - printf(")"); + if (file_printf(ms, " (") == -1) + return -1; + ms->flags &= ~MAGIC_COMPRESS; + (void)magic_buf(ms, buf, nbytes); + ms->flags |= MAGIC_COMPRESS; + if (file_printf(ms, ")") == -1) + return -1; return 1; } } - if (i == ncompr) - return 0; - - return 1; + return 0; } /* * `safe' write for sockets and pipes. */ -static int +private int swrite(int fd, const void *buf, size_t n) { int rv; @@ -106,7 +115,7 @@ swrite(int fd, const void *buf, size_t n) /* * `safe' read for sockets and pipes. */ -static int +private int sread(int fd, void *buf, size_t n) { int rv; @@ -129,8 +138,9 @@ sread(int fd, void *buf, size_t n) return rn; } -int -pipe2file(int fd, void *startbuf, size_t nbytes) +protected int +file_pipe2file(struct magic_set *ms, int fd, const void *startbuf, + size_t nbytes) { char buf[4096]; int r, tfd; @@ -151,9 +161,9 @@ pipe2file(int fd, void *startbuf, size_t nbytes) errno = r; #endif if (tfd == -1) { - error("Can't create temporary file for pipe copy (%s)\n", + file_error(ms, "Can't create temporary file for pipe copy (%s)", strerror(errno)); - /*NOTREACHED*/ + return -1; } if (swrite(tfd, startbuf, nbytes) != nbytes) @@ -166,15 +176,15 @@ pipe2file(int fd, void *startbuf, size_t nbytes) switch (r) { case -1: - error("Error copying from pipe to temp file (%s)\n", + file_error(ms, "Error copying from pipe to temp file (%s)", strerror(errno)); - /*NOTREACHED*/ + return -1; case 0: break; default: - error("Error while writing to temp file (%s)\n", + file_error(ms, "Error while writing to temp file (%s)", strerror(errno)); - /*NOTREACHED*/ + return -1; } /* @@ -183,14 +193,14 @@ pipe2file(int fd, void *startbuf, size_t nbytes) * can still access the phantom inode. */ if ((fd = dup2(tfd, fd)) == -1) { - error("Couldn't dup destcriptor for temp file(%s)\n", + file_error(ms, "Couldn't dup destcriptor for temp file (%s)", strerror(errno)); - /*NOTREACHED*/ + return -1; } (void)close(tfd); if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { - error("Couldn't seek on temp file (%s)\n", strerror(errno)); - /*NOTREACHED*/ + file_badseek(ms); + return -1; } return fd; } @@ -202,8 +212,9 @@ pipe2file(int fd, void *startbuf, size_t nbytes) #define FNAME (1 << 3) #define FCOMMENT (1 << 4) -static int -uncompressgzipped(const unsigned char *old, unsigned char **newch, int n) +private size_t +uncompressgzipped(struct magic_set *ms, const unsigned char *old, + unsigned char **newch, size_t n) { unsigned char flg = old[3]; int data_start = 10; @@ -229,7 +240,8 @@ uncompressgzipped(const unsigned char *old, unsigned char **newch, int n) return 0; } - z.next_in = (Bytef *)(old + data_start); + /* XXX: const castaway, via strchr */ + z.next_in = (Bytef *)strchr(old + data_start, old[data_start]); z.avail_in = n - data_start; z.next_out = *newch; z.avail_out = HOWMANY; @@ -239,13 +251,13 @@ uncompressgzipped(const unsigned char *old, unsigned char **newch, int n) rc = inflateInit2(&z, -15); if (rc != Z_OK) { - (void) fprintf(stderr,"%s: zlib: %s\n", progname, z.msg); + file_error(ms, "zlib: %s", z.msg); return 0; } rc = inflate(&z, Z_SYNC_FLUSH); if (rc != Z_OK && rc != Z_STREAM_END) { - fprintf(stderr,"%s: zlib: %s\n", progname, z.msg); + file_error(ms, "zlib: %s", z.msg); return 0; } @@ -259,9 +271,9 @@ uncompressgzipped(const unsigned char *old, unsigned char **newch, int n) } #endif -static int -uncompressbuf(int method, const unsigned char *old, unsigned char **newch, - int n) +private size_t +uncompressbuf(struct magic_set *ms, int method, const unsigned char *old, + unsigned char **newch, size_t n) { int fdin[2], fdout[2]; @@ -270,12 +282,12 @@ uncompressbuf(int method, const unsigned char *old, unsigned char **newch, #ifdef HAVE_LIBZ if (method == 2) - return uncompressgzipped(old,newch,n); + return uncompressgzipped(ms, old, newch, n); #endif if (pipe(fdin) == -1 || pipe(fdout) == -1) { - error("cannot create pipe (%s).\n", strerror(errno)); - /*NOTREACHED*/ + file_error(ms, "Cannot create pipe (%s)", strerror(errno)); + return -1; } switch (fork()) { case 0: /* child */ @@ -296,8 +308,8 @@ uncompressbuf(int method, const unsigned char *old, unsigned char **newch, exit(1); /*NOTREACHED*/ case -1: - error("could not fork (%s).\n", strerror(errno)); - /*NOTREACHED*/ + file_error(ms, "Could not fork (%s)", strerror(errno)); + return -1; default: /* parent */ (void) close(fdin[0]); diff --git a/src/file.c b/src/file.c index 2ccd8cab..c47f29db 100644 --- a/src/file.c +++ b/src/file.c @@ -25,11 +25,16 @@ * 4. This notice may not be removed or altered. */ +#include "magic.h" #include "file.h" + +#include #include #include #include +#include #include /* for MAXPATHLEN */ +#include #include /* for open() */ #ifdef RESTORE_TIME # if (__COHERENT__ >= 0x420) @@ -58,7 +63,7 @@ #include "patchlevel.h" #ifndef lint -FILE_RCSID("@(#)$Id: file.c,v 1.69 2003/02/27 20:47:46 christos Exp $") +FILE_RCSID("@(#)$Id: file.c,v 1.70 2003/03/23 04:06:05 christos Exp $") #endif /* lint */ @@ -69,7 +74,7 @@ FILE_RCSID("@(#)$Id: file.c,v 1.69 2003/02/27 20:47:46 christos Exp $") #endif #ifdef __EMX__ -static char *apptypeName = NULL; +private char *apptypeName = NULL; int os2_apptype (const char *fn, char *buf, int nb); #endif /* __EMX__ */ @@ -81,57 +86,50 @@ int os2_apptype (const char *fn, char *buf, int nb); #define MAXPATHLEN 512 #endif -int /* Global command-line options */ - debug = 0, /* debugging */ - lflag = 0, /* follow Symlinks (BSD only) */ +private int /* Global command-line options */ bflag = 0, /* brief output format */ - zflag = 0, /* follow (uncompress) compressed files */ - sflag = 0, /* read block special files */ - iflag = 0, nopad = 0, /* Don't pad output */ nobuffer = 0, /* Do not buffer stdout */ kflag = 0; /* Keep going after the first match */ -int /* Misc globals */ - nmagic = 0; /* number of valid magic[]s */ - -struct magic *magic; /* array of magic entries */ - -const char *magicfile = 0; /* where the magic is */ -const char *default_magicfile = MAGIC; +private const char *magicfile = 0; /* where the magic is */ +private const char *default_magicfile = MAGIC; +private char separator = ':'; /* Default field separator */ -char separator = ':'; /* Default field separator */ +private char *progname; /* used throughout */ -char *progname; /* used throughout */ -int lineno; /* line number in the magic file */ +private struct magic_set *magic; - -static void unwrap(char *fn); -static void usage(void); -#ifdef HAVE_GETOPT_LONG -static void help(void); +private void unwrap(char *); +private void usage(void); +#ifdef HAVE_GETOPT_H +private void help(void); #endif #if 0 -static int byteconv4(int, int, int); -static short byteconv2(int, int, int); +private int byteconv4(int, int, int); +private short byteconv2(int, int, int); #endif int main(int, char *[]); +private void process(const char *, int); +private void load(const char *, int); + /* * main - parse arguments and handle options */ int -main(int argc, char **argv) +main(int argc, char *argv[]) { int c; - int action = 0, didsomefiles = 0, errflg = 0, ret = 0, app = 0; + int action = 0, didsomefiles = 0, errflg = 0; + int flags = 0; char *mime, *home, *usermagic; struct stat sb; #define OPTSTRING "bcdf:F:ikm:nNsvzCL" #ifdef HAVE_GETOPT_LONG int longindex; - static struct option long_options[] = + private struct option long_options[] = { {"version", 0, 0, 'v'}, {"help", 0, 0, 0}, @@ -207,15 +205,12 @@ main(int argc, char **argv) action = COMPILE; break; case 'd': - ++debug; + flags |= MAGIC_DEBUG; break; case 'f': - if (!app) { - ret = apprentice(magicfile, action); - if (action) - exit(ret); - app = 1; - } + if(action) + usage(); + load(magicfile, flags); unwrap(optarg); ++didsomefiles; break; @@ -223,7 +218,7 @@ main(int argc, char **argv) separator = *optarg; break; case 'i': - iflag++; + flags |= MAGIC_MIME; if ((mime = malloc(strlen(magicfile) + 6)) != NULL) { (void)strcpy(mime, magicfile); (void)strcat(mime, ".mime"); @@ -243,7 +238,7 @@ main(int argc, char **argv) ++nopad; break; case 's': - sflag++; + flags |= MAGIC_DEVICES; break; case 'v': (void) fprintf(stdout, "%s-%d.%d\n", progname, @@ -252,11 +247,11 @@ main(int argc, char **argv) magicfile); return 1; case 'z': - zflag++; + flags |= MAGIC_COMPRESS; break; #ifdef S_IFLNK case 'L': - ++lflag; + flags |= MAGIC_SYMLINK; break; #endif case '?': @@ -269,11 +264,20 @@ main(int argc, char **argv) usage(); } - if (!app) { - ret = apprentice(magicfile, action); - if (action) - exit(ret); - app = 1; + switch(action) { + case CHECK: + case COMPILE: + magic = magic_open(flags); + if (magic == NULL) { + (void)fprintf(stderr, "%s: %s\n", progname, + strerror(errno)); + return 1; + } + return action == CHECK ? magic_check(magic, magicfile) : + magic_compile(magic, magicfile); + default: + load(magicfile, flags); + break; } if (optind == argc) { @@ -296,10 +300,27 @@ main(int argc, char **argv) } +private void +load(const char *m, int flags) +{ + if (magic) + 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); + } +} + /* * unwrap -- read a file of filenames, do each one. */ -static void +private void unwrap(char *fn) { char buf[MAXPATHLEN]; @@ -311,8 +332,9 @@ unwrap(char *fn) wid = 1; } else { if ((f = fopen(fn, "r")) == NULL) { - error("Cannot open `%s' (%s).\n", fn, strerror(errno)); - /*NOTREACHED*/ + (void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n", + progname, fn, strerror(errno)); + exit(1); } while (fgets(buf, MAXPATHLEN, f) != NULL) { @@ -334,6 +356,22 @@ unwrap(char *fn) (void) fclose(f); } +private void +process(const char *inname, int wid) +{ + const char *type; + + if (wid > 0 && !bflag) + (void) printf("%s%c%*s ", inname, separator, + (int) (nopad ? 0 : (wid - strlen(inname))), ""); + + type = magic_file(magic, inname); + if (type == NULL) + printf("ERROR: %s\n", magic_error(magic)); + else + printf("%s\n", type); +} + #if 0 /* @@ -343,7 +381,7 @@ unwrap(char *fn) * same whether to perform byte swapping * big_endian whether we are a big endian host */ -static int +private int byteconv4(int from, int same, int big_endian) { if (same) @@ -370,7 +408,7 @@ byteconv4(int from, int same, int big_endian) * byteconv2 * Same as byteconv4, but for shorts */ -static short +private short byteconv2(int from, int same, int big_endian) { if (same) @@ -392,156 +430,19 @@ byteconv2(int from, int same, int big_endian) } #endif -/* - * process - process input file - */ -void -process(const char *inname, int wid) -{ - int fd = 0; - static const char stdname[] = "standard input"; - unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */ - struct stat sb; - int nbytes = 0; /* number of bytes read from a datafile */ - char match = '\0'; - - if (strcmp("-", inname) == 0) { - if (fstat(0, &sb)<0) { - error("cannot fstat `%s' (%s).\n", stdname, - strerror(errno)); - /*NOTREACHED*/ - } - inname = stdname; - } - - if (wid > 0 && !bflag) - (void) printf("%s%c%*s", inname, separator, - (int) (nopad ? 0 : 1 + (wid - strlen(inname))), ""); - - if (inname != stdname) { - /* - * first try judging the file based on its filesystem status - */ - if (fsmagic(inname, &sb) != 0) { - putchar('\n'); - return; - } - - if ((fd = open(inname, O_RDONLY)) < 0) { - /* We can't open it, but we were able to stat it. */ - if (sb.st_mode & 0002) ckfputs("writable, ", stdout); - if (sb.st_mode & 0111) ckfputs("executable, ", stdout); - ckfprintf(stdout, "can't read `%s' (%s).\n", - inname, strerror(errno)); - return; - } - } - - - /* - * try looking at the first HOWMANY bytes - */ - if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) { - error("read failed (%s).\n", strerror(errno)); - /*NOTREACHED*/ - } - - if (nbytes == 0) - ckfputs(iflag ? "application/x-empty" : "empty", stdout); - else { - buf[nbytes++] = '\0'; /* null-terminate it */ - match = tryit(inname, buf, nbytes, zflag); - } - -#ifdef BUILTIN_ELF - if (match == 's' && nbytes > 5) { - /* - * 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 can't easily be extracted - * with rules in the magic file. - */ - tryelf(fd, buf, nbytes); - } -#endif - - if (inname != stdname) { -#ifdef RESTORE_TIME - /* - * 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 USE_UTIMES - struct timeval utsbuf[2]; - utsbuf[0].tv_sec = sb.st_atime; - utsbuf[1].tv_sec = sb.st_mtime; - - (void) utimes(inname, utsbuf); /* don't care if loses */ -# else - struct utimbuf utbuf; - - utbuf.actime = sb.st_atime; - utbuf.modtime = sb.st_mtime; - (void) utime(inname, &utbuf); /* don't care if loses */ -# endif -#endif - (void) close(fd); - } - (void) putchar('\n'); -} - - -int -tryit(const char *fn, unsigned char *buf, int nb, int zfl) -{ - - /* - * The main work is done here! - * We have the file name and/or the data buffer to be identified. - */ - -#ifdef __EMX__ - /* - * Ok, here's the right place to add a call to some os-specific - * routine, e.g. - */ - if (os2_apptype(fn, buf, nb) == 1) - return 'o'; -#endif - /* try compression stuff */ - if (zfl && zmagic(fn, buf, nb)) - return 'z'; - - /* try tests in /etc/magic (or surrogate magic file) */ - if (softmagic(buf, nb)) - return 's'; - - /* try known keywords, check whether it is ASCII */ - if (ascmagic(buf, nb)) - return 'a'; - - /* abandon hope, all ye who remain here */ - ckfputs(iflag ? "application/octet-stream" : "data", stdout); - return '\0'; -} - -static void +private void usage(void) { (void)fprintf(stderr, USAGE, progname); (void)fprintf(stderr, "Usage: %s -C [-m magic]\n", progname); -#ifdef HAVE_GETOPT_LONG +#ifdef HAVE_GETOPT_H (void)fputs("Try `file --help' for more information.\n", stderr); #endif exit(1); } -#ifdef HAVE_GETOPT_LONG -static void +#ifdef HAVE_GETOPT_H +private void help(void) { puts( @@ -556,10 +457,12 @@ help(void) " conjunction with -m to debug a new magic file\n" " before installing it\n" " -f, --files-from FILE read the filenames to be examined from FILE\n" +" -F, --separator char use char as separator instead of `:'\n" " -i, --mime output mime type strings\n" " -k, --keep-going don't stop at the first match\n" " -L, --dereference causes symlinks to be followed\n" " -n, --no-buffer do not buffer output\n" +" -N, --no-pad do not pad output\n" " -s, --special-files treat special (block/char devices) files as\n" " ordinary ones\n" " --help display this help and exit\n" diff --git a/src/file.h b/src/file.h index 874beb9e..d1662d03 100644 --- a/src/file.h +++ b/src/file.h @@ -1,6 +1,6 @@ /* * file.h - definitions for file(1) program - * @(#)$Id: file.h,v 1.45 2003/02/08 18:33:53 christos Exp $ + * @(#)$Id: file.h,v 1.46 2003/03/23 04:06:05 christos Exp $ * * Copyright (c) Ian F. Darwin, 1987. * Written by Ian F. Darwin. @@ -39,16 +39,24 @@ #include #endif +#include /* Include that here, to make sure __P gets defined */ #include -#include #ifdef HAVE_STDINT_H #include -#elif defined(HAVE_INTTYPES_H) +#endif +#ifdef HAVE_INTTYPES_H #include #endif /* Do this here and now, because struct stat gets re-defined on solaris */ #include + +#define private static +#ifndef protected +#define protected +#endif +#define public + #ifndef HOWMANY # define HOWMANY 65536 /* how much of the file to look at */ #endif @@ -131,48 +139,50 @@ struct magic { /* list of magic entries */ struct mlist { struct magic *magic; /* array of magic entries */ - uint32_t nmagic; /* number of entries in array */ + 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; }; -extern int apprentice(const char *, int); -extern int ascmagic(unsigned char *, int); -extern void error(const char *, ...); -extern void ckfputs(const char *, FILE *); +struct magic_set { + struct mlist *mlist; + struct cont { + size_t len; + int32_t *off; + } c; + struct out { + char *buf; + char *ptr; + size_t len; + size_t size; + } o; + int flags; + int haderr; +}; + struct stat; -extern int fsmagic(const char *, struct stat *); -extern char *fmttime(long, int); -extern int is_compress(const unsigned char *, int *); -extern int is_tar(unsigned char *, int); -extern void magwarn(const char *, ...); -extern void mdump(struct magic *); -extern void process(const char *, int); -extern void showstr(FILE *, const char *, int); -extern int softmagic(unsigned char *, int); -extern int tryit(const char *, unsigned char *, int, int); -extern int zmagic(const char *, unsigned char *, int); -extern void ckfprintf(FILE *, const char *, ...); -extern uint32_t signextend(struct magic *, unsigned int32); -extern void tryelf(int, unsigned char *, int); -extern int pipe2file(int, void *, size_t); - - -extern char *progname; /* the program name */ -extern const char *magicfile; /* name of the magic file */ -extern int lineno; /* current line number in magic file */ - -extern struct mlist mlist; /* list of arrays of magic entries */ - -extern int debug; /* enable debugging? */ -extern int zflag; /* process compressed files? */ -extern int lflag; /* follow symbolic links? */ -extern int sflag; /* read/analyze block special files? */ -extern int iflag; /* Output types as mime-types */ - -#ifdef NEED_GETOPT -extern int optind; /* From getopt(3) */ -extern char *optarg; -#endif +protected char *file_fmttime(long, int); +protected int file_buf(struct magic_set *, const void *buf, 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 *, const unsigned char *, size_t); +protected int file_ascmagic(struct magic_set *, const unsigned char *, size_t); +protected int file_is_tar(const unsigned char *, size_t); +protected int file_softmagic(struct magic_set *, const unsigned char *, size_t); +protected struct mlist *file_apprentice(struct magic_set *, const char *, int); +protected uint32_t file_signextend(struct magic_set *, struct magic *, uint32_t); +protected void file_badread(struct magic_set *); +protected void file_badseek(struct magic_set *); +protected void file_oomem(struct magic_set *); +protected void file_error(struct magic_set *, const char *, ...); +protected void file_magwarn(const char *, ...); +protected void file_mdump(struct magic *); +protected void file_showstr(FILE *, const char *, int); #ifndef HAVE_STRERROR extern int sys_nerr; @@ -193,5 +203,6 @@ extern char *sys_errlist[]; static const char *rcsid(const char *p) { \ return rcsid(p = id); \ } +#else #endif /* __file_h__ */ diff --git a/src/fsmagic.c b/src/fsmagic.c index fc6a29b2..63c43e82 100644 --- a/src/fsmagic.c +++ b/src/fsmagic.c @@ -26,11 +26,13 @@ */ #include "file.h" +#include "magic.h" #include #ifdef HAVE_UNISTD_H #include #endif #include +#include /* Since major is a function on SVR4, we can't use `ifndef major'. */ #ifdef MAJOR_IN_MKDEV # include @@ -51,11 +53,11 @@ #undef HAVE_MAJOR #ifndef lint -FILE_RCSID("@(#)$Id: fsmagic.c,v 1.36 2002/07/03 19:00:41 christos Exp $") +FILE_RCSID("@(#)$Id: fsmagic.c,v 1.37 2003/03/23 04:06:05 christos Exp $") #endif /* lint */ -int -fsmagic(const char *fn, struct stat *sb) +protected int +file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) { int ret = 0; @@ -64,41 +66,49 @@ fsmagic(const char *fn, struct stat *sb) * On 4.2BSD and similar systems, use lstat() to identify symlinks. */ #ifdef S_IFLNK - if (!lflag) + 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) { - ckfprintf(stdout, - /* Yes, I do mean stdout. */ - /* No \n, caller will provide. */ - "can't stat `%s' (%s).", fn, strerror(errno)); + if (file_printf(ms, "can't stat `%s' (%s)", + fn, strerror(errno)) == -1) + return -1; return 1; } - if (iflag) { + if ((ms->flags & MAGIC_MIME) != 0) { if ((sb->st_mode & S_IFMT) != S_IFREG) { - ckfputs("application/x-not-regular-file", stdout); + if (file_printf(ms, "application/x-not-regular-file") + == -1) + return -1; return 1; } } else { #ifdef S_ISUID - if (sb->st_mode & S_ISUID) ckfputs("setuid ", stdout); + if (sb->st_mode & S_ISUID) + if (file_printf(ms, "setuid ") == -1) + return -1; #endif #ifdef S_ISGID - if (sb->st_mode & S_ISGID) ckfputs("setgid ", stdout); + if (sb->st_mode & S_ISGID) + if (file_printf(ms, "setgid ") == -1) + return -1; #endif #ifdef S_ISVTX - if (sb->st_mode & S_ISVTX) ckfputs("sticky ", stdout); + if (sb->st_mode & S_ISVTX) + if (file_printf(ms, "sticky ") == -1) + return -1; #endif } switch (sb->st_mode & S_IFMT) { case S_IFDIR: - ckfputs("directory", stdout); + if (file_printf(ms, "directory") == -1) + return -1; return 1; #ifdef S_IFCHR case S_IFCHR: @@ -107,20 +117,22 @@ fsmagic(const char *fn, struct stat *sb) * like ordinary files. Otherwise, just report that they * are block special files and go on to the next file. */ - if (sflag) + if ((ms->flags & MAGIC_DEVICES) != 0) break; #ifdef HAVE_ST_RDEV # ifdef dv_unit - (void) printf("character special (%d/%d/%d)", - major(sb->st_rdev), - dv_unit(sb->st_rdev), - dv_subunit(sb->st_rdev)); + 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 - (void) printf("character special (%ld/%ld)", - (long) major(sb->st_rdev), (long) minor(sb->st_rdev)); + if (file_printf(ms, "character special (%ld/%ld)", + (long) major(sb->st_rdev), (long) minor(sb->st_rdev)) == -1) + return -1; # endif #else - (void) printf("character special"); + if (file_printf(ms, "character special") == -1) + return -1; #endif return 1; #endif @@ -131,32 +143,36 @@ fsmagic(const char *fn, struct stat *sb) * like ordinary files. Otherwise, just report that they * are block special files and go on to the next file. */ - if (sflag) + if ((ms->flags & MAGIC_DEVICES) != 0) break; #ifdef HAVE_ST_RDEV # ifdef dv_unit - (void) printf("block special (%d/%d/%d)", - major(sb->st_rdev), - dv_unit(sb->st_rdev), - dv_subunit(sb->st_rdev)); + 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 - (void) printf("block special (%ld/%ld)", - (long) major(sb->st_rdev), (long) minor(sb->st_rdev)); + if (file_printf(ms, "block special (%ld/%ld)", + (long)major(sb->st_rdev), (long)minor(sb->st_rdev)) == -1) + return -1; # endif #else - (void) printf("block special"); + 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: - ckfputs("fifo (named pipe)", stdout); + if (file_printf(ms, "fifo (named pipe)") == -1) + return -1; return 1; #endif #ifdef S_IFDOOR case S_IFDOOR: - ckfputs("door", stdout); + if (file_printf(ms, "door") == -1) + return -1; return 1; #endif #ifdef S_IFLNK @@ -167,8 +183,10 @@ fsmagic(const char *fn, struct stat *sb) struct stat tstatbuf; if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) { - ckfprintf(stdout, "unreadable symlink (%s).", - strerror(errno)); + if (file_printf(ms, + "unreadable symlink `%s' (%s)", + strerror(errno)) == -1) + return -1; return 1; } buf[nch] = '\0'; /* readlink(2) forgets this */ @@ -176,8 +194,9 @@ fsmagic(const char *fn, struct stat *sb) /* If broken symlink, say so and quit early. */ if (*buf == '/') { if (stat(buf, &tstatbuf) < 0) { - ckfprintf(stdout, - "broken symbolic link to %s", buf); + if (file_printf(ms, + "broken symbolic link to `%s'", buf) == -1) + return -1; return 1; } } @@ -189,25 +208,31 @@ fsmagic(const char *fn, struct stat *sb) tmp = buf; /* in current directory anyway */ } else { - strcpy (buf2, fn); /* take directory part */ + strcpy(buf2, fn); /* take directory part */ buf2[tmp-fn+1] = '\0'; - strcat (buf2, buf); /* plus (relative) symlink */ + strcat(buf2, buf); /* plus (relative) symlink */ tmp = buf2; } if (stat(tmp, &tstatbuf) < 0) { - ckfprintf(stdout, - "broken symbolic link to %s", buf); + if (file_printf(ms, + "broken symbolic link to `%s'", + buf) == -1) + return -1; return 1; } } /* Otherwise, handle it. */ - if (lflag) { - process(buf, strlen(buf)); - return 1; + 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 */ - ckfputs("symbolic link to ", stdout); - ckfputs(buf, stdout); + if (file_printf(ms, "symbolic link to `%s'", + buf) == -1) + return -1; } } return 1; @@ -215,14 +240,16 @@ fsmagic(const char *fn, struct stat *sb) #ifdef S_IFSOCK #ifndef __COHERENT__ case S_IFSOCK: - ckfputs("socket", stdout); + if (file_printf(ms, "socket") == -1) + return -1; return 1; #endif #endif case S_IFREG: break; default: - error("invalid mode 0%o.\n", sb->st_mode); + file_error(ms, "invalid mode 0%o", sb->st_mode); + return -1; /*NOTREACHED*/ } @@ -238,8 +265,10 @@ fsmagic(const char *fn, struct stat *sb) * the fact that it is empty will be detected and reported correctly * when we read the file.) */ - if (!sflag && sb->st_size == 0) { - ckfputs(iflag ? "application/x-empty" : "empty", stdout); + if ((ms->flags & MAGIC_DEVICES) == 0 && sb->st_size == 0) { + if (file_printf(ms, (ms->flags & MAGIC_MIME) ? + "application/x-empty" : "empty") == -1) + return -1; return 1; } return 0; diff --git a/src/is_tar.c b/src/is_tar.c index de7a1691..e19b7f6c 100644 --- a/src/is_tar.c +++ b/src/is_tar.c @@ -5,7 +5,7 @@ * Public Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu). * * @(#)list.c 1.18 9/23/86 Public Domain - gnu - * $Id: is_tar.c,v 1.17 2002/07/03 18:26:38 christos Exp $ + * $Id: is_tar.c,v 1.18 2003/03/23 04:06:05 christos Exp $ * * Comments changed and some code/comments reformatted * for file command by Ian Darwin. @@ -18,12 +18,12 @@ #include "tar.h" #ifndef lint -FILE_RCSID("@(#)$Id: is_tar.c,v 1.17 2002/07/03 18:26:38 christos Exp $") +FILE_RCSID("@(#)$Id: is_tar.c,v 1.18 2003/03/23 04:06:05 christos Exp $") #endif #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') ) -static int from_oct(int, char *); /* Decode octal number */ +private int from_oct(int, char *); /* Decode octal number */ /* * Return @@ -31,8 +31,8 @@ static int from_oct(int, char *); /* Decode octal number */ * 1 for old UNIX tar file, * 2 for Unix Std (POSIX) tar file. */ -int -is_tar(unsigned char *buf, int nbytes) +protected int +file_is_tar(const unsigned char *buf, size_t nbytes) { union record *header = (union record *)buf; int i; @@ -74,7 +74,7 @@ is_tar(unsigned char *buf, int nbytes) * * Result is -1 if the field is invalid (all blank, or nonoctal). */ -static int +private int from_oct(int digs, char *where) { int value; diff --git a/src/names.h b/src/names.h index ea4e85cc..6c5ea53d 100644 --- a/src/names.h +++ b/src/names.h @@ -10,7 +10,7 @@ * * See LEGAL.NOTICE * - * $Id: names.h,v 1.19 2002/05/16 15:01:41 christos Exp $ + * $Id: names.h,v 1.20 2003/03/23 04:06:05 christos Exp $ */ /* @@ -35,8 +35,8 @@ #define L_M4 13 /* M4 */ static const struct { - char *human; - char *mime; + const char *human; + const char *mime; } types[] = { { "C program", "text/x-c", }, { "C++ program", "text/x-c++" }, diff --git a/src/patchlevel.h b/src/patchlevel.h index bec30674..065c3c5f 100644 --- a/src/patchlevel.h +++ b/src/patchlevel.h @@ -1,30 +1,16 @@ #define FILE_VERSION_MAJOR 3 -#define patchlevel 41 +#define patchlevel 38 /* * Patchlevel file for Ian Darwin's MAGIC command. - * $Id: patchlevel.h,v 1.41 2003/02/27 20:53:45 christos Exp $ + * $Id: patchlevel.h,v 1.42 2003/03/23 04:06:05 christos Exp $ * * $Log: patchlevel.h,v $ - * 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 ) - * - eliminate unsigned char warnings (Petter Reinholdtsen ) - * - better elf PT_NOTE handling (Nalin Dahyabhai ) - * - add options to format the output differently - * - much more magic. + * Revision 1.42 2003/03/23 04:06:05 christos + * reorg * - * 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.1.1.1 2003/02/07 18:50:31 mru + * Initial librarification. * * Revision 1.38 2002/05/16 18:45:56 christos * - pt_note elf additions from NetBSD @@ -244,3 +230,4 @@ * Fix a tiny null-pointer bug in previous fix for tar archive + uncompress. * */ + diff --git a/src/print.c b/src/print.c index 0b1a0e4c..bf4c42e2 100644 --- a/src/print.c +++ b/src/print.c @@ -26,6 +26,8 @@ */ #include "file.h" +#include +#include #include #include #include @@ -35,21 +37,21 @@ #include #ifndef lint -FILE_RCSID("@(#)$Id: print.c,v 1.39 2002/07/09 15:46:23 christos Exp $") +FILE_RCSID("@(#)$Id: print.c,v 1.40 2003/03/23 04:06:05 christos Exp $") #endif /* lint */ #define SZOF(a) (sizeof(a) / sizeof(a[0])) #ifndef COMPILE_ONLY -void -mdump(struct magic *m) +protected void +file_mdump(struct magic *m) { - static const char *typ[] = { "invalid", "byte", "short", "invalid", + private const char *typ[] = { "invalid", "byte", "short", "invalid", "long", "string", "date", "beshort", "belong", "bedate", "leshort", "lelong", "ledate", "pstring", "ldate", "beldate", "leldate", "regex" }; - static const char optyp[] = { '@', '&', '|', '^', '+', '-', + private const char optyp[] = { '@', '&', '|', '^', '+', '-', '*', '/', '%' }; (void) fputc('[', stderr); (void) fprintf(stderr, ">>>>>>>> %d" + 8 - (m->cont_level & 7), @@ -105,17 +107,19 @@ mdump(struct magic *m) case STRING: case PSTRING: case REGEX: - showstr(stderr, m->value.s, -1); + file_showstr(stderr, m->value.s, -1); break; case DATE: case LEDATE: case BEDATE: - (void)fprintf(stderr, "%s,", fmttime(m->value.l, 1)); + (void)fprintf(stderr, "%s,", + file_fmttime(m->value.l, 1)); break; case LDATE: case LELDATE: case BELDATE: - (void)fprintf(stderr, "%s,", fmttime(m->value.l, 0)); + (void)fprintf(stderr, "%s,", + file_fmttime(m->value.l, 0)); break; default: (void) fputs("*bad*", stderr); @@ -126,72 +130,23 @@ mdump(struct magic *m) } #endif -/* - * ckfputs - fputs, but with error checking - * ckfprintf - fprintf, but with error checking - */ -void -ckfputs(const char *str, FILE *fil) -{ - if (fputs(str,fil) == EOF) - error("write failed.\n"); -} - /*VARARGS*/ -void -ckfprintf(FILE *f, const char *fmt, ...) +protected void +file_magwarn(const char *f, ...) { va_list va; - - va_start(va, fmt); - (void) vfprintf(f, fmt, va); - if (ferror(f)) - error("write failed.\n"); - va_end(va); -} - -/* - * error - print best error message possible and exit - */ -/*VARARGS*/ -void -error(const char *f, ...) -{ - va_list va; - va_start(va, f); - /* cuz we use stdout for most, stderr here */ - (void) fflush(stdout); - - if (progname != NULL) - (void) fprintf(stderr, "%s: ", progname); - (void) vfprintf(stderr, f, va); - va_end(va); - exit(1); -} - -/*VARARGS*/ -void -magwarn(const char *f, ...) -{ - va_list va; - va_start(va, f); /* cuz we use stdout for most, stderr here */ (void) fflush(stdout); - if (progname != NULL) - (void) fprintf(stderr, "%s: %s, %d: ", - progname, magicfile, lineno); (void) vfprintf(stderr, f, va); va_end(va); fputc('\n', stderr); } - -#ifndef COMPILE_ONLY -char * -fmttime(long v, int local) +protected char * +file_fmttime(long v, int local) { char *pp, *rt; time_t t = (time_t)v; @@ -201,9 +156,9 @@ fmttime(long v, int local) pp = ctime(&t); } else { #ifndef HAVE_DAYLIGHT - static int daylight = 0; + private int daylight = 0; #ifdef HAVE_TM_ISDST - static time_t now = (time_t)0; + private time_t now = (time_t)0; if (now == (time_t)0) { struct tm *tm1; @@ -223,4 +178,3 @@ fmttime(long v, int local) *rt = '\0'; return pp; } -#endif diff --git a/src/readelf.c b/src/readelf.c index 67dff14c..12eeee71 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -11,23 +11,24 @@ #include "readelf.h" #ifndef lint -FILE_RCSID("@(#)$Id: readelf.c,v 1.28 2003/03/18 19:20:24 christos Exp $") +FILE_RCSID("@(#)$Id: readelf.c,v 1.29 2003/03/23 04:06:05 christos Exp $") #endif #ifdef ELFCORE -static void dophn_core(int, int, int, off_t, int, size_t); +private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t); #endif -static void dophn_exec(int, int, int, off_t, int, size_t); -static void doshn(int, int, int, off_t, int, size_t); -static size_t donote(unsigned char *, size_t, size_t, int, int, int); +private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t); +private int doshn(struct magic_set *, int, int, int, off_t, int, size_t); +private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int, + int, int); #define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) -static uint16_t getu16(int, uint16_t); -static uint32_t getu32(int, uint32_t); -static uint64_t getu64(int, uint64_t); +private uint16_t getu16(int, uint16_t); +private uint32_t getu32(int, uint32_t); +private uint64_t getu64(int, uint64_t); -static uint16_t +private uint16_t getu16(int swap, uint16_t value) { union { @@ -46,7 +47,7 @@ getu16(int swap, uint16_t value) return value; } -static uint32_t +private uint32_t getu32(int swap, uint32_t value) { union { @@ -67,7 +68,7 @@ getu32(int swap, uint32_t value) return value; } -static uint64_t +private uint64_t getu64(int swap, uint64_t value) { union { @@ -174,36 +175,38 @@ size_t prpsoffsets64[] = { #define OS_STYLE_FREEBSD 1 #define OS_STYLE_NETBSD 2 -static const char *os_style_names[] = { +private const char *os_style_names[] = { "SVR4", "FreeBSD", "NetBSD", }; -static void -dophn_core(int class, int swap, int fd, off_t off, int num, size_t size) +private int +dophn_core(struct magic_set *ms, int class, int swap, int fd, off_t off, + int num, size_t size) { Elf32_Phdr ph32; - Elf32_Nhdr *nh32 = NULL; Elf64_Phdr ph64; - Elf64_Nhdr *nh64 = NULL; - size_t offset, noffset, reloffset; - unsigned char c; - int i, j; + size_t offset; char nbuf[BUFSIZ]; int bufsize; - int os_style = -1; - if (size != ph_size) - error("corrupted program header size.\n"); + if (size != ph_size) { + file_error(ms, "Corrupted program header size"); + return -1; + } /* * Loop through all the program headers. */ for ( ; num; num--) { - if (lseek(fd, off, SEEK_SET) == -1) - error("lseek failed (%s).\n", strerror(errno)); - if (read(fd, ph_addr, ph_size) == -1) - error("read failed (%s).\n", strerror(errno)); + if (lseek(fd, off, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } + if (read(fd, ph_addr, ph_size) == -1) { + file_badread(ms); + return -1; + } off += size; if (ph_type != PT_NOTE) continue; @@ -212,24 +215,31 @@ dophn_core(int class, int swap, int fd, off_t off, int num, size_t size) * This is a PT_NOTE section; loop through all the notes * in the section. */ - if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1) - error("lseek failed (%s).\n", strerror(errno)); + if (lseek(fd, (off_t) ph_offset, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } bufsize = read(fd, nbuf, BUFSIZ); - if (bufsize == -1) - error(": " "read failed (%s).\n", strerror(errno)); + if (bufsize == -1) { + file_badread(ms); + return -1; + } offset = 0; for (;;) { if (offset >= bufsize) break; - offset = donote(nbuf, offset, bufsize, class, swap, 4); + offset = donote(ms, nbuf, offset, bufsize, class, swap, + 4); + } } + return 0; } #endif -static size_t -donote(unsigned char *nbuf, size_t offset, size_t size, int class, int swap, - int align) +private size_t +donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, + int class, int swap, int align) { Elf32_Nhdr *nh32 = NULL; Elf64_Nhdr *nh64 = NULL; @@ -269,22 +279,28 @@ donote(unsigned char *nbuf, size_t offset, size_t size, int class, int swap, nh_type == NT_GNU_VERSION && nh_descsz == 16) { uint32_t *desc = (uint32_t *)&nbuf[doff]; - printf(", for GNU/"); + if (file_printf(ms, ", for GNU/") == -1) + return -1; switch (getu32(swap, desc[0])) { case GNU_OS_LINUX: - printf("Linux"); + if (file_printf(ms, "Linux") == -1) + return -1; break; case GNU_OS_HURD: - printf("Hurd"); + if (file_printf(ms, "Hurd") == -1) + return -1; break; case GNU_OS_SOLARIS: - printf("Solaris"); + if (file_printf(ms, "Solaris") == -1) + return -1; break; default: - printf(""); + if (file_printf(ms, "") == -1) + return -1; } - printf(" %d.%d.%d", getu32(swap, desc[1]), - getu32(swap, desc[2]), getu32(swap, desc[3])); + if (file_printf(ms, " %d.%d.%d", getu32(swap, desc[1]), + getu32(swap, desc[2]), getu32(swap, desc[3])) == -1) + return -1; return size; } @@ -292,7 +308,8 @@ donote(unsigned char *nbuf, size_t offset, size_t size, int class, int swap, nh_type == NT_NETBSD_VERSION && nh_descsz == 4) { uint32_t desc = getu32(swap, *(uint32_t *)&nbuf[doff]); - printf(", for NetBSD"); + if (file_printf(ms, ", for NetBSD") == -1) + return -1; /* * The version number used to be stuck as 199905, and was thus * basically content-free. Newer versions of NetBSD have fixed @@ -311,15 +328,20 @@ donote(unsigned char *nbuf, size_t offset, size_t size, int class, int swap, u_int ver_min = (desc / 1000000) % 100; u_int ver_maj = desc / 100000000; - printf(" %u.%u", ver_maj, ver_min); + if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) + return -1; if (ver_rel == 0 && ver_patch != 0) { - printf(".%u", ver_patch); + if (file_printf(ms, ".%u", ver_patch) == -1) + return -1; } else if (ver_rel != 0 && ver_rel <= 26) { - printf("%c", 'A' + ver_rel - 1); + if (file_printf(ms, "%c", 'A' + ver_rel - 1) == -1) + return -1; } else if (ver_rel != 0 && ver_rel <= 52) { - printf("Z%c", 'A' + ver_rel - 1); + if (file_printf(ms, "Z%c", 'A' + ver_rel - 1) == -1) + return -1; } else if (ver_rel != 0) { - printf(""); + if (file_printf(ms, "") == -1) + return -1; } } return size; @@ -329,22 +351,26 @@ donote(unsigned char *nbuf, size_t offset, size_t size, int class, int swap, nh_type == NT_FREEBSD_VERSION && nh_descsz == 4) { uint32_t desc = getu32(swap, *(uint32_t *)&nbuf[doff]); - printf(", for FreeBSD"); + if (file_printf(ms, ", for FreeBSD") == -1) + return -1; /* * Contents is __FreeBSD_version, whose relation to OS versions * is defined by a huge table in the Porters' Handbook. Happily, * the first three digits are the version number, at least in * versions of FreeBSD that use this note. */ - printf(" %d.%d", desc / 100000, desc / 10000 % 10); + if (file_printf(ms, " %d.%d", desc / 100000, desc / 10000 % 10) == -1) + return -1; if (desc / 1000 % 10 > 0) - printf(".%d", desc / 1000 % 10); + if (file_printf(ms, ".%d", desc / 1000 % 10) == -1) + return -1; return size; } if (nh_namesz == 8 && strcmp(&nbuf[noff], "OpenBSD") == 0 && nh_type == NT_OPENBSD_VERSION && nh_descsz == 4) { - printf(", for OpenBSD"); + if (file_printf(ms, ", for OpenBSD") == -1) + return -1; /* Content of note is always 0 */ return size; } @@ -378,7 +404,8 @@ donote(unsigned char *nbuf, size_t offset, size_t size, int class, int swap, #ifdef ELFCORE if (os_style != -1) - printf(", %s-style", os_style_names[os_style]); + if (file_printf(ms, ", %s-style", os_style_names[os_style]) == -1) + return -1; if (os_style == OS_STYLE_NETBSD && nh_type == NT_NETBSD_CORE_PROCINFO) { uint32_t signo; @@ -387,7 +414,8 @@ donote(unsigned char *nbuf, size_t offset, size_t size, int class, int swap, * offset 0x7c, and is up to 32-bytes, * including the terminating NUL. */ - printf(", from '%.31s'", &nbuf[doff + 0x7c]); + if (file_printf(ms, ", from '%.31s'", &nbuf[doff + 0x7c]) == -1) + return -1; /* * Extract the signal number. It is at @@ -395,7 +423,8 @@ donote(unsigned char *nbuf, size_t offset, size_t size, int class, int swap, */ memcpy(&signo, &nbuf[doff + 0x08], sizeof(signo)); - printf(" (signal %u)", getu32(swap, signo)); + if (file_printf(ms, " (signal %u)", getu32(swap, signo)) == -1) + return -1; return size; } else if (os_style != OS_STYLE_NETBSD && nh_type == NT_PRPSINFO) { int i, j; @@ -459,8 +488,9 @@ donote(unsigned char *nbuf, size_t offset, size_t size, int class, int swap, /* * Well, that worked. */ - printf(", from '%.16s'", - &nbuf[doff + prpsoffsets(i)]); + if (file_printf(ms, ", from '%.16s'", + &nbuf[doff + prpsoffsets(i)]) == -1) + return -1; return size; tryanother: @@ -472,27 +502,37 @@ donote(unsigned char *nbuf, size_t offset, size_t size, int class, int swap, return offset; } -static void -doshn(int class, int swap, int fd, off_t off, int num, size_t size) +private int +doshn(struct magic_set *ms, int class, int swap, int fd, off_t off, int num, + size_t size) { Elf32_Shdr sh32; Elf64_Shdr sh64; - if (size != sh_size) - error("corrupted section header size.\n"); + if (size != sh_size) { + file_error(ms, "Corrupted section header size"); + return -1; + } - if (lseek(fd, off, SEEK_SET) == -1) - error("lseek failed (%s).\n", strerror(errno)); + if (lseek(fd, off, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } for ( ; num; num--) { - if (read(fd, sh_addr, sh_size) == -1) - error("read failed (%s).\n", strerror(errno)); + if (read(fd, sh_addr, sh_size) == -1) { + file_badread(ms); + return -1; + } if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) { - (void) printf (", not stripped"); - return; + if (file_printf(ms, ", not stripped") == -1) + return -1; + return 0; } } - (void) printf (", stripped"); + if (file_printf(ms, ", stripped") == -1) + return -1; + return 0; } /* @@ -500,28 +540,37 @@ doshn(int class, int swap, int fd, off_t off, int num, size_t size) * for a PT_INTERP section; if one is found, it's dynamically linked, * otherwise it's statically linked. */ -static void -dophn_exec(int class, int swap, int fd, off_t off, int num, size_t size) +private int +dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off, + int num, size_t size) { Elf32_Phdr ph32; Elf64_Phdr ph64; - char *linking_style = "statically"; - char *shared_libraries = ""; + const char *linking_style = "statically"; + const char *shared_libraries = ""; char nbuf[BUFSIZ]; int bufsize; size_t offset; off_t savedoffset; - if (size != ph_size) - error("corrupted program header size.\n"); - if (lseek(fd, off, SEEK_SET) == -1) - error("lseek failed (%s).\n", strerror(errno)); + if (size != ph_size) { + file_error(ms, "Corrupted program header size"); + return -1; + } + if (lseek(fd, off, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } for ( ; num; num--) { - if (read(fd, ph_addr, ph_size) == -1) - error("read failed (%s).\n", strerror(errno)); - if ((savedoffset = lseek(fd, 0, SEEK_CUR)) == -1) - error("lseek failed (%s).\n", strerror(errno)); + if (read(fd, ph_addr, ph_size) == -1) { + file_badread(ms); + return -1; + } + if ((savedoffset = lseek(fd, 0, SEEK_CUR)) == (off_t)-1) { + file_badseek(ms); + return -1; + } switch (ph_type) { case PT_DYNAMIC: @@ -535,30 +584,41 @@ dophn_exec(int class, int swap, int fd, off_t off, int num, size_t size) * This is a PT_NOTE section; loop through all the notes * in the section. */ - if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1) - error("lseek failed (%s).\n", strerror(errno)); + if (lseek(fd, (off_t) ph_offset, SEEK_SET) + == (off_t)-1) { + file_badseek(ms); + return -1; + } bufsize = read(fd, nbuf, sizeof(nbuf)); - if (bufsize == -1) - error(": " "read failed (%s).\n", - strerror(errno)); + if (bufsize == -1) { + file_badread(ms); + return -1; + } offset = 0; for (;;) { if (offset >= bufsize) break; - offset = donote(nbuf, offset, bufsize, + offset = donote(ms, nbuf, offset, bufsize, class, swap, ph_align); } - if ((lseek(fd, savedoffset + offset, SEEK_SET)) == -1) - error("lseek failed (%s).\n", strerror(errno)); + if (lseek(fd, savedoffset + offset, SEEK_SET) + == (off_t)-1) { + file_badseek(ms); + return -1; + } break; } } - printf(", %s linked%s", linking_style, shared_libraries); + if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries) + == -1) + return -1; + return 0; } -void -tryelf(int fd, unsigned char *buf, int nbytes) +protected int +file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, + size_t nbytes) { union { int32_t l; @@ -571,7 +631,7 @@ tryelf(int fd, unsigned char *buf, int nbytes) * If we can't seek, it must be a pipe, socket or fifo. */ if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) - fd = pipe2file(fd, buf, nbytes); + fd = file_pipe2file(ms, fd, buf, nbytes); /* * ELF executables have multiple section headers in arbitrary @@ -582,7 +642,7 @@ tryelf(int fd, unsigned char *buf, int nbytes) if (buf[EI_MAG0] != ELFMAG0 || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) - return; + return 0; class = buf[4]; @@ -590,88 +650,88 @@ tryelf(int fd, unsigned char *buf, int nbytes) if (class == ELFCLASS32) { Elf32_Ehdr elfhdr; if (nbytes <= sizeof (Elf32_Ehdr)) - return; + return 0; u.l = 1; (void) memcpy(&elfhdr, buf, sizeof elfhdr); swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; - if (getu16(swap, elfhdr.e_type) == ET_CORE) + if (getu16(swap, elfhdr.e_type) == ET_CORE) { #ifdef ELFCORE - dophn_core(class, swap, - fd, - getu32(swap, elfhdr.e_phoff), - getu16(swap, elfhdr.e_phnum), - getu16(swap, elfhdr.e_phentsize)); + if (dophn_core(ms, class, swap, fd, + getu32(swap, elfhdr.e_phoff), + getu16(swap, elfhdr.e_phnum), + getu16(swap, elfhdr.e_phentsize)) == -1) + return -1; #else ; #endif - else { + } else { if (getu16(swap, elfhdr.e_type) == ET_EXEC) { - dophn_exec(class, swap, - fd, - getu32(swap, elfhdr.e_phoff), - getu16(swap, elfhdr.e_phnum), - getu16(swap, elfhdr.e_phentsize)); + if (dophn_exec(ms, class, swap, + fd, getu32(swap, elfhdr.e_phoff), + getu16(swap, elfhdr.e_phnum), + getu16(swap, elfhdr.e_phentsize)) == -1) + return -1; } - doshn(class, swap, - fd, - getu32(swap, elfhdr.e_shoff), - getu16(swap, elfhdr.e_shnum), - getu16(swap, elfhdr.e_shentsize)); + if (doshn(ms, class, swap, fd, + getu32(swap, elfhdr.e_shoff), + getu16(swap, elfhdr.e_shnum), + getu16(swap, elfhdr.e_shentsize)) == -1) + return -1; } - return; + return 1; } if (class == ELFCLASS64) { Elf64_Ehdr elfhdr; if (nbytes <= sizeof (Elf64_Ehdr)) - return; + return 0; u.l = 1; (void) memcpy(&elfhdr, buf, sizeof elfhdr); swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; - if (getu16(swap, elfhdr.e_type) == ET_CORE) + if (getu16(swap, elfhdr.e_type) == ET_CORE) { #ifdef ELFCORE - dophn_core(class, swap, - fd, + if (dophn_core(ms, class, swap, fd, #ifdef USE_ARRAY_FOR_64BIT_TYPES - getu32(swap, elfhdr.e_phoff[1]), + getu32(swap, elfhdr.e_phoff[1]), #else - getu64(swap, elfhdr.e_phoff), + getu64(swap, elfhdr.e_phoff), #endif - getu16(swap, elfhdr.e_phnum), - getu16(swap, elfhdr.e_phentsize)); + getu16(swap, elfhdr.e_phnum), + getu16(swap, elfhdr.e_phentsize)) == -1) + return -1; #else ; #endif - else - { + } else { if (getu16(swap, elfhdr.e_type) == ET_EXEC) { - dophn_exec(class, swap, - fd, + if (dophn_exec(ms, class, swap, fd, #ifdef USE_ARRAY_FOR_64BIT_TYPES - getu32(swap, elfhdr.e_phoff[1]), + getu32(swap, elfhdr.e_phoff[1]), #else - getu64(swap, elfhdr.e_phoff), + getu64(swap, elfhdr.e_phoff), #endif - getu16(swap, elfhdr.e_phnum), - getu16(swap, elfhdr.e_phentsize)); + getu16(swap, elfhdr.e_phnum), + getu16(swap, elfhdr.e_phentsize)) == -1) + return -1; } - doshn(class, swap, - fd, + if (doshn(ms, class, swap, fd, #ifdef USE_ARRAY_FOR_64BIT_TYPES - getu32(swap, elfhdr.e_shoff[1]), + getu32(swap, elfhdr.e_shoff[1]), #else - getu64(swap, elfhdr.e_shoff), + getu64(swap, elfhdr.e_shoff), #endif - getu16(swap, elfhdr.e_shnum), - getu16(swap, elfhdr.e_shentsize)); + getu16(swap, elfhdr.e_shnum), + getu16(swap, elfhdr.e_shentsize)) == -1) + return -1; } - return; + return 1; } + return 0; } #endif diff --git a/src/readelf.h b/src/readelf.h index f7494de6..8d80a588 100644 --- a/src/readelf.h +++ b/src/readelf.h @@ -1,8 +1,6 @@ -/* $NetBSD: readelf.h,v 1.9 2002/05/18 07:00:47 pooka Exp $ */ - /* * readelf.h - * @(#)Id: readelf.h,v 1.9 2002/05/16 18:45:56 christos Exp + * @(#)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. diff --git a/src/softmagic.c b/src/softmagic.c index d1ef94dd..c1c9ca35 100644 --- a/src/softmagic.c +++ b/src/softmagic.c @@ -26,6 +26,7 @@ */ #include "file.h" +#include "magic.h" #include #include #include @@ -34,17 +35,18 @@ #ifndef lint -FILE_RCSID("@(#)$Id: softmagic.c,v 1.54 2003/02/25 13:04:32 christos Exp $") +FILE_RCSID("@(#)$Id: softmagic.c,v 1.55 2003/03/23 04:06:05 christos Exp $") #endif /* lint */ -static int match(struct magic *, uint32_t, unsigned char *, int); -static int mget(union VALUETYPE *, unsigned char *, struct magic *, int); -static int mcheck(union VALUETYPE *, struct magic *); -static int32_t mprint(union VALUETYPE *, struct magic *); -static void mdebug(int32_t, char *, int); -static int mconvert(union VALUETYPE *, struct magic *); - -extern int kflag; +private int match(struct magic_set *, struct magic *, uint32_t, + const unsigned char *, size_t); +private int mget(struct magic_set *, union VALUETYPE *, const unsigned char *, + struct magic *, size_t); +private int mcheck(struct magic_set *, union VALUETYPE *, struct magic *); +private int32_t mprint(struct magic_set *, union VALUETYPE *, struct magic *); +private void mdebug(int32_t, const char *, size_t); +private int mconvert(struct magic_set *, union VALUETYPE *, struct magic *); +private int check_mem(struct magic_set *, int); /* * softmagic - lookup one file in database @@ -52,13 +54,12 @@ extern int kflag; * Passed the name and FILE * of one file to be typed. */ /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */ -int -softmagic(unsigned char *buf, int nbytes) +protected int +file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes) { struct mlist *ml; - - for (ml = mlist.next; ml != &mlist; ml = ml->next) - if (match(ml->magic, ml->nmagic, buf, nbytes)) + for (ml = ms->mlist->next; ml != ms->mlist; ml = ml->next) + if (match(ms, ml->magic, ml->nmagic, buf, nbytes)) return 1; return 0; @@ -91,44 +92,52 @@ softmagic(unsigned char *buf, int nbytes) * If a continuation matches, we bump the current continuation level * so that higher-level continuations are processed. */ -static int -match(struct magic *magic, uint32_t nmagic, unsigned char *s, int nbytes) +private int +match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, + const unsigned char *s, size_t nbytes) { int magindex = 0; int cont_level = 0; int need_separator = 0; union VALUETYPE p; - static int32_t *tmpoff = NULL; - static size_t tmplen = 0; int32_t oldoff = 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 */ - if (tmpoff == NULL) - if ((tmpoff = (int32_t *) malloc( - (tmplen = 20) * sizeof(*tmpoff))) == NULL) - error("out of memory\n"); + if (check_mem(ms, cont_level) == -1) + return -1; for (magindex = 0; magindex < nmagic; magindex++) { /* if main entry matches, print it... */ - if (!mget(&p, s, &magic[magindex], nbytes) || - !mcheck(&p, &magic[magindex])) { - /* - * main entry didn't match, - * flush its continuations - */ - while (magindex < nmagic && - magic[magindex + 1].cont_level != 0) - magindex++; - continue; + int flush = !mget(ms, &p, s, &magic[magindex], nbytes); + switch (mcheck(ms, &p, &magic[magindex])) { + case -1: + return -1; + case 0: + flush++; + default: + break; + } + if (flush) { + /* + * main entry didn't match, + * flush its continuations + */ + while (magindex < nmagic && + magic[magindex + 1].cont_level != 0) + magindex++; + continue; } - if (! firstline) { /* we found another match */ + if (!firstline) { /* we found another match */ /* put a newline and '-' to do some simple formatting*/ - printf("\n- "); + if (file_printf(ms, "\n- ") == -1) + return -1; } - tmpoff[cont_level] = mprint(&p, &magic[magindex]); + if ((ms->c.off[cont_level] = mprint(ms, &p, &magic[magindex])) + == -1) + return -1; /* * If we printed something, we'll need to print * a blank before we print something else. @@ -136,75 +145,94 @@ match(struct magic *magic, uint32_t nmagic, unsigned char *s, int nbytes) if (magic[magindex].desc[0]) need_separator = 1; /* and any continuations that match */ - if (++cont_level >= tmplen) - if ((tmpoff = (int32_t *) realloc(tmpoff, - (tmplen += 20) * sizeof(*tmpoff))) == NULL) - error("out of memory\n"); + if (check_mem(ms, ++cont_level) == -1) + return -1; + while (magic[magindex+1].cont_level != 0 && ++magindex < nmagic) { - if (cont_level >= magic[magindex].cont_level) { - if (cont_level > magic[magindex].cont_level) { - /* - * We're at the end of the level - * "cont_level" continuations. - */ - cont_level = magic[magindex].cont_level; - } - if (magic[magindex].flag & OFFADD) { - oldoff=magic[magindex].offset; - magic[magindex].offset += - tmpoff[cont_level-1]; + if (cont_level < magic[magindex].cont_level) + continue; + if (cont_level > magic[magindex].cont_level) { + /* + * We're at the end of the level + * "cont_level" continuations. + */ + cont_level = magic[magindex].cont_level; + } + if (magic[magindex].flag & OFFADD) { + oldoff=magic[magindex].offset; + magic[magindex].offset += ms->c.off[cont_level-1]; + } + if (!mget(ms, &p, s, &magic[magindex], nbytes)) + goto done; + + switch (mcheck(ms, &p, &magic[magindex])) { + case -1: + return -1; + case 0: + break; + default: + /* + * 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 + && (magic[magindex].nospflag == 0) + && (magic[magindex].desc[0] != '\0')) { + if (file_printf(ms, " ") == -1) + return -1; + need_separator = 0; } - if (mget(&p, s, &magic[magindex], nbytes) && - mcheck(&p, &magic[magindex])) { - /* - * 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 - && (magic[magindex].nospflag == 0) - && (magic[magindex].desc[0] != '\0') - ) { - (void) putchar(' '); - need_separator = 0; - } - tmpoff[cont_level] = - mprint(&p, &magic[magindex]); - if (magic[magindex].desc[0]) - need_separator = 1; + if ((ms->c.off[cont_level] = mprint(ms, &p, + &magic[magindex])) == -1) + return -1; + if (magic[magindex].desc[0]) + need_separator = 1; - /* - * If we see any continuations - * at a higher level, - * process them. - */ - if (++cont_level >= tmplen) - if ((tmpoff = - (int32_t *) realloc(tmpoff, - (tmplen += 20) - * sizeof(*tmpoff))) == NULL) - error("out of memory\n"); - } - if (magic[magindex].flag & OFFADD) { - magic[magindex].offset = oldoff; - } + /* + * If we see any continuations + * at a higher level, + * process them. + */ + if (check_mem(ms, ++cont_level) == -1) + return -1; + } +done: + if (magic[magindex].flag & OFFADD) { + magic[magindex].offset = oldoff; } } firstline = 0; returnval = 1; - if (!kflag) { + if ((ms->flags & MAGIC_CONTINUE) == 0) { return 1; /* don't keep searching */ } } return returnval; /* This is hit if -k is set or there is no match */ } -static int32_t -mprint(union VALUETYPE *p, struct magic *m) +private int +check_mem(struct magic_set *ms, int level) +{ + size_t len; + + if (level < ms->c.len) + return 0; + + len = (ms->c.len += 20) * sizeof(*ms->c.off); + ms->c.off = (ms->c.off == NULL) ? malloc(len) : realloc(ms->c.off, len); + if (ms->c.off != NULL) + return 0; + file_oomem(ms); + return -1; +} + +private int32_t +mprint(struct magic_set *ms, union VALUETYPE *p, struct magic *m) { uint32_t v; int32_t t=0 ; @@ -212,31 +240,35 @@ mprint(union VALUETYPE *p, struct magic *m) switch (m->type) { case BYTE: - v = signextend(m, p->b); - (void) printf(m->desc, (unsigned char) v); + v = file_signextend(ms, m, p->b); + if (file_printf(ms, m->desc, (unsigned char) v) == -1) + return -1; t = m->offset + sizeof(char); break; case SHORT: case BESHORT: case LESHORT: - v = signextend(m, p->h); - (void) printf(m->desc, (unsigned short) v); + v = file_signextend(ms, m, p->h); + if (file_printf(ms, m->desc, (unsigned short) v) == -1) + return -1; t = m->offset + sizeof(short); break; case LONG: case BELONG: case LELONG: - v = signextend(m, p->l); - (void) printf(m->desc, (uint32_t) v); + v = file_signextend(ms, m, p->l); + if (file_printf(ms, m->desc, (uint32_t) v) == -1) + return -1; t = m->offset + sizeof(int32_t); break; case STRING: case PSTRING: if (m->reln == '=') { - (void) printf(m->desc, m->value.s); + if (file_printf(ms, m->desc, m->value.s) == -1) + return -1; t = m->offset + strlen(m->value.s); } else { @@ -245,7 +277,8 @@ mprint(union VALUETYPE *p, struct magic *m) if (cp) *cp = '\0'; } - (void) printf(m->desc, p->s); + if (file_printf(ms, m->desc, p->s) == -1) + return -1; t = m->offset + strlen(p->s); } break; @@ -253,24 +286,27 @@ mprint(union VALUETYPE *p, struct magic *m) case DATE: case BEDATE: case LEDATE: - (void) printf(m->desc, fmttime(p->l, 1)); + if (file_printf(ms, m->desc, file_fmttime(p->l, 1)) == -1) + return -1; t = m->offset + sizeof(time_t); break; case LDATE: case BELDATE: case LELDATE: - (void) printf(m->desc, fmttime(p->l, 0)); + if (file_printf(ms, m->desc, file_fmttime(p->l, 0)) == -1) + return -1; t = m->offset + sizeof(time_t); break; case REGEX: - (void) printf(m->desc, p->s); + if (file_printf(ms, m->desc, p->s) == -1) + return -1; t = m->offset + strlen(p->s); break; default: - error("invalid m->type (%d) in mprint().\n", m->type); - /*NOTREACHED*/ + file_error(ms, "invalid m->type (%d) in mprint()", m->type); + return -1; } return(t); } @@ -280,8 +316,8 @@ mprint(union VALUETYPE *p, struct magic *m) * While we're here, let's apply the mask operation * (unless you have a better idea) */ -static int -mconvert(union VALUETYPE *p, struct magic *m) +private int +mconvert(struct magic_set *ms, union VALUETYPE *p, struct magic *m) { switch (m->type) { case BYTE: @@ -541,38 +577,43 @@ mconvert(union VALUETYPE *p, struct magic *m) case REGEX: return 1; default: - error("invalid type %d in mconvert().\n", m->type); + file_error(ms, "invalid type %d in mconvert()", m->type); return 0; } } -static void -mdebug(int32_t offset, char *str, int len) +private void +mdebug(int32_t offset, const char *str, size_t len) { (void) fprintf(stderr, "mget @%d: ", offset); - showstr(stderr, (char *) str, len); + file_showstr(stderr, str, len); (void) fputc('\n', stderr); (void) fputc('\n', stderr); } -static int -mget(union VALUETYPE *p, unsigned char *s, struct magic *m, int nbytes) +private int +mget(struct magic_set *ms, union VALUETYPE *p, const unsigned char *s, + struct magic *m, size_t nbytes) { int32_t offset = m->offset; if (m->type == REGEX) { - /* - * offset is interpreted as last line to search, - * (starting at 1), not as bytes-from start-of-file - */ - unsigned char *last = NULL; - p->buf = (char *)s; - for (; offset && (s = (unsigned char *)strchr(s, '\n')) != NULL; - offset--, s++) - last = s; - if (last != NULL) - *last = '\0'; + /* + * offset is interpreted as last line to search, + * (starting at 1), not as bytes-from start-of-file + */ + unsigned char *b, *last = NULL; + if ((b = p->buf = strdup(s)) == NULL) { + file_oomem(ms); + return -1; + } + + for (; offset && (b = (unsigned char *)strchr(b, '\n')) != NULL; + offset--, s++) + last = b; + if (last != NULL) + *last = '\0'; } else if (offset + sizeof(union VALUETYPE) <= nbytes) memcpy(p, s + offset, sizeof(union VALUETYPE)); else { @@ -586,9 +627,9 @@ mget(union VALUETYPE *p, unsigned char *s, struct magic *m, int nbytes) memcpy(p, s + offset, have); } - if (debug) { + if ((ms->flags & MAGIC_DEBUG) != 0) { mdebug(offset, (char *) p, sizeof(union VALUETYPE)); - mdump(m); + file_mdump(m); } if (m->flag & INDIR) { @@ -920,25 +961,24 @@ mget(union VALUETYPE *p, unsigned char *s, struct magic *m, int nbytes) memcpy(p, s + offset, sizeof(union VALUETYPE)); - if (debug) { + if ((ms->flags & MAGIC_DEBUG) != 0) { mdebug(offset, (char *) p, sizeof(union VALUETYPE)); - mdump(m); + file_mdump(m); } } - if (!mconvert(p, m)) + if (!mconvert(ms, p, m)) return 0; return 1; } -static int -mcheck(union VALUETYPE *p, struct magic *m) +private int +mcheck(struct magic_set *ms, union VALUETYPE *p, struct magic *m) { uint32_t l = m->value.l; uint32_t v; int matched; if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) { - fprintf(stderr, "BOINK"); return 1; } @@ -1021,38 +1061,41 @@ mcheck(union VALUETYPE *p, struct magic *m) rc = regcomp(&rx, m->value.s, REG_EXTENDED|REG_NOSUB); if (rc) { + free(p->buf); regerror(rc, &rx, errmsg, sizeof(errmsg)); - error("regex error %d, (%s)\n", rc, errmsg); + file_error(ms, "regex error %d, (%s)", rc, errmsg); + return -1; } else { rc = regexec(&rx, p->buf, 0, 0, 0); + free(p->buf); return !rc; } } default: - error("invalid type %d in mcheck().\n", m->type); - return 0;/*NOTREACHED*/ + file_error(ms, "invalid type %d in mcheck()", m->type); + return -1; } if(m->type != STRING && m->type != PSTRING) - v = signextend(m, v); + v = file_signextend(ms, m, v); switch (m->reln) { case 'x': - if (debug) + if ((ms->flags & MAGIC_DEBUG) != 0) (void) fprintf(stderr, "%u == *any* = 1\n", v); matched = 1; break; case '!': matched = v != l; - if (debug) + if ((ms->flags & MAGIC_DEBUG) != 0) (void) fprintf(stderr, "%u != %u = %d\n", v, l, matched); break; case '=': matched = v == l; - if (debug) + if ((ms->flags & MAGIC_DEBUG) != 0) (void) fprintf(stderr, "%u == %u = %d\n", v, l, matched); break; @@ -1060,13 +1103,13 @@ mcheck(union VALUETYPE *p, struct magic *m) case '>': if (m->flag & UNSIGNED) { matched = v > l; - if (debug) + if ((ms->flags & MAGIC_DEBUG) != 0) (void) fprintf(stderr, "%u > %u = %d\n", v, l, matched); } else { matched = (int32_t) v > (int32_t) l; - if (debug) + if ((ms->flags & MAGIC_DEBUG) != 0) (void) fprintf(stderr, "%d > %d = %d\n", v, l, matched); } @@ -1075,13 +1118,13 @@ mcheck(union VALUETYPE *p, struct magic *m) case '<': if (m->flag & UNSIGNED) { matched = v < l; - if (debug) + if ((ms->flags & MAGIC_DEBUG) != 0) (void) fprintf(stderr, "%u < %u = %d\n", v, l, matched); } else { matched = (int32_t) v < (int32_t) l; - if (debug) + if ((ms->flags & MAGIC_DEBUG) != 0) (void) fprintf(stderr, "%d < %d = %d\n", v, l, matched); } @@ -1089,22 +1132,22 @@ mcheck(union VALUETYPE *p, struct magic *m) case '&': matched = (v & l) == l; - if (debug) + if ((ms->flags & MAGIC_DEBUG) != 0) (void) fprintf(stderr, "((%x & %x) == %x) = %d\n", v, l, l, matched); break; case '^': matched = (v & l) != l; - if (debug) + if ((ms->flags & MAGIC_DEBUG) != 0) (void) fprintf(stderr, "((%x & %x) != %x) = %d\n", v, l, l, matched); break; default: matched = 0; - error("mcheck: can't happen: invalid relation %d.\n", m->reln); - break;/*NOTREACHED*/ + file_error(ms, "can't happen: invalid relation `%c'", m->reln); + return -1; } return matched; -- 2.40.0