hivex: Add metadata length functions for nodes and values
[hivex.git] / lib / hivex.c
index 4b9fcf0..3063c45 100644 (file)
@@ -585,6 +585,30 @@ hivex_root (hive_h *h)
   return ret;
 }
 
+size_t
+hivex_node_struct_length (hive_h *h, hive_node_h node)
+{
+  if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
+    errno = EINVAL;
+    return 0;
+  }
+
+  struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
+  size_t name_len = le16toh (nk->name_len);
+  /* -1 to avoid double-counting the first name character */
+  size_t ret = name_len + sizeof (struct ntreg_nk_record) - 1;
+  int used;
+  size_t seg_len = block_len (h, node, &used);
+  if (ret > seg_len) {
+    if (h->msglvl >= 2)
+      fprintf (stderr, "hivex_node_struct_length: returning EFAULT because"
+               " node name is too long (%zu, %zu)\n", name_len, seg_len);
+    errno = EFAULT;
+    return 0;
+  }
+  return ret;
+}
+
 char *
 hivex_node_name (hive_h *h, hive_node_h node)
 {
@@ -1189,8 +1213,22 @@ hivex_node_get_value (hive_h *h, hive_node_h node, const char *key)
   return ret;
 }
 
-char *
-hivex_value_key (hive_h *h, hive_value_h value)
+size_t
+hivex_value_struct_length (hive_h *h, hive_value_h value)
+{
+  size_t key_len;
+
+  errno = 0;
+  key_len = hivex_value_key_len (h, value);
+  if (key_len == 0 && errno != 0)
+    return 0;
+
+  /* -1 to avoid double-counting the first name character */
+  return key_len + sizeof (struct ntreg_vk_record) - 1;
+}
+
+size_t
+hivex_value_key_len (hive_h *h, hive_value_h value)
 {
   if (!IS_VALID_BLOCK (h, value) || !BLOCK_ID_EQ (h, value, "vk")) {
     errno = EINVAL;
@@ -1199,24 +1237,40 @@ hivex_value_key (hive_h *h, hive_value_h value)
 
   struct ntreg_vk_record *vk = (struct ntreg_vk_record *) (h->addr + value);
 
-  /* AFAIK the key is always plain ASCII, so no conversion to UTF-8 is
-   * necessary.  However we do need to nul-terminate the string.
-   */
-
   /* vk->name_len is unsigned, 16 bit, so this is safe ...  However
    * we have to make sure the length doesn't exceed the block length.
    */
-  size_t len = le16toh (vk->name_len);
+  size_t ret = le16toh (vk->name_len);
   size_t seg_len = block_len (h, value, NULL);
-  if (sizeof (struct ntreg_vk_record) + len - 1 > seg_len) {
+  if (sizeof (struct ntreg_vk_record) + ret - 1 > seg_len) {
     if (h->msglvl >= 2)
-      fprintf (stderr, "hivex_value_key: returning EFAULT"
+      fprintf (stderr, "hivex_value_key_len: returning EFAULT"
                " because key length is too long (%zu, %zu)\n",
-               len, seg_len);
+               ret, seg_len);
     errno = EFAULT;
-    return NULL;
+    return 0;
+  }
+  return ret;
+}
+
+char *
+hivex_value_key (hive_h *h, hive_value_h value)
+{
+  if (!IS_VALID_BLOCK (h, value) || !BLOCK_ID_EQ (h, value, "vk")) {
+    errno = EINVAL;
+    return 0;
   }
 
+  struct ntreg_vk_record *vk = (struct ntreg_vk_record *) (h->addr + value);
+
+  /* AFAIK the key is always plain ASCII, so no conversion to UTF-8 is
+   * necessary.  However we do need to nul-terminate the string.
+   */
+  errno = 0;
+  size_t len = hivex_value_key_len (h, value);
+  if (len == 0 && errno != 0)
+    return NULL;
+
   char *ret = malloc (len + 1);
   if (ret == NULL)
     return NULL;