=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/file/Attic/apprentice.c,v retrieving revision 1.25 retrieving revision 1.26 diff -u -r1.25 -r1.26 --- src/usr.bin/file/Attic/apprentice.c 2008/05/08 01:40:56 1.25 +++ src/usr.bin/file/Attic/apprentice.c 2009/04/24 18:54:34 1.26 @@ -1,4 +1,4 @@ -/* $OpenBSD: apprentice.c,v 1.25 2008/05/08 01:40:56 chl Exp $ */ +/* $OpenBSD: apprentice.c,v 1.26 2009/04/24 18:54:34 chl Exp $ */ /* * Copyright (c) Ian F. Darwin 1986-1995. * Software written by Ian F. Darwin and others; @@ -32,6 +32,7 @@ #include "file.h" #include "magic.h" +#include "patchlevel.h" #include #ifdef HAVE_UNISTD_H #include @@ -45,9 +46,11 @@ #ifdef QUICK #include #endif +#include +#include #ifndef lint -FILE_RCSID("@(#)$Id: apprentice.c,v 1.25 2008/05/08 01:40:56 chl Exp $") +FILE_RCSID("@(#)$Id: apprentice.c,v 1.26 2009/04/24 18:54:34 chl Exp $") #endif /* lint */ #define EATAB {while (isascii((unsigned char) *l) && \ @@ -93,28 +96,34 @@ int *, int); private int parse(struct magic_set *, struct magic_entry **, uint32_t *, const char *, size_t, int); +private int parse_mime(struct magic_set *, struct magic_entry **, uint32_t *, + const char *); private void eatsize(const char **); private int apprentice_1(struct magic_set *, const char *, int, struct mlist *); private size_t apprentice_magic_strength(const struct magic *); private int apprentice_sort(const void *, const void *); -private int apprentice_file(struct magic_set *, struct magic **, uint32_t *, +private int apprentice_load(struct magic_set *, struct magic **, uint32_t *, const char *, int); private void byteswap(struct magic *, uint32_t); private void bs1(struct magic *); private uint16_t swap2(uint16_t); private uint32_t swap4(uint32_t); private uint64_t swap8(uint64_t); -private char *mkdbname(const char *, char *, size_t, int); +private void mkdbname(const char *, char **, int); private int apprentice_map(struct magic_set *, struct magic **, uint32_t *, const char *); private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *, const char *); private int check_format_type(const char *, int); private int check_format(struct magic_set *, struct magic *); +private int get_op(char); private size_t maxmagic = 0; private size_t magicsize = sizeof(struct magic); +private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; +private const char mime_marker[] = "!:mime"; +private const size_t mime_marker_len = sizeof(mime_marker) - 1; #ifdef COMPILE_ONLY @@ -150,13 +159,13 @@ #endif /* COMPILE_ONLY */ static const struct type_tbl_s { - const char *name; + const char name[16]; const size_t len; const int type; const int format; } type_tbl[] = { # define XX(s) s, (sizeof(s) - 1) -# define XX_NULL NULL, 0 +# define XX_NULL "", 0 { XX("byte"), FILE_BYTE, FILE_FMT_NUM }, { XX("short"), FILE_SHORT, FILE_FMT_NUM }, { XX("default"), FILE_DEFAULT, FILE_FMT_STR }, @@ -189,6 +198,12 @@ { XX("qldate"), FILE_QLDATE, FILE_FMT_STR }, { XX("leqldate"), FILE_LEQLDATE, FILE_FMT_STR }, { XX("beqldate"), FILE_BEQLDATE, FILE_FMT_STR }, + { XX("float"), FILE_FLOAT, FILE_FMT_FLOAT }, + { XX("befloat"), FILE_BEFLOAT, FILE_FMT_FLOAT }, + { XX("lefloat"), FILE_LEFLOAT, FILE_FMT_FLOAT }, + { XX("double"), FILE_DOUBLE, FILE_FMT_DOUBLE }, + { XX("bedouble"), FILE_BEDOUBLE, FILE_FMT_DOUBLE }, + { XX("ledouble"), FILE_LEDOUBLE, FILE_FMT_DOUBLE }, { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, # undef XX # undef XX_NULL @@ -199,7 +214,7 @@ { const struct type_tbl_s *p; - for (p = type_tbl; p->name; p++) { + for (p = type_tbl; p->len; p++) { if (strncmp(l, p->name, p->len) == 0) { if (t) *t = l + p->len; @@ -219,7 +234,7 @@ return; done++; - for (p = type_tbl; p->name; p++) { + for (p = type_tbl; p->len; p++) { assert(p->type < FILE_NAMES_SIZE); file_names[p->type] = p->name; file_formats[p->type] = p->format; @@ -227,7 +242,7 @@ } /* - * Handle one file. + * Handle one file or directory. */ private int apprentice_1(struct magic_set *ms, const char *fn, int action, @@ -247,7 +262,7 @@ } if (action == FILE_COMPILE) { - rv = apprentice_file(ms, &magic, &nmagic, fn, action); + rv = apprentice_load(ms, &magic, &nmagic, fn, action); if (rv != 0) return -1; rv = apprentice_compile(ms, &magic, &nmagic, fn); @@ -259,14 +274,14 @@ if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) { if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "using regular magic file `%s'", fn); - rv = apprentice_file(ms, &magic, &nmagic, fn, action); + rv = apprentice_load(ms, &magic, &nmagic, fn, action); if (rv != 0) return -1; } mapped = rv; - if (magic == NULL || nmagic == 0) { + if (magic == NULL) { file_delmagic(magic, mapped, nmagic); return -1; } @@ -313,14 +328,13 @@ } } -/* const char *fn: list of magic files */ +/* const char *fn: list of magic files and directories */ protected struct mlist * file_apprentice(struct magic_set *ms, const char *fn, int action) { - char *p, *mfn, *afn = NULL; + char *p, *mfn; int file_err, errs = -1; struct mlist *mlist; - static const char mime[] = ".mime"; init_file_tables(); @@ -348,25 +362,8 @@ *p++ = '\0'; if (*fn == '\0') break; - if (ms->flags & MAGIC_MIME) { - size_t len = strlen(fn) + sizeof(mime); - if ((afn = malloc(len)) == NULL) { - free(mfn); - free(mlist); - file_oomem(ms, len); - return NULL; - } - (void)strlcpy(afn, fn, len); - (void)strlcat(afn, ".mime", len); - fn = afn; - } file_err = apprentice_1(ms, fn, action, mlist); - if (file_err > errs) - errs = file_err; - if (afn) { - free(afn); - afn = NULL; - } + errs = MAX(errs, file_err); fn = p; } if (errs == -1) { @@ -422,7 +419,7 @@ case FILE_SEARCH: case FILE_REGEX: - val += m->vallen; + val += m->vallen * MAX(MULT / m->vallen, 1); break; case FILE_DATE: @@ -433,6 +430,9 @@ case FILE_LELDATE: case FILE_BELDATE: case FILE_MELDATE: + case FILE_FLOAT: + case FILE_BEFLOAT: + case FILE_LEFLOAT: val += 4 * MULT; break; @@ -445,6 +445,9 @@ case FILE_QLDATE: case FILE_LEQLDATE: case FILE_BEQLDATE: + case FILE_DOUBLE: + case FILE_BEDOUBLE: + case FILE_LEDOUBLE: val += 8 * MULT; break; @@ -456,10 +459,10 @@ switch (m->reln) { case 'x': /* matches anything penalize */ + case '!': /* matches almost anything penalize */ val = 0; break; - case '!': case '=': /* Exact match, prefer */ val += MULT; break; @@ -503,36 +506,131 @@ return 1; } +private void +set_test_type(struct magic *mstart, struct magic *m) +{ + switch (m->type) { + case FILE_BYTE: + case FILE_SHORT: + case FILE_LONG: + case FILE_DATE: + case FILE_BESHORT: + case FILE_BELONG: + case FILE_BEDATE: + case FILE_LESHORT: + case FILE_LELONG: + case FILE_LEDATE: + case FILE_LDATE: + case FILE_BELDATE: + case FILE_LELDATE: + case FILE_MEDATE: + case FILE_MELDATE: + case FILE_MELONG: + case FILE_QUAD: + case FILE_LEQUAD: + case FILE_BEQUAD: + case FILE_QDATE: + case FILE_LEQDATE: + case FILE_BEQDATE: + case FILE_QLDATE: + case FILE_LEQLDATE: + case FILE_BEQLDATE: + case FILE_FLOAT: + case FILE_BEFLOAT: + case FILE_LEFLOAT: + case FILE_DOUBLE: + case FILE_BEDOUBLE: + case FILE_LEDOUBLE: + case FILE_STRING: + case FILE_PSTRING: + case FILE_BESTRING16: + case FILE_LESTRING16: + /* binary test, set flag */ + mstart->flag |= BINTEST; + break; + case FILE_REGEX: + case FILE_SEARCH: + /* binary test if pattern is not text */ + if (file_looks_utf8(m->value.s, m->vallen, NULL, NULL) == 0) + mstart->flag |= BINTEST; + break; + case FILE_DEFAULT: + /* can't deduce anything; we shouldn't see this at the + top level anyway */ + break; + case FILE_INVALID: + default: + /* invalid search type, but no need to complain here */ + break; + } +} + /* - * parse from a file - * const char *fn: name of magic file + * Load and parse one file. */ -private int -apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, - const char *fn, int action) +private void +load_1(struct magic_set *ms, int action, const char *fn, int *errs, + struct magic_entry **marray, uint32_t *marraycount) { - private const char hdr[] = - "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; - FILE *f; char line[BUFSIZ]; - int errs = 0; - struct magic_entry *marray; - uint32_t marraycount, i, mentrycount = 0; size_t lineno = 0; - - ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ - - f = fopen(ms->file = fn, "r"); + FILE *f = fopen(ms->file = fn, "r"); if (f == NULL) { if (errno != ENOENT) file_error(ms, errno, "cannot read magic file `%s'", - fn); - return -1; + fn); + (*errs)++; + } else { + /* read and parse this file */ + for (ms->line = 1; fgets(line, sizeof(line), f) != NULL; ms->line++) { + size_t len; + len = strlen(line); + if (len == 0) /* null line, garbage, etc */ + continue; + if (line[len - 1] == '\n') { + lineno++; + line[len - 1] = '\0'; /* delete newline */ + } + if (line[0] == '\0') /* empty, do not parse */ + continue; + if (line[0] == '#') /* comment, do not parse */ + continue; + if (len > mime_marker_len && + memcmp(line, mime_marker, mime_marker_len) == 0) { + /* MIME type */ + if (parse_mime(ms, marray, marraycount, + line + mime_marker_len) != 0) + (*errs)++; + continue; + } + if (parse(ms, marray, marraycount, line, lineno, action) != 0) + (*errs)++; + } + + (void)fclose(f); } +} +/* + * parse a file or directory of files + * const char *fn: name of magic file or directory + */ +private int +apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, + const char *fn, int action) +{ + int errs = 0; + struct magic_entry *marray; + uint32_t marraycount, i, mentrycount = 0, starttest; + char subfn[MAXPATHLEN]; + struct stat st; + DIR *dir; + struct dirent *d; + + ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ + maxmagic = MAXMAGIS; if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) { - (void)fclose(f); file_oomem(ms, maxmagic * sizeof(*marray)); return -1; } @@ -540,32 +638,63 @@ /* print silly verbose header for USG compat. */ if (action == FILE_CHECK) - (void)fprintf(stderr, "%s\n", hdr); + (void)fprintf(stderr, "%s\n", usg_hdr); - /* read and parse this file */ - for (ms->line = 1; fgets(line, sizeof(line), f) != NULL; ms->line++) { - size_t len; - len = strlen(line); - if (len == 0) /* null line, garbage, etc */ - continue; - if (line[len - 1] == '\n') { - lineno++; - line[len - 1] = '\0'; /* delete newline */ - } - if (line[0] == '\0') /* empty, do not parse */ - continue; - if (line[0] == '#') /* comment, do not parse */ - continue; - if (parse(ms, &marray, &marraycount, line, lineno, action) != 0) + /* load directory or file */ + if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { + dir = opendir(fn); + if (dir) { + while (d = readdir(dir)) { + snprintf(subfn, sizeof(subfn), "%s/%s", + fn, d->d_name); + if (stat(subfn, &st) == 0 && S_ISREG(st.st_mode)) { + load_1(ms, action, subfn, &errs, + &marray, &marraycount); + } + } + closedir(dir); + } else errs++; - } - - (void)fclose(f); + } else + load_1(ms, action, fn, &errs, &marray, &marraycount); if (errs) goto out; -#ifndef NOORDER + /* Set types of tests */ + for (i = 0; i < marraycount; ) { + if (marray[i].mp->cont_level != 0) { + i++; + continue; + } + + starttest = i; + do { + set_test_type(marray[starttest].mp, marray[i].mp); + if (ms->flags & MAGIC_DEBUG) { + (void)fprintf(stderr, "%s%s%s: %s\n", + marray[i].mp->mimetype, + marray[i].mp->mimetype[0] == '\0' ? "" : "; ", + marray[i].mp->desc[0] ? marray[i].mp->desc : "(no description)", + marray[i].mp->flag & BINTEST ? "binary" : "text"); + if (marray[i].mp->flag & BINTEST) { +#define SYMBOL "text" +#define SYMLEN sizeof(SYMBOL) + char *p = strstr(marray[i].mp->desc, "text"); + if (p && (p == marray[i].mp->desc || isspace(p[-1])) && + (p + SYMLEN - marray[i].mp->desc == MAXstring || + (p[SYMLEN] == '\0' || isspace(p[SYMLEN])))) { + (void)fprintf(stderr, + "*** Possible binary test for text type\n"); + } +#undef SYMBOL +#undef SYMLEN + } + } + } while (++i < marraycount && marray[i].mp->cont_level != 0); + } + qsort(marray, marraycount, sizeof(*marray), apprentice_sort); + /* * Make sure that any level 0 "default" line is last (if one exists). */ @@ -583,7 +712,6 @@ break; } } -#endif for (i = 0; i < marraycount; i++) mentrycount += marray[i].cont_count; @@ -648,6 +776,9 @@ case FILE_BELONG: case FILE_LELONG: case FILE_MELONG: + case FILE_FLOAT: + case FILE_BEFLOAT: + case FILE_LEFLOAT: v = (int32_t) v; break; case FILE_QUAD: @@ -659,6 +790,9 @@ case FILE_BEQLDATE: case FILE_LEQDATE: case FILE_LEQLDATE: + case FILE_DOUBLE: + case FILE_BEDOUBLE: + case FILE_LEDOUBLE: v = (int64_t) v; break; case FILE_STRING: @@ -680,7 +814,7 @@ } private int -string_modifier_check(struct magic_set *ms, struct magic const *m) +string_modifier_check(struct magic_set *ms, struct magic *m) { if ((ms->flags & MAGIC_CHECK) == 0) return 0; @@ -689,19 +823,28 @@ case FILE_BESTRING16: case FILE_LESTRING16: if (m->str_flags != 0) { - file_magwarn(ms, "no modifiers allowed for 16-bit strings\n"); + file_magwarn(ms, + "no modifiers allowed for 16-bit strings\n"); return -1; } break; case FILE_STRING: case FILE_PSTRING: if ((m->str_flags & REGEX_OFFSET_START) != 0) { - file_magwarn(ms, "'/%c' only allowed on regex and search\n", + file_magwarn(ms, + "'/%c' only allowed on regex and search\n", CHAR_REGEX_OFFSET_START); return -1; } break; case FILE_SEARCH: + if (m->str_range == 0) { + file_magwarn(ms, + "missing range; defaulting to %d\n", + STRING_DEFAULT_RANGE); + m->str_range = STRING_DEFAULT_RANGE; + return -1; + } break; case FILE_REGEX: if ((m->str_flags & STRING_COMPACT_BLANK) != 0) { @@ -752,19 +895,19 @@ private int get_cond(const char *l, const char **t) { - static struct cond_tbl_s { - const char *name; - const size_t len; - const int cond; + static const struct cond_tbl_s { + char name[8]; + size_t len; + int cond; } cond_tbl[] = { { "if", 2, COND_IF }, { "elif", 4, COND_ELIF }, { "else", 4, COND_ELSE }, - { NULL, 0, COND_NONE }, + { "", 0, COND_NONE }, }; - struct cond_tbl_s *p; + const struct cond_tbl_s *p; - for (p = cond_tbl; p->name; p++) { + for (p = cond_tbl; p->len; p++) { if (strncmp(l, p->name, p->len) == 0 && isspace((unsigned char)l[p->len])) { if (t) @@ -961,6 +1104,16 @@ case 'B': m->in_type = FILE_BYTE; break; + case 'e': + case 'f': + case 'g': + m->in_type = FILE_LEDOUBLE; + break; + case 'E': + case 'F': + case 'G': + m->in_type = FILE_BEDOUBLE; + break; default: if (ms->flags & MAGIC_CHECK) file_magwarn(ms, @@ -1031,7 +1184,7 @@ file_magwarn(ms, "'~' invalid for string types"); ++l; } - m->str_count = 0; + m->str_range = 0; m->str_flags = 0; m->num_mask = 0; if ((op = get_op(*l)) != -1) { @@ -1045,22 +1198,24 @@ eatsize(&l); } else if (op == FILE_OPDIVIDE) { - int have_count = 0; + int have_range = 0; while (!isspace((unsigned char)*++l)) { switch (*l) { - /* for portability avoid "case '0' ... '9':" */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': - case '9': { - if (have_count && ms->flags & MAGIC_CHECK) + case '9': + if (have_range && + (ms->flags & MAGIC_CHECK)) file_magwarn(ms, - "multiple counts"); - have_count = 1; - m->str_count = strtoul(l, &t, 0); + "multiple ranges"); + have_range = 1; + m->str_range = strtoul(l, &t, 0); + if (m->str_range == 0) + file_magwarn(ms, + "zero range"); l = t - 1; break; - } case CHAR_COMPACT_BLANK: m->str_flags |= STRING_COMPACT_BLANK; break; @@ -1085,7 +1240,8 @@ return -1; } /* allow multiple '/' for readability */ - if (l[1] == '/' && !isspace((unsigned char)l[2])) + if (l[1] == '/' && + !isspace((unsigned char)l[2])) l++; } if (string_modifier_check(ms, m) == -1) @@ -1148,13 +1304,12 @@ EATAB; if (l[0] == '\b') { ++l; - m->nospflag = 1; + m->flag |= NOSPACE; } else if ((l[0] == '\\') && (l[1] == 'b')) { ++l; ++l; - m->nospflag = 1; - } else - m->nospflag = 0; + m->flag |= NOSPACE; + } for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); ) continue; if (i == sizeof(m->desc)) { @@ -1176,12 +1331,60 @@ file_mdump(m); } #endif + m->mimetype[0] = '\0'; /* initialise MIME type to none */ if (m->cont_level == 0) ++(*nmentryp); /* make room for next */ return 0; } +/* + * parse a MIME annotation line from magic file, put into magic[index - 1] + * if valid + */ private int +parse_mime(struct magic_set *ms, struct magic_entry **mentryp, + uint32_t *nmentryp, const char *line) +{ + size_t i; + const char *l = line; + struct magic *m; + struct magic_entry *me; + + if (*nmentryp == 0) { + file_error(ms, 0, "No current entry for MIME type"); + return -1; + } + + me = &(*mentryp)[*nmentryp - 1]; + m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1]; + + if (m->mimetype[0] != '\0') { + file_error(ms, 0, "Current entry already has a MIME type: %s\n" + "Description: %s\nNew type: %s", m->mimetype, m->desc, l); + return -1; + } + + EATAB; + for (i = 0; + *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l)) + || strchr("-+/.", *l)) && i < sizeof(m->mimetype); + m->mimetype[i++] = *l++) + continue; + if (i == sizeof(m->mimetype)) { + m->desc[sizeof(m->mimetype) - 1] = '\0'; + if (ms->flags & MAGIC_CHECK) + file_magwarn(ms, "MIME type `%s' truncated %zu", + m->mimetype, i); + } else + m->mimetype[i] = '\0'; + + if (i > 0) + return 0; + else + return -1; +} + +private int check_format_type(const char *ptr, int type) { int quad = 0; @@ -1254,6 +1457,31 @@ return -1; } + case FILE_FMT_FLOAT: + case FILE_FMT_DOUBLE: + if (*ptr == '-') + ptr++; + if (*ptr == '.') + ptr++; + while (isdigit((unsigned char)*ptr)) ptr++; + if (*ptr == '.') + ptr++; + while (isdigit((unsigned char)*ptr)) ptr++; + + switch (*ptr++) { + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + return 0; + + default: + return -1; + } + + case FILE_FMT_STR: if (*ptr == '-') ptr++; @@ -1300,12 +1528,12 @@ assert(file_nformats == file_nnames); if (m->type >= file_nformats) { - file_error(ms, 0, "Internal error inconsistency between " + file_magwarn(ms, "Internal error inconsistency between " "m->type and format strings"); return -1; } if (file_formats[m->type] == FILE_FMT_NONE) { - file_error(ms, 0, "No format string for `%s' with description " + file_magwarn(ms, "No format string for `%s' with description " "`%s'", m->desc, file_names[m->type]); return -1; } @@ -1316,8 +1544,8 @@ * TODO: this error message is unhelpful if the format * string is not one character long */ - file_error(ms, 0, "Printf format `%c' is not valid for type " - " `%s' in description `%s'", + file_magwarn(ms, "Printf format `%c' is not valid for type " + "`%s' in description `%s'", ptr && *ptr ? *ptr : '?', file_names[m->type], m->desc); return -1; @@ -1325,7 +1553,7 @@ for (; *ptr; ptr++) { if (*ptr == '%') { - file_error(ms, 0, + file_magwarn(ms, "Too many format strings (should have at most one) " "for `%s' with description `%s'", file_names[m->type], m->desc); @@ -1360,7 +1588,31 @@ return -1; } m->vallen = slen; + if (m->type == FILE_PSTRING) + m->vallen++; return 0; + case FILE_FLOAT: + case FILE_BEFLOAT: + case FILE_LEFLOAT: + if (m->reln != 'x') { + char *ep; +#ifdef HAVE_STRTOF + m->value.f = strtof(*p, &ep); +#else + m->value.f = (float)strtod(*p, &ep); +#endif + *p = ep; + } + return 0; + case FILE_DOUBLE: + case FILE_BEDOUBLE: + case FILE_LEDOUBLE: + if (m->reln != 'x') { + char *ep; + m->value.d = strtod(*p, &ep); + *p = ep; + } + return 0; default: if (m->reln != 'x') { char *ep; @@ -1634,40 +1886,40 @@ uint32_t *ptr; uint32_t version; int needsbyteswap; - char buf[MAXPATHLEN]; - char *dbname = mkdbname(fn, buf, sizeof(buf), 0); + char *dbname = NULL; void *mm = NULL; + mkdbname(fn, &dbname, 0); if (dbname == NULL) - return -1; + goto error2; if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1) - return -1; + goto error2; if (fstat(fd, &st) == -1) { file_error(ms, errno, "cannot stat `%s'", dbname); - goto error; + goto error1; } - if (st.st_size < 16) { + if (st.st_size < 8) { file_error(ms, 0, "file `%s' is too small", dbname); - goto error; + goto error1; } #ifdef QUICK if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) { file_error(ms, errno, "cannot map `%s'", dbname); - goto error; + goto error1; } #define RET 2 #else if ((mm = malloc((size_t)st.st_size)) == NULL) { file_oomem(ms, (size_t)st.st_size); - goto error; + goto error1; } if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) { file_badread(ms); - goto error; + goto error1; } #define RET 1 #endif @@ -1678,7 +1930,7 @@ if (*ptr != MAGICNO) { if (swap4(*ptr) != MAGICNO) { file_error(ms, 0, "bad magic in `%s'"); - goto error; + goto error1; } needsbyteswap = 1; } else @@ -1688,17 +1940,21 @@ else version = ptr[1]; if (version != VERSIONNO) { - file_error(ms, 0, "version mismatch (%d != %d) in `%s'", - version, VERSIONNO, dbname); - goto error; + file_error(ms, 0, "File %d.%d supports only %d version magic " + "files. `%s' is version %d", FILE_VERSION_MAJOR, patchlevel, + VERSIONNO, dbname, version); + goto error1; } - *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)) - 1; + *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)); + if (*nmagicp > 0) + (*nmagicp)--; (*magicp)++; if (needsbyteswap) byteswap(*magicp, *nmagicp); + free(dbname); return RET; -error: +error1: if (fd != -1) (void)close(fd); if (mm) { @@ -1711,6 +1967,8 @@ *magicp = NULL; *nmagicp = 0; } +error2: + free(dbname); return -1; } @@ -1725,44 +1983,49 @@ uint32_t *nmagicp, const char *fn) { int fd; - char buf[MAXPATHLEN]; - char *dbname = mkdbname(fn, buf, sizeof(buf), 1); + char *dbname; + int rv = -1; + mkdbname(fn, &dbname, 1); + if (dbname == NULL) - return -1; + goto out; if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) { file_error(ms, errno, "cannot open `%s'", dbname); - return -1; + goto out; } if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) { file_error(ms, errno, "error writing `%s'", dbname); - return -1; + goto out; } if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET) != sizeof(struct magic)) { file_error(ms, errno, "error seeking `%s'", dbname); - return -1; + goto out; } if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp)) != (ssize_t)(sizeof(struct magic) * *nmagicp)) { file_error(ms, errno, "error writing `%s'", dbname); - return -1; + goto out; } (void)close(fd); - return 0; + rv = 0; +out: + free(dbname); + return rv; } private const char ext[] = ".mgc"; /* * make a dbname */ -private char * -mkdbname(const char *fn, char *buf, size_t bufsiz, int strip) +private void +mkdbname(const char *fn, char **buf, int strip) { if (strip) { const char *p; @@ -1770,8 +2033,11 @@ fn = ++p; } - (void)snprintf(buf, bufsiz, "%s%s", fn, ext); - return buf; + (void)asprintf(buf, "%s%s", fn, ext); + if (*buf && strlen(*buf) > MAXPATHLEN) { + free(*buf); + *buf = NULL; + } } /* @@ -1824,6 +2090,7 @@ uint32_t rv; uint8_t *s = (uint8_t *)(void *)&sv; uint8_t *d = (uint8_t *)(void *)&rv; +#if 0 d[0] = s[3]; d[1] = s[2]; d[2] = s[1]; @@ -1832,6 +2099,16 @@ d[5] = s[6]; d[6] = s[5]; d[7] = s[4]; +#else + d[0] = s[7]; + d[1] = s[6]; + d[2] = s[5]; + d[3] = s[4]; + d[4] = s[3]; + d[5] = s[2]; + d[6] = s[1]; + d[7] = s[0]; +#endif return rv; } @@ -1846,7 +2123,7 @@ m->in_offset = swap4((uint32_t)m->in_offset); m->lineno = swap4((uint32_t)m->lineno); if (IS_STRING(m->type)) { - m->str_count = swap4(m->str_count); + m->str_range = swap4(m->str_range); m->str_flags = swap4(m->str_flags); } else {