]> granicus.if.org Git - file/commitdiff
Add thumbs.db parsing support.
authorChristos Zoulas <christos@zoulas.com>
Thu, 24 Jul 2014 19:35:39 +0000 (19:35 +0000)
committerChristos Zoulas <christos@zoulas.com>
Thu, 24 Jul 2014 19:35:39 +0000 (19:35 +0000)
src/cdf.c
src/cdf.h
src/readcdf.c

index c258e82f35def06e1d031222ec7bb2d9d2b16228..5dbf3b13e65eecdb5dc8fb1699a4cdf242d021b1 100644 (file)
--- a/src/cdf.c
+++ b/src/cdf.c
@@ -35,7 +35,7 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: cdf.c,v 1.62 2014/06/04 17:26:07 christos Exp $")
+FILE_RCSID("@(#)$File: cdf.c,v 1.63 2014/06/09 13:04:37 christos Exp $")
 #endif
 
 #include <assert.h>
@@ -73,6 +73,8 @@ static union {
 #define CDF_TOLE8(x)   ((uint64_t)(NEED_SWAP ? _cdf_tole8(x) : (uint64_t)(x)))
 #define CDF_TOLE4(x)   ((uint32_t)(NEED_SWAP ? _cdf_tole4(x) : (uint32_t)(x)))
 #define CDF_TOLE2(x)   ((uint16_t)(NEED_SWAP ? _cdf_tole2(x) : (uint16_t)(x)))
+#define CDF_TOLE(x)    (sizeof(x) == 2 ? CDF_TOLE2(x) : (sizeof(x) == 4 ? \
+    CDF_TOLE4(x) : CDF_TOLE8(x)))
 #define CDF_GETUINT32(x, y)    cdf_getuint32(x, y)
 
 
@@ -731,6 +733,15 @@ cdf_read_summary_info(const cdf_info_t *info, const cdf_header_t *h,
            "\05SummaryInformation", scn);
 }
 
+int
+cdf_read_catalog(cdf_info_t *info, const cdf_header_t *h,
+    const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
+    const cdf_dir_t *dir, cdf_stream_t *scn)
+{
+       return cdf_read_user_stream(info, h, sat, ssat, sst, dir,
+           "Catalog", scn);
+}
+
 int
 cdf_read_user_stream(const cdf_info_t *info, const cdf_header_t *h,
     const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
@@ -985,6 +996,54 @@ cdf_unpack_summary_info(const cdf_stream_t *sst, const cdf_header_t *h,
 }
 
 
+#define extract_catalog_field(f, l) \
+    memcpy(&ce[i].f, b + (l), sizeof(ce[i].f)); \
+    ce[i].f = CDF_TOLE(ce[i].f)
+
+int
+cdf_unpack_catalog(const cdf_header_t *h, const cdf_stream_t *sst,
+    cdf_catalog_t **cat)
+{
+       size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
+           CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
+       const char *b = CAST(const char *, sst->sst_tab);
+       const char *eb = b + ss * sst->sst_len;
+       size_t nr, i, k;
+       cdf_catalog_entry_t *ce;
+       uint16_t reclen;
+       const uint16_t *np;
+
+       for (nr = 0; b < eb; nr++) {
+               memcpy(&reclen, b, sizeof(reclen));
+               reclen = CDF_TOLE2(reclen);
+               if (reclen == 0)
+                       break;
+               b += reclen;
+       }
+       *cat = CAST(cdf_catalog_t *,
+           malloc(sizeof(cdf_catalog_t) + nr * sizeof(*ce)));
+       (*cat)->cat_num = nr;
+       ce = (*cat)->cat_e;
+       b = CAST(const char *, sst->sst_tab);
+       for (i = 0; i < nr; i++) {
+               extract_catalog_field(ce_namlen, 0);
+               extract_catalog_field(ce_num, 2);
+               extract_catalog_field(ce_timestamp, 6);
+               reclen = ce[i].ce_namlen;
+               ce[i].ce_namlen =
+                   sizeof(ce[i].ce_name) / sizeof(ce[i].ce_name[0]) - 1;
+               if (ce[i].ce_namlen > reclen - 14)
+                       ce[i].ce_namlen = reclen - 14;
+               np = CAST(const uint16_t *, (b + 16));
+               for (k = 0; k < ce[i].ce_namlen; k++) {
+                       ce[i].ce_name[k] = np[k];
+                       CDF_TOLE2(ce[i].ce_name[k]);
+               }
+               ce[i].ce_name[ce[i].ce_namlen] = 0;
+               b += reclen;
+       }
+       return 0;
+}
 
 int
 cdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id)
@@ -1068,6 +1127,15 @@ cdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts)
        return len;
 }
 
+char *
+cdf_u16tos8(char *buf, size_t len, const uint16_t *p)
+{
+       size_t i;
+       for (i = 0; i < len && p[i]; i++)
+               buf[i] = (char)p[i];
+       buf[i] = '\0';
+       return buf;
+}
 
 #ifdef CDF_DEBUG
 void
@@ -1288,7 +1356,7 @@ cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst)
                return;
        (void)fprintf(stderr, "Endian: %x\n", ssi.si_byte_order);
        (void)fprintf(stderr, "Os Version %d.%d\n", ssi.si_os_version & 0xff,
-               ssi.si_os_version >> 8);
+           ssi.si_os_version >> 8);
        (void)fprintf(stderr, "Os %d\n", ssi.si_os);
        cdf_print_classid(buf, sizeof(buf), &ssi.si_class);
        (void)fprintf(stderr, "Class %s\n", buf);
@@ -1297,6 +1365,27 @@ cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst)
        free(info);
 }
 
+
+void
+cdf_dump_catalog(const cdf_header_t *h, const cdf_stream_t *sst)
+{
+       cdf_catalog_t *cat;
+       cdf_unpack_catalog(h, sst, &cat);
+       const cdf_catalog_entry_t *ce = cat->cat_e;
+       struct timespec ts;
+       char tbuf[64], sbuf[256];
+       size_t i;
+
+       printf("Catalog:\n");
+       for (i = 0; i < cat->cat_num; i++) {
+               cdf_timestamp_to_timespec(&ts, ce[i].ce_timestamp);
+               printf("\t%d %s %s", ce[i].ce_num,
+                   cdf_u16tos8(sbuf, ce[i].ce_namlen, ce[i].ce_name),
+                   cdf_ctime(&ts.tv_sec, tbuf));
+       }
+       free(cat);
+}
+
 #endif
 
 #ifdef TEST
@@ -1309,6 +1398,7 @@ main(int argc, char *argv[])
        cdf_stream_t sst, scn;
        cdf_dir_t dir;
        cdf_info_t info;
+       const cdf_directory_t *root;
 
        if (argc < 2) {
                (void)fprintf(stderr, "Usage: %s <filename>\n", getprogname());
@@ -1342,7 +1432,8 @@ main(int argc, char *argv[])
                if (cdf_read_dir(&info, &h, &sat, &dir) == -1)
                        err(1, "Cannot read dir");
 
-               if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst) == -1)
+               if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst, &root)
+                   == -1)
                        err(1, "Cannot read short stream");
 #ifdef CDF_DEBUG
                cdf_dump_stream(&h, &sst);
@@ -1355,9 +1446,17 @@ main(int argc, char *argv[])
 
                if (cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
                    &scn) == -1)
-                       err(1, "Cannot read summary info");
+                       warn("Cannot read summary info");
+#ifdef CDF_DEBUG
+               else
+                       cdf_dump_summary_info(&h, &scn);
+#endif
+               if (cdf_read_catalog(&info, &h, &sat, &ssat, &sst, &dir,
+                   &scn) == -1)
+                       warn("Cannot read catalog");
 #ifdef CDF_DEBUG
-               cdf_dump_summary_info(&h, &scn);
+               else
+                       cdf_dump_catalog(&h, &scn);
 #endif
 
                (void)close(info.i_fd);
index 910fb95fc34112894433b34b8aeabf3665c30cb5..16459997056e887b2fbca24ee832082fe618cb46 100644 (file)
--- a/src/cdf.h
+++ b/src/cdf.h
@@ -267,6 +267,19 @@ typedef struct {
        size_t i_len;
 } cdf_info_t;
 
+
+typedef struct {
+       uint16_t ce_namlen;
+       uint32_t ce_num;
+       uint64_t ce_timestamp; 
+       uint16_t ce_name[256];
+} cdf_catalog_entry_t;
+
+typedef struct {
+       size_t cat_num;
+       cdf_catalog_entry_t cat_e[0];
+} cdf_catalog_t;
+
 struct timespec;
 int cdf_timestamp_to_timespec(struct timespec *, cdf_timestamp_t);
 int cdf_timespec_to_timestamp(cdf_timestamp_t *, const struct timespec *);
@@ -301,11 +314,16 @@ int cdf_read_property_info(const cdf_stream_t *, const cdf_header_t *, uint32_t,
 int cdf_read_user_stream(const cdf_info_t *, const cdf_header_t *,
     const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *,
     const cdf_dir_t *, const char *, cdf_stream_t *);
+int cdf_read_catalog(cdf_info_t *, const cdf_header_t *,
+    const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *,
+    const cdf_dir_t *, cdf_stream_t *);
 int cdf_read_summary_info(const cdf_info_t *, const cdf_header_t *,
     const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *,
     const cdf_dir_t *, cdf_stream_t *);
 int cdf_unpack_summary_info(const cdf_stream_t *, const cdf_header_t *,
     cdf_summary_info_header_t *, cdf_property_info_t **, size_t *);
+int cdf_unpack_catalog(const cdf_header_t *, const cdf_stream_t *,
+    cdf_catalog_t **);
 int cdf_print_classid(char *, size_t, const cdf_classid_t *);
 int cdf_print_property_name(char *, size_t, uint32_t);
 int cdf_print_elapsed_time(char *, size_t, cdf_timestamp_t);
@@ -313,6 +331,7 @@ uint16_t cdf_tole2(uint16_t);
 uint32_t cdf_tole4(uint32_t);
 uint64_t cdf_tole8(uint64_t);
 char *cdf_ctime(const time_t *, char *);
+char *cdf_u16tos8(char *, size_t, const uint16_t *);
 
 #ifdef CDF_DEBUG
 void cdf_dump_header(const cdf_header_t *);
@@ -323,6 +342,7 @@ void cdf_dump_dir(const cdf_info_t *, const cdf_header_t *, const cdf_sat_t *,
     const cdf_sat_t *, const cdf_stream_t *, const cdf_dir_t *);
 void cdf_dump_property_info(const cdf_property_info_t *, size_t);
 void cdf_dump_summary_info(const cdf_header_t *, const cdf_stream_t *);
+void cdf_dump_catalog(const cdf_header_t *, const cdf_stream_t *);
 #endif
 
 
index e1b283122b3c9f96038ff3fbbb1cff64b5cef027..b6b1dcb85913970a086a10849546dd28e72f7a70 100644 (file)
@@ -26,7 +26,7 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: readcdf.c,v 1.43 2014/05/07 21:26:06 christos Exp $")
+FILE_RCSID("@(#)$File: readcdf.c,v 1.44 2014/05/14 23:22:48 christos Exp $")
 #endif
 
 #include <assert.h>
@@ -240,6 +240,37 @@ cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info,
         return 1;
 }
 
+private int
+cdf_file_catalog(struct magic_set *ms, const cdf_header_t *h,
+    const cdf_stream_t *sst)
+{
+       cdf_catalog_t *cat;
+       size_t i;
+       char buf[256];
+       cdf_catalog_entry_t *ce;
+
+        if (NOTMIME(ms)) {
+               if (file_printf(ms, "Microsoft Thumbs.db [") == -1)
+                       return -1;
+               if (cdf_unpack_catalog(h, sst, &cat) == -1)
+                       return -1;
+               ce = cat->cat_e;
+               /* skip first entry since it has a , or paren */
+               for (i = 1; i < cat->cat_num; i++)
+                       if (file_printf(ms, "%s%s",
+                           cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name),
+                           i == cat->cat_num - 1 ? "]" : ", ") == -1) {
+                               free(cat);
+                               return -1;
+                       }
+               free(cat);
+       } else {
+               if (file_printf(ms, "application/CDFV2") == -1)
+                       return -1;
+       }
+       return 1;
+}
+
 private int
 cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h,
     const cdf_stream_t *sst, const cdf_directory_t *root_storage)
@@ -285,11 +316,12 @@ cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h,
                if (root_storage) {
                        str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
                            clsid2desc);
-                       if (str)
+                       if (str) {
                                if (file_printf(ms, ", %s", str) == -1)
                                        return -2;
                        }
                }
+       }
 
         m = cdf_file_property_info(ms, info, count, root_storage);
         free(info);
@@ -404,8 +436,18 @@ file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf,
         if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
             &scn)) == -1) {
                 if (errno == ESRCH) {
-                        corrupt = expn;
-                        expn = "No summary info";
+                       if ((i = cdf_read_catalog(&info, &h, &sat, &ssat, &sst,
+                           &dir, &scn)) == -1) {
+                               corrupt = expn;
+                               expn = "No summary info";
+                               goto out4;
+                       }
+#ifdef CDF_DEBUG
+                       cdf_dump_catalog(&h, &scn);
+#endif
+                       if ((i = cdf_file_catalog(ms, &h, &scn))
+                           < 0)
+                               expn = "Can't expand catalog";
                 } else {
                         expn = "Cannot read summary info";
                 }