[BACK]Return to apprentice.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / file

Diff for /src/usr.bin/file/Attic/apprentice.c between version 1.25 and 1.26

version 1.25, 2008/05/08 01:40:56 version 1.26, 2009/04/24 18:54:34
Line 32 
Line 32 
   
 #include "file.h"  #include "file.h"
 #include "magic.h"  #include "magic.h"
   #include "patchlevel.h"
 #include <stdlib.h>  #include <stdlib.h>
 #ifdef HAVE_UNISTD_H  #ifdef HAVE_UNISTD_H
 #include <unistd.h>  #include <unistd.h>
Line 45 
Line 46 
 #ifdef QUICK  #ifdef QUICK
 #include <sys/mman.h>  #include <sys/mman.h>
 #endif  #endif
   #include <sys/types.h>
   #include <dirent.h>
   
 #ifndef lint  #ifndef lint
 FILE_RCSID("@(#)$Id$")  FILE_RCSID("@(#)$Id$")
Line 93 
Line 96 
     int *, int);      int *, int);
 private int parse(struct magic_set *, struct magic_entry **, uint32_t *,  private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
     const char *, size_t, int);      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 void eatsize(const char **);
 private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);  private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
 private size_t apprentice_magic_strength(const struct magic *);  private size_t apprentice_magic_strength(const struct magic *);
 private int apprentice_sort(const void *, const void *);  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);      const char *, int);
 private void byteswap(struct magic *, uint32_t);  private void byteswap(struct magic *, uint32_t);
 private void bs1(struct magic *);  private void bs1(struct magic *);
 private uint16_t swap2(uint16_t);  private uint16_t swap2(uint16_t);
 private uint32_t swap4(uint32_t);  private uint32_t swap4(uint32_t);
 private uint64_t swap8(uint64_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 *,  private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
     const char *);      const char *);
 private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,  private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
     const char *);      const char *);
 private int check_format_type(const char *, int);  private int check_format_type(const char *, int);
 private int check_format(struct magic_set *, struct magic *);  private int check_format(struct magic_set *, struct magic *);
   private int get_op(char);
   
 private size_t maxmagic = 0;  private size_t maxmagic = 0;
 private size_t magicsize = sizeof(struct magic);  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  #ifdef COMPILE_ONLY
   
Line 150 
Line 159 
 #endif /* COMPILE_ONLY */  #endif /* COMPILE_ONLY */
   
 static const struct type_tbl_s {  static const struct type_tbl_s {
         const char *name;          const char name[16];
         const size_t len;          const size_t len;
         const int type;          const int type;
         const int format;          const int format;
 } type_tbl[] = {  } type_tbl[] = {
 # define XX(s)          s, (sizeof(s) - 1)  # define XX(s)          s, (sizeof(s) - 1)
 # define XX_NULL        NULL, 0  # define XX_NULL        "", 0
         { XX("byte"),           FILE_BYTE,              FILE_FMT_NUM },          { XX("byte"),           FILE_BYTE,              FILE_FMT_NUM },
         { XX("short"),          FILE_SHORT,             FILE_FMT_NUM },          { XX("short"),          FILE_SHORT,             FILE_FMT_NUM },
         { XX("default"),        FILE_DEFAULT,           FILE_FMT_STR },          { XX("default"),        FILE_DEFAULT,           FILE_FMT_STR },
Line 189 
Line 198 
         { XX("qldate"),         FILE_QLDATE,            FILE_FMT_STR },          { XX("qldate"),         FILE_QLDATE,            FILE_FMT_STR },
         { XX("leqldate"),       FILE_LEQLDATE,          FILE_FMT_STR },          { XX("leqldate"),       FILE_LEQLDATE,          FILE_FMT_STR },
         { XX("beqldate"),       FILE_BEQLDATE,          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 },          { XX_NULL,              FILE_INVALID,           FILE_FMT_NONE },
 # undef XX  # undef XX
 # undef XX_NULL  # undef XX_NULL
Line 199 
Line 214 
 {  {
         const struct type_tbl_s *p;          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 (strncmp(l, p->name, p->len) == 0) {
                         if (t)                          if (t)
                                 *t = l + p->len;                                  *t = l + p->len;
Line 219 
Line 234 
                 return;                  return;
         done++;          done++;
   
         for (p = type_tbl; p->name; p++) {          for (p = type_tbl; p->len; p++) {
                 assert(p->type < FILE_NAMES_SIZE);                  assert(p->type < FILE_NAMES_SIZE);
                 file_names[p->type] = p->name;                  file_names[p->type] = p->name;
                 file_formats[p->type] = p->format;                  file_formats[p->type] = p->format;
Line 227 
Line 242 
 }  }
   
 /*  /*
  * Handle one file.   * Handle one file or directory.
  */   */
 private int  private int
 apprentice_1(struct magic_set *ms, const char *fn, int action,  apprentice_1(struct magic_set *ms, const char *fn, int action,
Line 247 
Line 262 
         }          }
   
         if (action == FILE_COMPILE) {          if (action == FILE_COMPILE) {
                 rv = apprentice_file(ms, &magic, &nmagic, fn, action);                  rv = apprentice_load(ms, &magic, &nmagic, fn, action);
                 if (rv != 0)                  if (rv != 0)
                         return -1;                          return -1;
                 rv = apprentice_compile(ms, &magic, &nmagic, fn);                  rv = apprentice_compile(ms, &magic, &nmagic, fn);
Line 259 
Line 274 
         if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {          if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
                 if (ms->flags & MAGIC_CHECK)                  if (ms->flags & MAGIC_CHECK)
                         file_magwarn(ms, "using regular magic file `%s'", fn);                          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)                  if (rv != 0)
                         return -1;                          return -1;
         }          }
   
         mapped = rv;          mapped = rv;
   
         if (magic == NULL || nmagic == 0) {          if (magic == NULL) {
                 file_delmagic(magic, mapped, nmagic);                  file_delmagic(magic, mapped, nmagic);
                 return -1;                  return -1;
         }          }
Line 313 
Line 328 
         }          }
 }  }
   
 /* const char *fn: list of magic files */  /* const char *fn: list of magic files and directories */
 protected struct mlist *  protected struct mlist *
 file_apprentice(struct magic_set *ms, const char *fn, int action)  file_apprentice(struct magic_set *ms, const char *fn, int action)
 {  {
         char *p, *mfn, *afn = NULL;          char *p, *mfn;
         int file_err, errs = -1;          int file_err, errs = -1;
         struct mlist *mlist;          struct mlist *mlist;
         static const char mime[] = ".mime";  
   
         init_file_tables();          init_file_tables();
   
Line 348 
Line 362 
                         *p++ = '\0';                          *p++ = '\0';
                 if (*fn == '\0')                  if (*fn == '\0')
                         break;                          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);                  file_err = apprentice_1(ms, fn, action, mlist);
                 if (file_err > errs)                  errs = MAX(errs, file_err);
                         errs = file_err;  
                 if (afn) {  
                         free(afn);  
                         afn = NULL;  
                 }  
                 fn = p;                  fn = p;
         }          }
         if (errs == -1) {          if (errs == -1) {
Line 422 
Line 419 
   
         case FILE_SEARCH:          case FILE_SEARCH:
         case FILE_REGEX:          case FILE_REGEX:
                 val += m->vallen;                  val += m->vallen * MAX(MULT / m->vallen, 1);
                 break;                  break;
   
         case FILE_DATE:          case FILE_DATE:
Line 433 
Line 430 
         case FILE_LELDATE:          case FILE_LELDATE:
         case FILE_BELDATE:          case FILE_BELDATE:
         case FILE_MELDATE:          case FILE_MELDATE:
           case FILE_FLOAT:
           case FILE_BEFLOAT:
           case FILE_LEFLOAT:
                 val += 4 * MULT;                  val += 4 * MULT;
                 break;                  break;
   
Line 445 
Line 445 
         case FILE_QLDATE:          case FILE_QLDATE:
         case FILE_LEQLDATE:          case FILE_LEQLDATE:
         case FILE_BEQLDATE:          case FILE_BEQLDATE:
           case FILE_DOUBLE:
           case FILE_BEDOUBLE:
           case FILE_LEDOUBLE:
                 val += 8 * MULT;                  val += 8 * MULT;
                 break;                  break;
   
Line 456 
Line 459 
   
         switch (m->reln) {          switch (m->reln) {
         case 'x':       /* matches anything penalize */          case 'x':       /* matches anything penalize */
           case '!':       /* matches almost anything penalize */
                 val = 0;                  val = 0;
                 break;                  break;
   
         case '!':  
         case '=':       /* Exact match, prefer */          case '=':       /* Exact match, prefer */
                 val += MULT;                  val += MULT;
                 break;                  break;
Line 503 
Line 506 
                 return 1;                  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   * Load and parse one file.
  * const char *fn: name of magic file  
  */   */
 private int  private void
 apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,  load_1(struct magic_set *ms, int action, const char *fn, int *errs,
     const char *fn, int action)     struct magic_entry **marray, uint32_t *marraycount)
 {  {
         private const char hdr[] =  
                 "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";  
         FILE *f;  
         char line[BUFSIZ];          char line[BUFSIZ];
         int errs = 0;  
         struct magic_entry *marray;  
         uint32_t marraycount, i, mentrycount = 0;  
         size_t lineno = 0;          size_t lineno = 0;
           FILE *f = fopen(ms->file = fn, "r");
         ms->flags |= MAGIC_CHECK;       /* Enable checks for parsed files */  
   
         f = fopen(ms->file = fn, "r");  
         if (f == NULL) {          if (f == NULL) {
                 if (errno != ENOENT)                  if (errno != ENOENT)
                         file_error(ms, errno, "cannot read magic file `%s'",                          file_error(ms, errno, "cannot read magic file `%s'",
                             fn);                                     fn);
                 return -1;                  (*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;          maxmagic = MAXMAGIS;
         if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) {          if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) {
                 (void)fclose(f);  
                 file_oomem(ms, maxmagic * sizeof(*marray));                  file_oomem(ms, maxmagic * sizeof(*marray));
                 return -1;                  return -1;
         }          }
Line 540 
Line 638 
   
         /* print silly verbose header for USG compat. */          /* print silly verbose header for USG compat. */
         if (action == FILE_CHECK)          if (action == FILE_CHECK)
                 (void)fprintf(stderr, "%s\n", hdr);                  (void)fprintf(stderr, "%s\n", usg_hdr);
   
         /* read and parse this file */          /* load directory or file */
         for (ms->line = 1; fgets(line, sizeof(line), f) != NULL; ms->line++) {          if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
                 size_t len;                  dir = opendir(fn);
                 len = strlen(line);                  if (dir) {
                 if (len == 0) /* null line, garbage, etc */                          while (d = readdir(dir)) {
                         continue;                                  snprintf(subfn, sizeof(subfn), "%s/%s",
                 if (line[len - 1] == '\n') {                                      fn, d->d_name);
                         lineno++;                                  if (stat(subfn, &st) == 0 && S_ISREG(st.st_mode)) {
                         line[len - 1] = '\0'; /* delete newline */                                          load_1(ms, action, subfn, &errs,
                 }                                              &marray, &marraycount);
                 if (line[0] == '\0')    /* empty, do not parse */                                  }
                         continue;                          }
                 if (line[0] == '#')     /* comment, do not parse */                          closedir(dir);
                         continue;                  } else
                 if (parse(ms, &marray, &marraycount, line, lineno, action) != 0)  
                         errs++;                          errs++;
         }          } else
                   load_1(ms, action, fn, &errs, &marray, &marraycount);
         (void)fclose(f);  
         if (errs)          if (errs)
                 goto out;                  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);          qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
   
         /*          /*
          * Make sure that any level 0 "default" line is last (if one exists).           * Make sure that any level 0 "default" line is last (if one exists).
          */           */
Line 583 
Line 712 
                         break;                          break;
                 }                  }
         }          }
 #endif  
   
         for (i = 0; i < marraycount; i++)          for (i = 0; i < marraycount; i++)
                 mentrycount += marray[i].cont_count;                  mentrycount += marray[i].cont_count;
Line 648 
Line 776 
                 case FILE_BELONG:                  case FILE_BELONG:
                 case FILE_LELONG:                  case FILE_LELONG:
                 case FILE_MELONG:                  case FILE_MELONG:
                   case FILE_FLOAT:
                   case FILE_BEFLOAT:
                   case FILE_LEFLOAT:
                         v = (int32_t) v;                          v = (int32_t) v;
                         break;                          break;
                 case FILE_QUAD:                  case FILE_QUAD:
Line 659 
Line 790 
                 case FILE_BEQLDATE:                  case FILE_BEQLDATE:
                 case FILE_LEQDATE:                  case FILE_LEQDATE:
                 case FILE_LEQLDATE:                  case FILE_LEQLDATE:
                   case FILE_DOUBLE:
                   case FILE_BEDOUBLE:
                   case FILE_LEDOUBLE:
                         v = (int64_t) v;                          v = (int64_t) v;
                         break;                          break;
                 case FILE_STRING:                  case FILE_STRING:
Line 680 
Line 814 
 }  }
   
 private int  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)          if ((ms->flags & MAGIC_CHECK) == 0)
                 return 0;                  return 0;
Line 689 
Line 823 
         case FILE_BESTRING16:          case FILE_BESTRING16:
         case FILE_LESTRING16:          case FILE_LESTRING16:
                 if (m->str_flags != 0) {                  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;                          return -1;
                 }                  }
                 break;                  break;
         case FILE_STRING:          case FILE_STRING:
         case FILE_PSTRING:          case FILE_PSTRING:
                 if ((m->str_flags & REGEX_OFFSET_START) != 0) {                  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);                              CHAR_REGEX_OFFSET_START);
                         return -1;                          return -1;
                 }                  }
                 break;                  break;
         case FILE_SEARCH:          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;                  break;
         case FILE_REGEX:          case FILE_REGEX:
                 if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {                  if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
Line 752 
Line 895 
 private int  private int
 get_cond(const char *l, const char **t)  get_cond(const char *l, const char **t)
 {  {
         static struct cond_tbl_s {          static const struct cond_tbl_s {
                 const char *name;                  char name[8];
                 const size_t len;                  size_t len;
                 const int cond;                  int cond;
         } cond_tbl[] = {          } cond_tbl[] = {
                 { "if",         2,      COND_IF },                  { "if",         2,      COND_IF },
                 { "elif",       4,      COND_ELIF },                  { "elif",       4,      COND_ELIF },
                 { "else",       4,      COND_ELSE },                  { "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 &&                  if (strncmp(l, p->name, p->len) == 0 &&
                     isspace((unsigned char)l[p->len])) {                      isspace((unsigned char)l[p->len])) {
                         if (t)                          if (t)
Line 961 
Line 1104 
                         case 'B':                          case 'B':
                                 m->in_type = FILE_BYTE;                                  m->in_type = FILE_BYTE;
                                 break;                                  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:                          default:
                                 if (ms->flags & MAGIC_CHECK)                                  if (ms->flags & MAGIC_CHECK)
                                         file_magwarn(ms,                                          file_magwarn(ms,
Line 1031 
Line 1184 
                         file_magwarn(ms, "'~' invalid for string types");                          file_magwarn(ms, "'~' invalid for string types");
                 ++l;                  ++l;
         }          }
         m->str_count = 0;          m->str_range = 0;
         m->str_flags = 0;          m->str_flags = 0;
         m->num_mask = 0;          m->num_mask = 0;
         if ((op = get_op(*l)) != -1) {          if ((op = get_op(*l)) != -1) {
Line 1045 
Line 1198 
                         eatsize(&l);                          eatsize(&l);
                 }                  }
                 else if (op == FILE_OPDIVIDE) {                  else if (op == FILE_OPDIVIDE) {
                         int have_count = 0;                          int have_range = 0;
                         while (!isspace((unsigned char)*++l)) {                          while (!isspace((unsigned char)*++l)) {
                                 switch (*l) {                                  switch (*l) {
                                 /* for portability avoid "case '0' ... '9':" */  
                                 case '0':  case '1':  case '2':                                  case '0':  case '1':  case '2':
                                 case '3':  case '4':  case '5':                                  case '3':  case '4':  case '5':
                                 case '6':  case '7':  case '8':                                  case '6':  case '7':  case '8':
                                 case '9': {                                  case '9':
                                         if (have_count && ms->flags & MAGIC_CHECK)                                          if (have_range &&
                                               (ms->flags & MAGIC_CHECK))
                                                 file_magwarn(ms,                                                  file_magwarn(ms,
                                                     "multiple counts");                                                      "multiple ranges");
                                         have_count = 1;                                          have_range = 1;
                                         m->str_count = strtoul(l, &t, 0);                                          m->str_range = strtoul(l, &t, 0);
                                           if (m->str_range == 0)
                                                   file_magwarn(ms,
                                                       "zero range");
                                         l = t - 1;                                          l = t - 1;
                                         break;                                          break;
                                 }  
                                 case CHAR_COMPACT_BLANK:                                  case CHAR_COMPACT_BLANK:
                                         m->str_flags |= STRING_COMPACT_BLANK;                                          m->str_flags |= STRING_COMPACT_BLANK;
                                         break;                                          break;
Line 1085 
Line 1240 
                                         return -1;                                          return -1;
                                 }                                  }
                                 /* allow multiple '/' for readability */                                  /* allow multiple '/' for readability */
                                 if (l[1] == '/' && !isspace((unsigned char)l[2]))                                  if (l[1] == '/' &&
                                       !isspace((unsigned char)l[2]))
                                         l++;                                          l++;
                         }                          }
                         if (string_modifier_check(ms, m) == -1)                          if (string_modifier_check(ms, m) == -1)
Line 1148 
Line 1304 
         EATAB;          EATAB;
         if (l[0] == '\b') {          if (l[0] == '\b') {
                 ++l;                  ++l;
                 m->nospflag = 1;                  m->flag |= NOSPACE;
         } else if ((l[0] == '\\') && (l[1] == 'b')) {          } else if ((l[0] == '\\') && (l[1] == 'b')) {
                 ++l;                  ++l;
                 ++l;                  ++l;
                 m->nospflag = 1;                  m->flag |= NOSPACE;
         } else          }
                 m->nospflag = 0;  
         for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )          for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
                 continue;                  continue;
         if (i == sizeof(m->desc)) {          if (i == sizeof(m->desc)) {
Line 1176 
Line 1331 
                 file_mdump(m);                  file_mdump(m);
         }          }
 #endif  #endif
           m->mimetype[0] = '\0';          /* initialise MIME type to none */
         if (m->cont_level == 0)          if (m->cont_level == 0)
                 ++(*nmentryp);          /* make room for next */                  ++(*nmentryp);          /* make room for next */
         return 0;          return 0;
 }  }
   
   /*
    * parse a MIME annotation line from magic file, put into magic[index - 1]
    * if valid
    */
 private int  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)  check_format_type(const char *ptr, int type)
 {  {
         int quad = 0;          int quad = 0;
Line 1254 
Line 1457 
                         return -1;                          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:          case FILE_FMT_STR:
                 if (*ptr == '-')                  if (*ptr == '-')
                         ptr++;                          ptr++;
Line 1300 
Line 1528 
         assert(file_nformats == file_nnames);          assert(file_nformats == file_nnames);
   
         if (m->type >= file_nformats) {          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");                      "m->type and format strings");
                 return -1;                  return -1;
         }          }
         if (file_formats[m->type] == FILE_FMT_NONE) {          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]);                      "`%s'", m->desc, file_names[m->type]);
                 return -1;                  return -1;
         }          }
Line 1316 
Line 1544 
                  * TODO: this error message is unhelpful if the format                   * TODO: this error message is unhelpful if the format
                  * string is not one character long                   * string is not one character long
                  */                   */
                 file_error(ms, 0, "Printf format `%c' is not valid for type "                  file_magwarn(ms, "Printf format `%c' is not valid for type "
                     " `%s' in description `%s'",                      "`%s' in description `%s'",
                     ptr && *ptr ? *ptr : '?',                      ptr && *ptr ? *ptr : '?',
                     file_names[m->type], m->desc);                      file_names[m->type], m->desc);
                 return -1;                  return -1;
Line 1325 
Line 1553 
   
         for (; *ptr; ptr++) {          for (; *ptr; ptr++) {
                 if (*ptr == '%') {                  if (*ptr == '%') {
                         file_error(ms, 0,                          file_magwarn(ms,
                             "Too many format strings (should have at most one) "                              "Too many format strings (should have at most one) "
                             "for `%s' with description `%s'",                              "for `%s' with description `%s'",
                             file_names[m->type], m->desc);                              file_names[m->type], m->desc);
Line 1360 
Line 1588 
                         return -1;                          return -1;
                 }                  }
                 m->vallen = slen;                  m->vallen = slen;
                   if (m->type == FILE_PSTRING)
                           m->vallen++;
                 return 0;                  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:          default:
                 if (m->reln != 'x') {                  if (m->reln != 'x') {
                         char *ep;                          char *ep;
Line 1634 
Line 1886 
         uint32_t *ptr;          uint32_t *ptr;
         uint32_t version;          uint32_t version;
         int needsbyteswap;          int needsbyteswap;
         char buf[MAXPATHLEN];          char *dbname = NULL;
         char *dbname = mkdbname(fn, buf, sizeof(buf), 0);  
         void *mm = NULL;          void *mm = NULL;
   
           mkdbname(fn, &dbname, 0);
         if (dbname == NULL)          if (dbname == NULL)
                 return -1;                  goto error2;
   
         if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)          if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
                 return -1;                  goto error2;
   
         if (fstat(fd, &st) == -1) {          if (fstat(fd, &st) == -1) {
                 file_error(ms, errno, "cannot stat `%s'", dbname);                  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);                  file_error(ms, 0, "file `%s' is too small", dbname);
                 goto error;                  goto error1;
         }          }
   
 #ifdef QUICK  #ifdef QUICK
         if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,          if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
             MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {              MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
                 file_error(ms, errno, "cannot map `%s'", dbname);                  file_error(ms, errno, "cannot map `%s'", dbname);
                 goto error;                  goto error1;
         }          }
 #define RET     2  #define RET     2
 #else  #else
         if ((mm = malloc((size_t)st.st_size)) == NULL) {          if ((mm = malloc((size_t)st.st_size)) == NULL) {
                 file_oomem(ms, (size_t)st.st_size);                  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) {          if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
                 file_badread(ms);                  file_badread(ms);
                 goto error;                  goto error1;
         }          }
 #define RET     1  #define RET     1
 #endif  #endif
Line 1678 
Line 1930 
         if (*ptr != MAGICNO) {          if (*ptr != MAGICNO) {
                 if (swap4(*ptr) != MAGICNO) {                  if (swap4(*ptr) != MAGICNO) {
                         file_error(ms, 0, "bad magic in `%s'");                          file_error(ms, 0, "bad magic in `%s'");
                         goto error;                          goto error1;
                 }                  }
                 needsbyteswap = 1;                  needsbyteswap = 1;
         } else          } else
Line 1688 
Line 1940 
         else          else
                 version = ptr[1];                  version = ptr[1];
         if (version != VERSIONNO) {          if (version != VERSIONNO) {
                 file_error(ms, 0, "version mismatch (%d != %d) in `%s'",                  file_error(ms, 0, "File %d.%d supports only %d version magic "
                     version, VERSIONNO, dbname);                      "files. `%s' is version %d", FILE_VERSION_MAJOR, patchlevel,
                 goto error;                      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)++;          (*magicp)++;
         if (needsbyteswap)          if (needsbyteswap)
                 byteswap(*magicp, *nmagicp);                  byteswap(*magicp, *nmagicp);
           free(dbname);
         return RET;          return RET;
   
 error:  error1:
         if (fd != -1)          if (fd != -1)
                 (void)close(fd);                  (void)close(fd);
         if (mm) {          if (mm) {
Line 1711 
Line 1967 
                 *magicp = NULL;                  *magicp = NULL;
                 *nmagicp = 0;                  *nmagicp = 0;
         }          }
   error2:
           free(dbname);
         return -1;          return -1;
 }  }
   
Line 1725 
Line 1983 
     uint32_t *nmagicp, const char *fn)      uint32_t *nmagicp, const char *fn)
 {  {
         int fd;          int fd;
         char buf[MAXPATHLEN];          char *dbname;
         char *dbname = mkdbname(fn, buf, sizeof(buf), 1);          int rv = -1;
   
           mkdbname(fn, &dbname, 1);
   
         if (dbname == NULL)          if (dbname == NULL)
                 return -1;                  goto out;
   
         if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {          if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
                 file_error(ms, errno, "cannot open `%s'", dbname);                  file_error(ms, errno, "cannot open `%s'", dbname);
                 return -1;                  goto out;
         }          }
   
         if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {          if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
                 file_error(ms, errno, "error writing `%s'", dbname);                  file_error(ms, errno, "error writing `%s'", dbname);
                 return -1;                  goto out;
         }          }
   
         if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)          if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
             != sizeof(struct magic)) {              != sizeof(struct magic)) {
                 file_error(ms, errno, "error seeking `%s'", dbname);                  file_error(ms, errno, "error seeking `%s'", dbname);
                 return -1;                  goto out;
         }          }
   
         if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp))          if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp))
             != (ssize_t)(sizeof(struct magic) * *nmagicp)) {              != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
                 file_error(ms, errno, "error writing `%s'", dbname);                  file_error(ms, errno, "error writing `%s'", dbname);
                 return -1;                  goto out;
         }          }
   
         (void)close(fd);          (void)close(fd);
         return 0;          rv = 0;
   out:
           free(dbname);
           return rv;
 }  }
   
 private const char ext[] = ".mgc";  private const char ext[] = ".mgc";
 /*  /*
  * make a dbname   * make a dbname
  */   */
 private char *  private void
 mkdbname(const char *fn, char *buf, size_t bufsiz, int strip)  mkdbname(const char *fn, char **buf, int strip)
 {  {
         if (strip) {          if (strip) {
                 const char *p;                  const char *p;
Line 1770 
Line 2033 
                         fn = ++p;                          fn = ++p;
         }          }
   
         (void)snprintf(buf, bufsiz, "%s%s", fn, ext);          (void)asprintf(buf, "%s%s", fn, ext);
         return buf;          if (*buf && strlen(*buf) > MAXPATHLEN) {
                   free(*buf);
                   *buf = NULL;
           }
 }  }
   
 /*  /*
Line 1824 
Line 2090 
         uint32_t rv;          uint32_t rv;
         uint8_t *s = (uint8_t *)(void *)&sv;          uint8_t *s = (uint8_t *)(void *)&sv;
         uint8_t *d = (uint8_t *)(void *)&rv;          uint8_t *d = (uint8_t *)(void *)&rv;
   #if 0
         d[0] = s[3];          d[0] = s[3];
         d[1] = s[2];          d[1] = s[2];
         d[2] = s[1];          d[2] = s[1];
Line 1832 
Line 2099 
         d[5] = s[6];          d[5] = s[6];
         d[6] = s[5];          d[6] = s[5];
         d[7] = s[4];          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;          return rv;
 }  }
   
Line 1846 
Line 2123 
         m->in_offset = swap4((uint32_t)m->in_offset);          m->in_offset = swap4((uint32_t)m->in_offset);
         m->lineno = swap4((uint32_t)m->lineno);          m->lineno = swap4((uint32_t)m->lineno);
         if (IS_STRING(m->type)) {          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);                  m->str_flags = swap4(m->str_flags);
         }          }
         else {          else {

Legend:
Removed from v.1.25  
changed lines
  Added in v.1.26