Refactoring/rewrites
authorEric Biggers <ebiggers3@gmail.com>
Mon, 17 Dec 2012 03:15:07 +0000 (21:15 -0600)
committerEric Biggers <ebiggers3@gmail.com>
Mon, 17 Dec 2012 03:15:07 +0000 (21:15 -0600)
New function dentry_tree_fix_inodes() to de-duplicate some code in
read_metadata_resource() and wimlib_add_image().

In wimlib_export_image(), search through the inode list when looking for lookup
table entries to export instead of the dentry tree.

In wimlib_mount_image(), search through the inode list when resolving lookup
table entries, and update the inode numbers at the same time.

src/add_image.c
src/export_image.c
src/hardlink.c
src/lookup_table.c
src/lookup_table.h
src/metadata_resource.c
src/mount_image.c
src/wim.c
src/wimlib_internal.h

index 20b554e..082c502 100644 (file)
@@ -53,7 +53,7 @@
  * @sd:                  The security data for the image.
  */
 int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry,
-                              struct wim_security_data *sd)
+                       struct wim_security_data *sd)
 {
        struct lookup_table_entry *metadata_lte;
        struct image_metadata *imd;
@@ -87,18 +87,12 @@ int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry,
        new_imd->root_dentry    = root_dentry;
        new_imd->metadata_lte   = metadata_lte;
        new_imd->security_data  = sd;
-       new_imd->modified       = true;
+       new_imd->modified       = 1;
 
        FREE(w->image_metadata);
-       w->image_metadata       = imd;
+       w->image_metadata = imd;
        w->hdr.image_count++;
-
-       /* Change the current image to the new one.  There should not be any
-        * ways for this to fail, since the image is valid and the dentry tree
-        * is already in memory. */
-       ret = select_wim_image(w, w->hdr.image_count);
-       wimlib_assert(ret == 0);
-       return ret;
+       return 0;
 err_free_imd:
        FREE(imd);
 err:
@@ -640,7 +634,6 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *source,
        struct dentry *root_dentry = NULL;
        struct wim_security_data *sd;
        struct capture_config config;
-       struct inode_table inode_tab;
        struct hlist_head inode_list;
        int ret;
 
@@ -737,16 +730,8 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *source,
        if (ret != 0)
                goto out_free_dentry_tree;
 
-       DEBUG("Inserting dentries into inode table");
-       ret = init_inode_table(&inode_tab, 9001);
-       if (ret != 0)
-               goto out_destroy_imd;
-
-       for_dentry_in_tree(root_dentry, inode_table_insert, &inode_tab);
 
-       DEBUG("Cleaning up the hard link groups");
-       ret = fix_inodes(&inode_tab, &inode_list);
-       destroy_inode_table(&inode_tab);
+       ret = dentry_tree_fix_inodes(root_dentry, &inode_list);
        if (ret != 0)
                goto out_destroy_imd;
 
index 6d38855..a24950a 100644 (file)
 #include "lookup_table.h"
 #include "xml.h"
 
-struct wim_pair {
-       WIMStruct *src_wim;
-       WIMStruct *dest_wim;
-       struct list_head lte_list_head;
-};
-
-static int allocate_lte_if_needed(struct dentry *dentry, void *arg)
+static int inode_allocate_needed_ltes(struct inode *inode,
+                                     struct lookup_table *src_lookup_table,
+                                     struct lookup_table *dest_lookup_table,
+                                     struct list_head *lte_list_head)
 {
-       const WIMStruct *src_wim, *dest_wim;
-       struct list_head *lte_list_head;
-       struct inode *inode;
-
-       src_wim = ((struct wim_pair*)arg)->src_wim;
-       dest_wim = ((struct wim_pair*)arg)->dest_wim;
-       lte_list_head = &((struct wim_pair*)arg)->lte_list_head;
-       inode = dentry->d_inode;
+       struct lookup_table_entry *src_lte, *dest_lte;
+       unsigned i;
 
-       wimlib_assert(!inode->resolved);
-
-       for (unsigned i = 0; i <= inode->num_ads; i++) {
-               struct lookup_table_entry *src_lte, *dest_lte;
+       inode_unresolve_ltes(inode);
+       for (i = 0; i <= inode->num_ads; i++) {
                src_lte = inode_stream_lte_unresolved(inode, i,
-                                                     src_wim->lookup_table);
-
-               if (src_lte && ++src_lte->out_refcnt == 1) {
+                                                     src_lookup_table);
+               if (src_lte && src_lte->out_refcnt == 0) {
+                       src_lte->out_refcnt = 1;
                        dest_lte = inode_stream_lte_unresolved(inode, i,
-                                                              dest_wim->lookup_table);
-
+                                                              dest_lookup_table);
                        if (!dest_lte) {
                                dest_lte = clone_lookup_table_entry(src_lte);
                                if (!dest_lte)
@@ -65,57 +53,40 @@ static int allocate_lte_if_needed(struct dentry *dentry, void *arg)
        return 0;
 }
 
-/*
- * This function takes in a dentry that was previously located only in image(s)
- * in @src_wim, but now is being added to @dest_wim.  For each stream associated
- * with the dentry, if there is already a lookup table entry for that stream in
- * the lookup table of the destination WIM file, its reference count is
- * incrementej.  Otherwise, a new lookup table entry is created that points back
- * to the stream in the source WIM file (through the @hash field combined with
- * the @wim field of the lookup table entry.)
- */
-static int add_lte_to_dest_wim(struct dentry *dentry, void *arg)
+static void inode_move_ltes_to_table(struct inode *inode,
+                                    struct lookup_table *src_lookup_table,
+                                    struct lookup_table *dest_lookup_table,
+                                    struct list_head *lte_list_head)
 {
-       WIMStruct *src_wim, *dest_wim;
-       struct inode *inode;
-
-       src_wim = ((struct wim_pair*)arg)->src_wim;
-       dest_wim = ((struct wim_pair*)arg)->dest_wim;
-       inode = dentry->d_inode;
-
-       wimlib_assert(!inode->resolved);
-
-       for (unsigned i = 0; i <= inode->num_ads; i++) {
-               struct lookup_table_entry *src_lte, *dest_lte;
-               src_lte = inode_stream_lte_unresolved(inode, i,
-                                                     src_wim->lookup_table);
-
-               if (!src_lte) /* Empty or nonexistent stream. */
-                       continue;
+       struct lookup_table_entry *src_lte, *dest_lte;
+       unsigned i;
+       struct dentry *dentry;
 
-               dest_lte = inode_stream_lte_unresolved(inode, i,
-                                                      dest_wim->lookup_table);
-               if (dest_lte) {
-                       dest_lte->refcnt++;
-               } else {
-                       struct list_head *lte_list_head;
-                       struct list_head *next;
-
-                       lte_list_head = &((struct wim_pair*)arg)->lte_list_head;
-                       wimlib_assert(!list_empty(lte_list_head));
+       inode_for_each_dentry(dentry, inode)
+               dentry->refcnt++;
 
-                       next = lte_list_head->next;
-                       list_del(next);
-                       dest_lte = container_of(next, struct lookup_table_entry,
-                                               staging_list);
-                       dest_lte->part_number = 1;
-                       dest_lte->refcnt = 1;
-                       wimlib_assert(hashes_equal(dest_lte->hash, src_lte->hash));
-
-                       lookup_table_insert(dest_wim->lookup_table, dest_lte);
+       for (i = 0; i <= inode->num_ads; i++) {
+               src_lte = inode_stream_lte_unresolved(inode, i, src_lookup_table);
+               if (src_lte) {
+                       dest_lte = inode_stream_lte_unresolved(inode, i,
+                                                              dest_lookup_table);
+                       if (!dest_lte) {
+                               struct list_head *next;
+
+                               wimlib_assert(!list_empty(lte_list_head));
+                               next = lte_list_head->next;
+                               list_del(next);
+                               dest_lte = container_of(next,
+                                                       struct lookup_table_entry,
+                                                       staging_list);
+                               dest_lte->part_number = 1;
+                               dest_lte->refcnt = 0;
+                               wimlib_assert(hashes_equal(dest_lte->hash, src_lte->hash));
+                               lookup_table_insert(dest_lookup_table, dest_lte);
+                       }
+                       dest_lte->refcnt += inode->link_count;
                }
        }
-       return 0;
 }
 
 /*
@@ -131,12 +102,13 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                                  unsigned num_additional_swms,
                                  wimlib_progress_func_t progress_func)
 {
-       int i;
        int ret;
-       struct dentry *root;
-       struct wim_pair wims;
        struct wim_security_data *sd;
        struct lookup_table *joined_tab, *src_wim_tab_save;
+       struct image_metadata *src_imd;
+       struct hlist_node *cur_node;
+       struct list_head lte_list_head;
+       struct inode *inode;
 
        if (dest_wim->hdr.total_parts != 1) {
                ERROR("Exporting an image to a split WIM is "
@@ -168,7 +140,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                                      "multiple images");
                                return WIMLIB_ERR_INVALID_PARAM;
                        }
-                       for (i = 1; i <= src_wim->hdr.image_count; i++) {
+                       for (int i = 1; i <= src_wim->hdr.image_count; i++) {
                                int new_flags = export_flags;
 
                                if (i != src_wim->hdr.boot_idx)
@@ -236,15 +208,18 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
        /* Pre-allocate the new lookup table entries that will be needed.  This
         * way, it's not possible to run out of memory part-way through
         * modifying the lookup table of the destination WIM. */
-       wims.src_wim = src_wim;
-       wims.dest_wim = dest_wim;
-       INIT_LIST_HEAD(&wims.lte_list_head);
+       INIT_LIST_HEAD(&lte_list_head);
        for_lookup_table_entry(src_wim->lookup_table, lte_zero_out_refcnt, NULL);
-       root = wim_root_dentry(src_wim);
-       for_dentry_in_tree(root, dentry_unresolve_ltes, NULL);
-       ret = for_dentry_in_tree(root, allocate_lte_if_needed, &wims);
-       if (ret != 0)
-               goto out_free_ltes;
+       src_imd = wim_get_current_image_metadata(src_wim);
+
+       hlist_for_each_entry(inode, cur_node, &src_imd->inode_list, hlist) {
+               ret = inode_allocate_needed_ltes(inode,
+                                                src_wim->lookup_table,
+                                                dest_wim->lookup_table,
+                                                &lte_list_head);
+               if (ret != 0)
+                       goto out_free_ltes;
+       }
 
        ret = xml_export_image(src_wim->wim_info, src_image,
                               &dest_wim->wim_info, dest_name,
@@ -252,21 +227,26 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
        if (ret != 0)
                goto out_free_ltes;
 
-       sd = wim_security_data(src_wim);
-       ret = add_new_dentry_tree(dest_wim, root, sd);
+       sd = src_imd->security_data;
+       ret = add_new_dentry_tree(dest_wim, src_imd->root_dentry, sd);
        if (ret != 0)
                goto out_xml_delete_image;
 
+       dest_wim->image_metadata[
+               dest_wim->hdr.image_count - 1].inode_list = src_imd->inode_list;
 
        /* All memory allocations have been taken care of, so it's no longer
         * possible for this function to fail.  Go ahead and increment the
         * reference counts of the dentry tree and security data, then update
         * the lookup table of the destination WIM and the boot index, if
         * needed. */
-       for_dentry_in_tree(root, increment_dentry_refcnt, NULL);
        sd->refcnt++;
-       for_dentry_in_tree(root, add_lte_to_dest_wim, &wims);
-       wimlib_assert(list_empty(&wims.lte_list_head));
+       hlist_for_each_entry(inode, cur_node, &src_imd->inode_list, hlist) {
+               inode_move_ltes_to_table(inode,
+                                        src_wim->lookup_table,
+                                        dest_wim->lookup_table,
+                                        &lte_list_head);
+       }
 
        if (export_flags & WIMLIB_EXPORT_FLAG_BOOT)
                wimlib_set_boot_idx(dest_wim, dest_wim->hdr.image_count);
@@ -278,7 +258,7 @@ out_xml_delete_image:
 out_free_ltes:
        {
                struct lookup_table_entry *lte, *tmp;
-               list_for_each_entry_safe(lte, tmp, &wims.lte_list_head, staging_list)
+               list_for_each_entry_safe(lte, tmp, &lte_list_head, staging_list)
                        free_lookup_table_entry(lte);
        }
 
index e3f9e27..7603670 100644 (file)
  *                            -----------------
  */
 
+/* Hash table to find inodes, identified by their inode ID.
+ * */
+struct inode_table {
+       /* Fields for the hash table */
+       struct hlist_head *array;
+       u64 num_entries;
+       u64 capacity;
+
+       /*
+        * Linked list of "extra" inodes.  These may be:
+        *
+        * - inodes with link count 1, which are all allowed to have 0 for their
+        *   inode number, meaning we cannot insert them into the hash table
+        *   before calling assign_inode_numbers().
+         *
+        * - Groups we create ourselves by splitting a nominal inode due to
+        *   inconsistencies in the dentries.  These inodes will share a inode
+        *   ID with some other inode until assign_inode_numbers() is called.
+        */
+       struct hlist_head extra_inodes;
+};
+
+static inline void destroy_inode_table(struct inode_table *table)
+{
+       FREE(table->array);
+}
 
-int init_inode_table(struct inode_table *table, size_t capacity)
+static int init_inode_table(struct inode_table *table, size_t capacity)
 {
        table->array = CALLOC(capacity, sizeof(table->array[0]));
        if (!table->array) {
@@ -65,7 +91,6 @@ int init_inode_table(struct inode_table *table, size_t capacity)
        return 0;
 }
 
-
 static inline size_t inode_link_count(const struct inode *inode)
 {
        const struct list_head *cur;
@@ -90,7 +115,7 @@ static inline size_t inode_link_count(const struct inode *inode)
  * we keep a linked list of the single dentries, and assign them inode
  * numbers later.
  */
-int inode_table_insert(struct dentry *dentry, void *__table)
+static int inode_table_insert(struct dentry *dentry, void *__table)
 {
        struct inode_table *table = __table;
        struct inode *d_inode = dentry->d_inode;
@@ -279,8 +304,8 @@ static int fix_true_inode(struct inode *inode, struct hlist_head *inode_list)
  * inodes'.  There will be just one `struct inode' for each hard link group
  * remaining.
  */
-static int
-fix_nominal_inode(struct inode *inode, struct hlist_head *inode_list)
+static int fix_nominal_inode(struct inode *inode,
+                            struct hlist_head *inode_list)
 {
        struct dentry *dentry;
        struct hlist_node *cur, *tmp;
@@ -413,7 +438,7 @@ next_dentry_2:
  * split inodes as well as the inodes that were good before, is returned in the
  * list @inode_list.
  */
-int fix_inodes(struct inode_table *table, struct hlist_head *inode_list)
+static int fix_inodes(struct inode_table *table, struct hlist_head *inode_list)
 {
        struct inode *inode;
        struct hlist_node *cur, *tmp;
@@ -430,3 +455,21 @@ int fix_inodes(struct inode_table *table, struct hlist_head *inode_list)
                hlist_add_head(cur, inode_list);
        return 0;
 }
+
+int dentry_tree_fix_inodes(struct dentry *root, struct hlist_head *inode_list)
+{
+       struct inode_table inode_tab;
+       int ret;
+
+       DEBUG("Inserting dentries into inode table");
+       ret = init_inode_table(&inode_tab, 9001);
+       if (ret != 0)
+               return ret;
+
+       for_dentry_in_tree(root, inode_table_insert, &inode_tab);
+
+       DEBUG("Cleaning up the hard link groups");
+       ret = fix_inodes(&inode_tab, inode_list);
+       destroy_inode_table(&inode_tab);
+       return ret;
+}
index f035996..67ce92a 100644 (file)
@@ -633,39 +633,40 @@ out:
 
 void inode_resolve_ltes(struct inode *inode, struct lookup_table *table)
 {
-       struct lookup_table_entry *lte;
-
-       wimlib_assert(!inode->resolved);
 
-       /* Resolve the default file stream */
-       lte = __lookup_resource(table, inode->hash);
-       inode->lte = lte;
-       inode->resolved = 1;
-
-       /* Resolve the alternate data streams */
-       for (u16 i = 0; i < inode->num_ads; i++) {
-               struct ads_entry *cur_entry = &inode->ads_entries[i];
-               lte = __lookup_resource(table, cur_entry->hash);
-               cur_entry->lte = lte;
+       if (!inode->resolved) {
+               struct lookup_table_entry *lte;
+               /* Resolve the default file stream */
+               lte = __lookup_resource(table, inode->hash);
+               inode->lte = lte;
+               inode->resolved = 1;
+
+               /* Resolve the alternate data streams */
+               for (u16 i = 0; i < inode->num_ads; i++) {
+                       struct ads_entry *cur_entry = &inode->ads_entries[i];
+                       lte = __lookup_resource(table, cur_entry->hash);
+                       cur_entry->lte = lte;
+               }
        }
 }
 
-static void inode_unresolve_ltes(struct inode *inode)
+void inode_unresolve_ltes(struct inode *inode)
 {
-       wimlib_assert(inode->resolved);
-       if (inode->lte)
-               copy_hash(inode->hash, inode->lte->hash);
-       else
-               zero_out_hash(inode->hash);
-
-       for (u16 i = 0; i < inode->num_ads; i++) {
-               if (inode->ads_entries[i].lte)
-                       copy_hash(inode->ads_entries[i].hash,
-                                 inode->ads_entries[i].lte->hash);
+       if (inode->resolved) {
+               if (inode->lte)
+                       copy_hash(inode->hash, inode->lte->hash);
                else
-                       zero_out_hash(inode->ads_entries[i].hash);
+                       zero_out_hash(inode->hash);
+
+               for (u16 i = 0; i < inode->num_ads; i++) {
+                       if (inode->ads_entries[i].lte)
+                               copy_hash(inode->ads_entries[i].hash,
+                                         inode->ads_entries[i].lte->hash);
+                       else
+                               zero_out_hash(inode->ads_entries[i].hash);
+               }
+               inode->resolved = 0;
        }
-       inode->resolved = 0;
 }
 
 /* Resolve a dentry's lookup table entries
@@ -679,15 +680,14 @@ static void inode_unresolve_ltes(struct inode *inode)
  */
 int dentry_resolve_ltes(struct dentry *dentry, void *table)
 {
-       if (!dentry->d_inode->resolved)
-               inode_resolve_ltes(dentry->d_inode, table);
+       wimlib_assert(dentry->refcnt == 1);
+       inode_resolve_ltes(dentry->d_inode, table);
        return 0;
 }
 
 int dentry_unresolve_ltes(struct dentry *dentry, void *ignore)
 {
-       if (dentry->d_inode->resolved)
-               inode_unresolve_ltes(dentry->d_inode);
+       inode_unresolve_ltes(dentry->d_inode);
        return 0;
 }
 
index 7038cc5..05ffbe6 100644 (file)
@@ -288,6 +288,8 @@ extern void inode_resolve_ltes(struct inode *inode,
                               struct lookup_table *table);
 
 extern int dentry_resolve_ltes(struct dentry *dentry, void *__table);
+
+extern void inode_unresolve_ltes(struct inode *inode);
 extern int dentry_unresolve_ltes(struct dentry *dentry, void *ignore);
 
 int write_lookup_table(struct lookup_table *table, FILE *out,
index 4f8be14..1972326 100644 (file)
@@ -48,7 +48,6 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd)
        u32 dentry_offset;
        int ret;
        struct dentry *dentry;
-       struct inode_table inode_tab;
        const struct lookup_table_entry *metadata_lte;
        u64 metadata_len;
        struct hlist_head inode_list;
@@ -157,16 +156,7 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd)
                goto out_free_dentry_tree;
 
        /* Build hash table that maps hard link group IDs to dentry sets */
-       DEBUG("Building link group table");
-       ret = init_inode_table(&inode_tab, 9001);
-       if (ret != 0)
-               goto out_free_dentry_tree;
-
-       for_dentry_in_tree(dentry, inode_table_insert, &inode_tab);
-
-       DEBUG("Fixing inconsistencies in the hard link groups");
-       ret = fix_inodes(&inode_tab, &inode_list);
-       destroy_inode_table(&inode_tab);
+       ret = dentry_tree_fix_inodes(dentry, &inode_list);
        if (ret != 0)
                goto out_free_dentry_tree;
 
index d3021a5..4add2a5 100644 (file)
@@ -1939,6 +1939,8 @@ WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        struct lookup_table *joined_tab, *wim_tab_save;
        struct image_metadata *imd;
        struct wimfs_context ctx;
+       struct hlist_node *cur_node;
+       struct inode *inode;
 
        DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ",
              wim, image, dir, mount_flags);
@@ -2072,15 +2074,18 @@ WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
                imd->has_been_mounted_rw = 1;
        }
 
-       /* Resolve all the lookup table entries of the dentry tree */
-       DEBUG("Resolving lookup table entries");
-       for_dentry_in_tree(imd->root_dentry, dentry_resolve_ltes,
-                          wim->lookup_table);
+       /* Resolve the lookup table entries for every inode in the image, and
+        * assign inode numbers */
+       DEBUG("Resolving lookup table entries and assigning inode numbers");
 
-       ctx.next_ino = assign_inode_numbers(&imd->inode_list);
+       ctx.next_ino = 1;
+       hlist_for_each_entry(inode, cur_node, &imd->inode_list, hlist) {
+               inode_resolve_ltes(inode, wim->lookup_table);
+               inode->ino = ctx.next_ino++;
+       }
+       /*ctx.next_ino = assign_inode_numbers(&imd->inode_list);*/
        DEBUG("(next_ino = %"PRIu64")", ctx.next_ino);
 
-
        DEBUG("Calling fuse_main()");
 
        ret = fuse_main(argc, argv, &wimfs_operations, &ctx);
index af5098c..5a38688 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
 #include "lookup_table.h"
 #include "xml.h"
 
-static inline struct image_metadata *
-wim_get_current_image_metadata(WIMStruct *w)
-{
-       return &w->image_metadata[w->current_image - 1];
-}
-
 static int print_metadata(WIMStruct *w)
 {
        DEBUG("Printing metadata for image %d", w->current_image);
index 7f2ee17..458cace 100644 (file)
@@ -320,6 +320,12 @@ wim_const_security_data(const WIMStruct *w)
        return w->image_metadata[w->current_image - 1].security_data;
 }
 
+static inline struct image_metadata *
+wim_get_current_image_metadata(WIMStruct *w)
+{
+       return &w->image_metadata[w->current_image - 1];
+}
+
 /* Nonzero if a struct resource_entry indicates a compressed resource. */
 static inline int resource_is_compressed(const struct resource_entry *entry)
 {
@@ -358,36 +364,10 @@ extern int add_new_dentry_tree(WIMStruct *dest_wim, struct dentry *root,
 
 /* hardlink.c */
 
-/* Hash table to find inodes, identified by their inode ID.
- * */
-struct inode_table {
-       /* Fields for the hash table */
-       struct hlist_head *array;
-       u64 num_entries;
-       u64 capacity;
-
-       /*
-        * Linked list of "extra" inodes.  These may be:
-        *
-        * - inodes with link count 1, which are all allowed to have 0 for their
-        *   inode number, meaning we cannot insert them into the hash table
-        *   before calling assign_inode_numbers().
-         *
-        * - Groups we create ourselves by splitting a nominal inode due to
-        *   inconsistencies in the dentries.  These inodes will share a inode
-        *   ID with some other inode until assign_inode_numbers() is called.
-        */
-       struct hlist_head extra_inodes;
-};
-
-extern int init_inode_table(struct inode_table *table, size_t capacity);
-static inline void destroy_inode_table(struct inode_table *table)
-{
-       FREE(table->array);
-}
-extern int inode_table_insert(struct dentry *dentry, void *__table);
 extern u64 assign_inode_numbers(struct hlist_head *inode_list);
-extern int fix_inodes(struct inode_table *table, struct hlist_head *inode_list);
+
+extern int dentry_tree_fix_inodes(struct dentry *root,
+                                 struct hlist_head *inode_list);
 
 /* header.c */
 extern int read_header(FILE *fp, struct wim_header *hdr, int split_ok);