From 3489da595e09caf8d6867661c45b4dab188f6ece Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 18 Aug 2012 23:32:58 -0500 Subject: [PATCH] hardlink fixes --- src/dentry.c | 13 ++++++++----- src/hardlink.c | 21 +++++++++++---------- src/modify.c | 44 ++++++++++++++++++++++++++----------------- src/security.c | 4 +--- src/wim.c | 13 ++++--------- src/wimlib_internal.h | 3 +++ 6 files changed, 54 insertions(+), 44 deletions(-) diff --git a/src/dentry.c b/src/dentry.c index e47f8380..cf77adc7 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -500,19 +500,21 @@ struct dentry *new_dentry(const char *name) dentry = MALLOC(sizeof(struct dentry)); if (!dentry) - return NULL; + goto err; dentry_common_init(dentry); - if (change_dentry_name(dentry, name) != 0) { - FREE(dentry); - return NULL; - } + if (change_dentry_name(dentry, name) != 0) + goto err; dentry_update_all_timestamps(dentry); dentry->next = dentry; dentry->prev = dentry; dentry->parent = dentry; return dentry; +err: + FREE(dentry); + ERROR("Failed to allocate new dentry"); + return NULL; } static void dentry_free_ads_entries(struct dentry *dentry) @@ -665,6 +667,7 @@ static int do_name_change(char **file_name_ret, *file_name_utf8_ret = file_name_utf8; *file_name_len_ret = utf16_len; *file_name_utf8_len_ret = utf8_len; + return 0; } /* Changes the name of a dentry to @new_name. Only changes the file_name and diff --git a/src/hardlink.c b/src/hardlink.c index 929837e5..67be5aab 100644 --- a/src/hardlink.c +++ b/src/hardlink.c @@ -6,7 +6,7 @@ struct link_group { u64 link_group_id; struct link_group *next; - struct list_head *link_group_head; + struct list_head dentry_list; }; struct link_group_table { @@ -15,6 +15,7 @@ struct link_group_table { u64 capacity; }; +#include struct link_group_table *new_link_group_table(u64 capacity) { @@ -43,7 +44,7 @@ int link_group_table_insert(struct dentry *dentry, struct link_group_table *tabl group = table->array[pos]; while (group) { if (group->link_group_id == dentry->hard_link) { - list_add(&dentry->link_group_list, group->link_group_head); + list_add(&dentry->link_group_list, &group->dentry_list); return 0; } group = group->next; @@ -54,11 +55,11 @@ int link_group_table_insert(struct dentry *dentry, struct link_group_table *tabl group = MALLOC(sizeof(struct link_group)); if (!group) return WIMLIB_ERR_NOMEM; - INIT_LIST_HEAD(&dentry->link_group_list); - group->link_group_id = dentry->hard_link; - group->next = table->array[pos]; - group->link_group_head = &dentry->link_group_list; - table->array[pos] = group; + group->link_group_id = dentry->hard_link; + group->next = table->array[pos]; + INIT_LIST_HEAD(&group->dentry_list); + list_add(&dentry->link_group_list, &group->dentry_list); + table->array[pos] = group; /* XXX Make the table grow when too many entries have been inserted. */ table->num_entries++; @@ -97,10 +98,10 @@ u64 assign_link_groups(struct link_group_table *table) struct dentry *dentry; while (group) { next_group = group->next; - if (list_empty(group->link_group_head)) { + if (list_is_singular(&group->dentry_list)) { /* Hard link group of size 1. Change the hard * link ID to 0 and discard the link_group */ - dentry = container_of(group->link_group_head, + dentry = container_of(group->dentry_list.next, struct dentry, link_group_list); dentry->hard_link = 0; @@ -110,7 +111,7 @@ u64 assign_link_groups(struct link_group_table *table) * dentries in the group the next available hard * link IDs and queue the group to be * re-inserted into the table. */ - list_for_each_entry(dentry, group->link_group_head, + list_for_each_entry(dentry, &group->dentry_list, link_group_list) dentry->hard_link = id; group->next = remaining_groups; diff --git a/src/modify.c b/src/modify.c index fab9ee05..947316aa 100644 --- a/src/modify.c +++ b/src/modify.c @@ -42,16 +42,19 @@ * the WIM. */ #define WIMLIB_ADD_IMAGE_FLAG_ROOT 0x80000000 -static void destroy_image_metadata(struct image_metadata *imd, - struct lookup_table *lt) +void destroy_image_metadata(struct image_metadata *imd,struct lookup_table *lt) { - free_dentry_tree(imd->root_dentry, lt, true); + if (lt) + free_dentry_tree(imd->root_dentry, lt, true); + else + free_dentry_tree(imd->root_dentry, NULL, false); free_security_data(imd->security_data); free_link_group_table(imd->lgt); /* Get rid of the lookup table entry for this image's metadata resource * */ - lookup_table_remove(lt, imd->metadata_lte); + if (lt) + lookup_table_remove(lt, imd->metadata_lte); } /* @@ -60,9 +63,7 @@ static void destroy_image_metadata(struct image_metadata *imd, * * @root: A dentry that has already been created for the root of the dentry * tree. - * @source_path: The path to the root of the tree on disk. - * @root_stat: A pointer to a `struct stat' that contains the metadata for the - * root of the tree on disk. + * @root_disk_path: The path to the root of the tree on disk. * @lookup_table: The lookup table for the WIM file. For each file added to the * dentry tree being built, an entry is added to the lookup table, * unless an identical file is already in the lookup table. These @@ -78,7 +79,7 @@ static int build_dentry_tree(struct dentry *root, const char *root_disk_path, struct lookup_table* lookup_table, int add_flags) { - DEBUG("`%s'", root_disk_path); + DEBUG("%s", root_disk_path); struct stat root_stbuf; int ret; int (*stat_fn)(const char *restrict, struct stat *restrict); @@ -130,10 +131,8 @@ static int build_dentry_tree(struct dentry *root, const char *root_disk_path, continue; strcpy(name + len + 1, p->d_name); child = new_dentry(p->d_name); - if (!child) { - ERROR("No memory to allocate new dentry"); + if (!child) return WIMLIB_ERR_NOMEM; - } ret = build_dentry_tree(child, name, lookup_table, add_flags); link_dentry(child, root); @@ -295,6 +294,7 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry) struct image_metadata *imd; struct image_metadata *new_imd; struct wim_security_data *sd; + struct link_group_table *lgt; DEBUG("Reallocating image metadata array for image_count = %u", w->hdr.image_count + 1); @@ -317,22 +317,30 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry) sd->refcnt = 1; sd->total_length = 8; + lgt = new_link_group_table(9001); + if (!lgt) + goto out_free_security_data; + metadata_lte->resource_entry.flags = WIM_RESHDR_FLAG_METADATA; randomize_byte_array(metadata_lte->hash, WIM_HASH_SIZE); lookup_table_insert(w->lookup_table, metadata_lte); - w->hdr.image_count++; + new_imd = &imd[w->hdr.image_count]; - new_imd = &imd[w->hdr.image_count - 1]; - new_imd->metadata_lte = metadata_lte; - new_imd->modified = true; new_imd->root_dentry = root_dentry; + new_imd->metadata_lte = metadata_lte; new_imd->security_data = sd; + new_imd->lgt = lgt; + new_imd->modified = true; + FREE(w->image_metadata); w->image_metadata = imd; + w->hdr.image_count++; /* Change the current image to the new one. */ return wimlib_select_image(w, w->hdr.image_count); +out_free_security_data: + FREE(sd); out_free_metadata_lte: FREE(metadata_lte); out_free_imd: @@ -520,7 +528,6 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, const char *flags_element, int flags) { struct dentry *root_dentry; - struct stat root_stat; struct image_metadata *imd; int ret; @@ -571,10 +578,12 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, if (ret != 0) goto out_free_dentry_tree; + DEBUG("Inserting dentries into hard link group table"); ret = for_dentry_in_tree(root_dentry, link_group_table_insert, - &w->image_metadata[w->hdr.image_count - 1].lgt); + w->image_metadata[w->hdr.image_count - 1].lgt); if (ret != 0) goto out_destroy_imd; + DEBUG("Assigning hard link groups"); assign_link_groups(w->image_metadata[w->hdr.image_count - 1].lgt); if (flags & WIMLIB_ADD_IMAGE_FLAG_BOOT) @@ -588,6 +597,7 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, out_destroy_imd: destroy_image_metadata(&w->image_metadata[w->hdr.image_count - 1], w->lookup_table); + w->hdr.image_count--; return ret; out_free_dentry_tree: free_dentry_tree(root_dentry, w->lookup_table, true); diff --git a/src/security.c b/src/security.c index ccca9624..b7b333e2 100644 --- a/src/security.c +++ b/src/security.c @@ -268,7 +268,7 @@ void free_security_data(struct wim_security_data *sd) if (!sd) return; wimlib_assert(sd->refcnt >= 1); - if (sd->refcnt == 1) { + if (--sd->refcnt == 0) { u8 **descriptors = sd->descriptors; u32 num_entries = sd->num_entries; if (descriptors) @@ -277,7 +277,5 @@ void free_security_data(struct wim_security_data *sd) FREE(sd->sizes); FREE(sd->descriptors); FREE(sd); - } else { - sd->refcnt--; } } diff --git a/src/wim.c b/src/wim.c index 12b84183..5507b212 100644 --- a/src/wim.c +++ b/src/wim.c @@ -207,10 +207,8 @@ int wimlib_select_image(WIMStruct *w, int image) imd = wim_get_current_image_metadata(w); if (!imd->modified) { DEBUG("Freeing image %u", w->current_image); - free_dentry_tree(imd->root_dentry, NULL, false); - imd->root_dentry = NULL; - free_security_data(imd->security_data); - imd->security_data = NULL; + destroy_image_metadata(imd, NULL); + memset(imd, 0, sizeof(*imd)); } } @@ -556,11 +554,8 @@ WIMLIBAPI void wimlib_free(WIMStruct *w) FREE(w->xml_data); free_wim_info(w->wim_info); if (w->image_metadata) { - for (i = 0; i < w->hdr.image_count; i++) { - free_dentry_tree(w->image_metadata[i].root_dentry, - NULL, false); - free_security_data(w->image_metadata[i].security_data); - } + for (i = 0; i < w->hdr.image_count; i++) + destroy_image_metadata(&w->image_metadata[i], NULL); FREE(w->image_metadata); } FREE(w); diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index ec1f2807..86b0716d 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -346,6 +346,9 @@ extern int write_integrity_table(FILE *out, u64 end_header_offset, int show_progress); extern int check_wim_integrity(WIMStruct *w, int show_progress, int *status); +/* modify.c */ +extern void destroy_image_metadata(struct image_metadata *imd, + struct lookup_table *lt); /* resource.c */ extern const u8 *get_resource_entry(const u8 *p, struct resource_entry *entry); -- 2.43.0