From: Eric Biggers Date: Sun, 19 Aug 2012 22:32:15 +0000 (-0500) Subject: Hard link fix X-Git-Tag: v1.0.0~127 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=ecdb6a689808479505db2761337493955269737b Hard link fix I'm noticing weird things in the Windows 7 install.wim file where WIM dentries are marked as being in the same hard link set, but the dentries have differences such as different file streams or different file permissions. I'm working around the problem by splitting these offending dentries into their own hard link groups. --- diff --git a/src/dentry.c b/src/dentry.c index ea21e07b..bccfce2c 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -592,8 +592,8 @@ int share_dentry_ads(struct dentry *master, struct dentry *slave) goto mismatch; } if (master->attributes & FILE_ATTRIBUTE_DIRECTORY) { - ERROR("`%s' is hard-linked to `%s', which is a directory ", - slave->full_path_utf8, master->full_path_utf8); + WARNING("`%s' is hard-linked to `%s', which is a directory ", + slave->full_path_utf8, master->full_path_utf8); return WIMLIB_ERR_INVALID_DENTRY; } if (master->security_id != slave->security_id) { @@ -613,10 +613,10 @@ int share_dentry_ads(struct dentry *master, struct dentry *slave) slave->link_group_master_status = GROUP_SLAVE; return 0; mismatch: - ERROR("Dentries `%s' and `%s' in the same hard-link group but " - "do not share the same %s", - master->full_path_utf8, slave->full_path_utf8, - mismatch_type); + WARNING("Dentries `%s' and `%s' in the same hard-link group but " + "do not share the same %s", + master->full_path_utf8, slave->full_path_utf8, + mismatch_type); return WIMLIB_ERR_INVALID_DENTRY; } diff --git a/src/extract.c b/src/extract.c index 4a2f55b7..4663df07 100644 --- a/src/extract.c +++ b/src/extract.c @@ -383,6 +383,7 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image, if (!(mnt_flags & NTFS_MF_MOUNTED)) { ERROR("NTFS-3g: Filesystem on `%s' is not mounted ", output_dir); + return WIMLIB_ERR_NTFS_3G; } if (mnt_flags & NTFS_MF_READONLY) { ERROR("NTFS-3g: Filesystem on `%s' is mounted " diff --git a/src/hardlink.c b/src/hardlink.c index 4640c9cf..7519b047 100644 --- a/src/hardlink.c +++ b/src/hardlink.c @@ -63,7 +63,6 @@ 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; - DEBUG("Insert single group `%s'", dentry->full_path_utf8); group->link_group_id = 0; group->next = table->singles; table->singles = group; @@ -155,7 +154,6 @@ u64 assign_link_groups(struct link_group_table *table) dentry = container_of(single->dentry_list, struct dentry, link_group_list); dentry->hard_link = id; - DEBUG("Assign single `%s'", dentry->full_path_utf8); pos = id % table->capacity; single->next = table->array[pos]; @@ -164,12 +162,15 @@ u64 assign_link_groups(struct link_group_table *table) single = next_single; id++; } + table->singles = NULL; return id; } -static int link_group_free_duplicate_data(struct link_group *group) +static int link_group_free_duplicate_data(struct link_group *group, + struct link_group **bad_links) { struct list_head *head; + struct list_head *next; struct dentry *master; head = group->dentry_list; @@ -177,12 +178,32 @@ static int link_group_free_duplicate_data(struct link_group *group) head = head->next; master->link_group_master_status = GROUP_MASTER; while (head != group->dentry_list) { - int ret = share_dentry_ads(master, - container_of(head, struct dentry, - link_group_list)); - if (ret != 0) - return ret; - head = head->next; + next = head->next; + struct dentry *slave; + int ret; + + slave = container_of(head, struct dentry, link_group_list); + ret = share_dentry_ads(master, slave); + + /* I would it to be an error if two dentries are the same hard + * link group but have irreconcilable differences such as + * different file permissions, but unfortunately some of M$'s + * WIMs contain many instances of this error. This problem is + * worked around here by splitting each offending dentry off + * into its own hard link group. */ + if (ret != 0) { + struct link_group *single; + single = MALLOC(sizeof(struct link_group)); + if (!single) + return WIMLIB_ERR_NOMEM; + single->link_group_id = 0; + single->next = *bad_links; + *bad_links = single; + INIT_LIST_HEAD(&slave->link_group_list); + single->dentry_list = &slave->link_group_list; + slave->link_group_master_status = GROUP_INDEPENDENT; + } + head = next; } return 0; } @@ -192,7 +213,9 @@ int link_groups_free_duplicate_data(struct link_group_table *table) for (u64 i = 0; i < table->capacity; i++) { struct link_group *group = table->array[i]; while (group) { - int ret = link_group_free_duplicate_data(group); + int ret; + ret = link_group_free_duplicate_data(group, + &table->singles); if (ret != 0) return ret; group = group->next;