PR/367: Brooks Davis: Add magic_load_buffers to provide a means to load the
authorChristos Zoulas <christos@zoulas.com>
Mon, 4 Aug 2014 06:19:44 +0000 (06:19 +0000)
committerChristos Zoulas <christos@zoulas.com>
Mon, 4 Aug 2014 06:19:44 +0000 (06:19 +0000)
magic database on environments that have no direct access to the filesystem.

ChangeLog
doc/libmagic.man
src/apprentice.c
src/file.h
src/magic.c
src/magic.h.in

index 6722e33a0f75f5e6d028dc6e9c8d781a94b0aac3..c0e7273c1fb938b61a0d42ff26112501e99664be 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2014-08-04   9:18  Christos Zoulas <christos@zoulas.com>
+
+       * add magic_load_buffers from Brooks Davis
+
 2014-07-24  16:40  Christos Zoulas <christos@zoulas.com>
 
        * add thumbs.db support
index 6ab6d71e7a149fc2ac990d3cb5a4f597794dc24b..6aa374f458b48dbfb5309d66140ce17768149c0c 100644 (file)
@@ -1,4 +1,4 @@
-.\" $File: libmagic.man,v 1.27 2013/01/06 20:56:52 christos Exp $
+.\" $File: libmagic.man,v 1.28 2014/03/02 14:47:16 christos Exp $
 .\"
 .\" Copyright (c) Christos Zoulas 2003.
 .\" All Rights Reserved.
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd January 6, 2012
+.Dd August 4, 2014
 .Dt LIBMAGIC 3
 .Os
 .Sh NAME
@@ -71,6 +71,8 @@
 .Ft int
 .Fn magic_load "magic_t cookie" "const char *filename"
 .Ft int
+.Fn magic_load_buffers "magic_t cookie" "void **buffers" "size_t *sizes" "size_t nbuffers"
+.Ft int
 .Fn magic_version "void"
 .Sh DESCRIPTION
 These functions
@@ -253,6 +255,19 @@ adds
 to the database filename as appropriate.
 .Pp
 The
+.Fn magic_load_buffers
+function takes an array of size
+.Fa nbuffers
+of
+.Fa buffers
+with a respective size for each in the array of
+.Fa sizes
+loaded with the contents of the magic databases from the filesystem.
+This function can be used in environment where the magic library does
+not have direct access to the filesystem, but can access the magic
+database via shared memory or other IPC means.
+.Pp
+The
 .Fn magic_version
 command returns the version number of this library which is compiled into
 the shared library using the constant
index d3c45f70a92af42fe110760f99974712e89cf023..c7931b8e2b065e939a19a9ccc577b790091727ed 100644 (file)
@@ -32,7 +32,7 @@
 #include "file.h"
 
 #ifndef        lint
-FILE_RCSID("@(#)$File: apprentice.c,v 1.211 2014/06/03 19:01:34 christos Exp $")
+FILE_RCSID("@(#)$File: apprentice.c,v 1.212 2014/06/26 12:53:36 christos Exp $")
 #endif /* lint */
 
 #include "magic.h"
@@ -86,6 +86,10 @@ FILE_RCSID("@(#)$File: apprentice.c,v 1.211 2014/06/03 19:01:34 christos Exp $")
 #define ALLOC_CHUNK    (size_t)10
 #define ALLOC_INCR     (size_t)200
 
+#define MAP_TYPE_MMAP  0
+#define MAP_TYPE_MALLOC        1
+#define MAP_TYPE_USER  2
+
 struct magic_entry {
        struct magic *mp;       
        uint32_t cont_count;
@@ -101,6 +105,7 @@ struct magic_entry_set {
 struct magic_map {
        void *p;
        size_t len;
+       int type;
        struct magic *magic[MAGIC_SETS];
        uint32_t nmagic[MAGIC_SETS];
 };
@@ -131,7 +136,10 @@ private uint16_t swap2(uint16_t);
 private uint32_t swap4(uint32_t);
 private uint64_t swap8(uint64_t);
 private char *mkdbname(struct magic_set *, const char *, int);
+private struct magic_map *apprentice_buf(struct magic_set *, struct magic *,
+    size_t);
 private struct magic_map *apprentice_map(struct magic_set *, const char *);
+private int check_buffer(struct magic_set *, struct magic_map *, const char *);
 private void apprentice_unmap(struct magic_map *);
 private int apprentice_compile(struct magic_set *, struct magic_map *,
     const char *);
@@ -518,9 +526,9 @@ apprentice_unmap(struct magic_map *map)
 {
        if (map == NULL)
                return;
-       if (map->p != NULL) {
+       if (map->p != NULL && map->type != MAP_TYPE_USER) {
 #ifdef QUICK
-               if (map->len)
+               if (map->type == MAP_TYPE_MMAP)
                        (void)munmap(map->p, map->len);
                else
 #endif
@@ -562,6 +570,56 @@ mlist_free(struct mlist *mlist)
        free(ml);
 }
 
+#ifndef COMPILE_ONLY
+/* void **bufs: an array of compiled magic files */
+protected int
+buffer_apprentice(struct magic_set *ms, struct magic **bufs,
+    size_t *sizes, size_t nbufs)
+{
+       size_t i;
+       struct mlist *ml;
+       struct magic_map *map;
+
+       if (nbufs == 0)
+               return -1;
+
+       if (ms->mlist[0] != NULL)
+               file_reset(ms);
+
+       init_file_tables();
+
+       for (i = 0; i < MAGIC_SETS; i++) {
+               mlist_free(ms->mlist[i]);
+               if ((ms->mlist[i] = mlist_alloc()) == NULL) {
+                       file_oomem(ms, sizeof(*ms->mlist[i]));
+                       if (i != 0) {
+                               --i;
+                               do
+                                       mlist_free(ms->mlist[i]);
+                               while (i != 0);
+                       }
+                       return -1;
+               }
+       }
+
+       for (i = 0; i < nbufs; i++) {
+               map = apprentice_buf(ms, bufs[i], sizes[i]);
+               if (map == NULL)
+                       return -1;
+
+               for (i = 0; i < MAGIC_SETS; i++) {
+                       if (add_mlist(ms->mlist[i], map, i) == -1) {
+                               file_oomem(ms, sizeof(*ml));
+                               apprentice_unmap(map);
+                               return -1;
+                       }
+               }
+       }
+
+       return 0;
+}
+#endif
+
 /* const char *fn: list of magic files and directories */
 protected int
 file_apprentice(struct magic_set *ms, const char *fn, int action)
@@ -2693,6 +2751,28 @@ eatsize(const char **p)
        *p = l;
 }
 
+/*
+ * handle a buffer containging a compiled file.
+ */
+private struct magic_map *
+apprentice_buf(struct magic_set *ms, struct magic *buf, size_t len)
+{
+       struct magic_map *map;
+
+       if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) {
+               file_oomem(ms, sizeof(*map));
+               return NULL;
+       }
+       map->len = len;
+       map->p = buf;
+       map->type = MAP_TYPE_USER;
+       if (check_buffer(ms, map, "buffer") != 0) {
+               apprentice_unmap(map);
+               return NULL;
+       }
+       return map;
+}
+
 /*
  * handle a compiled file.
  */
@@ -2702,12 +2782,8 @@ apprentice_map(struct magic_set *ms, const char *fn)
 {
        int fd;
        struct stat st;
-       uint32_t *ptr;
-       uint32_t version, entries, nentries;
-       int needsbyteswap;
        char *dbname = NULL;
        struct magic_map *map;
-       size_t i;
 
        fd = -1;
        if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) {
@@ -2739,6 +2815,7 @@ apprentice_map(struct magic_set *ms, const char *fn)
                file_error(ms, errno, "cannot map `%s'", dbname);
                goto error;
        }
+       map->type = MAP_TYPE_MMAP;
 #else
        if ((map->p = CAST(void *, malloc(map->len))) == NULL) {
                file_oomem(ms, map->len);
@@ -2748,16 +2825,39 @@ apprentice_map(struct magic_set *ms, const char *fn)
                file_badread(ms);
                goto error;
        }
-       map->len = 0;
+       map->type = MAP_TYPE_MALLOC;
 #define RET    1
 #endif
        (void)close(fd);
        fd = -1;
+
+       if (check_buffer(ms, map, dbname) != 0)
+               goto error;
+
+       free(dbname);
+       return map;
+
+error:
+       if (fd != -1)
+               (void)close(fd);
+       apprentice_unmap(map);
+       free(dbname);
+       return NULL;
+}
+
+private int
+check_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname)
+{
+       uint32_t *ptr;
+       uint32_t entries, nentries;
+       uint32_t version;
+       int i, needsbyteswap;
+
        ptr = CAST(uint32_t *, map->p);
        if (*ptr != MAGICNO) {
                if (swap4(*ptr) != MAGICNO) {
                        file_error(ms, 0, "bad magic in `%s'", dbname);
-                       goto error;
+                       return -1;
                }
                needsbyteswap = 1;
        } else
@@ -2770,15 +2870,15 @@ apprentice_map(struct magic_set *ms, const char *fn)
                file_error(ms, 0, "File %s supports only version %d magic "
                    "files. `%s' is version %d", VERSION,
                    VERSIONNO, dbname, version);
-               goto error;
+               return -1;
        }
-       entries = (uint32_t)(st.st_size / sizeof(struct magic));
-       if ((off_t)(entries * sizeof(struct magic)) != st.st_size) {
+       entries = (uint32_t)(map->len / sizeof(struct magic));
+       if ((entries * sizeof(struct magic)) != map->len) {
                file_error(ms, 0, "Size of `%s' %" INT64_T_FORMAT "u is not "
                    "a multiple of %" SIZE_T_FORMAT "u",
-                   dbname, (unsigned long long)st.st_size,
+                   dbname, (unsigned long long)map->len,
                    sizeof(struct magic));
-               goto error;
+               return -1;
        }
        map->magic[0] = CAST(struct magic *, map->p) + 1;
        nentries = 0;
@@ -2794,20 +2894,12 @@ apprentice_map(struct magic_set *ms, const char *fn)
        if (entries != nentries + 1) {
                file_error(ms, 0, "Inconsistent entries in `%s' %u != %u",
                    dbname, entries, nentries + 1);
-               goto error;
+               return -1;
        }
        if (needsbyteswap)
                for (i = 0; i < MAGIC_SETS; i++)
                        byteswap(map->magic[i], map->nmagic[i]);
-       free(dbname);
-       return map;
-
-error:
-       if (fd != -1)
-               (void)close(fd);
-       apprentice_unmap(map);
-       free(dbname);
-       return NULL;
+       return -1;
 }
 
 /*
index 8e1df2995280f9c944d0d5db3d1ecc0399289e83..fa933d85bda6b306070b313bee4a31451e2942d9 100644 (file)
@@ -27,7 +27,7 @@
  */
 /*
  * file.h - definitions for file(1) program
- * @(#)$File: file.h,v 1.151 2014/05/14 23:15:42 christos Exp $
+ * @(#)$File: file.h,v 1.152 2014/06/03 19:01:34 christos Exp $
  */
 
 #ifndef __file_h__
@@ -442,6 +442,8 @@ protected int file_is_tar(struct magic_set *, const unsigned char *, size_t);
 protected int file_softmagic(struct magic_set *, const unsigned char *, size_t,
     size_t, int, int);
 protected int file_apprentice(struct magic_set *, const char *, int);
+protected int buffer_apprentice(struct magic_set *, struct magic **,
+    size_t *, size_t);
 protected int file_magicfind(struct magic_set *, const char *, struct mlist *);
 protected uint64_t file_signextend(struct magic_set *, struct magic *,
     uint64_t);
index cbae198992f60e23fbf8498a07774809846cdd54..b2b87c903a8775e6c6ec45e35988f5aba44aa94c 100644 (file)
@@ -33,7 +33,7 @@
 #include "file.h"
 
 #ifndef        lint
-FILE_RCSID("@(#)$File: magic.c,v 1.83 2014/05/13 16:44:24 christos Exp $")
+FILE_RCSID("@(#)$File: magic.c,v 1.84 2014/05/14 23:15:42 christos Exp $")
 #endif /* lint */
 
 #include "magic.h"
@@ -257,6 +257,20 @@ magic_load(struct magic_set *ms, const char *magicfile)
        return file_apprentice(ms, magicfile, FILE_LOAD);
 }
 
+#ifndef COMPILE_ONLY
+/*
+ * Install a set of compiled magic buffers.
+ */
+public int
+magic_load_buffers(struct magic_set *ms, void **bufs, size_t *sizes,
+    size_t nbufs)
+{
+       if (ms == NULL)
+               return -1;
+       return buffer_apprentice(ms, (struct magic **)bufs, sizes, nbufs);
+}
+#endif
+
 public int
 magic_compile(struct magic_set *ms, const char *magicfile)
 {
index 86fc41b77f0f6dc989bbdb4a83903678bdbae0e3..4a3570523dd41147c04c035109c025620e561f71 100644 (file)
@@ -96,6 +96,8 @@ int magic_setflags(magic_t, int);
 
 int magic_version(void);
 int magic_load(magic_t, const char *);
+int magic_load_buffers(struct magic_set *, void **, size_t *, size_t);
+
 int magic_compile(magic_t, const char *);
 int magic_check(magic_t, const char *);
 int magic_list(magic_t, const char *);