X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Ftagged_items.c;h=85bcadfdf38274e7e346fe9c04285877ed2bd7c8;hb=4e0e062e081fcbb6a660084308287926c52c9353;hp=e3ba53f496612c7d95e8dabaa12d3512865edca6;hpb=5731558efd18b5199e0b63de16cf6b11a652104e;p=wimlib diff --git a/src/tagged_items.c b/src/tagged_items.c index e3ba53f4..85bcadfd 100644 --- a/src/tagged_items.c +++ b/src/tagged_items.c @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2014 Eric Biggers + * Copyright (C) 2014-2016 Eric Biggers * * This file is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free @@ -28,10 +28,11 @@ #include "wimlib/endianness.h" #include "wimlib/inode.h" +#include "wimlib/object_id.h" #include "wimlib/types.h" #include "wimlib/unix_data.h" -/* Used by the Microsoft implementation. */ +/* Object ID tag; this is also used by the Microsoft implementation. */ #define TAG_OBJECT_ID 0x00000001 /* Random number that we'll use for tagging our UNIX data items. */ @@ -44,18 +45,17 @@ struct tagged_item_header { le32 tag; /* Size of the data of this tagged item, in bytes. This excludes this - * header and should be a multiple of 8. - * - * (Actually, the MS implementation seems to round this up to an 8 byte - * boundary when calculating the offset to the next tagged item, but - * uses this length unmodified when validating the item. We might as - * well do the same.) */ + * header and should be a multiple of 8. */ le32 length; /* Variable length data */ u8 data[]; }; +/* Unconfirmed: are all 64 bytes of the object ID always present? Since NTFS-3g + * permits shorter object IDs, we'll do the same for now. */ +#define OBJECT_ID_MIN_LENGTH 16 + struct object_id_disk { u8 object_id[16]; u8 birth_volume_id[16]; @@ -76,11 +76,17 @@ struct wimlib_unix_data_disk { * NULL. */ static void * inode_get_tagged_item(const struct wim_inode *inode, - u32 desired_tag, u32 min_data_len) + u32 desired_tag, u32 min_data_len, u32 *actual_len_ret) { size_t minlen_with_hdr = sizeof(struct tagged_item_header) + min_data_len; - size_t len_remaining = inode->i_extra_size; - u8 *p = inode->i_extra; + size_t len_remaining; + u8 *p; + + if (!inode->i_extra) + return NULL; + + len_remaining = inode->i_extra->size; + p = inode->i_extra->data; /* Iterate through the tagged items. */ while (len_remaining >= minlen_with_hdr) { @@ -90,14 +96,19 @@ inode_get_tagged_item(const struct wim_inode *inode, hdr = (struct tagged_item_header *)p; tag = le32_to_cpu(hdr->tag); - len = le32_to_cpu(hdr->length); + len = ALIGN(le32_to_cpu(hdr->length), 8); - if (tag == desired_tag && len >= min_data_len) + /* Length overflow? */ + if (unlikely(len > len_remaining - sizeof(struct tagged_item_header))) + return NULL; + + /* Matches the item we wanted? */ + if (tag == desired_tag && len >= min_data_len) { + if (actual_len_ret) + *actual_len_ret = len; return hdr->data; + } - len = (len + 7) & ~7; - if (len_remaining <= sizeof(struct tagged_item_header) + len) - return NULL; len_remaining -= sizeof(struct tagged_item_header) + len; p += sizeof(struct tagged_item_header) + len; } @@ -111,36 +122,39 @@ inode_add_tagged_item(struct wim_inode *inode, u32 tag, u32 len) { size_t itemsize; size_t newsize; - u8 *buf; + struct wim_inode_extra *extra; struct tagged_item_header *hdr; /* We prepend the item instead of appending it because it's easier. */ - itemsize = sizeof(struct tagged_item_header) + ((len + 7) & ~7); - newsize = itemsize + inode->i_extra_size; + itemsize = sizeof(struct tagged_item_header) + ALIGN(len, 8); + newsize = itemsize; + if (inode->i_extra) + newsize += inode->i_extra->size; - buf = MALLOC(newsize); - if (!buf) + extra = MALLOC(sizeof(struct wim_inode_extra) + newsize); + if (!extra) return NULL; - - if (inode->i_extra_size) { - memcpy(buf + itemsize, inode->i_extra, inode->i_extra_size); + if (inode->i_extra) { + memcpy(&extra->data[itemsize], inode->i_extra->data, + inode->i_extra->size); FREE(inode->i_extra); } - inode->i_extra = buf; - inode->i_extra_size = newsize; + extra->size = newsize; + inode->i_extra = extra; - hdr = (struct tagged_item_header *)buf; + hdr = (struct tagged_item_header *)extra->data; hdr->tag = cpu_to_le32(tag); hdr->length = cpu_to_le32(len); - return memset(hdr->data, 0, (len + 7) & ~7); + return memset(hdr->data, 0, ALIGN(len, 8)); } static inline struct wimlib_unix_data_disk * inode_get_unix_data_disk(const struct wim_inode *inode) { return inode_get_tagged_item(inode, TAG_WIMLIB_UNIX_DATA, - sizeof(struct wimlib_unix_data_disk)); + sizeof(struct wimlib_unix_data_disk), + NULL); } static inline struct wimlib_unix_data_disk * @@ -211,3 +225,35 @@ inode_set_unix_data(struct wim_inode *inode, struct wimlib_unix_data *unix_data, p->rdev = cpu_to_le32(unix_data->rdev); return true; } + +/* Return %true iff the specified inode has an object ID. */ +bool +inode_has_object_id(const struct wim_inode *inode) +{ + return inode_get_object_id(inode, NULL) != NULL; +} + +/* Retrieve a pointer to the object ID of the specified inode and write its + * length to @len_ret. Return NULL if the inode does not have an object ID. */ +const void * +inode_get_object_id(const struct wim_inode *inode, u32 *len_ret) +{ + return inode_get_tagged_item(inode, TAG_OBJECT_ID, + OBJECT_ID_MIN_LENGTH, len_ret); +} + +/* Set the inode's object ID to the value specified by @object_id and @len. + * Assumes the inode didn't already have an object ID set. Returns %true if + * successful, %false if failed (out of memory). */ +bool +inode_set_object_id(struct wim_inode *inode, const void *object_id, u32 len) +{ + void *p; + + p = inode_add_tagged_item(inode, TAG_OBJECT_ID, len); + if (!p) + return false; + + memcpy(p, object_id, len); + return true; +}