]> wimlib.net Git - wimlib/blobdiff - src/hardlink.c
hardlink fixes
[wimlib] / src / hardlink.c
index 929837e534f8f7c38f94c6ee47f65acdd543280d..81eb10d4d54b529630cc6602e00083e41a16b71e 100644 (file)
@@ -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 <sys/mman.h>
 
 struct link_group_table *new_link_group_table(u64 capacity)
 {
@@ -35,15 +36,17 @@ int link_group_table_insert(struct dentry *dentry, struct link_group_table *tabl
        size_t pos;
        struct link_group *group;
 
-       if (dentry->hard_link == 0)
+       if (dentry->hard_link == 0) {
+               INIT_LIST_HEAD(&dentry->link_group_list);
                return 0;
+       }
 
        /* Try adding to existing hard link group */
        pos = dentry->hard_link % table->capacity;
        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 +57,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;
+       group->link_group_id   = dentry->hard_link;
+       group->next            = table->array[pos];
        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->dentry_list = &dentry->link_group_list;
+       table->array[pos]      = group;
 
        /* XXX Make the table grow when too many entries have been inserted. */
        table->num_entries++;
@@ -97,26 +100,30 @@ 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)) {
+                       u64 cur_id;
+                       struct list_head *dentry_list = group->dentry_list;
+                       if (dentry_list->next == 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,
-                                                     struct dentry,
-                                                     link_group_list);
-                               dentry->hard_link = 0;
+                               cur_id = 0;
                                FREE(group);
                        } else {
                                /* Hard link group of size > 1.  Assign the
                                 * 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,
-                                                   link_group_list)
-                                       dentry->hard_link = id;
+                               cur_id = id++;
                                group->next = remaining_groups;
                                remaining_groups = group;
-                               id++;
                        }
+                       struct list_head *cur = dentry_list;
+                       do {
+                               dentry = container_of(cur,
+                                                     struct dentry,
+                                                     link_group_list);
+                               dentry->hard_link = cur_id;
+                               cur = cur->next;
+                       } while (cur != dentry_list);
                        group = next_group;
                }
        }