From 20e4ed048c57bd26e7f4da4b265aedbdd4f574a6 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 3 Sep 2012 00:53:04 -0500 Subject: [PATCH] inode updates --- src/dentry.c | 53 ++++++----- src/dentry.h | 17 ++-- src/extract.c | 46 ++++----- src/hardlink.c | 214 ++++++++++++++++++------------------------ src/modify.c | 16 ++-- src/resource.c | 14 +-- src/wimlib_internal.h | 32 ++++++- 7 files changed, 198 insertions(+), 194 deletions(-) diff --git a/src/dentry.c b/src/dentry.c index 20fd3491..c7c5fb9b 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -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. */ diff --git a/src/dentry.h b/src/dentry.h index 5881c897..1e3a04bc 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -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); diff --git a/src/extract.c b/src/extract.c index 26164028..6f4e74c9 100644 --- a/src/extract.c +++ b/src/extract.c @@ -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; diff --git a/src/hardlink.c b/src/hardlink.c index d2876e5e..87f75a87 100644 --- a/src/hardlink.c +++ b/src/hardlink.c @@ -51,51 +51,34 @@ * ----------------- */ -/* 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; } diff --git a/src/modify.c b/src/modify.c index d2b03abe..ae6f98b4 100644 --- a/src/modify.c +++ b/src/modify.c @@ -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; diff --git a/src/resource.c b/src/resource.c index 167901c9..7baaa15c 100644 --- a/src/resource.c +++ b/src/resource.c @@ -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; diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index f9a4ad8a..c7a3f8fe 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -28,9 +28,10 @@ #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); -- 2.43.0