1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include <grub/types.h>
22 #include <grub/misc.h>
26 #include <grub/disk.h>
27 #include <grub/device.h>
28 #include <grub/term.h>
29 #include <grub/partition.h>
30 #include <grub/file.h>
31 #include <grub/normal.h>
32 #include <grub/extcmd.h>
33 #include <grub/datetime.h>
34 #include <grub/i18n.h>
36 #include <grub/time.h>
37 #include <grub/crypto.h>
38 #include <grub/ventoy.h>
39 #include "ventoy_def.h"
41 GRUB_MOD_LICENSE ("GPLv3+");
43 static int g_iso_fs_type
= 0;
44 static int g_wim_total_patch_count
= 0;
45 static int g_wim_valid_patch_count
= 0;
46 static wim_patch
*g_wim_patch_head
= NULL
;
48 static grub_uint64_t g_suppress_wincd_override_offset
= 0;
49 static grub_uint32_t g_suppress_wincd_override_data
= 0;
51 grub_uint8_t g_temp_buf
[512];
53 grub_ssize_t
lzx_decompress ( const void *data
, grub_size_t len
, void *buf
);
55 static wim_patch
*ventoy_find_wim_patch(const char *path
)
57 int len
= (int)grub_strlen(path
);
58 wim_patch
*node
= g_wim_patch_head
;
62 if (len
== node
->pathlen
&& 0 == grub_strcmp(path
, node
->path
))
72 static int ventoy_collect_wim_patch(const char *bcdfile
)
77 grub_file_t file
= NULL
;
79 wim_patch
*node
= NULL
;
85 g_ventoy_case_insensitive
= 1;
86 file
= grub_file_open(bcdfile
, VENTOY_FILE_TYPE
);
87 g_ventoy_case_insensitive
= 0;
90 debug("Failed to open file %s\n", bcdfile
);
95 buf
= grub_malloc(file
->size
+ 8);
101 grub_file_read(file
, buf
, file
->size
);
103 for (i
= 0; i
< (int)file
->size
- 8; i
++)
110 magic
= *(grub_uint64_t
*)(buf
+ i
);
113 if ((magic
== 0x006D00690077002EULL
) ||
114 (magic
== 0x004D00490057002EULL
) ||
115 (magic
== 0x006D00690057002EULL
))
117 for (j
= i
; j
> 0; j
-= 2)
119 if (*(grub_uint16_t
*)(buf
+ j
) == 0)
127 byte
= (grub_uint8_t
)(*(grub_uint16_t
*)(buf
+ j
+ 2));
128 if (byte
!= '/' && byte
!= '\\')
134 for (k
= 0, j
+= 2; k
< (int)sizeof(path
) - 1 && j
< i
+ 8; j
+= 2)
136 byte
= (grub_uint8_t
)(*(grub_uint16_t
*)(buf
+ j
));
138 if (byte
> '~' || byte
< ' ') /* not printable */
152 debug("@@@@ Find wim flag:<%s>\n", path
);
156 debug("Invalid wim file %d\n", k
);
158 else if (NULL
== ventoy_find_wim_patch(path
))
160 node
= grub_zalloc(sizeof(wim_patch
));
163 node
->pathlen
= grub_snprintf(node
->path
, sizeof(node
->path
), "%s", path
);
165 debug("add patch <%s>\n", path
);
167 if (g_wim_patch_head
)
169 node
->next
= g_wim_patch_head
;
171 g_wim_patch_head
= node
;
173 g_wim_total_patch_count
++;
178 debug("wim <%s> already exist\n", path
);
185 check_free(file
, grub_file_close
);
186 grub_check_free(buf
);
190 grub_err_t
ventoy_cmd_wim_patch_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
200 grub_snprintf(buf
, sizeof(buf
), "%d", g_wim_total_patch_count
);
201 ventoy_set_env(args
[0], buf
);
207 grub_err_t
ventoy_cmd_collect_wim_patch(grub_extcmd_context_t ctxt
, int argc
, char **args
)
209 wim_patch
*node
= NULL
;
220 debug("ventoy_cmd_collect_wim_patch %s %s\n", args
[0], args
[1]);
222 if (grub_strcmp(args
[0], "bcd") == 0)
224 ventoy_collect_wim_patch(args
[1]);
228 if (NULL
== ventoy_find_wim_patch(args
[1]))
230 node
= grub_zalloc(sizeof(wim_patch
));
233 node
->pathlen
= grub_snprintf(node
->path
, sizeof(node
->path
), "%s", args
[1]);
235 debug("add patch <%s>\n", args
[1]);
237 if (g_wim_patch_head
)
239 node
->next
= g_wim_patch_head
;
241 g_wim_patch_head
= node
;
243 g_wim_total_patch_count
++;
251 grub_err_t
ventoy_cmd_dump_wim_patch(grub_extcmd_context_t ctxt
, int argc
, char **args
)
254 wim_patch
*node
= NULL
;
260 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
262 grub_printf("%d %s [%s]\n", i
++, node
->path
, node
->valid
? "SUCCESS" : "FAIL");
269 static int wim_name_cmp(const char *search
, grub_uint16_t
*name
, grub_uint16_t namelen
)
271 char c1
= vtoy_to_upper(*search
);
272 char c2
= vtoy_to_upper(*name
);
274 while (namelen
> 0 && (c1
== c2
))
280 c1
= vtoy_to_upper(*search
);
281 c2
= vtoy_to_upper(*name
);
284 if (namelen
== 0 && *search
== 0)
292 static int ventoy_is_pe64(grub_uint8_t
*buffer
)
294 grub_uint32_t pe_off
;
296 if (buffer
[0] != 'M' || buffer
[1] != 'Z')
301 pe_off
= *(grub_uint32_t
*)(buffer
+ 60);
303 if (buffer
[pe_off
] != 'P' || buffer
[pe_off
+ 1] != 'E')
308 if (*(grub_uint16_t
*)(buffer
+ pe_off
+ 24) == 0x020b)
316 grub_err_t
ventoy_cmd_wimdows_reset(grub_extcmd_context_t ctxt
, int argc
, char **args
)
318 wim_patch
*next
= NULL
;
319 wim_patch
*node
= g_wim_patch_head
;
332 g_wim_patch_head
= NULL
;
333 g_wim_total_patch_count
= 0;
334 g_wim_valid_patch_count
= 0;
339 static int ventoy_load_jump_exe(const char *path
, grub_uint8_t
**data
, grub_uint32_t
*size
, wim_hash
*hash
)
345 debug("windows load jump %s\n", path
);
347 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", path
);
350 debug("Can't open file %s\n", path
);
354 align
= ventoy_align((int)file
->size
, 2048);
356 debug("file %s size:%d align:%u\n", path
, (int)file
->size
, align
);
358 *size
= (grub_uint32_t
)file
->size
;
359 *data
= (grub_uint8_t
*)grub_malloc(align
);
362 debug("Failed to alloc memory size %u\n", align
);
366 grub_file_read(file
, (*data
), file
->size
);
370 grub_crypto_hash(GRUB_MD_SHA1
, hash
->sha1
, (*data
), file
->size
);
374 debug("%s", "jump bin 64 hash: ");
375 for (i
= 0; i
< sizeof(hash
->sha1
); i
++)
377 ventoy_debug("%02x ", hash
->sha1
[i
]);
385 grub_file_close(file
);
389 static int ventoy_get_override_info(grub_file_t file
, wim_tail
*wim_data
)
391 grub_uint32_t start_block
;
392 grub_uint64_t file_offset
;
393 grub_uint64_t override_offset
;
394 grub_uint32_t override_len
;
395 grub_uint64_t fe_entry_size_offset
;
397 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
399 g_iso_fs_type
= wim_data
->iso_type
= 0;
400 override_len
= sizeof(ventoy_iso9660_override
);
401 override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
403 grub_file_read(file
, &start_block
, 1); // just read for hook trigger
404 file_offset
= grub_iso9660_get_last_read_pos(file
);
406 debug("iso9660 wim size:%llu override_offset:%llu file_offset:%llu\n",
407 (ulonglong
)file
->size
, (ulonglong
)override_offset
, (ulonglong
)file_offset
);
411 g_iso_fs_type
= wim_data
->iso_type
= 1;
412 override_len
= sizeof(ventoy_udf_override
);
413 override_offset
= grub_udf_get_last_file_attr_offset(file
, &start_block
, &fe_entry_size_offset
);
415 file_offset
= grub_udf_get_file_offset(file
);
417 debug("UDF wim size:%llu override_offset:%llu file_offset:%llu start_block=%u\n",
418 (ulonglong
)file
->size
, (ulonglong
)override_offset
, (ulonglong
)file_offset
, start_block
);
421 wim_data
->file_offset
= file_offset
;
422 wim_data
->udf_start_block
= start_block
;
423 wim_data
->fe_entry_size_offset
= fe_entry_size_offset
;
424 wim_data
->override_offset
= override_offset
;
425 wim_data
->override_len
= override_len
;
430 static int ventoy_read_resource(grub_file_t fp
, wim_resource_header
*head
, void **buffer
)
432 int decompress_len
= 0;
433 int total_decompress
= 0;
435 grub_uint32_t chunk_num
= 0;
436 grub_uint32_t chunk_size
= 0;
437 grub_uint32_t last_chunk_size
= 0;
438 grub_uint32_t last_decompress_size
= 0;
439 grub_uint32_t cur_offset
= 0;
440 grub_uint8_t
*cur_dst
= NULL
;
441 grub_uint8_t
*buffer_compress
= NULL
;
442 grub_uint8_t
*buffer_decompress
= NULL
;
443 grub_uint32_t
*chunk_offset
= NULL
;
445 buffer_decompress
= (grub_uint8_t
*)grub_malloc(head
->raw_size
+ head
->size_in_wim
);
446 if (NULL
== buffer_decompress
)
451 grub_file_seek(fp
, head
->offset
);
453 if (head
->size_in_wim
== head
->raw_size
)
455 grub_file_read(fp
, buffer_decompress
, head
->size_in_wim
);
456 *buffer
= buffer_decompress
;
460 buffer_compress
= buffer_decompress
+ head
->raw_size
;
461 grub_file_read(fp
, buffer_compress
, head
->size_in_wim
);
463 chunk_num
= (head
->raw_size
+ WIM_CHUNK_LEN
- 1) / WIM_CHUNK_LEN
;
464 cur_offset
= (chunk_num
- 1) * 4;
465 chunk_offset
= (grub_uint32_t
*)buffer_compress
;
467 cur_dst
= buffer_decompress
;
469 for (i
= 0; i
< chunk_num
- 1; i
++)
471 chunk_size
= (i
== 0) ? chunk_offset
[i
] : chunk_offset
[i
] - chunk_offset
[i
- 1];
473 if (WIM_CHUNK_LEN
== chunk_size
)
475 grub_memcpy(cur_dst
, buffer_compress
+ cur_offset
, chunk_size
);
476 decompress_len
= (int)chunk_size
;
480 decompress_len
= (int)lzx_decompress(buffer_compress
+ cur_offset
, chunk_size
, cur_dst
);
483 //debug("chunk_size:%u decompresslen:%d\n", chunk_size, decompress_len);
485 total_decompress
+= decompress_len
;
486 cur_dst
+= decompress_len
;
487 cur_offset
+= chunk_size
;
491 last_chunk_size
= (grub_uint32_t
)(head
->size_in_wim
- cur_offset
);
492 last_decompress_size
= head
->raw_size
- total_decompress
;
494 if (last_chunk_size
< WIM_CHUNK_LEN
&& last_chunk_size
== last_decompress_size
)
496 debug("Last chunk %u uncompressed\n", last_chunk_size
);
497 grub_memcpy(cur_dst
, buffer_compress
+ cur_offset
, last_chunk_size
);
498 decompress_len
= (int)last_chunk_size
;
502 decompress_len
= (int)lzx_decompress(buffer_compress
+ cur_offset
, head
->size_in_wim
- cur_offset
, cur_dst
);
505 cur_dst
+= decompress_len
;
506 total_decompress
+= decompress_len
;
508 if (cur_dst
!= buffer_decompress
+ head
->raw_size
)
510 debug("head->size_in_wim:%llu head->raw_size:%llu cur_dst:%p buffer_decompress:%p total_decompress:%d\n",
511 (ulonglong
)head
->size_in_wim
, (ulonglong
)head
->raw_size
, cur_dst
, buffer_decompress
, total_decompress
);
512 grub_free(buffer_decompress
);
516 *buffer
= buffer_decompress
;
521 static wim_directory_entry
* search_wim_dirent(wim_directory_entry
*dir
, const char *search_name
)
525 if (dir
->len
&& dir
->name_len
)
527 if (wim_name_cmp(search_name
, (grub_uint16_t
*)(dir
+ 1), dir
->name_len
/ 2) == 0)
532 dir
= (wim_directory_entry
*)((grub_uint8_t
*)dir
+ dir
->len
);
538 static wim_directory_entry
* search_full_wim_dirent
541 wim_directory_entry
*dir
,
545 wim_directory_entry
*subdir
= NULL
;
546 wim_directory_entry
*search
= dir
;
550 subdir
= (wim_directory_entry
*)((char *)meta_data
+ search
->subdir
);
551 search
= search_wim_dirent(subdir
, *path
);
558 static wim_directory_entry
* search_replace_wim_dirent(void *meta_data
, wim_directory_entry
*dir
)
560 wim_directory_entry
*wim_dirent
= NULL
;
561 const char *winpeshl_path
[] = { "Windows", "System32", "winpeshl.exe", NULL
};
562 //const char *native_path[] = { "Windows", "System32", "native.exe", NULL };
564 wim_dirent
= search_full_wim_dirent(meta_data
, dir
, winpeshl_path
);
565 debug("search winpeshl.exe %p\n", wim_dirent
);
572 wim_dirent
= search_full_wim_dirent(meta_data
, dir
, native_path
);
573 debug("search native.exe %p\n", wim_dirent
);
584 static wim_lookup_entry
* ventoy_find_look_entry(wim_header
*header
, wim_lookup_entry
*lookup
, wim_hash
*hash
)
588 for (i
= 0; i
< (grub_uint32_t
)header
->lookup
.raw_size
/ sizeof(wim_lookup_entry
); i
++)
590 if (grub_memcmp(&lookup
[i
].hash
, hash
, sizeof(wim_hash
)) == 0)
599 static wim_lookup_entry
* ventoy_find_meta_entry(wim_header
*header
, wim_lookup_entry
*lookup
)
602 grub_uint32_t index
= 0;;
604 if ((header
== NULL
) || (lookup
== NULL
))
609 for (i
= 0; i
< (grub_uint32_t
)header
->lookup
.raw_size
/ sizeof(wim_lookup_entry
); i
++)
611 if (lookup
[i
].resource
.flags
& RESHDR_FLAG_METADATA
)
614 if (index
== header
->boot_index
)
624 static int ventoy_update_all_hash(wim_patch
*patch
, void *meta_data
, wim_directory_entry
*dir
)
626 if ((meta_data
== NULL
) || (dir
== NULL
))
631 if (dir
->len
< sizeof(wim_directory_entry
))
638 if (dir
->subdir
== 0 && grub_memcmp(dir
->hash
.sha1
, patch
->old_hash
.sha1
, sizeof(wim_hash
)) == 0)
640 debug("find target file, name_len:%u upadte hash\n", dir
->name_len
);
641 grub_memcpy(dir
->hash
.sha1
, &(patch
->wim_data
.bin_hash
), sizeof(wim_hash
));
646 ventoy_update_all_hash(patch
, meta_data
, (wim_directory_entry
*)((char *)meta_data
+ dir
->subdir
));
649 dir
= (wim_directory_entry
*)((char *)dir
+ dir
->len
);
650 } while (dir
->len
>= sizeof(wim_directory_entry
));
655 static int ventoy_cat_exe_file_data(wim_tail
*wim_data
, grub_uint32_t exe_len
, grub_uint8_t
*exe_data
)
659 grub_uint32_t jump_len
= 0;
660 grub_uint32_t jump_align
= 0;
661 grub_uint8_t
*jump_data
= NULL
;
663 pe64
= ventoy_is_pe64(exe_data
);
665 grub_snprintf(file
, sizeof(file
), "%s/vtoyjump%d.exe", grub_env_get("vtoy_path"), pe64
? 64 : 32);
666 ventoy_load_jump_exe(file
, &jump_data
, &jump_len
, NULL
);
667 jump_align
= ventoy_align(jump_len
, 16);
669 wim_data
->jump_exe_len
= jump_len
;
670 wim_data
->bin_raw_len
= jump_align
+ sizeof(ventoy_os_param
) + sizeof(ventoy_windows_data
) + exe_len
;
671 wim_data
->bin_align_len
= ventoy_align(wim_data
->bin_raw_len
, 2048);
673 wim_data
->jump_bin_data
= grub_malloc(wim_data
->bin_align_len
);
674 if (wim_data
->jump_bin_data
)
676 grub_memcpy(wim_data
->jump_bin_data
, jump_data
, jump_len
);
677 grub_memcpy(wim_data
->jump_bin_data
+ jump_align
+ sizeof(ventoy_os_param
) + sizeof(ventoy_windows_data
), exe_data
, exe_len
);
680 debug("jump_exe_len:%u bin_raw_len:%u bin_align_len:%u\n",
681 wim_data
->jump_exe_len
, wim_data
->bin_raw_len
, wim_data
->bin_align_len
);
686 int ventoy_fill_windows_rtdata(void *buf
, char *isopath
)
690 ventoy_windows_data
*data
= (ventoy_windows_data
*)buf
;
692 grub_memset(data
, 0, sizeof(ventoy_windows_data
));
694 pos
= grub_strstr(isopath
, "/");
700 script
= ventoy_plugin_get_cur_install_template(pos
);
703 debug("auto install script <%s>\n", script
);
704 grub_snprintf(data
->auto_install_script
, sizeof(data
->auto_install_script
) - 1, "%s", script
);
708 debug("auto install script skipped or not configed %s\n", pos
);
714 static int ventoy_update_before_chain(ventoy_os_param
*param
, char *isopath
)
716 grub_uint32_t jump_align
= 0;
717 wim_lookup_entry
*meta_look
= NULL
;
718 wim_security_header
*security
= NULL
;
719 wim_directory_entry
*rootdir
= NULL
;
720 wim_header
*head
= NULL
;
721 wim_lookup_entry
*lookup
= NULL
;
722 wim_patch
*node
= NULL
;
723 wim_tail
*wim_data
= NULL
;
725 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
727 if (0 == node
->valid
)
732 wim_data
= &node
->wim_data
;
733 head
= &wim_data
->wim_header
;
734 lookup
= (wim_lookup_entry
*)wim_data
->new_lookup_data
;
736 jump_align
= ventoy_align(wim_data
->jump_exe_len
, 16);
737 if (wim_data
->jump_bin_data
)
739 grub_memcpy(wim_data
->jump_bin_data
+ jump_align
, param
, sizeof(ventoy_os_param
));
740 ventoy_fill_windows_rtdata(wim_data
->jump_bin_data
+ jump_align
+ sizeof(ventoy_os_param
), isopath
);
743 grub_crypto_hash(GRUB_MD_SHA1
, wim_data
->bin_hash
.sha1
, wim_data
->jump_bin_data
, wim_data
->bin_raw_len
);
745 security
= (wim_security_header
*)wim_data
->new_meta_data
;
746 rootdir
= (wim_directory_entry
*)(wim_data
->new_meta_data
+ ((security
->len
+ 7) & 0xFFFFFFF8U
));
748 /* update all winpeshl.exe dirent entry's hash */
749 ventoy_update_all_hash(node
, wim_data
->new_meta_data
, rootdir
);
751 /* update winpeshl.exe lookup entry data (hash/offset/length) */
752 if (node
->replace_look
)
754 debug("update replace lookup entry_id:%ld\n", ((long)node
->replace_look
- (long)lookup
) / sizeof(wim_lookup_entry
));
755 node
->replace_look
->resource
.raw_size
= wim_data
->bin_raw_len
;
756 node
->replace_look
->resource
.size_in_wim
= wim_data
->bin_raw_len
;
757 node
->replace_look
->resource
.flags
= 0;
758 node
->replace_look
->resource
.offset
= wim_data
->wim_align_size
;
760 grub_memcpy(node
->replace_look
->hash
.sha1
, wim_data
->bin_hash
.sha1
, sizeof(wim_hash
));
763 /* update metadata's hash */
764 meta_look
= ventoy_find_meta_entry(head
, lookup
);
767 debug("find meta lookup entry_id:%ld\n", ((long)meta_look
- (long)lookup
) / sizeof(wim_lookup_entry
));
768 grub_memcpy(&meta_look
->resource
, &head
->metadata
, sizeof(wim_resource_header
));
769 grub_crypto_hash(GRUB_MD_SHA1
, meta_look
->hash
.sha1
, wim_data
->new_meta_data
, wim_data
->new_meta_len
);
776 static int ventoy_wimdows_locate_wim(const char *disk
, wim_patch
*patch
)
780 grub_uint32_t exe_len
;
781 grub_uint8_t
*exe_data
= NULL
;
782 grub_uint8_t
*decompress_data
= NULL
;
783 wim_lookup_entry
*lookup
= NULL
;
784 wim_security_header
*security
= NULL
;
785 wim_directory_entry
*rootdir
= NULL
;
786 wim_directory_entry
*search
= NULL
;
787 wim_header
*head
= &(patch
->wim_data
.wim_header
);
788 wim_tail
*wim_data
= &patch
->wim_data
;
790 debug("windows locate wim start %s\n", patch
->path
);
792 g_ventoy_case_insensitive
= 1;
793 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", disk
, patch
->path
);
794 g_ventoy_case_insensitive
= 0;
798 debug("File %s%s NOT exist\n", disk
, patch
->path
);
802 ventoy_get_override_info(file
, &patch
->wim_data
);
804 grub_file_seek(file
, 0);
805 grub_file_read(file
, head
, sizeof(wim_header
));
807 if (grub_memcmp(head
->signature
, WIM_HEAD_SIGNATURE
, sizeof(head
->signature
)))
809 debug("Not a valid wim file %s\n", (char *)head
->signature
);
810 grub_file_close(file
);
814 if ((head
->flags
& FLAG_HEADER_COMPRESS_XPRESS
) || (head
->flags
& FLAG_HEADER_COMPRESS_LZMS
))
816 debug("Xpress or LZMS compress is not supported 0x%x\n", head
->flags
);
817 grub_file_close(file
);
821 rc
= ventoy_read_resource(file
, &head
->metadata
, (void **)&decompress_data
);
824 grub_printf("failed to read meta data %d\n", rc
);
825 grub_file_close(file
);
829 security
= (wim_security_header
*)decompress_data
;
830 rootdir
= (wim_directory_entry
*)(decompress_data
+ ((security
->len
+ 7) & 0xFFFFFFF8U
));
832 /* search winpeshl.exe dirent entry */
833 search
= search_replace_wim_dirent(decompress_data
, rootdir
);
836 debug("Failed to find replace file %p\n", search
);
837 grub_file_close(file
);
841 debug("find replace file at %p\n", search
);
843 grub_memcpy(&patch
->old_hash
, search
->hash
.sha1
, sizeof(wim_hash
));
845 debug("read lookup offset:%llu size:%llu\n", (ulonglong
)head
->lookup
.offset
, (ulonglong
)head
->lookup
.raw_size
);
846 lookup
= grub_malloc(head
->lookup
.raw_size
);
847 grub_file_seek(file
, head
->lookup
.offset
);
848 grub_file_read(file
, lookup
, head
->lookup
.raw_size
);
850 /* find and extact winpeshl.exe */
851 patch
->replace_look
= ventoy_find_look_entry(head
, lookup
, &patch
->old_hash
);
852 if (patch
->replace_look
)
854 exe_len
= (grub_uint32_t
)patch
->replace_look
->resource
.raw_size
;
855 debug("find replace lookup entry_id:%ld raw_size:%u\n",
856 ((long)patch
->replace_look
- (long)lookup
) / sizeof(wim_lookup_entry
), exe_len
);
858 if (0 == ventoy_read_resource(file
, &(patch
->replace_look
->resource
), (void **)&(exe_data
)))
860 ventoy_cat_exe_file_data(wim_data
, exe_len
, exe_data
);
865 debug("failed to read replace file meta data %u\n", exe_len
);
870 debug("failed to find lookup entry for replace file 0x%02x 0x%02x\n",
871 patch
->old_hash
.sha1
[0], patch
->old_hash
.sha1
[1]);
874 wim_data
->wim_raw_size
= (grub_uint32_t
)file
->size
;
875 wim_data
->wim_align_size
= ventoy_align(wim_data
->wim_raw_size
, 2048);
877 grub_check_free(wim_data
->new_meta_data
);
878 wim_data
->new_meta_data
= decompress_data
;
879 wim_data
->new_meta_len
= head
->metadata
.raw_size
;
880 wim_data
->new_meta_align_len
= ventoy_align(wim_data
->new_meta_len
, 2048);
882 grub_check_free(wim_data
->new_lookup_data
);
883 wim_data
->new_lookup_data
= (grub_uint8_t
*)lookup
;
884 wim_data
->new_lookup_len
= (grub_uint32_t
)head
->lookup
.raw_size
;
885 wim_data
->new_lookup_align_len
= ventoy_align(wim_data
->new_lookup_len
, 2048);
887 head
->metadata
.flags
= RESHDR_FLAG_METADATA
;
888 head
->metadata
.offset
= wim_data
->wim_align_size
+ wim_data
->bin_align_len
;
889 head
->metadata
.size_in_wim
= wim_data
->new_meta_len
;
890 head
->metadata
.raw_size
= wim_data
->new_meta_len
;
892 head
->lookup
.flags
= 0;
893 head
->lookup
.offset
= head
->metadata
.offset
+ wim_data
->new_meta_align_len
;
894 head
->lookup
.size_in_wim
= wim_data
->new_lookup_len
;
895 head
->lookup
.raw_size
= wim_data
->new_lookup_len
;
897 grub_file_close(file
);
899 debug("%s", "windows locate wim finish\n");
903 grub_err_t
ventoy_cmd_locate_wim_patch(grub_extcmd_context_t ctxt
, int argc
, char **args
)
905 wim_patch
*node
= g_wim_patch_head
;
913 if (0 == ventoy_wimdows_locate_wim(args
[0], node
))
916 g_wim_valid_patch_count
++;
925 static grub_uint32_t
ventoy_get_override_chunk_num(void)
927 grub_uint32_t chunk_num
= 0;
929 if (g_iso_fs_type
== 0)
933 /* 1: file_size and file_offset */
934 /* 2: new wim file header */
935 chunk_num
= g_wim_valid_patch_count
* 2;
941 /* 1: block count in Partition Descriptor */
944 /* 1: file_size in file_entry or extend_file_entry */
945 /* 2: data_size and position in extend data short ad */
946 /* 3: new wim file header */
947 chunk_num
= g_wim_valid_patch_count
* 3 + 1;
950 if (g_suppress_wincd_override_offset
> 0)
958 static void ventoy_fill_suppress_wincd_override_data(void *override
)
960 ventoy_override_chunk
*cur
= (ventoy_override_chunk
*)override
;
962 cur
->override_size
= 4;
963 cur
->img_offset
= g_suppress_wincd_override_offset
;
964 grub_memcpy(cur
->override_data
, &g_suppress_wincd_override_data
, cur
->override_size
);
967 static void ventoy_windows_fill_override_data_iso9660( grub_uint64_t isosize
, void *override
)
969 grub_uint64_t sector
;
970 grub_uint32_t new_wim_size
;
971 ventoy_override_chunk
*cur
;
972 wim_patch
*node
= NULL
;
973 wim_tail
*wim_data
= NULL
;
974 ventoy_iso9660_override
*dirent
= NULL
;
976 sector
= (isosize
+ 2047) / 2048;
978 cur
= (ventoy_override_chunk
*)override
;
980 if (g_suppress_wincd_override_offset
> 0)
982 ventoy_fill_suppress_wincd_override_data(cur
);
986 debug("ventoy_windows_fill_override_data_iso9660 %lu\n", (ulong
)isosize
);
988 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
990 wim_data
= &node
->wim_data
;
991 if (0 == node
->valid
)
996 new_wim_size
= wim_data
->wim_align_size
+ wim_data
->bin_align_len
+
997 wim_data
->new_meta_align_len
+ wim_data
->new_lookup_align_len
;
999 dirent
= (ventoy_iso9660_override
*)wim_data
->override_data
;
1001 dirent
->first_sector
= (grub_uint32_t
)sector
;
1002 dirent
->size
= new_wim_size
;
1003 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
1004 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
1006 sector
+= (new_wim_size
/ 2048);
1008 /* override 1: position and length in dirent */
1009 cur
->img_offset
= wim_data
->override_offset
;
1010 cur
->override_size
= wim_data
->override_len
;
1011 grub_memcpy(cur
->override_data
, wim_data
->override_data
, cur
->override_size
);
1014 /* override 2: new wim file header */
1015 cur
->img_offset
= wim_data
->file_offset
;
1016 cur
->override_size
= sizeof(wim_header
);
1017 grub_memcpy(cur
->override_data
, &(wim_data
->wim_header
), cur
->override_size
);
1024 static void ventoy_windows_fill_override_data_udf( grub_uint64_t isosize
, void *override
)
1026 grub_uint32_t data32
;
1027 grub_uint64_t data64
;
1028 grub_uint64_t sector
;
1029 grub_uint32_t new_wim_size
;
1030 grub_uint64_t total_wim_size
= 0;
1031 grub_uint32_t udf_start_block
= 0;
1032 ventoy_override_chunk
*cur
;
1033 wim_patch
*node
= NULL
;
1034 wim_tail
*wim_data
= NULL
;
1035 ventoy_udf_override
*udf
= NULL
;
1037 sector
= (isosize
+ 2047) / 2048;
1039 cur
= (ventoy_override_chunk
*)override
;
1041 if (g_suppress_wincd_override_offset
> 0)
1043 ventoy_fill_suppress_wincd_override_data(cur
);
1047 debug("ventoy_windows_fill_override_data_udf %lu\n", (ulong
)isosize
);
1049 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
1051 wim_data
= &node
->wim_data
;
1054 if (udf_start_block
== 0)
1056 udf_start_block
= wim_data
->udf_start_block
;
1058 new_wim_size
= wim_data
->wim_align_size
+ wim_data
->bin_align_len
+
1059 wim_data
->new_meta_align_len
+ wim_data
->new_lookup_align_len
;
1060 total_wim_size
+= new_wim_size
;
1064 //override 1: sector number in pd data
1065 cur
->img_offset
= grub_udf_get_last_pd_size_offset();
1066 cur
->override_size
= 4;
1067 data32
= sector
- udf_start_block
+ (total_wim_size
/ 2048);
1068 grub_memcpy(cur
->override_data
, &(data32
), 4);
1070 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
1072 wim_data
= &node
->wim_data
;
1073 if (0 == node
->valid
)
1078 new_wim_size
= wim_data
->wim_align_size
+ wim_data
->bin_align_len
+
1079 wim_data
->new_meta_align_len
+ wim_data
->new_lookup_align_len
;
1081 //override 2: filesize in file_entry
1083 cur
->img_offset
= wim_data
->fe_entry_size_offset
;
1084 cur
->override_size
= 8;
1085 data64
= new_wim_size
;
1086 grub_memcpy(cur
->override_data
, &(data64
), 8);
1088 udf
= (ventoy_udf_override
*)wim_data
->override_data
;
1089 udf
->length
= new_wim_size
;
1090 udf
->position
= (grub_uint32_t
)sector
- udf_start_block
;
1092 sector
+= (new_wim_size
/ 2048);
1094 /* override 3: position and length in extend data */
1096 cur
->img_offset
= wim_data
->override_offset
;
1097 cur
->override_size
= wim_data
->override_len
;
1098 grub_memcpy(cur
->override_data
, wim_data
->override_data
, cur
->override_size
);
1100 /* override 4: new wim file header */
1102 cur
->img_offset
= wim_data
->file_offset
;
1103 cur
->override_size
= sizeof(wim_header
);
1104 grub_memcpy(cur
->override_data
, &(wim_data
->wim_header
), cur
->override_size
);
1110 static grub_uint32_t
ventoy_windows_get_virt_data_size(void)
1112 grub_uint32_t size
= 0;
1113 wim_tail
*wim_data
= NULL
;
1114 wim_patch
*node
= g_wim_patch_head
;
1120 wim_data
= &node
->wim_data
;
1121 size
+= sizeof(ventoy_virt_chunk
) + wim_data
->bin_align_len
+
1122 wim_data
->new_meta_align_len
+ wim_data
->new_lookup_align_len
;
1130 static void ventoy_windows_fill_virt_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
1132 grub_uint64_t sector
;
1133 grub_uint32_t offset
;
1134 grub_uint32_t wim_secs
;
1135 grub_uint32_t mem_secs
;
1136 char *override
= NULL
;
1137 ventoy_virt_chunk
*cur
= NULL
;
1138 wim_tail
*wim_data
= NULL
;
1139 wim_patch
*node
= NULL
;
1141 sector
= (isosize
+ 2047) / 2048;
1142 offset
= sizeof(ventoy_virt_chunk
) * g_wim_valid_patch_count
;
1144 override
= (char *)chain
+ chain
->virt_chunk_offset
;
1145 cur
= (ventoy_virt_chunk
*)override
;
1147 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
1149 if (0 == node
->valid
)
1154 wim_data
= &node
->wim_data
;
1156 wim_secs
= wim_data
->wim_align_size
/ 2048;
1157 mem_secs
= (wim_data
->bin_align_len
+ wim_data
->new_meta_align_len
+ wim_data
->new_lookup_align_len
) / 2048;
1159 cur
->remap_sector_start
= sector
;
1160 cur
->remap_sector_end
= cur
->remap_sector_start
+ wim_secs
;
1161 cur
->org_sector_start
= (grub_uint32_t
)(wim_data
->file_offset
/ 2048);
1163 cur
->mem_sector_start
= cur
->remap_sector_end
;
1164 cur
->mem_sector_end
= cur
->mem_sector_start
+ mem_secs
;
1165 cur
->mem_sector_offset
= offset
;
1167 sector
+= wim_secs
+ mem_secs
;
1170 grub_memcpy(override
+ offset
, wim_data
->jump_bin_data
, wim_data
->bin_raw_len
);
1171 offset
+= wim_data
->bin_align_len
;
1173 grub_memcpy(override
+ offset
, wim_data
->new_meta_data
, wim_data
->new_meta_len
);
1174 offset
+= wim_data
->new_meta_align_len
;
1176 grub_memcpy(override
+ offset
, wim_data
->new_lookup_data
, wim_data
->new_lookup_len
);
1177 offset
+= wim_data
->new_lookup_align_len
;
1179 chain
->virt_img_size_in_bytes
+= wim_data
->wim_align_size
+
1180 wim_data
->bin_align_len
+
1181 wim_data
->new_meta_align_len
+
1182 wim_data
->new_lookup_align_len
;
1188 static int ventoy_windows_drive_map(ventoy_chain_head
*chain
)
1192 debug("drive map begin <%p> ...\n", chain
);
1194 if (chain
->disk_drive
== 0x80)
1196 disk
= grub_disk_open("hd1");
1199 grub_disk_close(disk
);
1200 debug("drive map needed %p\n", disk
);
1201 chain
->drive_map
= 0x81;
1205 debug("failed to open disk %s\n", "hd1");
1210 debug("no need to map 0x%x\n", chain
->disk_drive
);
1216 static int ventoy_suppress_windows_cd_prompt(void)
1219 const char *cdprompt
= NULL
;
1220 grub_uint64_t readpos
= 0;
1221 grub_file_t file
= NULL
;
1222 grub_uint8_t data
[32];
1224 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
1225 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
1227 debug("VTOY_WINDOWS_CD_PROMPT:<%s>\n", cdprompt
);
1231 g_ventoy_case_insensitive
= 1;
1232 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/boot/bootfix.bin", "(loop)");
1233 g_ventoy_case_insensitive
= 0;
1237 debug("Failed to open %s\n", "bootfix.bin");
1241 grub_file_read(file
, data
, 32);
1243 if (file
->fs
&& file
->fs
->name
&& grub_strcmp(file
->fs
->name
, "udf") == 0)
1245 readpos
= grub_udf_get_file_offset(file
);
1249 readpos
= grub_iso9660_get_last_read_pos(file
);
1252 debug("bootfix.bin readpos:%lu (sector:%lu) data: %02x %02x %02x %02x\n",
1253 (ulong
)readpos
, (ulong
)readpos
/ 2048, data
[24], data
[25], data
[26], data
[27]);
1255 if (*(grub_uint32_t
*)(data
+ 24) == 0x13cd0080)
1257 g_suppress_wincd_override_offset
= readpos
+ 24;
1258 g_suppress_wincd_override_data
= 0x13cd00fd;
1263 debug("g_suppress_wincd_override_offset:%lu\n", (ulong
)g_suppress_wincd_override_offset
);
1266 check_free(file
, grub_file_close
);
1271 grub_err_t
ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1273 int unknown_image
= 0;
1274 int ventoy_compatible
= 0;
1275 grub_uint32_t size
= 0;
1276 grub_uint64_t isosize
= 0;
1277 grub_uint32_t boot_catlog
= 0;
1278 grub_uint32_t img_chunk_size
= 0;
1279 grub_uint32_t override_size
= 0;
1280 grub_uint32_t virt_chunk_size
= 0;
1283 const char *pLastChain
= NULL
;
1284 const char *compatible
;
1285 ventoy_chain_head
*chain
;
1291 debug("chain data begin <%s> ...\n", args
[0]);
1293 compatible
= grub_env_get("ventoy_compatible");
1294 if (compatible
&& compatible
[0] == 'Y')
1296 ventoy_compatible
= 1;
1299 if (NULL
== g_img_chunk_list
.chunk
)
1301 grub_printf("ventoy not ready\n");
1305 if (0 == ventoy_compatible
&& g_wim_valid_patch_count
== 0)
1308 debug("Warning: %s was not recognized by Ventoy\n", args
[0]);
1311 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1317 isosize
= file
->size
;
1319 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1322 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1324 grub_env_set("LoadIsoEfiDriver", "on");
1329 if (ventoy_is_efi_os())
1331 grub_env_set("LoadIsoEfiDriver", "on");
1335 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1339 g_suppress_wincd_override_offset
= 0;
1340 if (!ventoy_is_efi_os()) /* legacy mode */
1342 ventoy_suppress_windows_cd_prompt();
1345 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1347 if (ventoy_compatible
|| unknown_image
)
1349 override_size
= g_suppress_wincd_override_offset
> 0 ? sizeof(ventoy_override_chunk
) : 0;
1350 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
;
1354 override_size
= ventoy_get_override_chunk_num() * sizeof(ventoy_override_chunk
);
1355 virt_chunk_size
= ventoy_windows_get_virt_data_size();
1356 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1359 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1362 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1365 debug("free last chain memory %p\n", chain
);
1370 chain
= grub_malloc(size
);
1373 grub_printf("Failed to alloc chain memory size %u\n", size
);
1374 grub_file_close(file
);
1378 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1379 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1380 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1381 grub_env_set("vtoy_chain_mem_size", envbuf
);
1383 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1385 /* part 1: os parameter */
1386 g_ventoy_chain_type
= ventoy_chain_windows
;
1387 ventoy_fill_os_param(file
, &(chain
->os_param
));
1389 if (0 == unknown_image
)
1391 ventoy_update_before_chain(&(chain
->os_param
), args
[0]);
1394 /* part 2: chain head */
1395 disk
= file
->device
->disk
;
1396 chain
->disk_drive
= disk
->id
;
1397 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1398 chain
->real_img_size_in_bytes
= file
->size
;
1399 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1400 chain
->boot_catalog
= boot_catlog
;
1402 if (!ventoy_is_efi_os())
1404 grub_file_seek(file
, boot_catlog
* 2048);
1405 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1408 /* part 3: image chunk */
1409 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1410 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1411 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1413 if (ventoy_compatible
|| unknown_image
)
1415 if (g_suppress_wincd_override_offset
> 0)
1417 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1418 chain
->override_chunk_num
= 1;
1419 ventoy_fill_suppress_wincd_override_data((char *)chain
+ chain
->override_chunk_offset
);
1425 if (0 == g_wim_valid_patch_count
)
1430 /* part 4: override chunk */
1431 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1432 chain
->override_chunk_num
= ventoy_get_override_chunk_num();
1434 if (g_iso_fs_type
== 0)
1436 ventoy_windows_fill_override_data_iso9660(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1440 ventoy_windows_fill_override_data_udf(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
1443 /* part 5: virt chunk */
1444 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1445 chain
->virt_chunk_num
= g_wim_valid_patch_count
;
1446 ventoy_windows_fill_virt_data(isosize
, chain
);
1448 if (ventoy_is_efi_os() == 0)
1450 ventoy_windows_drive_map(chain
);
1453 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1456 static grub_uint32_t
ventoy_get_wim_iso_offset(const char *filepath
)
1458 grub_uint32_t imgoffset
;
1462 grub_snprintf(cmdbuf
, sizeof(cmdbuf
), "loopback wimiso %s", filepath
);
1463 grub_script_execute_sourcecode(cmdbuf
);
1465 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", "(wimiso)/boot/boot.wim");
1468 grub_printf("Failed to open boot.wim file in the image file\n");
1472 imgoffset
= (grub_uint32_t
)grub_iso9660_get_last_file_dirent_pos(file
) + 2;
1474 debug("wimiso wim direct offset: %u\n", imgoffset
);
1476 grub_file_close(file
);
1478 grub_script_execute_sourcecode("loopback -d wimiso");
1483 static int ventoy_get_wim_chunklist(const char *filename
, ventoy_img_chunk_list
*wimchunk
, grub_uint64_t
*wimsize
)
1485 grub_file_t wimfile
;
1487 wimfile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", filename
);
1493 grub_memset(wimchunk
, 0, sizeof(ventoy_img_chunk_list
));
1494 wimchunk
->chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
1495 if (NULL
== wimchunk
->chunk
)
1497 grub_file_close(wimfile
);
1498 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
1501 wimchunk
->max_chunk
= DEFAULT_CHUNK_NUM
;
1502 wimchunk
->cur_chunk
= 0;
1504 ventoy_get_block_list(wimfile
, wimchunk
, wimfile
->device
->disk
->partition
->start
);
1506 *wimsize
= wimfile
->size
;
1507 grub_file_close(wimfile
);
1512 grub_err_t
ventoy_cmd_wim_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1514 grub_uint32_t i
= 0;
1515 grub_uint32_t imgoffset
= 0;
1516 grub_uint32_t size
= 0;
1517 grub_uint32_t isosector
= 0;
1518 grub_uint64_t wimsize
= 0;
1519 grub_uint32_t boot_catlog
= 0;
1520 grub_uint32_t img_chunk1_size
= 0;
1521 grub_uint32_t img_chunk2_size
= 0;
1522 grub_uint32_t override_size
= 0;
1525 const char *pLastChain
= NULL
;
1526 ventoy_chain_head
*chain
;
1527 ventoy_iso9660_override
*dirent
;
1528 ventoy_img_chunk
*chunknode
;
1529 ventoy_override_chunk
*override
;
1530 ventoy_img_chunk_list wimchunk
;
1536 debug("wim chain data begin <%s> ...\n", args
[0]);
1538 if (NULL
== g_wimiso_chunk_list
.chunk
|| NULL
== g_wimiso_path
)
1540 grub_printf("ventoy not ready\n");
1544 imgoffset
= ventoy_get_wim_iso_offset(g_wimiso_path
);
1547 grub_printf("image offset not found\n");
1551 if (0 != ventoy_get_wim_chunklist(args
[0], &wimchunk
, &wimsize
))
1553 grub_printf("Failed to get wim chunklist\n");
1557 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", g_wimiso_path
);
1563 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1565 img_chunk1_size
= g_wimiso_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1566 img_chunk2_size
= wimchunk
.cur_chunk
* sizeof(ventoy_img_chunk
);
1567 override_size
= sizeof(ventoy_override_chunk
);
1569 size
= sizeof(ventoy_chain_head
) + img_chunk1_size
+ img_chunk2_size
+ override_size
;
1571 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1574 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1577 debug("free last chain memory %p\n", chain
);
1582 chain
= grub_malloc(size
);
1585 grub_printf("Failed to alloc chain memory size %u\n", size
);
1586 grub_file_close(file
);
1590 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1591 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1592 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1593 grub_env_set("vtoy_chain_mem_size", envbuf
);
1595 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1597 /* part 1: os parameter */
1598 g_ventoy_chain_type
= ventoy_chain_wim
;
1599 ventoy_fill_os_param(file
, &(chain
->os_param
));
1601 /* part 2: chain head */
1602 disk
= file
->device
->disk
;
1603 chain
->disk_drive
= disk
->id
;
1604 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1605 chain
->real_img_size_in_bytes
= ventoy_align_2k(file
->size
) + ventoy_align_2k(wimsize
);
1606 chain
->virt_img_size_in_bytes
= chain
->real_img_size_in_bytes
;
1607 chain
->boot_catalog
= boot_catlog
;
1609 if (!ventoy_is_efi_os())
1611 grub_file_seek(file
, boot_catlog
* 2048);
1612 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1615 /* part 3: image chunk */
1616 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1617 chain
->img_chunk_num
= g_wimiso_chunk_list
.cur_chunk
+ wimchunk
.cur_chunk
;
1618 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_wimiso_chunk_list
.chunk
, img_chunk1_size
);
1620 /* fs cluster size >= 2048, so don't need to proc align */
1623 chunknode
= wimchunk
.chunk
+ wimchunk
.cur_chunk
- 1;
1624 i
= (chunknode
->disk_end_sector
+ 1 - chunknode
->disk_start_sector
) % 4;
1627 chunknode
->disk_end_sector
+= 4 - i
;
1630 isosector
= (grub_uint32_t
)((file
->size
+ 2047) / 2048);
1631 for (i
= 0; i
< wimchunk
.cur_chunk
; i
++)
1633 chunknode
= wimchunk
.chunk
+ i
;
1634 chunknode
->img_start_sector
= isosector
;
1635 chunknode
->img_end_sector
= chunknode
->img_start_sector
+
1636 ((chunknode
->disk_end_sector
+ 1 - chunknode
->disk_start_sector
) / 4) - 1;
1637 isosector
= chunknode
->img_end_sector
+ 1;
1640 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
+ img_chunk1_size
, wimchunk
.chunk
, img_chunk2_size
);
1642 /* part 4: override chunk */
1643 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk1_size
+ img_chunk2_size
;
1644 chain
->override_chunk_num
= 1;
1646 override
= (ventoy_override_chunk
*)((char *)chain
+ chain
->override_chunk_offset
);
1647 override
->img_offset
= imgoffset
;
1648 override
->override_size
= sizeof(ventoy_iso9660_override
);
1650 dirent
= (ventoy_iso9660_override
*)(override
->override_data
);
1651 dirent
->first_sector
= (grub_uint32_t
)((file
->size
+ 2047) / 2048);
1652 dirent
->size
= (grub_uint32_t
)(wimsize
);
1653 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
1654 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
1656 debug("imgoffset=%u first_sector=0x%x size=0x%x\n", imgoffset
, dirent
->first_sector
, dirent
->size
);
1658 if (ventoy_is_efi_os() == 0)
1660 ventoy_windows_drive_map(chain
);
1663 grub_file_close(file
);
1665 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);