-/* We want to be able to show the names of the file attribute flags that are
- * set. */
-struct file_attr_flag {
- u32 flag;
- const char *name;
-};
-struct file_attr_flag file_attr_flags[] = {
- {FILE_ATTRIBUTE_READONLY, "READONLY"},
- {FILE_ATTRIBUTE_HIDDEN, "HIDDEN"},
- {FILE_ATTRIBUTE_SYSTEM, "SYSTEM"},
- {FILE_ATTRIBUTE_DIRECTORY, "DIRECTORY"},
- {FILE_ATTRIBUTE_ARCHIVE, "ARCHIVE"},
- {FILE_ATTRIBUTE_DEVICE, "DEVICE"},
- {FILE_ATTRIBUTE_NORMAL, "NORMAL"},
- {FILE_ATTRIBUTE_TEMPORARY, "TEMPORARY"},
- {FILE_ATTRIBUTE_SPARSE_FILE, "SPARSE_FILE"},
- {FILE_ATTRIBUTE_REPARSE_POINT, "REPARSE_POINT"},
- {FILE_ATTRIBUTE_COMPRESSED, "COMPRESSED"},
- {FILE_ATTRIBUTE_OFFLINE, "OFFLINE"},
- {FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,"NOT_CONTENT_INDEXED"},
- {FILE_ATTRIBUTE_ENCRYPTED, "ENCRYPTED"},
- {FILE_ATTRIBUTE_VIRTUAL, "VIRTUAL"},
-};
-
-/* Prints a directory entry. @lookup_table is a pointer to the lookup table, if
- * available. If the dentry is unresolved and the lookup table is NULL, the
- * lookup table entries will not be printed. Otherwise, they will be. */
-int print_dentry(struct wim_dentry *dentry, void *lookup_table)
-{
- const u8 *hash;
- struct wim_lookup_table_entry *lte;
- const struct wim_inode *inode = dentry->d_inode;
- char buf[50];
-
- printf("[DENTRY]\n");
- printf("Length = %"PRIu64"\n", dentry->length);
- printf("Attributes = 0x%x\n", inode->i_attributes);
- for (size_t i = 0; i < ARRAY_LEN(file_attr_flags); i++)
- if (file_attr_flags[i].flag & inode->i_attributes)
- printf(" FILE_ATTRIBUTE_%s is set\n",
- file_attr_flags[i].name);
- printf("Security ID = %d\n", inode->i_security_id);
- printf("Subdir offset = %"PRIu64"\n", dentry->subdir_offset);
-
- wim_timestamp_to_str(inode->i_creation_time, buf, sizeof(buf));
- printf("Creation Time = %s\n", buf);
-
- wim_timestamp_to_str(inode->i_last_access_time, buf, sizeof(buf));
- printf("Last Access Time = %s\n", buf);
-
- wim_timestamp_to_str(inode->i_last_write_time, buf, sizeof(buf));
- printf("Last Write Time = %s\n", buf);
-
- printf("Reparse Tag = 0x%"PRIx32"\n", inode->i_reparse_tag);
- printf("Hard Link Group = 0x%"PRIx64"\n", inode->i_ino);
- printf("Hard Link Group Size = %"PRIu32"\n", inode->i_nlink);
- printf("Number of Alternate Data Streams = %hu\n", inode->i_num_ads);
- printf("Filename (UTF-8) = \"%s\"\n", dentry->file_name_utf8);
- /*printf("Filename (UTF-8) Length = %hu\n", dentry->file_name_utf8_len);*/
- printf("Short Name (UTF-16LE) = \"");
- print_string(dentry->short_name, dentry->short_name_len);
- puts("\"");
- /*printf("Short Name Length = %hu\n", dentry->short_name_len);*/
- printf("Full Path (UTF-8) = \"%s\"\n", dentry->full_path_utf8);
- lte = inode_stream_lte(dentry->d_inode, 0, lookup_table);
- if (lte) {
- print_lookup_table_entry(lte, stdout);
- } else {
- hash = inode_stream_hash(inode, 0);
- if (hash) {
- printf("Hash = 0x");
- print_hash(hash);
- putchar('\n');
- putchar('\n');
- }
- }
- for (u16 i = 0; i < inode->i_num_ads; i++) {
- printf("[Alternate Stream Entry %u]\n", i);
- printf("Name = \"%s\"\n", inode->i_ads_entries[i].stream_name_utf8);
- printf("Name Length (UTF-16) = %u\n",
- inode->i_ads_entries[i].stream_name_len);
- hash = inode_stream_hash(inode, i + 1);
- if (hash) {
- printf("Hash = 0x");
- print_hash(hash);
- putchar('\n');
- }
- print_lookup_table_entry(inode_stream_lte(inode, i + 1, lookup_table),
- stdout);
- }
- return 0;
+ if (likely(list_empty(&child->d_ci_conflict_list)))
+ /* Only one dentry has this case-insensitive name; return it */
+ return child;
+
+ /* Multiple dentries have the same case-insensitive name. Choose the
+ * dentry with the same case-sensitive name, if one exists; otherwise
+ * print a warning and choose one of the possible dentries arbitrarily.
+ */
+ struct wim_dentry *alt = child;
+ size_t num_alts = 0;
+
+ do {
+ num_alts++;
+ if (!dentry_compare_names_case_sensitive(&dummy, alt))
+ return alt;
+ alt = list_entry(alt->d_ci_conflict_list.next,
+ struct wim_dentry, d_ci_conflict_list);
+ } while (alt != child);
+
+ WARNING("Result of case-insensitive lookup is ambiguous\n"
+ " (returning \"%"TS"\" of %zu "
+ "possible files, including \"%"TS"\")",
+ dentry_full_path(child),
+ num_alts,
+ dentry_full_path(list_entry(child->d_ci_conflict_list.next,
+ struct wim_dentry,
+ d_ci_conflict_list)));
+ return child;