* This file is part of wimlib, a library for working with WIM files.
*
* wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at your option)
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
* any later version.
*
* wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
- * You should have received a copy of the GNU Lesser General Public License
+ * You should have received a copy of the GNU General Public License
* along with wimlib; if not, see http://www.gnu.org/licenses/.
*/
size_t pos;
struct link_group *group;
- if (dentry->hard_link == 0) {
+ if (dentry->link_group_id == 0) {
/* Single group--- Add to the list of extra groups (we can't put
* it in the table itself because all the singles have a link
* group ID of 0) */
* though) */
/* Try adding to existing hard link group */
- pos = dentry->hard_link % table->capacity;
+ pos = dentry->link_group_id % table->capacity;
group = table->array[pos];
while (group) {
- if (group->link_group_id == dentry->hard_link) {
+ if (group->link_group_id == dentry->link_group_id) {
list_add(&dentry->link_group_list,
group->dentry_list);
return 0;
group = MALLOC(sizeof(struct link_group));
if (!group)
return WIMLIB_ERR_NOMEM;
- group->link_group_id = dentry->hard_link;
+ group->link_group_id = dentry->link_group_id;
group->next = table->array[pos];
INIT_LIST_HEAD(&dentry->link_group_list);
group->dentry_list = &dentry->link_group_list;
/* Frees a link group table. */
void free_link_group_table(struct link_group_table *table)
{
- struct link_group *single, *next;
-
if (table) {
if (table->array)
for (size_t i = 0; i < table->capacity; i++)
}
}
-u64 assign_link_group_ids_to_list(struct link_group *group, u64 id,
- struct link_group **extra_groups)
+static u64
+assign_link_group_ids_to_list(struct link_group *group, u64 id,
+ struct link_group **extra_groups)
{
struct dentry *dentry;
struct list_head *cur_head;
dentry = container_of(cur_head,
struct dentry,
link_group_list);
- dentry->hard_link = id;
+ dentry->link_group_id = id;
cur_head = cur_head->next;
} while (cur_head != cur_group->dentry_list);
cur_group->link_group_id = id;
return true;
}
+#ifdef ENABLE_DEBUG
+static void
+print_dentry_list(const struct dentry *first_dentry)
+{
+ const struct dentry *dentry = first_dentry;
+ do {
+ printf("`%s'\n", dentry->full_path_utf8);
+ } while ((dentry = container_of(dentry->link_group_list.next,
+ struct dentry,
+ link_group_list)) != first_dentry);
+}
+#endif
+
/* Fix up a "true" link group and check for inconsistencies */
static int
fix_true_link_group(struct dentry *first_dentry)
u64 last_ctime = 0;
u64 last_mtime = 0;
u64 last_atime = 0;
+ bool found_short_name = false;
dentry = first_dentry;
do {
if (!ref_dentry || ref_dentry->num_ads == 0)
ref_dentry = dentry;
+ if (dentry->short_name_len) {
+ if (found_short_name) {
+ ERROR("Multiple short names in hard link "
+ "group!");
+ inconsistent_link_group(first_dentry);
+ return WIMLIB_ERR_INVALID_DENTRY;
+ } else {
+ found_short_name = true;
+ }
+ }
if (dentry->creation_time > last_ctime)
last_ctime = dentry->creation_time;
if (dentry->last_write_time > last_mtime)
* the same hard link group ID.
*
* If dentries in the group are found to be inconsistent, we may split the group
- * into several groups. @new_groups points to a linked list of these "extra"
- * groups, and if we create any, they will be added to this list.
+ * into several "true" hard link groups. @new_groups points to a linked list of
+ * these split groups, and if we create any, they will be added to this list.
*
* After splitting up each nominal link group into the "true" link groups we
* will canonicalize the link groups. To do this, we:
*
* - Assign all the dentries in the link group the most recent timestamp
* among all the corresponding timestamps in the link group, for each of
- * the three categories of time stamps
+ * the three categories of time stamps.
*
* - Make sure the dentry->hash field is valid in all the dentries, if
* possible (this field may be all zeroes, and in the context of a hard
- * link group must be interpreted as implicitly refering to the same stream
- * as another dentry is the hard link group that does *not* have all zeroes
- * for the stream hash).
+ * link group this must be interpreted as implicitly refering to the same
+ * stream as another dentry in the hard link group that does NOT have all
+ * zeroes for this field).
*
* - Make sure dentry->num_ads is the same in all the dentries in the link
- * group. In some cases, it's possible for it to be set to 0 when it must
- * be interpreted as being the same as the number of alternate data streams
- * in another dentry in the hard link group that has a nonzero number of
- * alternate data streams.
+ * group. In some cases, it's possible for it to be set to 0 when it
+ * actually must be interpreted as being the same as the number of
+ * alternate data streams in another dentry in the hard link group that has
+ * a nonzero number of alternate data streams.
*
* - Make sure only the dentry->ads_entries array is only allocated for one
* dentry in the hard link group. This dentry will have
int ret;
size_t num_true_link_groups;
struct list_head *head;
- u64 link_group_id;
LIST_HEAD(dentries_with_data_streams);
LIST_HEAD(dentries_with_no_data_streams);
/* If there are no dentries with data streams, we require the nominal
* link group to be a true link group */
- if (list_empty(&dentries_with_data_streams))
+ if (list_empty(&dentries_with_data_streams)) {
+ #ifdef ENABLE_DEBUG
+ {
+ size_t size = dentry_link_group_size(dentry);
+ if (size > 1) {
+ DEBUG("Found link group of size %zu without "
+ "any data streams:", size);
+ print_dentry_list(dentry);
+ DEBUG("We are going to interpret it as true "
+ "link group, provided that the dentries "
+ "are consistent.");
+ }
+ }
+ #endif
return fix_true_link_group(container_of(group->dentry_list,
struct dentry,
link_group_list));
+ }
/* One or more dentries had data streams specified. We check each of
* these dentries for consistency with the others to form a set of true
ERROR("group to assign them to.");
return WIMLIB_ERR_INVALID_DENTRY;
}
+ /* Assign the streamless dentries to the one and only true link
+ * group. */
ref_dentry = container_of(true_link_groups.next,
struct dentry,
tmp_list);
- list_splice(&dentries_with_no_data_streams,
- &ref_dentry->link_group_list);
+ list_for_each_entry(dentry, &dentries_with_no_data_streams, tmp_list)
+ list_add(&dentry->link_group_list, &ref_dentry->link_group_list);
}
if (num_true_link_groups != 1) {
- WARNING("Split nominal link group 0x%"PRIx64" into %zu "
- "link groups",
- group->link_group_id, num_true_link_groups);
+ #ifdef ENABLE_DEBUG
+ {
+ printf("Split nominal link group 0x%"PRIx64" into %zu "
+ "link groups:\n",
+ group->link_group_id, num_true_link_groups);
+ puts("------------------------------------------------------------------------------");
+ size_t i = 1;
+ list_for_each_entry(dentry, &true_link_groups, tmp_list) {
+ printf("[Split link group %zu]\n", i++);
+ print_dentry_list(dentry);
+ putchar('\n');
+ }
+ puts("------------------------------------------------------------------------------");
+ }
+ #endif
}
list_for_each_entry(dentry, &true_link_groups, tmp_list) {
ERROR("Out of memory");
return WIMLIB_ERR_NOMEM;
}
- group->link_group_id = link_group_id;
+ group->link_group_id = dentry->link_group_id;
group->dentry_list = &dentry->link_group_list;
group->next = *new_groups;
*new_groups = group;
/*
* Goes through each link group and shares the ads_entries (Alternate Data
- * Stream entries) field of each dentry between members of a hard link group.
+ * Stream entries) field of each dentry among members of a hard link group.
*
* In the process, the dentries in each link group are checked for consistency.
* If they contain data features that indicate they cannot really be in the same
* hard link group, this should be an error, but in reality this case needs to
* be handled, so we split the dentries into different hard link groups.
*
- * One of the dentries in the group is arbitrarily assigned the role of "owner"
- * (ADS_ENTRIES_OWNER), while the others are "users" (ADS_ENTRIES_USER).
+ * One of the dentries in each hard link group group is arbitrarily assigned the
+ * role of "owner" of the memory pointed to by the @ads_entries field,
+ * (ADS_ENTRIES_OWNER), while the others are "users" (ADS_ENTRIES_USER) who are
+ * not allowed to free the memory.
*/
int fix_link_groups(struct link_group_table *table)
{