1 #include "wimlib_internal.h"
4 #include "lookup_table.h"
8 struct link_group *next;
9 struct list_head *dentry_list;
12 struct link_group_table {
13 struct link_group **array;
16 struct link_group *singles;
21 struct link_group_table *new_link_group_table(u64 capacity)
23 struct link_group_table *table;
24 struct link_group **array;
26 table = MALLOC(sizeof(struct link_group_table));
29 array = CALLOC(capacity, sizeof(array[0]));
34 table->num_entries = 0;
35 table->capacity = capacity;
37 table->singles = NULL;
40 ERROR("Failed to allocate memory for link group table with capacity %zu",
45 /* Insert a dentry into the hard link group table based on its hard link group
48 * If there is already a dentry in the table having the same hard link group ID,
49 * we link the dentries together in a circular list.
51 * If the hard link group ID is 0, this is a no-op and the dentry is not
54 int link_group_table_insert(struct dentry *dentry, struct link_group_table *table)
57 struct link_group *group;
59 if (dentry->hard_link == 0) {
60 /* Single group--- Add to the singles list (we can't put it in
61 * the table itself because all the singles have a link group ID
63 group = MALLOC(sizeof(struct link_group));
65 return WIMLIB_ERR_NOMEM;
66 DEBUG("Insert single group `%s'", dentry->full_path_utf8);
67 group->link_group_id = 0;
68 group->next = table->singles;
69 table->singles = group;
70 INIT_LIST_HEAD(&dentry->link_group_list);
71 group->dentry_list = &dentry->link_group_list;
75 /* Try adding to existing hard link group */
76 pos = dentry->hard_link % table->capacity;
77 group = table->array[pos];
79 if (group->link_group_id == dentry->hard_link) {
80 list_add(&dentry->link_group_list, group->dentry_list);
86 /* Add new hard link group to the table */
88 group = MALLOC(sizeof(struct link_group));
90 return WIMLIB_ERR_NOMEM;
91 group->link_group_id = dentry->hard_link;
92 group->next = table->array[pos];
93 INIT_LIST_HEAD(&dentry->link_group_list);
94 group->dentry_list = &dentry->link_group_list;
95 table->array[pos] = group;
97 /* XXX Make the table grow when too many entries have been inserted. */
102 /* Frees a link group table. */
103 void free_link_group_table(struct link_group_table *table)
108 for (u64 i = 0; i < table->capacity; i++) {
109 struct link_group *group = table->array[i];
110 struct link_group *next;
122 /* Assign the link group IDs to dentries in a link group table, and return the
123 * next available link group ID. */
124 u64 assign_link_groups(struct link_group_table *table)
126 DEBUG("Assigning link groups");
128 for (u64 i = 0; i < table->capacity; i++) {
129 struct link_group *group = table->array[i];
130 struct link_group *next_group;
131 struct dentry *dentry;
132 struct list_head *cur;
134 cur = group->dentry_list;
136 dentry = container_of(cur,
139 dentry->hard_link = id;
141 } while (cur != group->dentry_list);
147 struct link_group *single = table->singles;
149 struct dentry *dentry;
150 struct link_group *next_single;
153 next_single = single->next;
155 dentry = container_of(single->dentry_list, struct dentry,
157 dentry->hard_link = id;
158 DEBUG("Assign single `%s'", dentry->full_path_utf8);
160 pos = id % table->capacity;
161 single->next = table->array[pos];
162 table->array[pos] = single;
164 single = next_single;
170 static int link_group_free_duplicate_data(struct link_group *group)
172 struct list_head *head;
173 struct dentry *master;
175 head = group->dentry_list;
176 master = container_of(head, struct dentry, link_group_list);
178 master->link_group_master_status = GROUP_MASTER;
179 while (head != group->dentry_list) {
180 int ret = share_dentry_ads(master,
181 container_of(head, struct dentry,
190 int link_groups_free_duplicate_data(struct link_group_table *table)
192 for (u64 i = 0; i < table->capacity; i++) {
193 struct link_group *group = table->array[i];
195 int ret = link_group_free_duplicate_data(group);