4 * Support for tagged metadata items that can be appended to WIM directory
9 * Copyright (C) 2014-2016 Eric Biggers
11 * This file is free software; you can redistribute it and/or modify it under
12 * the terms of the GNU Lesser General Public License as published by the Free
13 * Software Foundation; either version 3 of the License, or (at your option) any
16 * This file is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this file; if not, see http://www.gnu.org/licenses/.
29 #include "wimlib/assert.h"
30 #include "wimlib/endianness.h"
31 #include "wimlib/inode.h"
32 #include "wimlib/tagged_items.h"
33 #include "wimlib/unix_data.h"
36 * Header that begins each tagged metadata item associated with a file in a WIM
39 struct tagged_item_header {
41 /* identifies the type of metadata item (see TAG_* constants) */
44 /* size of this item's data in bytes, excluding this header */
47 /* followed by the item's data */
50 /* then zero-padded to an 8-byte boundary */
51 } _aligned_attribute(8);
54 * Retrieve from @inode the first metadata item that is tagged with @tag and
55 * contains at least @min_len bytes of data. If found, return a pointer to the
56 * item's data and write its actual length to @actual_len_ret if not NULL. If
57 * not found, return NULL.
60 inode_get_tagged_item(const struct wim_inode *inode, u32 tag, u32 min_len,
63 struct tagged_item_header *hdr;
69 hdr = (struct tagged_item_header *)inode->i_extra->data;
70 len_remaining = inode->i_extra->size;
72 /* Iterate through the tagged items. */
73 while (len_remaining >= sizeof(*hdr) + min_len) {
74 u32 len = le32_to_cpu(hdr->length);
75 u32 full_len = sizeof(*hdr) + ALIGN(len, 8);
77 /* Length overflow (corrupted item list)? */
78 if (unlikely(full_len < len || full_len > len_remaining))
81 /* Matches the item we wanted? */
82 if (le32_to_cpu(hdr->tag) == tag && len >= min_len) {
84 *actual_len_ret = len;
88 len_remaining -= full_len;
89 hdr = (struct tagged_item_header *)((u8 *)hdr + full_len);
95 * Add a tagged item to the specified inode and return a pointer to its
96 * uninitialized data, which the caller must initialize. No check is made for
97 * whether the inode already has item(s) with the specified tag.
100 inode_add_tagged_item(struct wim_inode *inode, u32 tag, u32 len)
102 struct wim_inode_extra *extra;
103 struct tagged_item_header *hdr;
104 size_t oldsize = (inode->i_extra ? inode->i_extra->size : 0);
105 size_t newsize = oldsize + sizeof(*hdr) + ALIGN(len, 8);
107 wimlib_assert(oldsize % 8 == 0);
109 extra = REALLOC(inode->i_extra, sizeof(*extra) + newsize);
112 inode->i_extra = extra;
113 extra->size = newsize;
114 hdr = (struct tagged_item_header *)&extra->data[oldsize];
115 hdr->tag = cpu_to_le32(tag);
116 hdr->length = cpu_to_le32(len);
117 memset(hdr->data + len, 0, -len & 7); /* pad to next 8-byte boundary */
122 * Add a tagged item containing the specified data to the specified inode, first
123 * removing any existing items with the same tag. Returns %true if successful,
124 * %false if failed (out of memory).
127 inode_set_tagged_item(struct wim_inode *inode, u32 tag,
128 const void *data, u32 len)
133 /* Remove any existing items with the same tag */
134 while ((p = inode_get_tagged_item(inode, tag, 0, &old_len)) != NULL) {
135 p -= sizeof(struct tagged_item_header);
136 old_len += sizeof(struct tagged_item_header);
137 old_len = ALIGN(old_len, 8);
138 memmove(p, p + old_len, (inode->i_extra->data +
139 inode->i_extra->size) - (p + old_len));
140 inode->i_extra->size -= old_len;
143 /* Add the new item */
144 p = inode_add_tagged_item(inode, tag, len);
147 memcpy(p, data, len);
151 struct wimlib_unix_data_disk {
158 static inline struct wimlib_unix_data_disk *
159 inode_get_unix_data_disk(const struct wim_inode *inode)
161 return inode_get_tagged_item(inode, TAG_WIMLIB_UNIX_DATA,
162 sizeof(struct wimlib_unix_data_disk),
166 /* Return %true iff the specified inode has standard UNIX metadata. */
168 inode_has_unix_data(const struct wim_inode *inode)
170 return inode_get_unix_data_disk(inode) != NULL;
174 * Get an inode's standard UNIX metadata.
176 * If the inode has standard UNIX metadata, returns %true and fills @unix_data.
177 * Otherwise returns %false.
180 inode_get_unix_data(const struct wim_inode *inode,
181 struct wimlib_unix_data *unix_data)
183 const struct wimlib_unix_data_disk *p;
185 p = inode_get_unix_data_disk(inode);
189 unix_data->uid = le32_to_cpu(p->uid);
190 unix_data->gid = le32_to_cpu(p->gid);
191 unix_data->mode = le32_to_cpu(p->mode);
192 unix_data->rdev = le32_to_cpu(p->rdev);
197 * Set an inode's standard UNIX metadata.
199 * Callers must specify all members in @unix_data. If the inode does not yet
200 * have standard UNIX metadata, it is given these values. Otherwise, only the
201 * values that also have the corresponding flags in @which set are changed.
203 * Returns %true if successful, %false if failed (out of memory).
206 inode_set_unix_data(struct wim_inode *inode, struct wimlib_unix_data *unix_data,
209 struct wimlib_unix_data_disk *p;
211 p = inode_get_unix_data_disk(inode);
213 p = inode_add_tagged_item(inode, TAG_WIMLIB_UNIX_DATA,
217 which = UNIX_DATA_ALL;
219 if (which & UNIX_DATA_UID)
220 p->uid = cpu_to_le32(unix_data->uid);
221 if (which & UNIX_DATA_GID)
222 p->gid = cpu_to_le32(unix_data->gid);
223 if (which & UNIX_DATA_MODE)
224 p->mode = cpu_to_le32(unix_data->mode);
225 if (which & UNIX_DATA_RDEV)
226 p->rdev = cpu_to_le32(unix_data->rdev);