Add support for specifying header information before reading file
authorJonathan Dieter <jdieter@gmail.com>
Wed, 30 May 2018 11:01:35 +0000 (14:01 +0300)
committerJonathan Dieter <jdieter@gmail.com>
Wed, 30 May 2018 11:01:35 +0000 (14:01 +0300)
Signed-off-by: Jonathan Dieter <jdieter@gmail.com>
include/zck.h
src/lib/comp/comp.c
src/lib/zck.c
src/lib/zck_private.h
src/zck.c

index fffacf38e47404a4c4f67f1c799951c1d322289a..af70e4f12e8985da58de0328c936134b84261f8f 100644 (file)
@@ -24,12 +24,14 @@ typedef enum zck_comp {
 typedef enum zck_ioption {
     ZCK_HASH_FULL_TYPE = 0,     /* Set full file hash type, using zck_hash */
     ZCK_HASH_CHUNK_TYPE,        /* Set chunk hash type using zck_hash */
+    ZCK_VAL_HEADER_HASH_TYPE,   /* Set what the header hash type *should* be */
+    ZCK_VAL_HEADER_LENGTH,      /* Set what the header length *should* be */
     ZCK_COMP_TYPE = 100,        /* Set compression type using zck_comp */
-    ZCK_COMP_DICT_SIZE,         /* Set compression dictionary size */
     ZCK_ZSTD_COMP_LEVEL = 1000  /* Set zstd compression level */
 } zck_ioption;
 
 typedef enum zck_soption {
+    ZCK_VAL_HEADER_DIGEST = 0,  /* Set what the header hash *should* be */
     ZCK_COMP_DICT = 100         /* Set compression dictionary */
 } zck_soption;
 
@@ -108,7 +110,8 @@ void zck_free(zckCtx **zck);
  * Options
  *******************************************************************/
 /* Set string option */
-int zck_set_soption(zckCtx *zck, zck_soption option, const void *value)
+int zck_set_soption(zckCtx *zck, zck_soption option, const void *value,
+                    size_t length)
     __attribute__ ((warn_unused_result));
 /* Set integer option */
 int zck_set_ioption(zckCtx *zck, zck_ioption option, ssize_t value)
index cb04566e1750599bd2061875ebd4d5805b97485d..1277bb12f604aeb2ea339bf8361f2797176e7e75 100644 (file)
@@ -224,8 +224,6 @@ int comp_ioption(zckCtx *zck, zck_ioption option, ssize_t value) {
     }
     if(option == ZCK_COMP_TYPE) {
         return set_comp_type(zck, value);
-    } else if(option == ZCK_COMP_DICT_SIZE) {
-        zck->comp.dict_size = value;
     } else {
         if(zck && zck->comp.set_parameter)
             return zck->comp.set_parameter(&(zck->comp), option, &value);
@@ -237,7 +235,8 @@ int comp_ioption(zckCtx *zck, zck_ioption option, ssize_t value) {
     return True;
 }
 
-int comp_soption(zckCtx *zck, zck_soption option, const void *value) {
+int comp_soption(zckCtx *zck, zck_soption option, const void *value,
+                 size_t length) {
     VALIDATE(zck);
 
     /* Cannot change compression parameters after compression has started */
@@ -247,19 +246,15 @@ int comp_soption(zckCtx *zck, zck_soption option, const void *value) {
         return False;
     }
     if(option == ZCK_COMP_DICT) {
-        if(zck->comp.dict_size == 0) {
-            zck_log(ZCK_LOG_ERROR,
-                    "Dict size must be set before adding dict\n");
-            return False;
-        }
-        char *dict = zmalloc(zck->comp.dict_size);
+        char *dict = zmalloc(length);
         if(dict == NULL) {
             zck_log(ZCK_LOG_ERROR, "Unable to allocate %lu bytes\n",
-                    zck->comp.dict_size);
+                    length);
             return False;
         }
-        memcpy(dict, value, zck->comp.dict_size);
+        memcpy(dict, value, length);
         zck->comp.dict = dict;
+        zck->comp.dict_size = length;
     } else {
         if(zck && zck->comp.set_parameter)
             return zck->comp.set_parameter(&(zck->comp), option, value);
index 2f078e9b70d8d16087d5b481494a5d8b82de0de2..a9cec56f6791cd609365dfbf0a76cb4e26de4c9e 100644 (file)
                                 return False; \
                             }
 
+#define VALIDATE_WRITE(f)   VALIDATE(f); \
+                            if(f->mode != ZCK_MODE_WRITE) { \
+                                zck_log(ZCK_LOG_ERROR, \
+                                        "zckCtx not opened for writing\n"); \
+                                return False; \
+                            }
+
 int PUBLIC zck_set_ioption(zckCtx *zck, zck_ioption option, ssize_t value) {
     /* Set hash type */
     if(option == ZCK_HASH_FULL_TYPE) {
+        VALIDATE_WRITE(zck);
         return set_full_hash_type(zck, value);
     } else if(option == ZCK_HASH_CHUNK_TYPE) {
+        VALIDATE_WRITE(zck);
         return set_chunk_hash_type(zck, value);
 
+    /* Validation options */
+    } else if(option == ZCK_VAL_HEADER_HASH_TYPE) {
+        VALIDATE_READ(zck);
+        if(value < 0) {
+            zck_log(ZCK_LOG_ERROR,
+                    "Header hash type can't be less than zero: %li\n",
+                    value);
+            return False;
+        }
+        /* Make sure that header hash type is set before the header digest,
+         * otherwise we run the risk of a buffer overflow */
+        if(zck->prep_digest != NULL) {
+            zck_log(ZCK_LOG_ERROR,
+                    "For validation, you must set the header hash type "
+                    "*before* the header digest itself\n");
+            return False;
+        }
+        zck->prep_hash_type = value;
+    } else if(option == ZCK_VAL_HEADER_LENGTH) {
+        VALIDATE_READ(zck);
+        if(value < 0) {
+            zck_log(ZCK_LOG_ERROR,
+                    "Header size validation can't be less than zero: %li\n",
+                    value);
+            return False;
+        }
+        zck->prep_hdr_size = value;
+
     /* Hash options */
     } else if(option < 100) {
         /* Currently no hash options other than setting hash type, so bail */
@@ -62,31 +99,51 @@ int PUBLIC zck_set_ioption(zckCtx *zck, zck_ioption option, ssize_t value) {
 
     /* Compression options */
     } else if(option < 2000) {
+        VALIDATE_WRITE(zck);
         return comp_ioption(zck, option, value);
 
     /* Unknown options */
     } else {
-        zck_log(ZCK_LOG_ERROR, "Unknown option %lu\n", value);
+        zck_log(ZCK_LOG_ERROR, "Unknown integer option %i\n", option);
         return False;
     }
+    return True;
 }
 
-int PUBLIC zck_set_soption(zckCtx *zck, zck_soption option, const void *value) {
-    /* Hash options */
-    if(option < 100) {
-        /* Currently no hash options other than setting hash type, so bail */
-        zck_log(ZCK_LOG_ERROR, "Unknown option %lu\n", value);
-        return False;
+int PUBLIC zck_set_soption(zckCtx *zck, zck_soption option, const void *value,
+                           size_t length) {
+    /* Validation options */
+    if(option == ZCK_VAL_HEADER_DIGEST) {
+        VALIDATE_READ(zck);
+        zckHashType chk_type = {0};
+        if(zck->prep_hash_type < 0) {
+            zck_log(ZCK_LOG_ERROR,
+                    "For validation, you must set the header hash type "
+                    "*before* the header digest itself\n");
+            return False;
+        }
+        if(!zck_hash_setup(&chk_type, zck->prep_hash_type))
+            return False;
+        if(chk_type.digest_size != length) {
+            zck_log(ZCK_LOG_ERROR, "Hash digest size mismatch for header "
+                    "validation\n"
+                    "Expected: %lu\nProvided: %lu\n", chk_type.digest_size,
+                    length);
+            return False;
+        }
+        zck->prep_digest = zmalloc(length);
+        memcpy(zck->prep_digest, value, length);
 
     /* Compression options */
     } else if(option < 2000) {
-        return comp_soption(zck, option, value);
+        return comp_soption(zck, option, value, length);
 
     /* Unknown options */
     } else {
-        zck_log(ZCK_LOG_ERROR, "Unknown option %lu\n", value);
+        zck_log(ZCK_LOG_ERROR, "Unknown string option %i\n", option);
         return False;
     }
+    return True;
 }
 int PUBLIC zck_close(zckCtx *zck) {
     VALIDATE(zck);
@@ -345,15 +402,12 @@ int zck_import_dict(zckCtx *zck) {
     zck_log(ZCK_LOG_DEBUG, "Resetting compression\n");
     if(!zck_comp_reset(zck))
         return False;
-    zck_log(ZCK_LOG_DEBUG, "Setting dict size\n");
-    if(!zck_set_ioption(zck, ZCK_COMP_DICT_SIZE, size))
-        return False;
     zck_log(ZCK_LOG_DEBUG, "Setting dict\n");
-    if(!zck_set_soption(zck, ZCK_COMP_DICT, data))
+    if(!zck_set_soption(zck, ZCK_COMP_DICT, data, size))
         return False;
+    free(data);
     if(!zck_comp_init(zck))
         return False;
-    free(data);
 
     return True;
 }
index 725ff106db3f89cf91c27f2425adfcd2ab43c507..a29a9be10b93bc7c8e9da0b577de3bf4231e43f6 100644 (file)
@@ -261,7 +261,8 @@ ssize_t comp_read(zckCtx *zck, char *dst, size_t dst_size, int use_dict)
     __attribute__ ((warn_unused_result));
 int comp_ioption(zckCtx *zck, zck_ioption option, ssize_t value)
     __attribute__ ((warn_unused_result));
-int comp_soption(zckCtx *zck, zck_soption option, const void *value)
+int comp_soption(zckCtx *zck, zck_soption option, const void *value,
+                 size_t length)
     __attribute__ ((warn_unused_result));
 
 /* dl/range.c */
index aad3722a43082e6578df22706731b26d40f0357b..a3a688d704d778fe5b5797d30933e456e59d9a7d 100644 (file)
--- a/src/zck.c
+++ b/src/zck.c
@@ -173,9 +173,7 @@ int main (int argc, char *argv[]) {
         exit(1);
     }*/
     if(dict_size > 0) {
-        if(!zck_set_ioption(zck, ZCK_COMP_DICT_SIZE, dict_size))
-            exit(1);
-        if(!zck_set_soption(zck, ZCK_COMP_DICT, dict))
+        if(!zck_set_soption(zck, ZCK_COMP_DICT, dict, dict_size))
             exit(1);
     }
     free(dict);