+/* Reads the children of a dentry, and all their children, ..., etc. from the
+ * metadata resource and into the dentry tree.
+ *
+ * @metadata_resource: An array that contains the uncompressed metadata
+ * resource for the WIM file.
+ *
+ * @metadata_resource_len: The length of the uncompressed metadata resource, in
+ * bytes.
+ *
+ * @dentry: A pointer to a `struct dentry' that is the root of the directory
+ * tree and has already been read from the metadata resource. It
+ * does not need to be the real root because this procedure is
+ * called recursively.
+ *
+ * @return: Zero on success, nonzero on failure.
+ */
+int read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
+ struct dentry *dentry)
+{
+ u64 cur_offset = dentry->subdir_offset;
+ struct dentry *prev_child = NULL;
+ struct dentry *first_child = NULL;
+ struct dentry *child;
+ struct dentry cur_child;
+ int ret;
+
+ /*
+ * If @dentry has no child dentries, nothing more needs to be done for
+ * this branch. This is the case for regular files, symbolic links, and
+ * *possibly* empty directories (although an empty directory may also
+ * have one child dentry that is the special end-of-directory dentry)
+ */
+ if (cur_offset == 0)
+ return 0;
+
+ /* Find and read all the children of @dentry. */
+ while (1) {
+
+ /* Read next child of @dentry into @cur_child. */
+ ret = read_dentry(metadata_resource, metadata_resource_len,
+ cur_offset, &cur_child);
+ if (ret != 0)
+ break;
+
+ /* Check for end of directory. */
+ if (cur_child.length == 0)
+ break;
+
+ /* Not end of directory. Allocate this child permanently and
+ * link it to the parent and previous child. */
+ child = MALLOC(sizeof(struct dentry));
+ if (!child) {
+ ERROR("Failed to allocate %zu bytes for new dentry",
+ sizeof(struct dentry));
+ ret = WIMLIB_ERR_NOMEM;
+ break;
+ }
+ memcpy(child, &cur_child, sizeof(struct dentry));
+
+ if (prev_child) {
+ prev_child->next = child;
+ child->prev = prev_child;
+ } else {
+ first_child = child;
+ }
+
+ child->parent = dentry;
+ prev_child = child;
+ inode_add_dentry(child, child->d_inode);
+
+ /* If there are children of this child, call this procedure
+ * recursively. */
+ if (child->subdir_offset != 0) {
+ ret = read_dentry_tree(metadata_resource,
+ metadata_resource_len, child);
+ if (ret != 0)
+ break;
+ }
+
+ /* Advance to the offset of the next child. Note: We need to
+ * advance by the TOTAL length of the dentry, not by the length
+ * child->length, which although it does take into account the
+ * padding, it DOES NOT take into account alternate stream
+ * entries. */
+ cur_offset += dentry_total_length(child);
+ }
+
+ /* Link last child to first one, and set parent's children pointer to
+ * the first child. */
+ if (prev_child) {
+ prev_child->next = first_child;
+ first_child->prev = prev_child;
+ }
+ dentry->d_inode->children = first_child;
+ return ret;
+}
+
+/*