-/* 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 dentry *dentry, void *lookup_table)
-{
- const u8 *hash;
- struct lookup_table_entry *lte;
- const struct inode *inode = dentry->d_inode;
- time_t time;
- char *p;
-
- printf("[DENTRY]\n");
- printf("Length = %"PRIu64"\n", dentry->length);
- printf("Attributes = 0x%x\n", inode->attributes);
- for (unsigned i = 0; i < ARRAY_LEN(file_attr_flags); i++)
- if (file_attr_flags[i].flag & inode->attributes)
- printf(" FILE_ATTRIBUTE_%s is set\n",
- file_attr_flags[i].name);
- printf("Security ID = %d\n", inode->security_id);
- printf("Subdir offset = %"PRIu64"\n", dentry->subdir_offset);
-
- /* Translate the timestamps into something readable */
- time = wim_timestamp_to_unix(inode->creation_time);
- p = asctime(gmtime(&time));
- *(strrchr(p, '\n')) = '\0';
- printf("Creation Time = %s UTC\n", p);
-
- time = wim_timestamp_to_unix(inode->last_access_time);
- p = asctime(gmtime(&time));
- *(strrchr(p, '\n')) = '\0';
- printf("Last Access Time = %s UTC\n", p);
-
- time = wim_timestamp_to_unix(inode->last_write_time);
- p = asctime(gmtime(&time));
- *(strrchr(p, '\n')) = '\0';
- printf("Last Write Time = %s UTC\n", p);
-
- printf("Reparse Tag = 0x%"PRIx32"\n", inode->reparse_tag);
- printf("Hard Link Group = 0x%"PRIx64"\n", inode->ino);
- printf("Hard Link Group Size = %"PRIu32"\n", inode->link_count);
- printf("Number of Alternate Data Streams = %hu\n", inode->num_ads);
- printf("Filename = \"");
- print_string(dentry->file_name, dentry->file_name_len);
- puts("\"");
- printf("Filename Length = %hu\n", dentry->file_name_len);
- 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 = \"");
- 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);
+ 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;
+}
+
+/* Returns the child of @dentry that has the file name @name. Returns NULL if
+ * no child has the name. */
+struct wim_dentry *
+get_dentry_child_with_name(const struct wim_dentry *dentry, const tchar *name,
+ CASE_SENSITIVITY_TYPE case_type)
+{
+#if TCHAR_IS_UTF16LE
+ return get_dentry_child_with_utf16le_name(dentry, name,
+ tstrlen(name) * sizeof(tchar),
+ case_type);
+#else
+ utf16lechar *utf16le_name;
+ size_t utf16le_name_nbytes;
+ int ret;
+ struct wim_dentry *child;
+
+ ret = tstr_to_utf16le(name, tstrlen(name) * sizeof(tchar),
+ &utf16le_name, &utf16le_name_nbytes);
+ if (ret) {
+ child = NULL;