+static int calculate_dentry_statistics(struct wim_dentry *dentry, void *arg)
+{
+ struct image_info *info = arg;
+ struct wim_lookup_table *lookup_table = info->lookup_table;
+ const struct wim_inode *inode = dentry->d_inode;
+ struct wim_lookup_table_entry *lte;
+
+ /* Update directory count and file count.
+ *
+ * Each dentry counts as either a file or a directory, but not both.
+ * The root directory is an exception: it is not counted at all.
+ *
+ * Symbolic links and junction points (and presumably other reparse
+ * points) count as regular files. This is despite the fact that
+ * junction points have FILE_ATTRIBUTE_DIRECTORY set.
+ */
+ if (dentry_is_root(dentry))
+ return 0;
+
+ if (inode_is_directory(inode))
+ info->dir_count++;
+ else
+ info->file_count++;
+
+ /*
+ * Update total bytes and hard link bytes.
+ *
+ * Unfortunately there are some inconsistencies/bugs in the way this is
+ * done.
+ *
+ * If there are no alternate data streams in the image, the "total
+ * bytes" is the sum of the size of the un-named data stream of each
+ * inode times the link count of that inode. In other words, it would
+ * be the total number of bytes of regular files you would have if you
+ * extracted the full image without any hard-links. The "hard link
+ * bytes" is equal to the "total bytes" minus the size of the un-named
+ * data stream of each inode. In other words, the "hard link bytes"
+ * counts the size of the un-named data stream for all the links to each
+ * inode except the first one.
+ *
+ * Reparse points and directories don't seem to be counted in either the
+ * total bytes or the hard link bytes.
+ *
+ * And now we get to the most confusing part, the alternate data
+ * streams. They are not counted in the "total bytes". However, if the
+ * link count of an inode with alternate data streams is 2 or greater,
+ * the size of all the alternate data streams is included in the "hard
+ * link bytes", and this size is multiplied by the link count (NOT one
+ * less than the link count).
+ */
+ lte = inode_unnamed_lte(inode, info->lookup_table);
+ if (lte) {
+ info->total_bytes += wim_resource_size(lte);
+ if (!dentry_is_first_in_inode(dentry))
+ info->hard_link_bytes += wim_resource_size(lte);
+ }
+
+ if (inode->i_nlink >= 2 && dentry_is_first_in_inode(dentry)) {
+ for (unsigned i = 0; i < inode->i_num_ads; i++) {
+ if (inode->i_ads_entries[i].stream_name_len) {
+ lte = inode_stream_lte(inode, i + 1, lookup_table);
+ if (lte) {
+ info->hard_link_bytes += inode->i_nlink *
+ wim_resource_size(lte);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * Calculate what to put in the <FILECOUNT>, <DIRCOUNT>, <TOTALBYTES>, and
+ * <HARDLINKBYTES> elements of each <IMAGE>.
+ *
+ * Please note there is no official documentation for exactly how this is done.
+ * But, see calculate_dentry_statistics().
+ */