dentry->d_short_name_nbytes);
len = ALIGN(len, 8);
- len += ALIGN(inode->i_extra_size, 8);
+ if (inode->i_extra)
+ len += ALIGN(inode->i_extra->size, 8);
if (!(inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED)) {
/*
/*
* Calculate the full path to @dentry within the WIM image, if not already done.
*
- * The full name will be saved in the cached value 'dentry->_full_path'.
+ * The full name will be saved in the cached value 'dentry->d_full_path'.
*
* Whenever possible, use dentry_full_path() instead of calling this and
- * accessing _full_path directly.
+ * accessing d_full_path directly.
*
* Returns 0 or an error code resulting from a failed string conversion.
*/
size_t dummy;
const struct wim_dentry *d;
- if (dentry->_full_path)
+ if (dentry->d_full_path)
return 0;
ulen = 0;
d = dentry;
do {
p -= d->d_name_nbytes / sizeof(utf16lechar);
- memcpy(p, d->d_name, d->d_name_nbytes);
+ if (d->d_name_nbytes)
+ memcpy(p, d->d_name, d->d_name_nbytes);
*--p = cpu_to_le16(WIM_PATH_SEPARATOR);
d = d->d_parent; /* assumes d == d->d_parent for root */
} while (!dentry_is_root(d));
wimlib_assert(p == ubuf);
return utf16le_to_tstr(ubuf, ulen * sizeof(utf16lechar),
- &dentry->_full_path, &dummy);
+ &dentry->d_full_path, &dummy);
}
/*
dentry_full_path(struct wim_dentry *dentry)
{
calculate_dentry_full_path(dentry);
- return dentry->_full_path;
+ return dentry->d_full_path;
}
static int
get_dentry_child_with_utf16le_name(const struct wim_dentry *dentry,
const utf16lechar *name,
size_t name_nbytes,
- CASE_SENSITIVITY_TYPE case_ctype)
+ CASE_SENSITIVITY_TYPE case_type)
{
const struct wim_inode *dir = dentry->d_inode;
- bool ignore_case = will_ignore_case(case_ctype);
+ bool ignore_case = will_ignore_case(case_type);
struct wim_dentry dummy;
struct wim_dentry *child;
return 0;
}
-static int
-dentry_clear_inode_visited(struct wim_dentry *dentry, void *_ignore)
-{
- dentry->d_inode->i_visited = 0;
- return 0;
-}
-
-void
-dentry_tree_clear_inode_visited(struct wim_dentry *root)
-{
- for_dentry_in_tree(root, dentry_clear_inode_visited, NULL);
-}
-
/*
* Free a WIM dentry.
*
d_disassociate(dentry);
FREE(dentry->d_name);
FREE(dentry->d_short_name);
- FREE(dentry->_full_path);
+ FREE(dentry->d_full_path);
FREE(dentry);
}
}
p++;
if (unlikely(p < end)) {
- inode->i_extra = memdup(p, end - p);
+ inode->i_extra = MALLOC(sizeof(struct wim_inode_extra) +
+ end - p);
if (!inode->i_extra)
return WIMLIB_ERR_NOMEM;
- inode->i_extra_size = end - p;
+ inode->i_extra->size = end - p;
+ memcpy(inode->i_extra->data, p, end - p);
}
return 0;
}
* There will be an unnamed data stream, a reparse point stream, or both an
* unnamed data stream and a reparse point stream. In addition, there may be
* named data streams.
+ *
+ * NOTE: if the file has a reparse point stream or at least one named data
+ * stream, then WIMGAPI puts *all* streams in the extra stream entries and
+ * leaves the default stream hash zeroed. wimlib now does the same. However,
+ * for input we still support the default hash field being used, since wimlib
+ * used to use it and MS software is somewhat accepting of it as well.
*/
static void
assign_stream_types_unencrypted(struct wim_inode *inode)
if (stream_is_named(strm)) {
/* Named data stream */
strm->stream_type = STREAM_TYPE_DATA;
- } else if (!is_zero_hash(strm->_stream_hash)) {
+ } else if (i != 0 || !is_zero_hash(strm->_stream_hash)) {
+ /* Unnamed stream in the extra stream entries, OR the
+ * default stream in the dentry provided that it has a
+ * nonzero hash. */
if ((inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
!found_reparse_point_stream) {
found_reparse_point_stream = true;
found_unnamed_data_stream = true;
strm->stream_type = STREAM_TYPE_DATA;
}
- } else {
- /* If no stream name is specified and the hash is zero,
- * then remember this stream for later so that we can
- * assign it to the unnamed data stream if we don't find
- * a better candidate. */
+ } else if (!unnamed_stream_with_zero_hash) {
unnamed_stream_with_zero_hash = strm;
}
}
- if (!found_unnamed_data_stream && unnamed_stream_with_zero_hash != NULL)
- unnamed_stream_with_zero_hash->stream_type = STREAM_TYPE_DATA;
+ if (unnamed_stream_with_zero_hash) {
+ int type = STREAM_TYPE_UNKNOWN;
+ if ((inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
+ !found_reparse_point_stream) {
+ type = STREAM_TYPE_REPARSE_POINT;
+ } else if (!found_unnamed_data_stream) {
+ type = STREAM_TYPE_DATA;
+ }
+ unnamed_stream_with_zero_hash->stream_type = type;
+ }
}
/*
u64 calculated_size;
int ret;
- BUILD_BUG_ON(sizeof(struct wim_dentry_on_disk) != WIM_DENTRY_DISK_SIZE);
+ STATIC_ASSERT(sizeof(struct wim_dentry_on_disk) == WIM_DENTRY_DISK_SIZE);
/* Before reading the whole dentry, we need to read just the length.
* This is because a dentry of length 8 (that is, just the length field)
static int
read_dentry_tree_recursive(const u8 * restrict buf, size_t buf_len,
- struct wim_dentry * restrict dir)
+ struct wim_dentry * restrict dir, unsigned depth)
{
u64 cur_offset = dir->d_subdir_offset;
- /* Check for cyclic directory structure, which would cause infinite
- * recursion if not handled. */
- for (struct wim_dentry *d = dir->d_parent;
- !dentry_is_root(d); d = d->d_parent)
- {
- if (unlikely(d->d_subdir_offset == cur_offset)) {
- ERROR("Cyclic directory structure detected: children "
- "of \"%"TS"\" coincide with children of \"%"TS"\"",
- dentry_full_path(dir), dentry_full_path(d));
- return WIMLIB_ERR_INVALID_METADATA_RESOURCE;
- }
+ /* Disallow extremely deep or cyclic directory structures */
+ if (unlikely(depth >= 16384)) {
+ ERROR("Directory structure too deep!");
+ return WIMLIB_ERR_INVALID_METADATA_RESOURCE;
}
for (;;) {
if (likely(dentry_is_directory(child))) {
ret = read_dentry_tree_recursive(buf,
buf_len,
- child);
+ child,
+ depth + 1);
if (ret)
return ret;
} else {
int ret;
struct wim_dentry *root;
- DEBUG("Reading dentry tree (root_offset=%"PRIu64")", root_offset);
-
ret = read_dentry(buf, buf_len, &root_offset, &root);
if (ret)
return ret;
}
if (likely(root->d_subdir_offset != 0)) {
- ret = read_dentry_tree_recursive(buf, buf_len, root);
+ ret = read_dentry_tree_recursive(buf, buf_len, root, 0);
if (ret)
goto err_free_dentry_tree;
}
while ((uintptr_t)p & 7)
*p++ = 0;
- if (inode->i_extra_size) {
+ if (inode->i_extra) {
/* Extra tagged items --- not usually present. */
- p = mempcpy(p, inode->i_extra, inode->i_extra_size);
+ p = mempcpy(p, inode->i_extra->data, inode->i_extra->size);
/* Align to 8-byte boundary */
while ((uintptr_t)p & 7)
u8 *
write_dentry_tree(struct wim_dentry *root, u8 *p)
{
- DEBUG("Writing dentry tree.");
-
- wimlib_assert(root != NULL);
-
/* write root dentry and end-of-directory entry following it */
p = write_dentry(root, p);
*(u64*)p = 0;