+
+/* Windows */
+static const utf16lechar windows_name[] = {
+ cpu_to_le16('W'), cpu_to_le16('i'), cpu_to_le16('n'),
+ cpu_to_le16('d'), cpu_to_le16('o'), cpu_to_le16('w'),
+ cpu_to_le16('s'),
+};
+
+/* System32 */
+static const utf16lechar system32_name[] = {
+ cpu_to_le16('S'), cpu_to_le16('y'), cpu_to_le16('s'),
+ cpu_to_le16('t'), cpu_to_le16('e'), cpu_to_le16('m'),
+ cpu_to_le16('3'), cpu_to_le16('2'),
+};
+
+/* kernel32.dll */
+static const utf16lechar kernel32_name[] = {
+ cpu_to_le16('k'), cpu_to_le16('e'), cpu_to_le16('r'),
+ cpu_to_le16('n'), cpu_to_le16('e'), cpu_to_le16('l'),
+ cpu_to_le16('3'), cpu_to_le16('2'), cpu_to_le16('.'),
+ cpu_to_le16('d'), cpu_to_le16('l'), cpu_to_le16('l'),
+};
+
+/* config */
+static const utf16lechar config_name[] = {
+ cpu_to_le16('c'), cpu_to_le16('o'), cpu_to_le16('n'),
+ cpu_to_le16('f'), cpu_to_le16('i'), cpu_to_le16('g'),
+};
+
+/* SOFTWARE */
+static const utf16lechar software_name[] = {
+ cpu_to_le16('S'), cpu_to_le16('O'), cpu_to_le16('F'),
+ cpu_to_le16('T'), cpu_to_le16('W'), cpu_to_le16('A'),
+ cpu_to_le16('R'), cpu_to_le16('E'),
+};
+
+/* SYSTEM */
+static const utf16lechar system_name[] = {
+ cpu_to_le16('S'), cpu_to_le16('Y'), cpu_to_le16('S'),
+ cpu_to_le16('T'), cpu_to_le16('E'), cpu_to_le16('M'),
+};
+
+#define GET_CHILD(parent, child_name) \
+ get_dentry_child_with_utf16le_name(parent, \
+ child_name, \
+ sizeof(child_name), \
+ WIMLIB_CASE_INSENSITIVE)
+
+static bool
+is_default_systemroot(const struct wim_dentry *potential_systemroot)
+{
+ return !cmp_utf16le_strings(potential_systemroot->d_name,
+ potential_systemroot->d_name_nbytes / 2,
+ windows_name,
+ ARRAY_LEN(windows_name),
+ true);
+}
+
+/*
+ * Set Windows-specific XML information for the currently selected WIM image.
+ *
+ * This process is heavily based on heuristics and hard-coded logic related to
+ * where Windows stores certain types of information. Therefore, it simply
+ * tries to set as much information as possible. If there's a problem, it skips
+ * the affected information and proceeds to the next part. It only returns an
+ * error code if there was a severe problem such as out-of-memory.
+ */
+int
+set_windows_specific_info(WIMStruct *wim)
+{
+ const struct wim_dentry *root, *potential_systemroot,
+ *best_systemroot = NULL,
+ *best_kernel32 = NULL,
+ *best_software = NULL,
+ *best_system = NULL;
+ int best_score = 0;
+
+ root = wim_get_current_root_dentry(wim);
+ if (!root)
+ return 0;
+
+ /* Find the system root. This is usually the toplevel directory
+ * "Windows", but it might be a different toplevel directory. Choose
+ * the directory that contains the greatest number of the files we want:
+ * System32/kernel32.dll, System32/config/SOFTWARE, and
+ * System32/config/SYSTEM. Compare all names case insensitively. */
+ for_dentry_child(potential_systemroot, root) {
+ const struct wim_dentry *system32, *kernel32, *config,
+ *software = NULL, *system = NULL;
+ int score;
+
+ if (!dentry_is_directory(potential_systemroot))
+ continue;
+ system32 = GET_CHILD(potential_systemroot, system32_name);
+ if (!system32)
+ continue;
+ kernel32 = GET_CHILD(system32, kernel32_name);
+ config = GET_CHILD(system32, config_name);
+ if (config) {
+ software = GET_CHILD(config, software_name);
+ system = GET_CHILD(config, system_name);
+ }
+
+ score = !!kernel32 + !!software + !!system;
+ if (score >= best_score) {
+ /* If there's a tie, prefer the "Windows" directory. */
+ if (score > best_score ||
+ is_default_systemroot(potential_systemroot))
+ {
+ best_score = score;
+ best_systemroot = potential_systemroot;
+ best_kernel32 = kernel32;
+ best_software = software;
+ best_system = system;
+ }
+ }
+ }
+
+ if (likely(best_score == 0))
+ return 0; /* No Windows system root found. */
+
+ /* Found the Windows system root. */
+ return do_set_windows_specific_info(wim, best_systemroot, best_kernel32,
+ best_software, best_system);
+}