]> wimlib.net Git - wimlib/commitdiff
Hard link fix
authorEric Biggers <ebiggers3@gmail.com>
Sun, 19 Aug 2012 22:32:15 +0000 (17:32 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sun, 19 Aug 2012 22:32:15 +0000 (17:32 -0500)
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.

src/dentry.c
src/extract.c
src/hardlink.c

index ea21e07b57e90540adfccd65fb0485adeab3e39e..bccfce2c540e4475b74e4619982965835c0adc49 100644 (file)
@@ -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;
 }
 
index 4a2f55b79da3f2eda9c55d1858a8cd5cdb794863..4663df072569918cbb3b78189d487d8d4281bcd2 100644 (file)
@@ -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 "
index 4640c9cf12524471f7efb92b977e5c8ecaf73358..7519b0470b5c82958145088fa0e85601dda14f5d 100644 (file)
@@ -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;