Fix up calculation of image XML statistics
authorEric Biggers <ebiggers3@gmail.com>
Wed, 5 Sep 2012 00:46:21 +0000 (19:46 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Wed, 5 Sep 2012 00:46:21 +0000 (19:46 -0500)
src/dentry.c
src/dentry.h
src/modify.c
src/ntfs-apply.c
src/xml.c
src/xml.h

index d92fb85263942593b02afa228a423b5d39e7507f..aec94c3435c901778f73894459f208eef33e7db0 100644 (file)
@@ -842,58 +842,6 @@ void unlink_dentry(struct dentry *dentry)
 }
 #endif
 
 }
 #endif
 
-/* Parameters for calculate_dentry_statistics(). */
-struct image_statistics {
-       struct lookup_table *lookup_table;
-       u64 *dir_count;
-       u64 *file_count;
-       u64 *total_bytes;
-       u64 *hard_link_bytes;
-};
-
-static int calculate_dentry_statistics(struct dentry *dentry, void *arg)
-{
-       struct image_statistics *stats;
-       struct lookup_table_entry *lte; 
-       
-       stats = arg;
-
-       if (dentry_is_directory(dentry) && !dentry_is_root(dentry))
-               ++*stats->dir_count;
-       else
-               ++*stats->file_count;
-
-       for (unsigned i = 0; i <= dentry->d_inode->num_ads; i++) {
-               lte = inode_stream_lte(dentry->d_inode, i, stats->lookup_table);
-               if (lte) {
-                       *stats->total_bytes += wim_resource_size(lte);
-                       if (++lte->out_refcnt == 1)
-                               *stats->hard_link_bytes += wim_resource_size(lte);
-               }
-       }
-       return 0;
-}
-
-/* Calculates some statistics about a dentry tree. */
-void calculate_dir_tree_statistics(struct dentry *root, struct lookup_table *table, 
-                                  u64 *dir_count_ret, u64 *file_count_ret, 
-                                  u64 *total_bytes_ret, 
-                                  u64 *hard_link_bytes_ret)
-{
-       struct image_statistics stats;
-       *dir_count_ret         = 0;
-       *file_count_ret        = 0;
-       *total_bytes_ret       = 0;
-       *hard_link_bytes_ret   = 0;
-       stats.lookup_table     = table;
-       stats.dir_count       = dir_count_ret;
-       stats.file_count      = file_count_ret;
-       stats.total_bytes     = total_bytes_ret;
-       stats.hard_link_bytes = hard_link_bytes_ret;
-       for_lookup_table_entry(table, lte_zero_out_refcnt, NULL);
-       for_dentry_in_tree(root, calculate_dentry_statistics, &stats);
-}
-
 static inline struct dentry *inode_first_dentry(struct inode *inode)
 {
        wimlib_assert(inode->dentry_list.next != &inode->dentry_list);
 static inline struct dentry *inode_first_dentry(struct inode *inode)
 {
        wimlib_assert(inode->dentry_list.next != &inode->dentry_list);
index cea2c5478ff2e0a2e64642fc146026c313154b8b..b51000a28ff871949caae9f28a1439903fdbb34b 100644 (file)
@@ -296,6 +296,12 @@ static inline bool dentry_is_extracted(const struct dentry *dentry)
        return dentry->is_extracted;
 }
 
        return dentry->is_extracted;
 }
 
+static inline bool dentry_is_first_in_inode(const struct dentry *dentry)
+{
+       return container_of(dentry->d_inode->dentry_list.next,
+                           struct dentry,
+                           inode_dentry_list) == dentry;
+}
 
 extern u64 dentry_correct_total_length(const struct dentry *dentry);
 
 
 extern u64 dentry_correct_total_length(const struct dentry *dentry);
 
@@ -342,13 +348,6 @@ extern int increment_dentry_refcnt(struct dentry *dentry, void *ignore);
 extern void unlink_dentry(struct dentry *dentry);
 extern void link_dentry(struct dentry *dentry, struct dentry *parent);
 
 extern void unlink_dentry(struct dentry *dentry);
 extern void link_dentry(struct dentry *dentry, struct dentry *parent);
 
-extern void calculate_dir_tree_statistics(struct dentry *root, 
-                                         struct lookup_table *table, 
-                                         u64 *dir_count_ret, 
-                                         u64 *file_count_ret, 
-                                         u64 *total_bytes_ret, 
-                                         u64 *hard_link_bytes_ret);
-
 extern int verify_dentry(struct dentry *dentry, void *wim);
 
 
 extern int verify_dentry(struct dentry *dentry, void *wim);
 
 
index 0d3c05a59f36b2472ca8880135a59b6c7d61ce72..dc55d5fa8534ffc5ff0fcf0e7580e0511666bbd3 100644 (file)
@@ -891,7 +891,7 @@ int do_add_image(WIMStruct *w, const char *dir, const char *name,
        if (flags & WIMLIB_ADD_IMAGE_FLAG_BOOT)
                wimlib_set_boot_idx(w, w->hdr.image_count);
 
        if (flags & WIMLIB_ADD_IMAGE_FLAG_BOOT)
                wimlib_set_boot_idx(w, w->hdr.image_count);
 
-       ret = xml_add_image(w, root_dentry, name);
+       ret = xml_add_image(w, name);
        if (ret != 0)
                goto out_destroy_imd;
 
        if (ret != 0)
                goto out_destroy_imd;
 
index 6409472a3c866d1ee5a8ea0055a4390ee2d68ee1..d6271f79094795d12a4788ee646f8aca0be814a0 100644 (file)
@@ -442,8 +442,10 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
                        /* Can't make a hard link; extract the file itself */
                        FREE(inode->extracted_file);
                        inode->extracted_file = STRDUP(dentry->full_path_utf8);
                        /* Can't make a hard link; extract the file itself */
                        FREE(inode->extracted_file);
                        inode->extracted_file = STRDUP(dentry->full_path_utf8);
-                       if (!inode->extracted_file)
-                               return WIMLIB_ERR_NOMEM;
+                       if (!inode->extracted_file) {
+                               ret = WIMLIB_ERR_NOMEM;
+                               goto out_close_dir_ni;
+                       }
                }
        }
 
                }
        }
 
index 73ba38e41f14b3f0be756048641d57610936098e..eb963aabe882b4d44c46c9cd37ce7d96dff8f1c6 100644 (file)
--- a/src/xml.c
+++ b/src/xml.c
@@ -27,6 +27,7 @@
 #include "dentry.h"
 #include "xml.h"
 #include "timestamp.h"
 #include "dentry.h"
 #include "xml.h"
 #include "timestamp.h"
+#include "lookup_table.h"
 #include <string.h>
 #include <time.h>
 #include <libxml/parser.h>
 #include <string.h>
 #include <time.h>
 #include <libxml/parser.h>
@@ -74,7 +75,10 @@ struct image_info {
        char *description;
        char  *display_name;
        char  *display_description;
        char *description;
        char  *display_name;
        char  *display_description;
-       char  *flags;
+       union {
+               char  *flags;
+               struct lookup_table *lookup_table;
+       };
 };
 
 
 };
 
 
@@ -957,27 +961,115 @@ void xml_set_memory_allocator(void *(*malloc_func)(size_t),
 }
 #endif
 
 }
 #endif
 
+/* Parameters for calculate_dentry_statistics(). */
+struct image_statistics {
+       struct lookup_table *lookup_table;
+       u64 *dir_count;
+       u64 *file_count;
+       u64 *total_bytes;
+       u64 *hard_link_bytes;
+};
+
+static int calculate_dentry_statistics(struct dentry *dentry, void *arg)
+{
+       struct image_info *info = arg; 
+       struct lookup_table *lookup_table = info->lookup_table;
+       const struct inode *inode = dentry->d_inode;
+       struct 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.
+        *
+        * 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->link_count >= 2 && dentry_is_first_in_inode(dentry)) {
+               for (unsigned i = 0; i < inode->num_ads; i++) {
+                       if (inode->ads_entries[i].stream_name_len) {
+                               lte = inode_stream_lte(inode, i + 1, lookup_table);
+                               if (lte) {
+                                       info->hard_link_bytes += inode->link_count *
+                                                                wim_resource_size(lte);
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
 void xml_update_image_info(WIMStruct *w, int image)
 {
        struct image_info *image_info;
        struct dentry *root; 
 void xml_update_image_info(WIMStruct *w, int image)
 {
        struct image_info *image_info;
        struct dentry *root; 
+       char *flags_save;
 
        DEBUG("Updating the image info for image %d", image);
 
        image_info = &w->wim_info->images[image - 1];
 
        DEBUG("Updating the image info for image %d", image);
 
        image_info = &w->wim_info->images[image - 1];
-       root = w->image_metadata[image - 1].root_dentry;
 
 
-       calculate_dir_tree_statistics(root, w->lookup_table, 
-                                     &image_info->dir_count,
-                                     &image_info->file_count, 
-                                     &image_info->total_bytes,
-                                     &image_info->hard_link_bytes);
+       image_info->file_count      = 0;
+       image_info->dir_count       = 0;
+       image_info->total_bytes     = 0;
+       image_info->hard_link_bytes = 0;
+
+       flags_save = image_info->flags;
+       image_info->lookup_table = w->lookup_table;
 
 
+       for_dentry_in_tree(w->image_metadata[image - 1].root_dentry,
+                          calculate_dentry_statistics,
+                          image_info);
+                          
+       image_info->lookup_table = NULL;
+       image_info->flags = flags_save;
        image_info->last_modification_time = get_wim_timestamp();
 }
 
 /* Adds an image to the XML information. */
        image_info->last_modification_time = get_wim_timestamp();
 }
 
 /* Adds an image to the XML information. */
-int xml_add_image(WIMStruct *w, struct dentry *root_dentry, const char *name)
+int xml_add_image(WIMStruct *w, const char *name)
 {
        struct wim_info *wim_info;
        struct image_info *image_info;
 {
        struct wim_info *wim_info;
        struct image_info *image_info;
index fb296000c855edc48a32ce4cd6c02570615661d6..701a93a34fd01187e4d66dbd2200b54203fb2d00 100644 (file)
--- a/src/xml.h
+++ b/src/xml.h
@@ -7,7 +7,7 @@
 struct wim_info {
        u64 total_bytes;
        u64 num_images;
 struct wim_info {
        u64 total_bytes;
        u64 num_images;
-       /* Array of WIMImageInfos, one for each image in the WIM that is
+       /* Array of `struct image_info's, one for each image in the WIM that is
         * mentioned in the XML data. */
        struct image_info *images;
 };
         * mentioned in the XML data. */
        struct image_info *images;
 };
@@ -24,8 +24,7 @@ extern void xml_update_image_info(WIMStruct *w, int image);
 
 extern void xml_delete_image(struct wim_info **wim_info_p, int image);
 
 
 extern void xml_delete_image(struct wim_info **wim_info_p, int image);
 
-extern int xml_add_image(WIMStruct *w, struct dentry *root_dentry, 
-                        const char *name);
+extern int xml_add_image(WIMStruct *w, const char *name);
 
 extern void free_wim_info(struct wim_info *info);
 
 
 extern void free_wim_info(struct wim_info *info);