inode updates
authorEric Biggers <ebiggers3@gmail.com>
Mon, 3 Sep 2012 05:53:04 +0000 (00:53 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Mon, 3 Sep 2012 05:53:04 +0000 (00:53 -0500)
src/dentry.c
src/dentry.h
src/extract.c
src/hardlink.c
src/modify.c
src/resource.c
src/wimlib_internal.h

index 20fd34912efa0d9533952b89116026a3d2841ba1..c7c5fb9b9df6f5f9fa5d93263ab652a5d187654d 100644 (file)
@@ -96,10 +96,9 @@ u64 dentry_total_length(const struct dentry *dentry)
        return __dentry_total_length(dentry, dentry->length);
 }
 
-/* Transfers file attributes from a `stat' buffer to a struct dentry. */
-void stbuf_to_dentry(const struct stat *stbuf, struct dentry *dentry)
+/* Transfers file attributes from a `stat' buffer to an inode. */
+void stbuf_to_inode(const struct stat *stbuf, struct inode *inode)
 {
-       struct inode *inode = dentry->inode;
        if (S_ISLNK(stbuf->st_mode)) {
                inode->attributes = FILE_ATTRIBUTE_REPARSE_POINT;
                inode->reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
@@ -109,9 +108,9 @@ void stbuf_to_dentry(const struct stat *stbuf, struct dentry *dentry)
                inode->attributes = FILE_ATTRIBUTE_NORMAL;
        }
        if (sizeof(ino_t) >= 8)
-               dentry->link_group_id = (u64)stbuf->st_ino;
+               inode->ino = (u64)stbuf->st_ino;
        else
-               dentry->link_group_id = (u64)stbuf->st_ino |
+               inode->ino = (u64)stbuf->st_ino |
                                   ((u64)stbuf->st_dev << (sizeof(ino_t) * 8));
        /* Set timestamps */
        inode->creation_time = timespec_to_wim_timestamp(&stbuf->st_mtim);
@@ -464,15 +463,6 @@ int print_dentry(struct dentry *dentry, void *lookup_table)
                                file_attr_flags[i].name);
        printf("Security ID       = %d\n", inode->security_id);
        printf("Subdir offset     = %"PRIu64"\n", dentry->subdir_offset);
-#if 0
-       printf("Unused1           = 0x%"PRIu64"\n", dentry->unused1);
-       printf("Unused2           = %"PRIu64"\n", dentry->unused2);
-#endif
-#if 0
-       printf("Creation Time     = 0x%"PRIx64"\n");
-       printf("Last Access Time  = 0x%"PRIx64"\n");
-       printf("Last Write Time   = 0x%"PRIx64"\n");
-#endif
 
        /* Translate the timestamps into something readable */
        time = wim_timestamp_to_unix(inode->creation_time);
@@ -491,7 +481,8 @@ int print_dentry(struct dentry *dentry, void *lookup_table)
        printf("Last Write Time   = %s UTC\n", p);
 
        printf("Reparse Tag       = 0x%"PRIx32"\n", inode->reparse_tag);
-       printf("Hard Link Group   = 0x%"PRIx64"\n", dentry->link_group_id);
+       printf("Hard Link Group   = 0x%"PRIx64"\n", inode->ino);
+       printf("Hard Link Group Size = %"PRIu32"\n", inode->link_count);
        printf("Number of Alternate Data Streams = %hu\n", inode->num_ads);
        printf("Filename          = \"");
        print_string(dentry->file_name, dentry->file_name_len);
@@ -540,18 +531,26 @@ static void dentry_common_init(struct dentry *dentry)
        dentry->refcnt = 1;
 }
 
-struct inode *new_inode()
+struct inode *new_timeless_inode()
 {
        struct inode *inode = CALLOC(1, sizeof(struct inode));
-       u64 now = get_wim_timestamp();
        if (!inode)
                return NULL;
        inode->security_id = -1;
        inode->link_count = 1;
+       INIT_LIST_HEAD(&inode->dentry_list);
+       return inode;
+}
+
+struct inode *new_inode()
+{
+       struct inode *inode = new_timeless_inode();
+       if (!inode)
+               return NULL;
+       u64 now = get_wim_timestamp();
        inode->creation_time = now;
        inode->last_access_time = now;
        inode->last_write_time = now;
-       INIT_LIST_HEAD(&inode->dentry_list);
        return inode;
 }
 
@@ -668,9 +667,10 @@ static void inode_free_ads_entries(struct inode *inode)
 
 void free_inode(struct inode *inode)
 {
-       wimlib_assert(inode);
-       inode_free_ads_entries(inode);
-       FREE(inode);
+       if (inode) {
+               inode_free_ads_entries(inode);
+               FREE(inode);
+       }
 }
 
 void put_inode(struct inode *inode)
@@ -686,6 +686,7 @@ void put_inode(struct inode *inode)
 void free_dentry(struct dentry *dentry)
 {
        wimlib_assert(dentry);
+
        FREE(dentry->file_name);
        FREE(dentry->file_name_utf8);
        FREE(dentry->short_name);
@@ -1154,7 +1155,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
                return WIMLIB_ERR_INVALID_DENTRY;
        }
 
-       inode = new_inode();
+       inode = new_timeless_inode();
        if (!inode)
                return WIMLIB_ERR_NOMEM;
 
@@ -1186,7 +1187,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
                p += 4;
        } else {
                p = get_u32(p, &inode->reparse_tag);
-               p = get_u64(p, &dentry->link_group_id);
+               p = get_u64(p, &inode->ino);
        }
 
        /* By the way, the reparse_reserved field does not actually exist (at
@@ -1317,6 +1318,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
 
        /* We've read all the data for this dentry.  Set the names and their
         * lengths, and we've done. */
+       dentry->inode              = inode;
        dentry->file_name          = file_name;
        dentry->file_name_utf8     = file_name_utf8;
        dentry->short_name         = short_name;
@@ -1457,10 +1459,10 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p)
        } else {
                u64 link_group_id;
                p = put_u32(p, 0);
-               if (dentry->inode->link_count == 1)
+               if (inode->link_count == 1)
                        link_group_id = 0;
                else
-                       link_group_id = dentry->inode->ino;
+                       link_group_id = inode->ino;
                p = put_u64(p, link_group_id);
        }
        p = put_u16(p, inode->num_ads);
@@ -1630,6 +1632,7 @@ int read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
 
                child->parent = dentry;
                prev_child = child;
+               list_add(&child->inode_dentry_list, &child->inode->dentry_list);
 
                /* If there are children of this child, call this procedure
                 * recursively. */
index 5881c89707e6dc78b121728d6a758b65789f534a..1e3a04bc13aba41abc8f452ba87e6607f7fe9baa 100644 (file)
@@ -160,6 +160,12 @@ struct inode {
 
        struct ads_entry **ads_entries;
 
+       /* If the file is part of a hard link set, all the directory entries in
+        * the set will share the same value for this field. 
+        *
+        * Unfortunately, in some WIMs it is NOT the case that all dentries that
+        * share this field are actually in the same hard link set, although the
+        * WIMs that wimlib writes maintain this restriction. */
        u64 ino;
 
        struct list_head dentry_list;
@@ -241,13 +247,6 @@ struct dentry {
         * read_dentry() function. */
        //u32 reparse_reserved;
 
-       /* If the file is part of a hard link set, all the directory entries in
-        * the set will share the same value for this field. 
-        *
-        * Unfortunately, in some WIMs it is NOT the case that all dentries that
-        * share this field are actually in the same hard link set, although the
-        * WIMs that wimlib writes maintain this restriction. */
-       u64 link_group_id;
 
        /* Length of short filename, in bytes, not including the terminating
         * zero wide-character. */
@@ -303,7 +302,7 @@ extern const char *path_stream_name(const char *path);
 extern u64 dentry_total_length(const struct dentry *dentry);
 extern u64 dentry_correct_total_length(const struct dentry *dentry);
 
-extern void stbuf_to_dentry(const struct stat *stbuf, struct dentry *dentry);
+extern void stbuf_to_inode(const struct stat *stbuf, struct inode *inode);
 
 extern int for_dentry_in_tree(struct dentry *root, 
                              int (*visitor)(struct dentry*, void*), 
@@ -334,6 +333,8 @@ extern struct dentry *get_dentry_child_with_name(const struct dentry *dentry,
 extern void dentry_update_all_timestamps(struct dentry *dentry);
 extern void init_dentry(struct dentry *dentry, const char *name);
 extern struct dentry *new_dentry(const char *name);
+extern struct inode *new_inode();
+extern struct inode *new_timeless_inode();
 extern struct dentry *new_dentry_with_inode(const char *name);
 
 extern void dentry_free_ads_entries(struct dentry *dentry);
index 26164028ee9d6dc5f73d2af2f1987f445abbd29d..6f4e74c95a1007114d449e61ae50ef9be49e8df6 100644 (file)
@@ -126,27 +126,29 @@ static int extract_regular_file_unlinked(WIMStruct *w,
        int ret;
        struct inode *inode = dentry->inode;
 
-       if (!(extract_flags & WIMLIB_EXTRACT_FLAG_MULTI_IMAGE)) {
-               /* This dentry is one of a hard link set of at least 2 dentries.
-                * If one of the other dentries has already been extracted, make
-                * a hard link to the file corresponding to this
-                * already-extracted directory.  Otherwise, extract the
-                * file, and set the dentry->extracted_file field so that other
+       if (!((extract_flags & WIMLIB_EXTRACT_FLAG_MULTI_IMAGE)
+               && (extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
+                                    WIMLIB_EXTRACT_FLAG_HARDLINK))))
+       {
+               /* If the dentry is one of a hard link set of at least 2
+                * dentries and one of the other dentries has already been
+                * extracted, make a hard link to the file corresponding to this
+                * already-extracted directory.  Otherwise, extract the file,
+                * and set the inode->extracted_file field so that other
                 * dentries in the hard link group can link to it. */
-               struct dentry *other;
-               if (inode->extracted_file) {
-                       DEBUG("Extracting hard link `%s' => `%s'",
-                             output_path, inode->extracted_file);
-                       if (link(inode->extracted_file, output_path) != 0) {
-                               ERROR_WITH_ERRNO("Failed to hard link "
-                                                "`%s' to `%s'",
-                                                output_path,
-                                                inode->extracted_file);
-                               return WIMLIB_ERR_LINK;
-                       }
-                       return 0;
-               }
                if (inode->link_count > 1) {
+                       if (inode->extracted_file) {
+                               DEBUG("Extracting hard link `%s' => `%s'",
+                                     output_path, inode->extracted_file);
+                               if (link(inode->extracted_file, output_path) != 0) {
+                                       ERROR_WITH_ERRNO("Failed to hard link "
+                                                        "`%s' to `%s'",
+                                                        output_path,
+                                                        inode->extracted_file);
+                                       return WIMLIB_ERR_LINK;
+                               }
+                               return 0;
+                       }
                        FREE(inode->extracted_file);
                        inode->extracted_file = STRDUP(output_path);
                        if (!inode->extracted_file) {
@@ -169,16 +171,16 @@ static int extract_regular_file_unlinked(WIMStruct *w,
                /* Empty file with no lookup table entry */
                DEBUG("Empty file `%s'.", output_path);
                ret = 0;
-               goto done;
+               goto out;
        }
 
        ret = extract_full_wim_resource_to_fd(lte, out_fd);
        if (ret != 0) {
                ERROR("Failed to extract resource to `%s'", output_path);
-               goto done;
+               goto out;
        }
 
-done:
+out:
        if (close(out_fd) != 0) {
                ERROR_WITH_ERRNO("Failed to close file `%s'", output_path);
                ret = WIMLIB_ERR_WRITE;
index d2876e5e35185dc4ca51f58343e0ad56c47d72d3..87f75a872a5a6d56d87835b51111b946bd231a81 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;
-};
-
-/* Returns pointer to a new inode table having the specified capacity */
-struct inode_table *new_inode_table(size_t capacity)
+
+int init_inode_table(struct inode_table *table, size_t capacity)
 {
-       struct inode_table *table;
-       struct hlist_head *array;
-
-       table = MALLOC(sizeof(struct inode_table));
-       if (!table)
-               goto err;
-       array = CALLOC(capacity, sizeof(array[0]));
-       if (!array) {
-               FREE(table);
-               goto err;
+       table->array = CALLOC(capacity, sizeof(table->array[0]));
+       if (!table->array) {
+               ERROR("Cannot initalize inode table: out of memory");
+               return WIMLIB_ERR_NOMEM;
        }
        table->num_entries  = 0;
        table->capacity     = capacity;
-       table->array        = array;
        INIT_HLIST_HEAD(&table->extra_inodes);
-       return table;
-err:
-       ERROR("Failed to allocate memory for inode table with capacity %zu",
-             capacity);
-       return NULL;
+       return 0;
+}
+
+
+static size_t inode_link_count(const struct inode *inode)
+{
+       const struct list_head *cur;
+       size_t size = 0;
+       list_for_each(cur, &inode->dentry_list)
+               size++;
+       return size;
+}
+
+static struct dentry *inode_first_dentry(struct inode *inode)
+{
+       return container_of(inode->dentry_list.next, struct dentry,
+                           inode_dentry_list);
 }
 
 /* 
@@ -116,21 +99,24 @@ err:
 int inode_table_insert(struct dentry *dentry, void *__table)
 {
        struct inode_table *table = __table;
-       size_t pos;
-       struct inode *inode;
        struct inode *d_inode = dentry->inode;
 
        if (d_inode->ino == 0) {
-
                /* Single inode--- Add to the list of extra inodes (we can't put
                 * it in the table itself because all the singles have a link
                 * inode ID of 0) */
-               list_add(&dentry->inode_dentry_list, &d_inode->dentry_list);
                hlist_add_head(&d_inode->hlist, &table->extra_inodes);
+
+               wimlib_assert(d_inode->dentry_list.next == &dentry->inode_dentry_list);
+               wimlib_assert(d_inode->dentry_list.prev == &dentry->inode_dentry_list);
+               wimlib_assert(d_inode->link_count == 1);
        } else {
-                /* Hard inode that may contain multiple dentries (the code
-                 * will work even if the inode actually contains only 1 dentry
-                 * though) */
+               /* Inode that may have multiple corresponding dentries (the code
+                * will work even if the inode actually contains only 1 dentry
+                * though) */
+
+               size_t pos;
+               struct inode *inode;
                struct hlist_node *cur;
 
                /* Try adding to existing inode */
@@ -139,13 +125,18 @@ int inode_table_insert(struct dentry *dentry, void *__table)
                        if (inode->ino == d_inode->ino) {
                                list_add(&dentry->inode_dentry_list,
                                         &inode->dentry_list);
+                               inode->link_count++;
+                               return 0;
                        }
                }
 
                /* Add new inode to the table */
-               list_add(&dentry->inode_dentry_list, &d_inode->dentry_list);
                hlist_add_head(&d_inode->hlist, &table->array[pos]);
 
+               wimlib_assert(d_inode->dentry_list.next == &dentry->inode_dentry_list);
+               wimlib_assert(d_inode->dentry_list.prev == &dentry->inode_dentry_list);
+               wimlib_assert(d_inode->link_count == 1);
+
                /* XXX Make the table grow when too many entries have been
                 * inserted. */
                table->num_entries++;
@@ -153,26 +144,6 @@ int inode_table_insert(struct dentry *dentry, void *__table)
        return 0;
 }
 
-/* Frees a inode table. */
-void free_inode_table(struct inode_table *table)
-{
-       if (table) {
-               FREE(table->array);
-                FREE(table);
-        }
-}
-
-static u64
-assign_inos_to_list(struct hlist_head *head, u64 cur_ino)
-{
-       struct inode *inode;
-       struct hlist_node *cur;
-       struct dentry *dentry;
-       hlist_for_each_entry(inode, cur, head, hlist) {
-       }
-       return cur_ino;
-}
-
 /* Assign the inode numbers to dentries in a inode table, and return the
  * next available inode ID. */
 u64 assign_inode_numbers(struct hlist_head *inode_list)
@@ -182,8 +153,6 @@ u64 assign_inode_numbers(struct hlist_head *inode_list)
        u64 cur_ino = 1;
        struct dentry *dentry;
        hlist_for_each_entry(inode, cur, inode_list, hlist) {
-               list_for_each_entry(dentry, &inode->dentry_list, inode_dentry_list)
-                       dentry->link_group_id = cur_ino;
                inode->ino = cur_ino;
                cur_ino++;
        }
@@ -207,49 +176,49 @@ static void inconsistent_inode(const struct inode *inode)
        print_inode_dentries(inode);
 }
 
-static bool ref_dentries_consistent(const struct dentry * restrict ref_dentry_1,
-                                   const struct dentry * restrict ref_dentry_2)
+static bool ref_inodes_consistent(const struct inode * restrict ref_inode_1,
+                                 const struct inode * restrict ref_inode_2)
 {
-       wimlib_assert(ref_dentry_1 != ref_dentry_2);
+       wimlib_assert(ref_inode_1 != ref_inode_2);
 
-       if (ref_dentry_1->inode->num_ads != ref_dentry_2->inode->num_ads)
+       if (ref_inode_1->num_ads != ref_inode_2->num_ads)
                return false;
-       if (ref_dentry_1->inode->security_id != ref_dentry_2->inode->security_id
-           || ref_dentry_1->inode->attributes != ref_dentry_2->inode->attributes)
+       if (ref_inode_1->security_id != ref_inode_2->security_id
+           || ref_inode_1->attributes != ref_inode_2->attributes)
                return false;
-       for (unsigned i = 0; i <= ref_dentry_1->inode->num_ads; i++) {
+       for (unsigned i = 0; i <= ref_inode_1->num_ads; i++) {
                const u8 *ref_1_hash, *ref_2_hash;
-               ref_1_hash = inode_stream_hash(ref_dentry_1->inode, i);
-               ref_2_hash = inode_stream_hash(ref_dentry_2->inode, i);
+               ref_1_hash = inode_stream_hash(ref_inode_1, i);
+               ref_2_hash = inode_stream_hash(ref_inode_2, i);
                if (!hashes_equal(ref_1_hash, ref_2_hash))
                        return false;
-               if (i && !ads_entries_have_same_name(ref_dentry_1->inode->ads_entries[i - 1],
-                                                    ref_dentry_2->inode->ads_entries[i - 1]))
+               if (i && !ads_entries_have_same_name(ref_inode_1->ads_entries[i - 1],
+                                                    ref_inode_2->ads_entries[i - 1]))
                        return false;
 
        }
        return true;
 }
 
-static bool dentries_consistent(const struct dentry * restrict ref_dentry,
-                               const struct dentry * restrict dentry)
+static bool inodes_consistent(const struct inode * restrict ref_inode,
+                             const struct inode * restrict inode)
 {
-       wimlib_assert(ref_dentry != dentry);
+       wimlib_assert(ref_inode != inode);
 
-       if (ref_dentry->inode->num_ads != dentry->inode->num_ads &&
-           dentry->inode->num_ads != 0)
+       if (ref_inode->num_ads != inode->num_ads &&
+           inode->num_ads != 0)
                return false;
-       if (ref_dentry->inode->security_id != dentry->inode->security_id
-           || ref_dentry->inode->attributes != dentry->inode->attributes)
+       if (ref_inode->security_id != inode->security_id
+           || ref_inode->attributes != inode->attributes)
                return false;
-       for (unsigned i = 0; i <= min(ref_dentry->inode->num_ads, dentry->inode->num_ads); i++) {
+       for (unsigned i = 0; i <= min(ref_inode->num_ads, inode->num_ads); i++) {
                const u8 *ref_hash, *hash;
-               ref_hash = inode_stream_hash(ref_dentry->inode, i);
-               hash = inode_stream_hash(dentry->inode, i);
+               ref_hash = inode_stream_hash(ref_inode, i);
+               hash = inode_stream_hash(inode, i);
                if (!hashes_equal(ref_hash, hash) && !is_zero_hash(hash))
                        return false;
-               if (i && !ads_entries_have_same_name(ref_dentry->inode->ads_entries[i - 1],
-                                                    dentry->inode->ads_entries[i - 1]))
+               if (i && !ads_entries_have_same_name(ref_inode->ads_entries[i - 1],
+                                                    inode->ads_entries[i - 1]))
                        return false;
        }
        return true;
@@ -269,26 +238,13 @@ print_dentry_list(const struct dentry *first_dentry)
 
 #endif
 
-static size_t inode_link_count(const struct inode *inode)
-{
-       const struct list_head *cur;
-       size_t size = 0;
-       list_for_each(cur, &inode->dentry_list)
-               size++;
-       return size;
-}
-
-static struct dentry *inode_first_dentry(struct inode *inode)
-{
-       return container_of(inode->dentry_list.next, struct dentry,
-                           inode_dentry_list);
-}
 
 /* Fix up a "true" inode and check for inconsistencies */
 static int fix_true_inode(struct inode *inode)
 {
        struct dentry *dentry;
        struct dentry *ref_dentry = NULL;
+       struct inode *ref_inode;
        u64 last_ctime = 0;
        u64 last_mtime = 0;
        u64 last_atime = 0;
@@ -315,22 +271,25 @@ static int fix_true_inode(struct inode *inode)
                        last_atime = dentry->inode->last_access_time;
        }
 
+       ref_inode = ref_dentry->inode;
+       ref_inode->link_count = 1;
+
        list_for_each_entry(dentry, &inode->dentry_list, inode_dentry_list) {
                if (dentry != ref_dentry) {
-                       if (!dentries_consistent(ref_dentry, dentry)) {
-                               inconsistent_inode(inode);
+                       if (!inodes_consistent(ref_inode, dentry->inode)) {
+                               inconsistent_inode(dentry->inode);
                                return WIMLIB_ERR_INVALID_DENTRY;
                        }
                        /* Free the unneeded `struct inode'. */
                        free_inode(dentry->inode);
-                       dentry->inode = ref_dentry->inode;
-                       ref_dentry->inode->link_count++;
+                       dentry->inode = ref_inode;
+                       ref_inode->link_count++;
                }
        }
-       ref_dentry->inode->creation_time = last_ctime;
-       ref_dentry->inode->last_write_time = last_mtime;
-       ref_dentry->inode->last_access_time = last_atime;
-       wimlib_assert(inode_link_count(inode) == inode->link_count);
+       ref_inode->creation_time = last_ctime;
+       ref_inode->last_write_time = last_mtime;
+       ref_inode->last_access_time = last_atime;
+       wimlib_assert(inode_link_count(ref_inode) == ref_inode->link_count);
        return 0;
 }
 
@@ -352,11 +311,13 @@ static int fix_true_inode(struct inode *inode)
 static int
 fix_nominal_inode(struct inode *inode, struct hlist_head *inode_list)
 {
-       struct dentry *tmp, *dentry, *ref_dentry;
-       struct hlist_node *cur;
+       struct dentry *dentry, *ref_dentry;
+       struct hlist_node *cur, *tmp;
        int ret;
        size_t num_true_inodes;
 
+       wimlib_assert(inode->link_count == inode_link_count(inode));
+
        LIST_HEAD(dentries_with_data_streams);
        LIST_HEAD(dentries_with_no_data_streams);
        HLIST_HEAD(true_inodes);
@@ -383,6 +344,7 @@ fix_nominal_inode(struct inode *inode, struct hlist_head *inode_list)
        /* If there are no dentries with data streams, we require the nominal
         * inode to be a true inode */
        if (list_empty(&dentries_with_data_streams)) {
+               DEBUG("No data streams");
        #ifdef ENABLE_DEBUG
                {
                        if (inode->link_count > 1) {
@@ -410,16 +372,16 @@ fix_nominal_inode(struct inode *inode, struct hlist_head *inode_list)
                 * of the true inodes are consistent with this
                 * dentry, make a new one. */
                hlist_for_each_entry(inode, cur, &true_inodes, hlist) {
-                       if (ref_dentries_consistent(inode_first_dentry(inode), dentry)) {
+                       if (ref_inodes_consistent(inode, dentry->inode)) {
                                list_add(&dentry->inode_dentry_list,
                                         &inode->dentry_list);
                                goto next_dentry_2;
                        }
                }
                num_true_inodes++;
-               hlist_add_head(&dentry->inode->hlist, &true_inodes);
                INIT_LIST_HEAD(&dentry->inode->dentry_list);
                list_add(&dentry->inode_dentry_list, &dentry->inode->dentry_list);
+               hlist_add_head(&dentry->inode->hlist, &true_inodes);
 next_dentry_2:
                ;
        }
@@ -439,9 +401,11 @@ next_dentry_2:
                        ERROR("inode to assign them to.");
                        return WIMLIB_ERR_INVALID_DENTRY;
                }
+               inode = container_of(true_inodes.first,
+                                    struct inode,
+                                    hlist);
                /* Assign the streamless dentries to the one and only true link
                 * inode. */
-               ref_dentry = inode_first_dentry(inode);
                list_for_each_entry(dentry, &dentries_with_no_data_streams, tmp_list)
                        list_add(&dentry->inode_dentry_list, &inode->dentry_list);
        }
@@ -463,7 +427,7 @@ next_dentry_2:
                #endif
         }
 
-       hlist_for_each_entry(inode, cur, &true_inodes, hlist) {
+       hlist_for_each_entry_safe(inode, cur, tmp, &true_inodes, hlist) {
                hlist_add_head(&inode->hlist, inode_list);
                ret = fix_true_inode(inode);
                if (ret != 0)
@@ -485,14 +449,16 @@ int fix_inodes(struct inode_table *table, struct hlist_head *inode_list)
 {
        struct inode *inode;
        struct hlist_node *cur, *tmp;
-       int ret = 0;
+       int ret;
        INIT_HLIST_HEAD(inode_list);
        for (u64 i = 0; i < table->capacity; i++) {
                hlist_for_each_entry_safe(inode, cur, tmp, &table->array[i], hlist) {
                        ret = fix_nominal_inode(inode, inode_list);
                        if (ret != 0)
-                               break;
+                               return ret;
                }
        }
-       return ret;
+       hlist_for_each_safe(cur, tmp, &table->extra_inodes)
+               hlist_add_head(cur, inode_list);
+       return 0;
 }
index d2b03abe88607c04666da6bea041b91eec06cd70..ae6f98b46231bc23b5dfd6bbe4595074b06a92a3 100644 (file)
@@ -131,7 +131,7 @@ static int build_dentry_tree(struct dentry **root_ret, const char *root_disk_pat
        if (!root)
                return WIMLIB_ERR_NOMEM;
 
-       stbuf_to_dentry(&root_stbuf, root);
+       stbuf_to_inode(&root_stbuf, root->inode);
        add_flags &= ~WIMLIB_ADD_IMAGE_FLAG_ROOT;
        root->inode->resolved = true;
 
@@ -805,7 +805,7 @@ int do_add_image(WIMStruct *w, const char *dir, const char *name,
        struct dentry *root_dentry = NULL;
        struct wim_security_data *sd;
        struct capture_config config;
-       struct inode_table *inode_tab;
+       struct inode_table inode_tab;
        struct hlist_head inode_list;
        int ret;
 
@@ -871,11 +871,15 @@ int do_add_image(WIMStruct *w, const char *dir, const char *name,
                goto out_free_dentry_tree;
 
        DEBUG("Inserting dentries into inode table");
-       for_dentry_in_tree(root_dentry, inode_table_insert, inode_tab);
+       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("Cleanup up the hard link groups");
-       ret = fix_inodes(inode_tab, &inode_list);
-       free_inode_table(inode_tab);
+       DEBUG("Cleaning up the hard link groups");
+       ret = fix_inodes(&inode_tab, &inode_list);
+       destroy_inode_table(&inode_tab);
        if (ret != 0)
                goto out_destroy_imd;
 
index 167901c9f7ae79f00398617a90f624a17bba60b1..7baaa15ca4ba4c59d4126e76be0baf1d086fb4b3 100644 (file)
@@ -1128,7 +1128,7 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd)
        u32 dentry_offset;
        int ret;
        struct dentry *dentry;
-       struct inode_table *inode_tab;
+       struct inode_table inode_tab;
        const struct lookup_table_entry *metadata_lte;
        u64 metadata_len;
        u64 metadata_offset;
@@ -1204,6 +1204,7 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd)
        dentry->prev   = dentry;
        if (ret != 0)
                goto out_free_dentry_tree;
+       list_add(&dentry->inode_dentry_list, &dentry->inode->dentry_list);
 
        /* Now read the entire directory entry tree into memory. */
        DEBUG("Reading dentry tree");
@@ -1219,14 +1220,15 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd)
 
        /* Build hash table that maps hard link group IDs to dentry sets */
        DEBUG("Building link group table");
-       inode_tab = new_inode_table(9001);
-       if (!inode_tab)
+       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);
+
+       for_dentry_in_tree(dentry, inode_table_insert, &inode_tab);
 
        DEBUG("Fixing inconsistencies in the link groups");
-       ret = fix_inodes(inode_tab, &inode_list);
-       free_inode_table(inode_tab);
+       ret = fix_inodes(&inode_tab, &inode_list);
+       destroy_inode_table(&inode_tab);
        if (ret != 0)
                goto out_free_dentry_tree;
 
index f9a4ad8af5a6a1138868e9cd0baae00fe2057047..c7a3f8fec75a01364fa7077cba5605549ce7efdb 100644 (file)
 #define _WIMLIB_INTERNAL_H
 
 #include "util.h"
+#include "list.h"
 
 struct stat;
-struct hlist_head;
+struct dentry;
 struct inode;
 
 #define WIM_MAGIC_LEN  8
@@ -347,9 +348,34 @@ struct capture_config {
 
 /* hardlink.c */
 
-struct inode_table *new_inode_table(size_t capacity);
+/* 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;
+};
+
+int init_inode_table(struct inode_table *table, size_t capacity);
+static inline void destroy_inode_table(struct inode_table *table)
+{
+       FREE(table->array);
+}
 int inode_table_insert(struct dentry *dentry, void *__table);
-void free_inode_table(struct inode_table *table);
 u64 assign_inode_numbers(struct hlist_head *inode_list);
 int fix_inodes(struct inode_table *table, struct hlist_head *inode_list);