+ SetLastError(0);
+ if (!ReadFile(h, contents, info.nFileSizeLow, &bytes_read, NULL) ||
+ bytes_read != info.nFileSizeLow)
+ {
+ win32_error(GetLastError(), L"\"%ls\": Can't read data", path);
+ CloseHandle(h);
+ ret = WIMLIB_ERR_READ;
+ goto out_free_contents;
+ }
+
+ CloseHandle(h);
+
+ if (info.nFileSizeLow < sizeof(struct WimOverlay_dat_header)) {
+ ERROR("\"%ls\": File is unexpectedly small (only %"PRIu32" bytes)",
+ path, (u32)info.nFileSizeLow);
+ ret = WIMLIB_ERR_UNSUPPORTED;
+ goto out_free_contents;
+ }
+
+ hdr = (const struct WimOverlay_dat_header *)contents;
+
+ if (hdr->magic != WIMOVERLAY_DAT_MAGIC ||
+ hdr->wim_provider_version != WIM_PROVIDER_CURRENT_VERSION ||
+ hdr->unknown_0x08 != 0x00000028 ||
+ (hdr->num_entries_1 != hdr->num_entries_2) ||
+ hdr->unknown_0x14 != 0x00000000)
+ {
+ ERROR("\"%ls\": Header contains unexpected data:", path);
+ if (wimlib_print_errors) {
+ print_byte_field((const u8 *)hdr,
+ sizeof(struct WimOverlay_dat_header),
+ wimlib_error_file);
+ fputc('\n', wimlib_error_file);
+ }
+ ret = WIMLIB_ERR_UNSUPPORTED;
+ goto out_free_contents;
+ }
+
+ if ((u64)hdr->num_entries_1 * sizeof(struct WimOverlay_dat_entry_1) >
+ info.nFileSizeLow - sizeof(struct WimOverlay_dat_header))
+ {
+ ERROR("\"%ls\": File is unexpectedly small "
+ "(only %"PRIu32" bytes, but has %"PRIu32" entries)",
+ path, (u32)info.nFileSizeLow, hdr->num_entries_1);
+ ret = WIMLIB_ERR_UNSUPPORTED;
+ goto out_free_contents;
+ }
+
+ for (u32 i = 0; i < hdr->num_entries_1; i++) {
+ const struct WimOverlay_dat_entry_1 *entry_1;
+ const struct WimOverlay_dat_entry_2 *entry_2;
+ u32 wim_file_name_length;
+
+ entry_1 = &hdr->entry_1s[i];
+
+ if (((u64)entry_1->entry_2_offset +
+ (u64)entry_1->entry_2_length) >
+ info.nFileSizeLow)
+ {
+ ERROR("\"%ls\": entry %"PRIu32" (2) "
+ "(data source ID 0x%016"PRIx64") "
+ "overflows file",
+ path, i, entry_1->data_source_id);
+ ret = WIMLIB_ERR_UNSUPPORTED;
+ goto out_free_contents;
+ }
+ if (entry_1->entry_2_length < sizeof(struct WimOverlay_dat_entry_2)) {
+ ERROR("\"%ls\": entry %"PRIu32" (2) "
+ "(data source ID 0x%016"PRIx64") "
+ "is too short",
+ path, i, entry_1->data_source_id);
+ ret = WIMLIB_ERR_UNSUPPORTED;
+ goto out_free_contents;
+ }
+
+ if (entry_1->entry_2_offset % 2 != 0) {
+ ERROR("\"%ls\": entry %"PRIu32" (2) "
+ "(data source ID 0x%016"PRIx64") "
+ "is misaligned",
+ path, i, entry_1->data_source_id);
+ ret = WIMLIB_ERR_UNSUPPORTED;
+ goto out_free_contents;
+ }
+
+ entry_2 = (const struct WimOverlay_dat_entry_2 *)
+ ((const u8 *)hdr + entry_1->entry_2_offset);
+
+ wim_file_name_length = entry_1->entry_2_length -
+ sizeof(struct WimOverlay_dat_entry_2);
+ if ((wim_file_name_length < 2 * sizeof(wchar_t)) ||
+ (wim_file_name_length % sizeof(wchar_t) != 0) ||
+ (wmemchr(entry_2->wim_file_name, L'\0',
+ wim_file_name_length / sizeof(wchar_t))
+ != &entry_2->wim_file_name[wim_file_name_length /
+ sizeof(wchar_t) - 1]))
+ {
+ ERROR("\"%ls\": entry %"PRIu32" (2) "
+ "(data source ID 0x%016"PRIx64") "
+ "has invalid WIM file name",
+ path, i, entry_1->data_source_id);
+ if (wimlib_print_errors) {
+ print_byte_field((const u8 *)entry_2->wim_file_name,
+ wim_file_name_length,
+ wimlib_error_file);
+ fputc('\n', wimlib_error_file);
+ }
+ ret = WIMLIB_ERR_UNSUPPORTED;
+ goto out_free_contents;
+ }
+
+ if (entry_2->unknown_0x00 != 0x00000000 ||
+ entry_2->unknown_0x04 != 0x00000000 ||
+ entry_2->unknown_0x0C != 0x00000000 ||
+ entry_2->entry_2_length != entry_1->entry_2_length ||
+ entry_2->unknown_0x10 != 0x00000005 ||
+ entry_2->unknown_0x14 != 0x00000001 ||
+ entry_2->inner_struct_size != entry_1->entry_2_length - 0x14 ||
+ entry_2->unknown_0x1C != 0x00000005 ||
+ entry_2->unknown_0x20 != 0x00000006 ||
+ entry_2->unknown_0x24 != 0x00000000 ||
+ entry_2->unknown_0x28 != 0x00000048 ||
+ entry_2->unknown_0x2C != 0x00000000 ||
+ entry_2->unknown_0x40 != 0x00000000 ||
+ (entry_2->partition_table_type != WIMOVERLAY_PARTITION_TYPE_GPT &&
+ entry_2->partition_table_type != WIMOVERLAY_PARTITION_TYPE_MBR) ||
+ (entry_2->partition_table_type == WIMOVERLAY_PARTITION_TYPE_MBR &&
+ entry_2->partition.mbr.padding != 0) ||
+ (entry_2->partition_table_type == WIMOVERLAY_PARTITION_TYPE_GPT &&
+ entry_2->partition.mbr.padding == 0) ||
+ entry_2->unknown_0x58[0] != 0x00000000 ||
+ entry_2->unknown_0x58[1] != 0x00000000 ||
+ entry_2->unknown_0x58[2] != 0x00000000 ||
+ entry_2->unknown_0x58[3] != 0x00000000)
+ {
+ ERROR("\"%ls\": entry %"PRIu32" (2) "
+ "(data source ID 0x%016"PRIx64") "
+ "contains unexpected data!",
+ path, i, entry_1->data_source_id);
+ if (wimlib_print_errors) {
+ print_byte_field((const u8 *)entry_2,
+ entry_1->entry_2_length,
+ wimlib_error_file);
+ fputc('\n', wimlib_error_file);
+ }
+ ret = WIMLIB_ERR_UNSUPPORTED;
+ goto out_free_contents;
+ }
+ }
+
+ *contents_ret = contents;
+ return 0;
+
+out_free_contents:
+ FREE(contents);
+ return ret;
+}
+
+/*
+ * Update WimOverlay.dat manually in order to add a WIM data source to the
+ * target volume.
+ *
+ * THIS CODE IS EXPERIMENTAL AS I HAD TO REVERSE ENGINEER THE FILE FORMAT!
+ *
+ * @path
+ * Target drive. Must be a letter followed by a colon (e.g. D:).
+ * @wim_path
+ * Absolute path to the WIM file. It must begin with a drive letter; for
+ * example, D:\install.wim.
+ * @wim_guid
+ * GUID of the WIM, from the WIM header.
+ * @image
+ * Number of the image in the WIM to specify in the new entry.
+ * @data_source_id_ret
+ * On success, the allocated data source ID is returned here.
+ */
+static int
+update_wimoverlay_manually(const wchar_t *drive, const wchar_t *wim_path,
+ const u8 wim_guid[GUID_SIZE],
+ int image, u64 *data_source_id_ret)
+{
+ wchar_t path_main[] = L"A:\\System Volume Information\\WimOverlay.dat";
+ wchar_t path_backup[] = L"A:\\System Volume Information\\WimOverlay.backup";
+ wchar_t path_wimlib_backup[] = L"A:\\System Volume Information\\WimOverlay.wimlib_backup";
+ wchar_t path_new[] = L"A:\\System Volume Information\\WimOverlay.wimlib_new";
+ void *old_contents;
+ void *new_contents;
+ u32 new_contents_size;
+ u64 new_data_source_id;
+ int ret;
+
+ wimlib_assert(drive[0] != L'\0' &&
+ drive[1] == L':' &&
+ drive[2] == L'\0');
+
+ path_main[0] = drive[0];
+ path_backup[0] = drive[0];
+ path_wimlib_backup[0] = drive[0];
+ path_new[0] = drive[0];
+
+ ret = read_wimoverlay_dat(path_main, &old_contents);
+ if (ret)
+ goto out;
+
+ ret = prepare_wimoverlay_dat(old_contents, wim_path, wim_guid, image,
+ &new_contents, &new_contents_size,
+ &new_data_source_id);
+ FREE(old_contents);
+ if (ret)
+ goto out;
+
+ /* Write WimOverlay.wimlib_new */
+ ret = write_wimoverlay_dat(path_new,
+ new_contents, new_contents_size);
+ if (ret)
+ goto out_free_new_contents;
+
+ /* Write WimOverlay.backup */
+ ret = write_wimoverlay_dat(path_backup,
+ new_contents, new_contents_size);
+ if (ret)
+ goto out_free_new_contents;
+
+ if (old_contents) {
+ /* Rename WimOverlay.dat => WimOverlay.wimlib_backup */
+ ret = win32_rename_replacement(path_main, path_wimlib_backup);
+ if (ret) {
+ ERROR_WITH_ERRNO("Can't rename \"%ls\" => \"%ls\"",
+ path_main, path_wimlib_backup);
+ ret = WIMLIB_ERR_RENAME;
+ goto out_free_new_contents;
+ }
+ }
+
+ /* Rename WimOverlay.wimlib_new => WimOverlay.dat */
+ ret = win32_rename_replacement(path_new, path_main);
+ if (ret) {
+ ERROR_WITH_ERRNO("Can't rename \"%ls\" => \"%ls\"",
+ path_new, path_main);
+ ret = WIMLIB_ERR_RENAME;
+ }
+out_free_new_contents:
+ FREE(new_contents);
+out:
+ if (ret == WIMLIB_ERR_UNSUPPORTED) {
+ ERROR("Please report to developer ("PACKAGE_BUGREPORT").\n"
+ " If possible send the file \"%ls\".\n\n", path_main);
+ }
+ if (ret == 0)
+ *data_source_id_ret = new_data_source_id;
+ return ret;