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
);
54 grub_ssize_t
xca_decompress ( const void *data
, grub_size_t len
, void *buf
);
56 static wim_patch
*ventoy_find_wim_patch(const char *path
)
58 int len
= (int)grub_strlen(path
);
59 wim_patch
*node
= g_wim_patch_head
;
63 if (len
== node
->pathlen
&& 0 == grub_strcmp(path
, node
->path
))
73 static int ventoy_collect_wim_patch(const char *bcdfile
)
78 grub_file_t file
= NULL
;
80 wim_patch
*node
= NULL
;
86 g_ventoy_case_insensitive
= 1;
87 file
= grub_file_open(bcdfile
, VENTOY_FILE_TYPE
);
88 g_ventoy_case_insensitive
= 0;
91 debug("Failed to open file %s\n", bcdfile
);
96 buf
= grub_malloc(file
->size
+ 8);
102 grub_file_read(file
, buf
, file
->size
);
104 for (i
= 0; i
< (int)file
->size
- 8; i
++)
111 magic
= *(grub_uint64_t
*)(buf
+ i
);
114 if ((magic
== 0x006D00690077002EULL
) ||
115 (magic
== 0x004D00490057002EULL
) ||
116 (magic
== 0x006D00690057002EULL
))
118 for (j
= i
; j
> 0; j
-= 2)
120 if (*(grub_uint16_t
*)(buf
+ j
) == 0)
128 byte
= (grub_uint8_t
)(*(grub_uint16_t
*)(buf
+ j
+ 2));
129 if (byte
!= '/' && byte
!= '\\')
135 for (k
= 0, j
+= 2; k
< (int)sizeof(path
) - 1 && j
< i
+ 8; j
+= 2)
137 byte
= (grub_uint8_t
)(*(grub_uint16_t
*)(buf
+ j
));
139 if (byte
> '~' || byte
< ' ') /* not printable */
153 debug("@@@@ Find wim flag:<%s>\n", path
);
157 debug("Invalid wim file %d\n", k
);
159 else if (NULL
== ventoy_find_wim_patch(path
))
161 node
= grub_zalloc(sizeof(wim_patch
));
164 node
->pathlen
= grub_snprintf(node
->path
, sizeof(node
->path
), "%s", path
);
166 debug("add patch <%s>\n", path
);
168 if (g_wim_patch_head
)
170 node
->next
= g_wim_patch_head
;
172 g_wim_patch_head
= node
;
174 g_wim_total_patch_count
++;
179 debug("wim <%s> already exist\n", path
);
186 check_free(file
, grub_file_close
);
187 grub_check_free(buf
);
191 grub_err_t
ventoy_cmd_wim_patch_count(grub_extcmd_context_t ctxt
, int argc
, char **args
)
201 grub_snprintf(buf
, sizeof(buf
), "%d", g_wim_total_patch_count
);
202 ventoy_set_env(args
[0], buf
);
208 grub_err_t
ventoy_cmd_collect_wim_patch(grub_extcmd_context_t ctxt
, int argc
, char **args
)
210 wim_patch
*node
= NULL
;
221 debug("ventoy_cmd_collect_wim_patch %s %s\n", args
[0], args
[1]);
223 if (grub_strcmp(args
[0], "bcd") == 0)
225 ventoy_collect_wim_patch(args
[1]);
229 if (NULL
== ventoy_find_wim_patch(args
[1]))
231 node
= grub_zalloc(sizeof(wim_patch
));
234 node
->pathlen
= grub_snprintf(node
->path
, sizeof(node
->path
), "%s", args
[1]);
236 debug("add patch <%s>\n", args
[1]);
238 if (g_wim_patch_head
)
240 node
->next
= g_wim_patch_head
;
242 g_wim_patch_head
= node
;
244 g_wim_total_patch_count
++;
252 grub_err_t
ventoy_cmd_dump_wim_patch(grub_extcmd_context_t ctxt
, int argc
, char **args
)
255 wim_patch
*node
= NULL
;
261 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
263 grub_printf("%d %s [%s]\n", i
++, node
->path
, node
->valid
? "SUCCESS" : "FAIL");
270 static int wim_name_cmp(const char *search
, grub_uint16_t
*name
, grub_uint16_t namelen
)
272 char c1
= vtoy_to_upper(*search
);
273 char c2
= vtoy_to_upper(*name
);
275 while (namelen
> 0 && (c1
== c2
))
281 c1
= vtoy_to_upper(*search
);
282 c2
= vtoy_to_upper(*name
);
285 if (namelen
== 0 && *search
== 0)
293 static int ventoy_is_pe64(grub_uint8_t
*buffer
)
295 grub_uint32_t pe_off
;
297 if (buffer
[0] != 'M' || buffer
[1] != 'Z')
302 pe_off
= *(grub_uint32_t
*)(buffer
+ 60);
304 if (buffer
[pe_off
] != 'P' || buffer
[pe_off
+ 1] != 'E')
309 if (*(grub_uint16_t
*)(buffer
+ pe_off
+ 24) == 0x020b)
317 grub_err_t
ventoy_cmd_is_pe64(grub_extcmd_context_t ctxt
, int argc
, char **args
)
321 grub_uint8_t buf
[512];
326 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
332 grub_memset(buf
, 0, 512);
333 grub_file_read(file
, buf
, 512);
334 if (ventoy_is_pe64(buf
))
336 debug("%s is PE64\n", args
[0]);
341 debug("%s is PE32\n", args
[0]);
343 grub_file_close(file
);
348 grub_err_t
ventoy_cmd_sel_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
352 char configfile
[128];
358 debug("select wimboot argc:%d\n", argc
);
360 buf
= (char *)grub_malloc(8192);
366 size
= (int)grub_snprintf(buf
, 8192,
367 "menuentry \"Windows Setup (32-bit)\" {\n"
368 " set vtoy_wimboot_sel=32\n"
370 "menuentry \"Windows Setup (64-bit)\" {\n"
371 " set vtoy_wimboot_sel=64\n"
376 g_ventoy_menu_esc
= 1;
377 g_ventoy_suppress_esc
= 1;
378 g_ventoy_suppress_esc_default
= 1;
380 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, size
);
381 grub_script_execute_sourcecode(configfile
);
383 g_ventoy_menu_esc
= 0;
384 g_ventoy_suppress_esc
= 0;
388 if (g_ventoy_last_entry
== 0)
390 debug("last entry=%d %s=32\n", g_ventoy_last_entry
, args
[0]);
391 grub_env_set(args
[0], "32");
395 debug("last entry=%d %s=64\n", g_ventoy_last_entry
, args
[0]);
396 grub_env_set(args
[0], "64");
399 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
402 grub_err_t
ventoy_cmd_wimdows_reset(grub_extcmd_context_t ctxt
, int argc
, char **args
)
404 wim_patch
*next
= NULL
;
405 wim_patch
*node
= g_wim_patch_head
;
418 g_wim_patch_head
= NULL
;
419 g_wim_total_patch_count
= 0;
420 g_wim_valid_patch_count
= 0;
425 static int ventoy_load_jump_exe(const char *path
, grub_uint8_t
**data
, grub_uint32_t
*size
, wim_hash
*hash
)
431 debug("windows load jump %s\n", path
);
433 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", path
);
436 debug("Can't open file %s\n", path
);
440 align
= ventoy_align((int)file
->size
, 2048);
442 debug("file %s size:%d align:%u\n", path
, (int)file
->size
, align
);
444 *size
= (grub_uint32_t
)file
->size
;
445 *data
= (grub_uint8_t
*)grub_malloc(align
);
448 debug("Failed to alloc memory size %u\n", align
);
452 grub_file_read(file
, (*data
), file
->size
);
456 grub_crypto_hash(GRUB_MD_SHA1
, hash
->sha1
, (*data
), file
->size
);
460 debug("%s", "jump bin 64 hash: ");
461 for (i
= 0; i
< sizeof(hash
->sha1
); i
++)
463 ventoy_debug("%02x ", hash
->sha1
[i
]);
471 grub_file_close(file
);
475 static int ventoy_get_override_info(grub_file_t file
, wim_tail
*wim_data
)
477 grub_uint32_t start_block
;
478 grub_uint64_t file_offset
;
479 grub_uint64_t override_offset
;
480 grub_uint32_t override_len
;
481 grub_uint64_t fe_entry_size_offset
;
483 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
485 g_iso_fs_type
= wim_data
->iso_type
= 0;
486 override_len
= sizeof(ventoy_iso9660_override
);
487 override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
489 grub_file_read(file
, &start_block
, 1); // just read for hook trigger
490 file_offset
= grub_iso9660_get_last_read_pos(file
);
492 debug("iso9660 wim size:%llu override_offset:%llu file_offset:%llu\n",
493 (ulonglong
)file
->size
, (ulonglong
)override_offset
, (ulonglong
)file_offset
);
497 g_iso_fs_type
= wim_data
->iso_type
= 1;
498 override_len
= sizeof(ventoy_udf_override
);
499 override_offset
= grub_udf_get_last_file_attr_offset(file
, &start_block
, &fe_entry_size_offset
);
501 file_offset
= grub_udf_get_file_offset(file
);
503 debug("UDF wim size:%llu override_offset:%llu file_offset:%llu start_block=%u\n",
504 (ulonglong
)file
->size
, (ulonglong
)override_offset
, (ulonglong
)file_offset
, start_block
);
507 wim_data
->file_offset
= file_offset
;
508 wim_data
->udf_start_block
= start_block
;
509 wim_data
->fe_entry_size_offset
= fe_entry_size_offset
;
510 wim_data
->override_offset
= override_offset
;
511 wim_data
->override_len
= override_len
;
516 static int ventoy_read_resource(grub_file_t fp
, wim_header
*wimhdr
, wim_resource_header
*head
, void **buffer
)
518 int decompress_len
= 0;
519 int total_decompress
= 0;
521 grub_uint32_t chunk_num
= 0;
522 grub_uint32_t chunk_size
= 0;
523 grub_uint32_t last_chunk_size
= 0;
524 grub_uint32_t last_decompress_size
= 0;
525 grub_uint32_t cur_offset
= 0;
526 grub_uint8_t
*cur_dst
= NULL
;
527 grub_uint8_t
*buffer_compress
= NULL
;
528 grub_uint8_t
*buffer_decompress
= NULL
;
529 grub_uint32_t
*chunk_offset
= NULL
;
531 buffer_decompress
= (grub_uint8_t
*)grub_malloc(head
->raw_size
+ head
->size_in_wim
);
532 if (NULL
== buffer_decompress
)
537 grub_file_seek(fp
, head
->offset
);
539 if (head
->size_in_wim
== head
->raw_size
)
541 grub_file_read(fp
, buffer_decompress
, head
->size_in_wim
);
542 *buffer
= buffer_decompress
;
546 buffer_compress
= buffer_decompress
+ head
->raw_size
;
547 grub_file_read(fp
, buffer_compress
, head
->size_in_wim
);
549 chunk_num
= (head
->raw_size
+ WIM_CHUNK_LEN
- 1) / WIM_CHUNK_LEN
;
550 cur_offset
= (chunk_num
- 1) * 4;
551 chunk_offset
= (grub_uint32_t
*)buffer_compress
;
553 //debug("%llu %llu chunk_num=%lu", (ulonglong)head->size_in_wim, (ulonglong)head->raw_size, chunk_num);
555 cur_dst
= buffer_decompress
;
557 for (i
= 0; i
< chunk_num
- 1; i
++)
559 chunk_size
= (i
== 0) ? chunk_offset
[i
] : chunk_offset
[i
] - chunk_offset
[i
- 1];
561 if (WIM_CHUNK_LEN
== chunk_size
)
563 grub_memcpy(cur_dst
, buffer_compress
+ cur_offset
, chunk_size
);
564 decompress_len
= (int)chunk_size
;
568 if (wimhdr
->flags
& FLAG_HEADER_COMPRESS_XPRESS
)
570 decompress_len
= (int)xca_decompress(buffer_compress
+ cur_offset
, chunk_size
, cur_dst
);
574 decompress_len
= (int)lzx_decompress(buffer_compress
+ cur_offset
, chunk_size
, cur_dst
);
578 //debug("chunk_size:%u decompresslen:%d\n", chunk_size, decompress_len);
580 total_decompress
+= decompress_len
;
581 cur_dst
+= decompress_len
;
582 cur_offset
+= chunk_size
;
586 last_chunk_size
= (grub_uint32_t
)(head
->size_in_wim
- cur_offset
);
587 last_decompress_size
= head
->raw_size
- total_decompress
;
589 if (last_chunk_size
< WIM_CHUNK_LEN
&& last_chunk_size
== last_decompress_size
)
591 debug("Last chunk %u uncompressed\n", last_chunk_size
);
592 grub_memcpy(cur_dst
, buffer_compress
+ cur_offset
, last_chunk_size
);
593 decompress_len
= (int)last_chunk_size
;
597 if (wimhdr
->flags
& FLAG_HEADER_COMPRESS_XPRESS
)
599 decompress_len
= (int)xca_decompress(buffer_compress
+ cur_offset
, head
->size_in_wim
- cur_offset
, cur_dst
);
603 decompress_len
= (int)lzx_decompress(buffer_compress
+ cur_offset
, head
->size_in_wim
- cur_offset
, cur_dst
);
607 cur_dst
+= decompress_len
;
608 total_decompress
+= decompress_len
;
610 //debug("last chunk_size:%u decompresslen:%d tot:%d\n", last_chunk_size, decompress_len, total_decompress);
612 if (cur_dst
!= buffer_decompress
+ head
->raw_size
)
614 debug("head->size_in_wim:%llu head->raw_size:%llu cur_dst:%p buffer_decompress:%p total_decompress:%d\n",
615 (ulonglong
)head
->size_in_wim
, (ulonglong
)head
->raw_size
, cur_dst
, buffer_decompress
, total_decompress
);
616 grub_free(buffer_decompress
);
620 *buffer
= buffer_decompress
;
625 static wim_directory_entry
* search_wim_dirent(wim_directory_entry
*dir
, const char *search_name
)
629 if (dir
->len
&& dir
->name_len
)
631 if (wim_name_cmp(search_name
, (grub_uint16_t
*)(dir
+ 1), dir
->name_len
/ 2) == 0)
636 dir
= (wim_directory_entry
*)((grub_uint8_t
*)dir
+ dir
->len
);
642 static wim_directory_entry
* search_full_wim_dirent
645 wim_directory_entry
*dir
,
649 wim_directory_entry
*subdir
= NULL
;
650 wim_directory_entry
*search
= dir
;
654 subdir
= (wim_directory_entry
*)((char *)meta_data
+ search
->subdir
);
655 search
= search_wim_dirent(subdir
, *path
);
664 static wim_lookup_entry
* ventoy_find_look_entry(wim_header
*header
, wim_lookup_entry
*lookup
, wim_hash
*hash
)
668 for (i
= 0; i
< (grub_uint32_t
)header
->lookup
.raw_size
/ sizeof(wim_lookup_entry
); i
++)
670 if (grub_memcmp(&lookup
[i
].hash
, hash
, sizeof(wim_hash
)) == 0)
679 static int parse_registry_setup_cmdline
683 wim_lookup_entry
*lookup
,
685 wim_directory_entry
*dir
,
693 grub_uint32_t reglen
= 0;
695 reg_vk
*regvk
= NULL
;
696 wim_lookup_entry
*look
= NULL
;
697 wim_directory_entry
*wim_dirent
= NULL
;
698 char *decompress_data
= NULL
;
699 const char *reg_path
[] = { "Windows", "System32", "config", "SYSTEM", NULL
};
701 wim_dirent
= search_full_wim_dirent(meta_data
, dir
, reg_path
);
702 debug("search reg SYSTEM %p\n", wim_dirent
);
708 grub_memset(&zerohash
, 0, sizeof(zerohash
));
709 if (grub_memcmp(&zerohash
, wim_dirent
->hash
.sha1
, sizeof(wim_hash
)) == 0)
714 look
= ventoy_find_look_entry(head
, lookup
, &wim_dirent
->hash
);
720 reglen
= (grub_uint32_t
)look
->resource
.raw_size
;
721 debug("find system lookup entry_id:%ld raw_size:%u\n",
722 ((long)look
- (long)lookup
) / sizeof(wim_lookup_entry
), reglen
);
724 if (0 != ventoy_read_resource(file
, head
, &(look
->resource
), (void **)&(decompress_data
)))
729 if (grub_strncmp(decompress_data
+ 0x1000, "hbin", 4))
734 for (i
= 0x1000; i
+ sizeof(reg_vk
) < reglen
; i
+= 8)
736 regvk
= (reg_vk
*)(decompress_data
+ i
);
737 if (regvk
->sig
== 0x6B76 && regvk
->namesize
== 7 &&
738 regvk
->datatype
== 1 && regvk
->flag
== 1)
740 if (grub_strncasecmp((char *)(regvk
+ 1), "cmdline", 7) == 0)
742 debug("find registry cmdline i:%u offset:(0x%x)%u size:(0x%x)%u\n",
743 i
, regvk
->dataoffset
, regvk
->dataoffset
, regvk
->datasize
, regvk
->datasize
);
749 if (i
+ sizeof(reg_vk
) >= reglen
|| regvk
== NULL
)
754 if (regvk
->datasize
== 0 || (regvk
->datasize
& 0x80000000) > 0 ||
755 regvk
->dataoffset
== 0 || regvk
->dataoffset
== 0xFFFFFFFF)
760 if (regvk
->datasize
/ 2 >= buflen
)
765 debug("start offset is 0x%x(%u)\n", 0x1000 + regvk
->dataoffset
+ 4, 0x1000 + regvk
->dataoffset
+ 4);
767 for (i
= 0; i
< regvk
->datasize
; i
+=2)
769 c
= (char)(*(grub_uint16_t
*)(decompress_data
+ 0x1000 + regvk
->dataoffset
+ 4 + i
));
776 grub_check_free(decompress_data
);
780 static int parse_custom_setup_path(char *cmdline
, const char **path
, char *exefile
)
787 if ((cmdline
[0] == 'x' || cmdline
[0] == 'X') && cmdline
[1] == ':')
789 pos1
= pos2
= cmdline
+ 3;
791 while (i
< VTOY_MAX_DIR_DEPTH
&& *pos2
)
793 while (*pos2
&& *pos2
!= '\\' && *pos2
!= '/')
810 if (i
== 0 || i
>= VTOY_MAX_DIR_DEPTH
)
817 path
[i
++] = "Windows";
818 path
[i
++] = "System32";
822 pos1
= (char *)path
[i
- 1];
823 while (*pos1
!= ' ' && *pos1
!= '\t' && *pos1
)
829 len
= (int)grub_strlen(path
[i
- 1]);
830 if (len
< 4 || grub_strcasecmp(path
[i
- 1] + len
- 4, ".exe") != 0)
832 grub_snprintf(exefile
, 256, "%s.exe", path
[i
- 1]);
833 path
[i
- 1] = exefile
;
837 debug("custom setup: %d <%s>\n", i
, path
[i
- 1]);
841 static wim_directory_entry
* search_replace_wim_dirent
845 wim_lookup_entry
*lookup
,
847 wim_directory_entry
*dir
851 char exefile
[256] = {0};
852 char cmdline
[256] = {0};
853 wim_directory_entry
*wim_dirent
= NULL
;
854 wim_directory_entry
*pecmd_dirent
= NULL
;
855 const char *peset_path
[] = { "Windows", "System32", "peset.exe", NULL
};
856 const char *pecmd_path
[] = { "Windows", "System32", "pecmd.exe", NULL
};
857 const char *winpeshl_path
[] = { "Windows", "System32", "winpeshl.exe", NULL
};
858 const char *custom_path
[VTOY_MAX_DIR_DEPTH
+ 1] = { NULL
};
860 pecmd_dirent
= search_full_wim_dirent(meta_data
, dir
, pecmd_path
);
861 debug("search pecmd.exe %p\n", pecmd_dirent
);
865 ret
= parse_registry_setup_cmdline(file
, head
, lookup
, meta_data
, dir
, cmdline
, sizeof(cmdline
) - 1);
868 debug("registry setup cmdline:<%s>\n", cmdline
);
870 if (grub_strncasecmp(cmdline
, "PECMD", 5) == 0)
872 wim_dirent
= pecmd_dirent
;
874 else if (grub_strncasecmp(cmdline
, "PESET", 5) == 0)
876 wim_dirent
= search_full_wim_dirent(meta_data
, dir
, peset_path
);
877 debug("search peset.exe %p\n", wim_dirent
);
879 else if (grub_strncasecmp(cmdline
, "WINPESHL", 8) == 0)
881 wim_dirent
= search_full_wim_dirent(meta_data
, dir
, winpeshl_path
);
882 debug("search winpeshl.exe %p\n", wim_dirent
);
884 else if (0 == parse_custom_setup_path(cmdline
, custom_path
, exefile
))
886 wim_dirent
= search_full_wim_dirent(meta_data
, dir
, custom_path
);
887 debug("search custom path %p\n", wim_dirent
);
897 debug("registry setup cmdline failed : %d\n", ret
);
901 wim_dirent
= pecmd_dirent
;
907 wim_dirent
= search_full_wim_dirent(meta_data
, dir
, winpeshl_path
);
908 debug("search winpeshl.exe %p\n", wim_dirent
);
918 static wim_lookup_entry
* ventoy_find_meta_entry(wim_header
*header
, wim_lookup_entry
*lookup
)
921 grub_uint32_t index
= 0;;
923 if ((header
== NULL
) || (lookup
== NULL
))
928 for (i
= 0; i
< (grub_uint32_t
)header
->lookup
.raw_size
/ sizeof(wim_lookup_entry
); i
++)
930 if (lookup
[i
].resource
.flags
& RESHDR_FLAG_METADATA
)
933 if (index
== header
->boot_index
)
943 static grub_uint64_t
ventoy_get_stream_len(wim_directory_entry
*dir
)
946 grub_uint64_t offset
= 0;
947 wim_stream_entry
*stream
= (wim_stream_entry
*)((char *)dir
+ dir
->len
);
949 for (i
= 0; i
< dir
->streams
; i
++)
951 offset
+= stream
->len
;
952 stream
= (wim_stream_entry
*)((char *)stream
+ stream
->len
);
958 static int ventoy_update_stream_hash(wim_patch
*patch
, wim_directory_entry
*dir
)
961 grub_uint64_t offset
= 0;
962 wim_stream_entry
*stream
= (wim_stream_entry
*)((char *)dir
+ dir
->len
);
964 for (i
= 0; i
< dir
->streams
; i
++)
966 if (grub_memcmp(stream
->hash
.sha1
, patch
->old_hash
.sha1
, sizeof(wim_hash
)) == 0)
968 debug("find target stream %u, name_len:%u upadte hash\n", i
, stream
->name_len
);
969 grub_memcpy(stream
->hash
.sha1
, &(patch
->wim_data
.bin_hash
), sizeof(wim_hash
));
972 offset
+= stream
->len
;
973 stream
= (wim_stream_entry
*)((char *)stream
+ stream
->len
);
979 static int ventoy_update_all_hash(wim_patch
*patch
, void *meta_data
, wim_directory_entry
*dir
)
981 if ((meta_data
== NULL
) || (dir
== NULL
))
986 if (dir
->len
< sizeof(wim_directory_entry
))
993 if (dir
->subdir
== 0 && grub_memcmp(dir
->hash
.sha1
, patch
->old_hash
.sha1
, sizeof(wim_hash
)) == 0)
995 debug("find target file, name_len:%u upadte hash\n", dir
->name_len
);
996 grub_memcpy(dir
->hash
.sha1
, &(patch
->wim_data
.bin_hash
), sizeof(wim_hash
));
1001 ventoy_update_all_hash(patch
, meta_data
, (wim_directory_entry
*)((char *)meta_data
+ dir
->subdir
));
1006 ventoy_update_stream_hash(patch
, dir
);
1007 dir
= (wim_directory_entry
*)((char *)dir
+ dir
->len
+ ventoy_get_stream_len(dir
));
1011 dir
= (wim_directory_entry
*)((char *)dir
+ dir
->len
);
1013 } while (dir
->len
>= sizeof(wim_directory_entry
));
1018 static int ventoy_cat_exe_file_data(wim_tail
*wim_data
, grub_uint32_t exe_len
, grub_uint8_t
*exe_data
, int windatalen
)
1022 grub_uint32_t jump_len
= 0;
1023 grub_uint32_t jump_align
= 0;
1024 grub_uint8_t
*jump_data
= NULL
;
1026 pe64
= ventoy_is_pe64(exe_data
);
1028 grub_snprintf(file
, sizeof(file
), "%s/vtoyjump%d.exe", grub_env_get("vtoy_path"), pe64
? 64 : 32);
1029 ventoy_load_jump_exe(file
, &jump_data
, &jump_len
, NULL
);
1030 jump_align
= ventoy_align(jump_len
, 16);
1032 wim_data
->jump_exe_len
= jump_len
;
1033 wim_data
->bin_raw_len
= jump_align
+ sizeof(ventoy_os_param
) + windatalen
+ exe_len
;
1034 wim_data
->bin_align_len
= ventoy_align(wim_data
->bin_raw_len
, 2048);
1036 wim_data
->jump_bin_data
= grub_malloc(wim_data
->bin_align_len
);
1037 if (wim_data
->jump_bin_data
)
1039 grub_memcpy(wim_data
->jump_bin_data
, jump_data
, jump_len
);
1040 grub_memcpy(wim_data
->jump_bin_data
+ jump_align
+ sizeof(ventoy_os_param
) + windatalen
, exe_data
, exe_len
);
1043 debug("jump_exe_len:%u bin_raw_len:%u bin_align_len:%u\n",
1044 wim_data
->jump_exe_len
, wim_data
->bin_raw_len
, wim_data
->bin_align_len
);
1049 static int ventoy_get_windows_rtdata_len(const char *iso
, int *flag
)
1052 int template_file_len
= 0;
1054 char *script
= NULL
;
1055 install_template
*template_node
= NULL
;
1058 size
= (int)sizeof(ventoy_windows_data
);
1060 pos
= grub_strstr(iso
, "/");
1066 script
= ventoy_plugin_get_cur_install_template(pos
, &template_node
);
1069 (*flag
) |= WINDATA_FLAG_TEMPLATE
;
1070 template_file_len
= template_node
->filelen
;
1073 return size
+ template_file_len
;
1076 static int ventoy_fill_windows_rtdata(void *buf
, char *isopath
, int dataflag
)
1078 int template_len
= 0;
1081 char *script
= NULL
;
1082 const char *env
= NULL
;
1083 install_template
*template_node
= NULL
;
1084 ventoy_windows_data
*data
= (ventoy_windows_data
*)buf
;
1086 grub_memset(data
, 0, sizeof(ventoy_windows_data
));
1088 env
= grub_env_get("VTOY_WIN11_BYPASS_CHECK");
1089 if (env
&& env
[0] == '1' && env
[1] == 0)
1091 data
->windows11_bypass_check
= 1;
1094 pos
= grub_strstr(isopath
, "/");
1100 if (dataflag
& WINDATA_FLAG_TEMPLATE
)
1102 script
= ventoy_plugin_get_cur_install_template(pos
, &template_node
);
1105 data
->auto_install_len
= template_len
= template_node
->filelen
;
1106 debug("auto install script OK <%s> <len:%d>\n", script
, template_len
);
1107 end
= ventoy_str_last(script
, '/');
1108 grub_snprintf(data
->auto_install_script
, sizeof(data
->auto_install_script
) - 1, "%s", end
? end
+ 1 : script
);
1109 grub_memcpy(data
+ 1, template_node
->filebuf
, template_len
);
1114 debug("auto install script skipped or not configed %s\n", pos
);
1117 script
= (char *)ventoy_plugin_get_injection(pos
);
1120 if (ventoy_check_file_exist("%s%s", ventoy_get_env("vtoy_iso_part"), script
))
1122 debug("injection archive <%s> OK\n", script
);
1123 grub_snprintf(data
->injection_archive
, sizeof(data
->injection_archive
) - 1, "%s", script
);
1127 debug("injection archive <%s> NOT exist\n", script
);
1132 debug("injection archive not configed %s\n", pos
);
1138 static int ventoy_update_before_chain(ventoy_os_param
*param
, char *isopath
)
1140 grub_uint32_t jump_align
= 0;
1141 wim_lookup_entry
*meta_look
= NULL
;
1142 wim_security_header
*security
= NULL
;
1143 wim_directory_entry
*rootdir
= NULL
;
1144 wim_header
*head
= NULL
;
1145 wim_lookup_entry
*lookup
= NULL
;
1146 wim_patch
*node
= NULL
;
1147 wim_tail
*wim_data
= NULL
;
1149 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
1151 if (0 == node
->valid
)
1156 wim_data
= &node
->wim_data
;
1157 head
= &wim_data
->wim_header
;
1158 lookup
= (wim_lookup_entry
*)wim_data
->new_lookup_data
;
1160 jump_align
= ventoy_align(wim_data
->jump_exe_len
, 16);
1161 if (wim_data
->jump_bin_data
)
1163 grub_memcpy(wim_data
->jump_bin_data
+ jump_align
, param
, sizeof(ventoy_os_param
));
1164 ventoy_fill_windows_rtdata(wim_data
->jump_bin_data
+ jump_align
+ sizeof(ventoy_os_param
), isopath
, wim_data
->windata_flag
);
1167 grub_crypto_hash(GRUB_MD_SHA1
, wim_data
->bin_hash
.sha1
, wim_data
->jump_bin_data
, wim_data
->bin_raw_len
);
1169 security
= (wim_security_header
*)wim_data
->new_meta_data
;
1170 if (security
->len
> 0)
1172 rootdir
= (wim_directory_entry
*)(wim_data
->new_meta_data
+ ((security
->len
+ 7) & 0xFFFFFFF8U
));
1176 rootdir
= (wim_directory_entry
*)(wim_data
->new_meta_data
+ 8);
1179 /* update all winpeshl.exe dirent entry's hash */
1180 ventoy_update_all_hash(node
, wim_data
->new_meta_data
, rootdir
);
1182 /* update winpeshl.exe lookup entry data (hash/offset/length) */
1183 if (node
->replace_look
)
1185 debug("update replace lookup entry_id:%ld\n", ((long)node
->replace_look
- (long)lookup
) / sizeof(wim_lookup_entry
));
1186 node
->replace_look
->resource
.raw_size
= wim_data
->bin_raw_len
;
1187 node
->replace_look
->resource
.size_in_wim
= wim_data
->bin_raw_len
;
1188 node
->replace_look
->resource
.flags
= 0;
1189 node
->replace_look
->resource
.offset
= wim_data
->wim_align_size
;
1191 grub_memcpy(node
->replace_look
->hash
.sha1
, wim_data
->bin_hash
.sha1
, sizeof(wim_hash
));
1194 /* update metadata's hash */
1195 meta_look
= ventoy_find_meta_entry(head
, lookup
);
1198 debug("find meta lookup entry_id:%ld\n", ((long)meta_look
- (long)lookup
) / sizeof(wim_lookup_entry
));
1199 grub_memcpy(&meta_look
->resource
, &head
->metadata
, sizeof(wim_resource_header
));
1200 grub_crypto_hash(GRUB_MD_SHA1
, meta_look
->hash
.sha1
, wim_data
->new_meta_data
, wim_data
->new_meta_len
);
1207 static int ventoy_wimdows_locate_wim(const char *disk
, wim_patch
*patch
, int windatalen
)
1212 grub_uint32_t exe_len
;
1213 grub_uint8_t
*exe_data
= NULL
;
1214 grub_uint8_t
*decompress_data
= NULL
;
1215 wim_lookup_entry
*lookup
= NULL
;
1216 wim_security_header
*security
= NULL
;
1217 wim_directory_entry
*rootdir
= NULL
;
1218 wim_directory_entry
*search
= NULL
;
1219 wim_stream_entry
*stream
= NULL
;
1220 wim_header
*head
= &(patch
->wim_data
.wim_header
);
1221 wim_tail
*wim_data
= &patch
->wim_data
;
1223 debug("windows locate wim start %s\n", patch
->path
);
1225 g_ventoy_case_insensitive
= 1;
1226 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", disk
, patch
->path
);
1227 g_ventoy_case_insensitive
= 0;
1231 debug("File %s%s NOT exist\n", disk
, patch
->path
);
1235 ventoy_get_override_info(file
, &patch
->wim_data
);
1237 grub_file_seek(file
, 0);
1238 grub_file_read(file
, head
, sizeof(wim_header
));
1240 if (grub_memcmp(head
->signature
, WIM_HEAD_SIGNATURE
, sizeof(head
->signature
)))
1242 debug("Not a valid wim file %s\n", (char *)head
->signature
);
1243 grub_file_close(file
);
1247 if (head
->flags
& FLAG_HEADER_COMPRESS_LZMS
)
1249 debug("LZMS compress is not supported 0x%x\n", head
->flags
);
1250 grub_file_close(file
);
1254 rc
= ventoy_read_resource(file
, head
, &head
->metadata
, (void **)&decompress_data
);
1257 grub_printf("failed to read meta data %d\n", rc
);
1258 grub_file_close(file
);
1262 security
= (wim_security_header
*)decompress_data
;
1263 if (security
->len
> 0)
1265 rootdir
= (wim_directory_entry
*)(decompress_data
+ ((security
->len
+ 7) & 0xFFFFFFF8U
));
1269 rootdir
= (wim_directory_entry
*)(decompress_data
+ 8);
1273 debug("read lookup offset:%llu size:%llu\n", (ulonglong
)head
->lookup
.offset
, (ulonglong
)head
->lookup
.raw_size
);
1274 lookup
= grub_malloc(head
->lookup
.raw_size
);
1275 grub_file_seek(file
, head
->lookup
.offset
);
1276 grub_file_read(file
, lookup
, head
->lookup
.raw_size
);
1280 /* search winpeshl.exe dirent entry */
1281 search
= search_replace_wim_dirent(file
, head
, lookup
, decompress_data
, rootdir
);
1284 debug("Failed to find replace file %p\n", search
);
1285 grub_file_close(file
);
1289 debug("find replace file at %p\n", search
);
1291 grub_memset(&patch
->old_hash
, 0, sizeof(wim_hash
));
1292 if (grub_memcmp(&patch
->old_hash
, search
->hash
.sha1
, sizeof(wim_hash
)) == 0)
1294 debug("search hash all 0, now do deep search\n");
1295 stream
= (wim_stream_entry
*)((char *)search
+ search
->len
);
1296 for (i
= 0; i
< search
->streams
; i
++)
1298 if (stream
->name_len
== 0)
1300 grub_memcpy(&patch
->old_hash
, stream
->hash
.sha1
, sizeof(wim_hash
));
1301 debug("new search hash: %02x %02x %02x %02x %02x %02x %02x %02x\n",
1302 ventoy_varg_8(patch
->old_hash
.sha1
));
1305 stream
= (wim_stream_entry
*)((char *)stream
+ stream
->len
);
1310 grub_memcpy(&patch
->old_hash
, search
->hash
.sha1
, sizeof(wim_hash
));
1314 /* find and extact winpeshl.exe */
1315 patch
->replace_look
= ventoy_find_look_entry(head
, lookup
, &patch
->old_hash
);
1316 if (patch
->replace_look
)
1318 exe_len
= (grub_uint32_t
)patch
->replace_look
->resource
.raw_size
;
1319 debug("find replace lookup entry_id:%ld raw_size:%u\n",
1320 ((long)patch
->replace_look
- (long)lookup
) / sizeof(wim_lookup_entry
), exe_len
);
1322 if (0 == ventoy_read_resource(file
, head
, &(patch
->replace_look
->resource
), (void **)&(exe_data
)))
1324 ventoy_cat_exe_file_data(wim_data
, exe_len
, exe_data
, windatalen
);
1325 grub_free(exe_data
);
1329 debug("failed to read replace file meta data %u\n", exe_len
);
1334 debug("failed to find lookup entry for replace file %02x %02x %02x %02x\n",
1335 ventoy_varg_4(patch
->old_hash
.sha1
));
1338 wim_data
->wim_raw_size
= (grub_uint32_t
)file
->size
;
1339 wim_data
->wim_align_size
= ventoy_align(wim_data
->wim_raw_size
, 2048);
1341 grub_check_free(wim_data
->new_meta_data
);
1342 wim_data
->new_meta_data
= decompress_data
;
1343 wim_data
->new_meta_len
= head
->metadata
.raw_size
;
1344 wim_data
->new_meta_align_len
= ventoy_align(wim_data
->new_meta_len
, 2048);
1346 grub_check_free(wim_data
->new_lookup_data
);
1347 wim_data
->new_lookup_data
= (grub_uint8_t
*)lookup
;
1348 wim_data
->new_lookup_len
= (grub_uint32_t
)head
->lookup
.raw_size
;
1349 wim_data
->new_lookup_align_len
= ventoy_align(wim_data
->new_lookup_len
, 2048);
1351 head
->metadata
.flags
= RESHDR_FLAG_METADATA
;
1352 head
->metadata
.offset
= wim_data
->wim_align_size
+ wim_data
->bin_align_len
;
1353 head
->metadata
.size_in_wim
= wim_data
->new_meta_len
;
1354 head
->metadata
.raw_size
= wim_data
->new_meta_len
;
1356 head
->lookup
.flags
= 0;
1357 head
->lookup
.offset
= head
->metadata
.offset
+ wim_data
->new_meta_align_len
;
1358 head
->lookup
.size_in_wim
= wim_data
->new_lookup_len
;
1359 head
->lookup
.raw_size
= wim_data
->new_lookup_len
;
1361 grub_file_close(file
);
1363 debug("%s", "windows locate wim finish\n");
1367 grub_err_t
ventoy_cmd_sel_winpe_wim(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1374 wim_patch
*node
= NULL
;
1375 wim_patch
*tmp
= NULL
;
1376 grub_file_t file
= NULL
;
1377 wim_header
*head
= NULL
;
1383 len
= 8 * VTOY_SIZE_1KB
;
1384 cmd
= (char *)grub_malloc(len
+ sizeof(wim_header
));
1390 head
= (wim_header
*)(cmd
+ len
);
1391 grub_env_unset("vtoy_pe_wim_path");
1393 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
1396 for (tmp
= g_wim_patch_head
; tmp
!= node
; tmp
= tmp
->next
)
1398 if (tmp
->valid
&& grub_strcasecmp(tmp
->path
, node
->path
) == 0)
1410 g_ventoy_case_insensitive
= 1;
1411 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->path
);
1412 g_ventoy_case_insensitive
= 0;
1415 debug("File %s%s NOT exist\n", args
[0], node
->path
);
1419 grub_file_read(file
, head
, sizeof(wim_header
));
1420 if (grub_memcmp(head
->signature
, WIM_HEAD_SIGNATURE
, sizeof(head
->signature
)))
1422 debug("Not a valid wim file %s\n", (char *)head
->signature
);
1423 grub_file_close(file
);
1427 if (head
->flags
& FLAG_HEADER_COMPRESS_LZMS
)
1429 debug("LZMS compress is not supported 0x%x\n", head
->flags
);
1430 grub_file_close(file
);
1434 grub_file_close(file
);
1437 vtoy_len_ssprintf(cmd
, pos
, len
, "menuentry \"%s\" --class=\"sel_wim\" {\n echo \"\"\n}\n", node
->path
);
1442 g_ventoy_menu_esc
= 1;
1443 g_ventoy_suppress_esc
= 1;
1444 g_ventoy_suppress_esc_default
= 0;
1446 grub_snprintf(cfgfile
, sizeof(cfgfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)cmd
, pos
);
1447 grub_script_execute_sourcecode(cfgfile
);
1449 g_ventoy_menu_esc
= 0;
1450 g_ventoy_suppress_esc
= 0;
1451 g_ventoy_suppress_esc_default
= 1;
1453 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
1457 if (i
== g_ventoy_last_entry
)
1459 grub_env_set("vtoy_pe_wim_path", node
->path
);
1471 grub_err_t
ventoy_cmd_locate_wim_patch(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1475 wim_patch
*node
= g_wim_patch_head
;
1481 datalen
= ventoy_get_windows_rtdata_len(args
[1], &dataflag
);
1485 node
->wim_data
.windata_flag
= dataflag
;
1486 if (0 == ventoy_wimdows_locate_wim(args
[0], node
, datalen
))
1489 g_wim_valid_patch_count
++;
1498 static grub_uint32_t
ventoy_get_override_chunk_num(void)
1500 grub_uint32_t chunk_num
= 0;
1502 if (g_iso_fs_type
== 0)
1506 /* 1: file_size and file_offset */
1507 /* 2: new wim file header */
1508 chunk_num
= g_wim_valid_patch_count
* 2;
1514 /* 1: block count in Partition Descriptor */
1517 /* 1: file_size in file_entry or extend_file_entry */
1518 /* 2: data_size and position in extend data short ad */
1519 /* 3: new wim file header */
1520 chunk_num
= g_wim_valid_patch_count
* 3 + 1;
1523 if (g_suppress_wincd_override_offset
> 0)
1531 static void ventoy_fill_suppress_wincd_override_data(void *override
)
1533 ventoy_override_chunk
*cur
= (ventoy_override_chunk
*)override
;
1535 cur
->override_size
= 4;
1536 cur
->img_offset
= g_suppress_wincd_override_offset
;
1537 grub_memcpy(cur
->override_data
, &g_suppress_wincd_override_data
, cur
->override_size
);
1540 static void ventoy_windows_fill_override_data_iso9660( grub_uint64_t isosize
, void *override
)
1542 grub_uint64_t sector
;
1543 grub_uint32_t new_wim_size
;
1544 ventoy_override_chunk
*cur
;
1545 wim_patch
*node
= NULL
;
1546 wim_tail
*wim_data
= NULL
;
1547 ventoy_iso9660_override
*dirent
= NULL
;
1549 sector
= (isosize
+ 2047) / 2048;
1551 cur
= (ventoy_override_chunk
*)override
;
1553 if (g_suppress_wincd_override_offset
> 0)
1555 ventoy_fill_suppress_wincd_override_data(cur
);
1559 debug("ventoy_windows_fill_override_data_iso9660 %lu\n", (ulong
)isosize
);
1561 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
1563 wim_data
= &node
->wim_data
;
1564 if (0 == node
->valid
)
1569 new_wim_size
= wim_data
->wim_align_size
+ wim_data
->bin_align_len
+
1570 wim_data
->new_meta_align_len
+ wim_data
->new_lookup_align_len
;
1572 dirent
= (ventoy_iso9660_override
*)wim_data
->override_data
;
1574 dirent
->first_sector
= (grub_uint32_t
)sector
;
1575 dirent
->size
= new_wim_size
;
1576 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
1577 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
1579 sector
+= (new_wim_size
/ 2048);
1581 /* override 1: position and length in dirent */
1582 cur
->img_offset
= wim_data
->override_offset
;
1583 cur
->override_size
= wim_data
->override_len
;
1584 grub_memcpy(cur
->override_data
, wim_data
->override_data
, cur
->override_size
);
1587 /* override 2: new wim file header */
1588 cur
->img_offset
= wim_data
->file_offset
;
1589 cur
->override_size
= sizeof(wim_header
);
1590 grub_memcpy(cur
->override_data
, &(wim_data
->wim_header
), cur
->override_size
);
1597 static int ventoy_windows_fill_udf_short_ad(grub_file_t isofile
, grub_uint32_t curpos
,
1598 wim_tail
*wim_data
, grub_uint32_t new_wim_size
)
1601 grub_uint32_t total
= 0;
1602 grub_uint32_t left_size
= 0;
1603 ventoy_udf_override
*udf
= NULL
;
1604 ventoy_udf_override tmp
[4];
1606 grub_memset(tmp
, 0, sizeof(tmp
));
1607 grub_file_seek(isofile
, wim_data
->override_offset
);
1608 grub_file_read(isofile
, tmp
, sizeof(tmp
));
1610 left_size
= new_wim_size
;
1611 udf
= (ventoy_udf_override
*)wim_data
->override_data
;
1613 for (i
= 0; i
< 4; i
++)
1615 total
+= tmp
[i
].length
;
1616 if (total
>= wim_data
->wim_raw_size
)
1618 udf
->length
= left_size
;
1619 udf
->position
= curpos
;
1624 udf
->length
= tmp
[i
].length
;
1625 udf
->position
= curpos
;
1628 left_size
-= tmp
[i
].length
;
1629 curpos
+= udf
->length
/ 2048;
1631 wim_data
->override_len
+= sizeof(ventoy_udf_override
);
1634 debug("######## Too many udf ad ######\n");
1638 static void ventoy_windows_fill_override_data_udf(grub_file_t isofile
, void *override
)
1640 grub_uint32_t data32
;
1641 grub_uint64_t data64
;
1642 grub_uint64_t sector
;
1643 grub_uint32_t new_wim_size
;
1644 grub_uint64_t total_wim_size
= 0;
1645 grub_uint32_t udf_start_block
= 0;
1646 ventoy_override_chunk
*cur
;
1647 wim_patch
*node
= NULL
;
1648 wim_tail
*wim_data
= NULL
;
1650 sector
= (isofile
->size
+ 2047) / 2048;
1652 cur
= (ventoy_override_chunk
*)override
;
1654 if (g_suppress_wincd_override_offset
> 0)
1656 ventoy_fill_suppress_wincd_override_data(cur
);
1660 debug("ventoy_windows_fill_override_data_udf %lu\n", (ulong
)isofile
->size
);
1662 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
1664 wim_data
= &node
->wim_data
;
1667 if (udf_start_block
== 0)
1669 udf_start_block
= wim_data
->udf_start_block
;
1671 new_wim_size
= wim_data
->wim_align_size
+ wim_data
->bin_align_len
+
1672 wim_data
->new_meta_align_len
+ wim_data
->new_lookup_align_len
;
1673 total_wim_size
+= new_wim_size
;
1677 //override 1: sector number in pd data
1678 cur
->img_offset
= grub_udf_get_last_pd_size_offset();
1679 cur
->override_size
= 4;
1680 data32
= sector
- udf_start_block
+ (total_wim_size
/ 2048);
1681 grub_memcpy(cur
->override_data
, &(data32
), 4);
1683 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
1685 wim_data
= &node
->wim_data
;
1686 if (0 == node
->valid
)
1691 new_wim_size
= wim_data
->wim_align_size
+ wim_data
->bin_align_len
+
1692 wim_data
->new_meta_align_len
+ wim_data
->new_lookup_align_len
;
1694 //override 2: filesize in file_entry
1696 cur
->img_offset
= wim_data
->fe_entry_size_offset
;
1697 cur
->override_size
= 8;
1698 data64
= new_wim_size
;
1699 grub_memcpy(cur
->override_data
, &(data64
), 8);
1701 /* override 3: position and length in extend data */
1702 ventoy_windows_fill_udf_short_ad(isofile
, (grub_uint32_t
)sector
- udf_start_block
, wim_data
, new_wim_size
);
1704 sector
+= (new_wim_size
/ 2048);
1707 cur
->img_offset
= wim_data
->override_offset
;
1708 cur
->override_size
= wim_data
->override_len
;
1709 grub_memcpy(cur
->override_data
, wim_data
->override_data
, cur
->override_size
);
1711 /* override 4: new wim file header */
1713 cur
->img_offset
= wim_data
->file_offset
;
1714 cur
->override_size
= sizeof(wim_header
);
1715 grub_memcpy(cur
->override_data
, &(wim_data
->wim_header
), cur
->override_size
);
1721 static grub_uint32_t
ventoy_windows_get_virt_data_size(void)
1723 grub_uint32_t size
= 0;
1724 wim_tail
*wim_data
= NULL
;
1725 wim_patch
*node
= g_wim_patch_head
;
1731 wim_data
= &node
->wim_data
;
1732 size
+= sizeof(ventoy_virt_chunk
) + wim_data
->bin_align_len
+
1733 wim_data
->new_meta_align_len
+ wim_data
->new_lookup_align_len
;
1741 static void ventoy_windows_fill_virt_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
1743 grub_uint64_t sector
;
1744 grub_uint32_t offset
;
1745 grub_uint32_t wim_secs
;
1746 grub_uint32_t mem_secs
;
1747 char *override
= NULL
;
1748 ventoy_virt_chunk
*cur
= NULL
;
1749 wim_tail
*wim_data
= NULL
;
1750 wim_patch
*node
= NULL
;
1752 sector
= (isosize
+ 2047) / 2048;
1753 offset
= sizeof(ventoy_virt_chunk
) * g_wim_valid_patch_count
;
1755 override
= (char *)chain
+ chain
->virt_chunk_offset
;
1756 cur
= (ventoy_virt_chunk
*)override
;
1758 for (node
= g_wim_patch_head
; node
; node
= node
->next
)
1760 if (0 == node
->valid
)
1765 wim_data
= &node
->wim_data
;
1767 wim_secs
= wim_data
->wim_align_size
/ 2048;
1768 mem_secs
= (wim_data
->bin_align_len
+ wim_data
->new_meta_align_len
+ wim_data
->new_lookup_align_len
) / 2048;
1770 cur
->remap_sector_start
= sector
;
1771 cur
->remap_sector_end
= cur
->remap_sector_start
+ wim_secs
;
1772 cur
->org_sector_start
= (grub_uint32_t
)(wim_data
->file_offset
/ 2048);
1774 cur
->mem_sector_start
= cur
->remap_sector_end
;
1775 cur
->mem_sector_end
= cur
->mem_sector_start
+ mem_secs
;
1776 cur
->mem_sector_offset
= offset
;
1778 sector
+= wim_secs
+ mem_secs
;
1781 grub_memcpy(override
+ offset
, wim_data
->jump_bin_data
, wim_data
->bin_raw_len
);
1782 offset
+= wim_data
->bin_align_len
;
1784 grub_memcpy(override
+ offset
, wim_data
->new_meta_data
, wim_data
->new_meta_len
);
1785 offset
+= wim_data
->new_meta_align_len
;
1787 grub_memcpy(override
+ offset
, wim_data
->new_lookup_data
, wim_data
->new_lookup_len
);
1788 offset
+= wim_data
->new_lookup_align_len
;
1790 chain
->virt_img_size_in_bytes
+= wim_data
->wim_align_size
+
1791 wim_data
->bin_align_len
+
1792 wim_data
->new_meta_align_len
+
1793 wim_data
->new_lookup_align_len
;
1799 static int ventoy_windows_drive_map(ventoy_chain_head
*chain
, int vlnk
)
1804 debug("drive map begin <%p> <%d> ...\n", chain
, vlnk
);
1806 disk
= grub_disk_open("hd1");
1809 grub_disk_close(disk
);
1811 debug("BIOS hd1 exist\n");
1815 debug("failed to open disk %s\n", "hd1");
1820 if (g_ventoy_disk_bios_id
== 0x80 && hd1
)
1822 debug("drive map needed vlnk %p\n", disk
);
1823 chain
->drive_map
= 0x81;
1826 else if (chain
->disk_drive
== 0x80)
1830 debug("drive map needed normal %p\n", disk
);
1831 chain
->drive_map
= 0x81;
1836 debug("no need to map 0x%x\n", chain
->disk_drive
);
1842 static int ventoy_suppress_windows_cd_prompt(void)
1845 const char *cdprompt
= NULL
;
1846 grub_uint64_t readpos
= 0;
1847 grub_file_t file
= NULL
;
1848 grub_uint8_t data
[32];
1850 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
1851 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
1853 debug("VTOY_WINDOWS_CD_PROMPT:<%s>\n", cdprompt
);
1857 g_ventoy_case_insensitive
= 1;
1858 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s/boot/bootfix.bin", "(loop)");
1859 g_ventoy_case_insensitive
= 0;
1863 debug("Failed to open %s\n", "bootfix.bin");
1867 grub_file_read(file
, data
, 32);
1869 if (file
->fs
&& file
->fs
->name
&& grub_strcmp(file
->fs
->name
, "udf") == 0)
1871 readpos
= grub_udf_get_file_offset(file
);
1875 readpos
= grub_iso9660_get_last_read_pos(file
);
1878 debug("bootfix.bin readpos:%lu (sector:%lu) data: %02x %02x %02x %02x\n",
1879 (ulong
)readpos
, (ulong
)readpos
/ 2048, data
[24], data
[25], data
[26], data
[27]);
1881 if (*(grub_uint32_t
*)(data
+ 24) == 0x13cd0080)
1883 g_suppress_wincd_override_offset
= readpos
+ 24;
1884 g_suppress_wincd_override_data
= 0x13cd00fd;
1889 debug("g_suppress_wincd_override_offset:%lu\n", (ulong
)g_suppress_wincd_override_offset
);
1892 check_free(file
, grub_file_close
);
1897 static int ventoy_extract_init_exe(char *wimfile
, grub_uint8_t
**pexe_data
, grub_uint32_t
*pexe_len
, char *exe_name
)
1902 grub_file_t file
= NULL
;
1903 grub_uint32_t exe_len
= 0;
1904 wim_header
*head
= NULL
;
1905 grub_uint16_t
*uname
= NULL
;
1906 grub_uint8_t
*exe_data
= NULL
;
1907 grub_uint8_t
*decompress_data
= NULL
;
1908 wim_lookup_entry
*lookup
= NULL
;
1909 wim_security_header
*security
= NULL
;
1910 wim_directory_entry
*rootdir
= NULL
;
1911 wim_directory_entry
*search
= NULL
;
1912 wim_stream_entry
*stream
= NULL
;
1913 wim_lookup_entry
*replace_look
= NULL
;
1919 file
= grub_file_open(wimfile
, VENTOY_FILE_TYPE
);
1925 grub_file_read(file
, head
, sizeof(wim_header
));
1926 rc
= ventoy_read_resource(file
, head
, &head
->metadata
, (void **)&decompress_data
);
1929 grub_printf("failed to read meta data %d\n", rc
);
1933 security
= (wim_security_header
*)decompress_data
;
1934 if (security
->len
> 0)
1936 rootdir
= (wim_directory_entry
*)(decompress_data
+ ((security
->len
+ 7) & 0xFFFFFFF8U
));
1940 rootdir
= (wim_directory_entry
*)(decompress_data
+ 8);
1943 debug("read lookup offset:%llu size:%llu\n", (ulonglong
)head
->lookup
.offset
, (ulonglong
)head
->lookup
.raw_size
);
1944 lookup
= grub_malloc(head
->lookup
.raw_size
);
1945 grub_file_seek(file
, head
->lookup
.offset
);
1946 grub_file_read(file
, lookup
, head
->lookup
.raw_size
);
1948 /* search winpeshl.exe dirent entry */
1949 search
= search_replace_wim_dirent(file
, head
, lookup
, decompress_data
, rootdir
);
1952 debug("Failed to find replace file %p\n", search
);
1956 uname
= (grub_uint16_t
*)(search
+ 1);
1957 for (i
= 0; i
< search
->name_len
/ 2 && i
< 200; i
++)
1959 exe_name
[i
] = (char)uname
[i
];
1962 debug("find replace file at %p <%s>\n", search
, exe_name
);
1964 grub_memset(&hashdata
, 0, sizeof(wim_hash
));
1965 if (grub_memcmp(&hashdata
, search
->hash
.sha1
, sizeof(wim_hash
)) == 0)
1967 debug("search hash all 0, now do deep search\n");
1968 stream
= (wim_stream_entry
*)((char *)search
+ search
->len
);
1969 for (i
= 0; i
< search
->streams
; i
++)
1971 if (stream
->name_len
== 0)
1973 grub_memcpy(&hashdata
, stream
->hash
.sha1
, sizeof(wim_hash
));
1974 debug("new search hash: %02x %02x %02x %02x %02x %02x %02x %02x\n",
1975 ventoy_varg_8(hashdata
.sha1
));
1978 stream
= (wim_stream_entry
*)((char *)stream
+ stream
->len
);
1983 grub_memcpy(&hashdata
, search
->hash
.sha1
, sizeof(wim_hash
));
1986 /* find and extact winpeshl.exe */
1987 replace_look
= ventoy_find_look_entry(head
, lookup
, &hashdata
);
1990 exe_len
= (grub_uint32_t
)replace_look
->resource
.raw_size
;
1991 debug("find replace lookup entry_id:%ld raw_size:%u\n",
1992 ((long)replace_look
- (long)lookup
) / sizeof(wim_lookup_entry
), exe_len
);
1994 if (0 != ventoy_read_resource(file
, head
, &(replace_look
->resource
), (void **)&(exe_data
)))
1998 debug("failed to read replace file meta data %u\n", exe_len
);
2003 debug("failed to find lookup entry for replace file %02x %02x %02x %02x\n",
2004 ventoy_varg_4(hashdata
.sha1
));
2010 *pexe_data
= exe_data
;
2011 *pexe_len
= exe_len
;
2016 grub_check_free(lookup
);
2017 grub_check_free(decompress_data
);
2018 check_free(file
, grub_file_close
);
2023 grub_err_t
ventoy_cmd_windows_wimboot_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2029 grub_uint32_t exe_len
= 0;
2030 grub_uint32_t jump_align
= 0;
2031 const char *addr
= NULL
;
2032 ventoy_chain_head
*chain
= NULL
;
2033 grub_uint8_t
*param
= NULL
;
2034 grub_uint8_t
*exe_data
= NULL
;
2035 ventoy_windows_data
*rtdata
= NULL
;
2036 char envbuf
[64] = {0};
2037 char exename
[128] = {0};
2043 addr
= grub_env_get("vtoy_chain_mem_addr");
2046 debug("Failed to find vtoy_chain_mem_addr\n");
2050 chain
= (ventoy_chain_head
*)(void *)grub_strtoul(addr
, NULL
, 16);
2052 if (grub_memcmp(&g_ventoy_guid
, &chain
->os_param
.guid
, 16) != 0)
2054 debug("os_param.guid not match\n");
2058 datalen
= ventoy_get_windows_rtdata_len(chain
->os_param
.vtoy_img_path
, &dataflag
);
2060 rc
= ventoy_extract_init_exe(args
[0], &exe_data
, &exe_len
, exename
);
2065 wim64
= ventoy_is_pe64(exe_data
);
2067 grub_memset(&wim_data
, 0, sizeof(wim_data
));
2068 ventoy_cat_exe_file_data(&wim_data
, exe_len
, exe_data
, datalen
);
2069 grub_check_free(exe_data
);
2071 jump_align
= ventoy_align(wim_data
.jump_exe_len
, 16);
2072 param
= wim_data
.jump_bin_data
;
2074 grub_memcpy(param
+ jump_align
, &chain
->os_param
, sizeof(ventoy_os_param
));
2076 rtdata
= (ventoy_windows_data
*)(param
+ jump_align
+ sizeof(ventoy_os_param
));
2077 ventoy_fill_windows_rtdata(rtdata
, chain
->os_param
.vtoy_img_path
, dataflag
);
2079 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (ulong
)param
);
2080 grub_env_set("vtoy_wimboot_mem_addr", envbuf
);
2081 debug("vtoy_wimboot_mem_addr: %s\n", envbuf
);
2083 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", wim_data
.bin_align_len
);
2084 grub_env_set("vtoy_wimboot_mem_size", envbuf
);
2085 debug("vtoy_wimboot_mem_size: %s\n", envbuf
);
2087 grub_env_set(args
[1], exename
);
2088 grub_env_set(args
[2], wim64
? "64" : "32");
2090 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2093 grub_err_t
ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2095 int unknown_image
= 0;
2096 int ventoy_compatible
= 0;
2097 grub_uint32_t size
= 0;
2098 grub_uint64_t isosize
= 0;
2099 grub_uint32_t boot_catlog
= 0;
2100 grub_uint32_t img_chunk_size
= 0;
2101 grub_uint32_t override_size
= 0;
2102 grub_uint32_t virt_chunk_size
= 0;
2105 const char *pLastChain
= NULL
;
2106 const char *compatible
;
2107 ventoy_chain_head
*chain
;
2113 debug("chain data begin <%s> ...\n", args
[0]);
2115 compatible
= grub_env_get("ventoy_compatible");
2116 if (compatible
&& compatible
[0] == 'Y')
2118 ventoy_compatible
= 1;
2121 if (NULL
== g_img_chunk_list
.chunk
)
2123 grub_printf("ventoy not ready\n");
2127 if (0 == ventoy_compatible
&& g_wim_valid_patch_count
== 0)
2130 if (!g_ventoy_wimboot_mode
)
2132 debug("Warning: %s was not recognized by Ventoy\n", args
[0]);
2136 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2142 isosize
= file
->size
;
2144 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
2147 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
2149 grub_env_set("LoadIsoEfiDriver", "on");
2154 if (ventoy_is_efi_os())
2156 grub_env_set("LoadIsoEfiDriver", "on");
2160 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
2164 g_suppress_wincd_override_offset
= 0;
2165 if (!ventoy_is_efi_os()) /* legacy mode */
2167 ventoy_suppress_windows_cd_prompt();
2170 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
2172 if (ventoy_compatible
|| unknown_image
)
2174 override_size
= g_suppress_wincd_override_offset
> 0 ? sizeof(ventoy_override_chunk
) : 0;
2175 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
;
2179 override_size
= ventoy_get_override_chunk_num() * sizeof(ventoy_override_chunk
);
2180 virt_chunk_size
= ventoy_windows_get_virt_data_size();
2181 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
2184 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
2187 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
2190 debug("free last chain memory %p\n", chain
);
2195 chain
= ventoy_alloc_chain(size
);
2198 grub_printf("Failed to alloc chain win1 memory size %u\n", size
);
2199 grub_file_close(file
);
2203 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
2204 grub_env_set("vtoy_chain_mem_addr", envbuf
);
2205 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
2206 grub_env_set("vtoy_chain_mem_size", envbuf
);
2208 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
2210 /* part 1: os parameter */
2211 g_ventoy_chain_type
= ventoy_chain_windows
;
2212 ventoy_fill_os_param(file
, &(chain
->os_param
));
2214 if (0 == unknown_image
)
2216 ventoy_update_before_chain(&(chain
->os_param
), args
[0]);
2219 /* part 2: chain head */
2220 disk
= file
->device
->disk
;
2221 chain
->disk_drive
= disk
->id
;
2222 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
2223 chain
->real_img_size_in_bytes
= file
->size
;
2224 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
2225 chain
->boot_catalog
= boot_catlog
;
2227 if (!ventoy_is_efi_os())
2229 grub_file_seek(file
, boot_catlog
* 2048);
2230 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
2233 /* part 3: image chunk */
2234 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
2235 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
2236 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
2238 if (ventoy_compatible
|| unknown_image
)
2240 if (g_suppress_wincd_override_offset
> 0)
2242 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
2243 chain
->override_chunk_num
= 1;
2244 ventoy_fill_suppress_wincd_override_data((char *)chain
+ chain
->override_chunk_offset
);
2250 if (0 == g_wim_valid_patch_count
)
2255 /* part 4: override chunk */
2256 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
2257 chain
->override_chunk_num
= ventoy_get_override_chunk_num();
2259 if (g_iso_fs_type
== 0)
2261 ventoy_windows_fill_override_data_iso9660(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
2265 ventoy_windows_fill_override_data_udf(file
, (char *)chain
+ chain
->override_chunk_offset
);
2268 /* part 5: virt chunk */
2269 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
2270 chain
->virt_chunk_num
= g_wim_valid_patch_count
;
2271 ventoy_windows_fill_virt_data(isosize
, chain
);
2273 if (ventoy_is_efi_os() == 0)
2275 ventoy_windows_drive_map(chain
, file
->vlnk
);
2278 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2281 static grub_uint32_t
ventoy_get_wim_iso_offset(const char *filepath
)
2283 grub_uint32_t imgoffset
;
2287 grub_snprintf(cmdbuf
, sizeof(cmdbuf
), "loopback wimiso \"%s\"", filepath
);
2288 grub_script_execute_sourcecode(cmdbuf
);
2290 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", "(wimiso)/boot/boot.wim");
2293 grub_printf("Failed to open boot.wim file in the image file\n");
2297 imgoffset
= (grub_uint32_t
)grub_iso9660_get_last_file_dirent_pos(file
) + 2;
2299 debug("wimiso wim direct offset: %u\n", imgoffset
);
2301 grub_file_close(file
);
2303 grub_script_execute_sourcecode("loopback -d wimiso");
2308 static int ventoy_get_wim_chunklist(grub_file_t wimfile
, ventoy_img_chunk_list
*wimchunk
)
2310 grub_memset(wimchunk
, 0, sizeof(ventoy_img_chunk_list
));
2311 wimchunk
->chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2312 if (NULL
== wimchunk
->chunk
)
2314 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2317 wimchunk
->max_chunk
= DEFAULT_CHUNK_NUM
;
2318 wimchunk
->cur_chunk
= 0;
2320 ventoy_get_block_list(wimfile
, wimchunk
, wimfile
->device
->disk
->partition
->start
);
2325 grub_err_t
ventoy_cmd_is_standard_winiso(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2329 char prefix
[32] = {0};
2330 const char *chkfile
[] =
2332 "boot/bcd", "boot/boot.sdi", NULL
2338 if (ventoy_check_file_exist("%s/sources/boot.wim", args
[0]))
2342 else if (ventoy_check_file_exist("%s/x86/sources/boot.wim", args
[0]))
2344 grub_snprintf(prefix
, sizeof(prefix
), "/x86");
2346 else if (ventoy_check_file_exist("%s/x64/sources/boot.wim", args
[0]))
2348 grub_snprintf(prefix
, sizeof(prefix
), "/x64");
2352 debug("No boot.wim found.\n");
2356 for (i
= 0; chkfile
[i
]; i
++)
2358 if (!ventoy_check_file_exist("%s%s/%s", args
[0], prefix
, chkfile
[i
]))
2360 debug("%s not found.\n", chkfile
[i
]);
2365 if ((!ventoy_check_file_exist("%s%s/sources/install.wim", args
[0], prefix
)) &&
2366 (!ventoy_check_file_exist("%s%s/sources/install.esd", args
[0], prefix
)))
2368 debug("No install.wim(esd) found.\n");
2372 if (!ventoy_check_file_exist("%s/setup.exe", args
[0]))
2374 debug("No setup.exe found.\n");
2379 debug("This is standard Windows ISO.\n");
2386 grub_err_t
ventoy_cmd_wim_check_bootable(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2388 grub_uint32_t boot_index
;
2389 grub_file_t file
= NULL
;
2390 wim_header
*wimhdr
= NULL
;
2395 wimhdr
= grub_zalloc(sizeof(wim_header
));
2401 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2408 grub_file_read(file
, wimhdr
, sizeof(wim_header
));
2409 grub_file_close(file
);
2410 boot_index
= wimhdr
->boot_index
;
2413 if (boot_index
== 0)
2418 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2421 static grub_err_t
ventoy_vlnk_wim_chain_data(grub_file_t wimfile
)
2423 grub_uint32_t i
= 0;
2424 grub_uint32_t imgoffset
= 0;
2425 grub_uint32_t size
= 0;
2426 grub_uint32_t isosector
= 0;
2427 grub_uint64_t wimsize
= 0;
2428 grub_uint32_t boot_catlog
= 0;
2429 grub_uint32_t img_chunk1_size
= 0;
2430 grub_uint32_t img_chunk2_size
= 0;
2431 grub_uint32_t override_size
= 0;
2434 const char *pLastChain
= NULL
;
2435 ventoy_chain_head
*chain
;
2436 ventoy_iso9660_override
*dirent
;
2437 ventoy_img_chunk
*chunknode
;
2438 ventoy_override_chunk
*override
;
2439 ventoy_img_chunk_list wimchunk
;
2442 debug("vlnk wim chain data begin <%s> ...\n", wimfile
->name
);
2444 if (NULL
== g_wimiso_chunk_list
.chunk
|| NULL
== g_wimiso_path
)
2446 grub_printf("ventoy not ready\n");
2450 imgoffset
= ventoy_get_wim_iso_offset(g_wimiso_path
);
2453 grub_printf("image offset not found\n");
2457 if (0 != ventoy_get_wim_chunklist(wimfile
, &wimchunk
))
2459 grub_printf("Failed to get wim chunklist\n");
2462 wimsize
= wimfile
->size
;
2464 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", g_wimiso_path
);
2470 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
2472 img_chunk1_size
= g_wimiso_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
2473 img_chunk2_size
= wimchunk
.cur_chunk
* sizeof(ventoy_img_chunk
);
2474 override_size
= sizeof(ventoy_override_chunk
) + g_wimiso_size
;
2476 size
= sizeof(ventoy_chain_head
) + img_chunk1_size
+ img_chunk2_size
+ override_size
;
2478 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
2481 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
2484 debug("free last chain memory %p\n", chain
);
2489 chain
= ventoy_alloc_chain(size
);
2492 grub_printf("Failed to alloc chain win2 memory size %u\n", size
);
2493 grub_file_close(file
);
2497 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
2498 grub_env_set("vtoy_chain_mem_addr", envbuf
);
2499 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
2500 grub_env_set("vtoy_chain_mem_size", envbuf
);
2502 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
2504 /* part 1: os parameter */
2505 g_ventoy_chain_type
= ventoy_chain_wim
;
2506 ventoy_fill_os_param(wimfile
, &(chain
->os_param
));
2508 /* part 2: chain head */
2509 disk
= wimfile
->device
->disk
;
2510 chain
->disk_drive
= disk
->id
;
2511 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
2512 chain
->real_img_size_in_bytes
= ventoy_align_2k(file
->size
) + ventoy_align_2k(wimsize
);
2513 chain
->virt_img_size_in_bytes
= chain
->real_img_size_in_bytes
;
2514 chain
->boot_catalog
= boot_catlog
;
2516 if (!ventoy_is_efi_os())
2518 grub_file_seek(file
, boot_catlog
* 2048);
2519 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
2522 /* part 3: image chunk */
2523 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
2524 chain
->img_chunk_num
= g_wimiso_chunk_list
.cur_chunk
+ wimchunk
.cur_chunk
;
2525 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_wimiso_chunk_list
.chunk
, img_chunk1_size
);
2527 chunknode
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
2528 for (i
= 0; i
< g_wimiso_chunk_list
.cur_chunk
; i
++)
2530 chunknode
->disk_end_sector
= chunknode
->disk_end_sector
- chunknode
->disk_start_sector
;
2531 chunknode
->disk_start_sector
= 0;
2535 /* fs cluster size >= 2048, so don't need to proc align */
2538 chunknode
= wimchunk
.chunk
+ wimchunk
.cur_chunk
- 1;
2539 i
= (chunknode
->disk_end_sector
+ 1 - chunknode
->disk_start_sector
) % 4;
2542 chunknode
->disk_end_sector
+= 4 - i
;
2545 isosector
= (grub_uint32_t
)((file
->size
+ 2047) / 2048);
2546 for (i
= 0; i
< wimchunk
.cur_chunk
; i
++)
2548 chunknode
= wimchunk
.chunk
+ i
;
2549 chunknode
->img_start_sector
= isosector
;
2550 chunknode
->img_end_sector
= chunknode
->img_start_sector
+
2551 ((chunknode
->disk_end_sector
+ 1 - chunknode
->disk_start_sector
) / 4) - 1;
2552 isosector
= chunknode
->img_end_sector
+ 1;
2555 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
+ img_chunk1_size
, wimchunk
.chunk
, img_chunk2_size
);
2557 /* part 4: override chunk */
2558 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk1_size
+ img_chunk2_size
;
2559 chain
->override_chunk_num
= 1;
2561 override
= (ventoy_override_chunk
*)((char *)chain
+ chain
->override_chunk_offset
);
2562 override
->img_offset
= 0;
2563 override
->override_size
= g_wimiso_size
;
2565 grub_file_seek(file
, 0);
2566 grub_file_read(file
, override
->override_data
, file
->size
);
2568 dirent
= (ventoy_iso9660_override
*)(override
->override_data
+ imgoffset
);
2569 dirent
->first_sector
= (grub_uint32_t
)((file
->size
+ 2047) / 2048);
2570 dirent
->size
= (grub_uint32_t
)(wimsize
);
2571 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
2572 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
2574 debug("imgoffset=%u first_sector=0x%x size=0x%x\n", imgoffset
, dirent
->first_sector
, dirent
->size
);
2576 if (ventoy_is_efi_os() == 0)
2578 ventoy_windows_drive_map(chain
, 0);
2581 grub_file_close(file
);
2583 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2586 static grub_err_t
ventoy_normal_wim_chain_data(grub_file_t wimfile
)
2588 grub_uint32_t i
= 0;
2589 grub_uint32_t imgoffset
= 0;
2590 grub_uint32_t size
= 0;
2591 grub_uint32_t isosector
= 0;
2592 grub_uint64_t wimsize
= 0;
2593 grub_uint32_t boot_catlog
= 0;
2594 grub_uint32_t img_chunk1_size
= 0;
2595 grub_uint32_t img_chunk2_size
= 0;
2596 grub_uint32_t override_size
= 0;
2599 const char *pLastChain
= NULL
;
2600 ventoy_chain_head
*chain
;
2601 ventoy_iso9660_override
*dirent
;
2602 ventoy_img_chunk
*chunknode
;
2603 ventoy_override_chunk
*override
;
2604 ventoy_img_chunk_list wimchunk
;
2607 debug("normal wim chain data begin <%s> ...\n", wimfile
->name
);
2609 if (NULL
== g_wimiso_chunk_list
.chunk
|| NULL
== g_wimiso_path
)
2611 grub_printf("ventoy not ready\n");
2615 imgoffset
= ventoy_get_wim_iso_offset(g_wimiso_path
);
2618 grub_printf("image offset not found\n");
2622 if (0 != ventoy_get_wim_chunklist(wimfile
, &wimchunk
))
2624 grub_printf("Failed to get wim chunklist\n");
2627 wimsize
= wimfile
->size
;
2629 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", g_wimiso_path
);
2635 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
2637 img_chunk1_size
= g_wimiso_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
2638 img_chunk2_size
= wimchunk
.cur_chunk
* sizeof(ventoy_img_chunk
);
2639 override_size
= sizeof(ventoy_override_chunk
);
2641 size
= sizeof(ventoy_chain_head
) + img_chunk1_size
+ img_chunk2_size
+ override_size
;
2643 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
2646 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
2649 debug("free last chain memory %p\n", chain
);
2654 chain
= ventoy_alloc_chain(size
);
2657 grub_printf("Failed to alloc chain win3 memory size %u\n", size
);
2658 grub_file_close(file
);
2662 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
2663 grub_env_set("vtoy_chain_mem_addr", envbuf
);
2664 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
2665 grub_env_set("vtoy_chain_mem_size", envbuf
);
2667 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
2669 /* part 1: os parameter */
2670 g_ventoy_chain_type
= ventoy_chain_wim
;
2671 ventoy_fill_os_param(file
, &(chain
->os_param
));
2673 /* part 2: chain head */
2674 disk
= file
->device
->disk
;
2675 chain
->disk_drive
= disk
->id
;
2676 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
2677 chain
->real_img_size_in_bytes
= ventoy_align_2k(file
->size
) + ventoy_align_2k(wimsize
);
2678 chain
->virt_img_size_in_bytes
= chain
->real_img_size_in_bytes
;
2679 chain
->boot_catalog
= boot_catlog
;
2681 if (!ventoy_is_efi_os())
2683 grub_file_seek(file
, boot_catlog
* 2048);
2684 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
2687 /* part 3: image chunk */
2688 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
2689 chain
->img_chunk_num
= g_wimiso_chunk_list
.cur_chunk
+ wimchunk
.cur_chunk
;
2690 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_wimiso_chunk_list
.chunk
, img_chunk1_size
);
2692 /* fs cluster size >= 2048, so don't need to proc align */
2695 chunknode
= wimchunk
.chunk
+ wimchunk
.cur_chunk
- 1;
2696 i
= (chunknode
->disk_end_sector
+ 1 - chunknode
->disk_start_sector
) % 4;
2699 chunknode
->disk_end_sector
+= 4 - i
;
2702 isosector
= (grub_uint32_t
)((file
->size
+ 2047) / 2048);
2703 for (i
= 0; i
< wimchunk
.cur_chunk
; i
++)
2705 chunknode
= wimchunk
.chunk
+ i
;
2706 chunknode
->img_start_sector
= isosector
;
2707 chunknode
->img_end_sector
= chunknode
->img_start_sector
+
2708 ((chunknode
->disk_end_sector
+ 1 - chunknode
->disk_start_sector
) / 4) - 1;
2709 isosector
= chunknode
->img_end_sector
+ 1;
2712 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
+ img_chunk1_size
, wimchunk
.chunk
, img_chunk2_size
);
2714 /* part 4: override chunk */
2715 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk1_size
+ img_chunk2_size
;
2716 chain
->override_chunk_num
= 1;
2718 override
= (ventoy_override_chunk
*)((char *)chain
+ chain
->override_chunk_offset
);
2719 override
->img_offset
= imgoffset
;
2720 override
->override_size
= sizeof(ventoy_iso9660_override
);
2722 dirent
= (ventoy_iso9660_override
*)(override
->override_data
);
2723 dirent
->first_sector
= (grub_uint32_t
)((file
->size
+ 2047) / 2048);
2724 dirent
->size
= (grub_uint32_t
)(wimsize
);
2725 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
2726 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
2728 debug("imgoffset=%u first_sector=0x%x size=0x%x\n", imgoffset
, dirent
->first_sector
, dirent
->size
);
2730 if (ventoy_is_efi_os() == 0)
2732 ventoy_windows_drive_map(chain
, 0);
2735 grub_file_close(file
);
2737 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2740 grub_err_t
ventoy_cmd_wim_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2743 grub_file_t wimfile
;
2748 wimfile
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2756 ret
= ventoy_vlnk_wim_chain_data(wimfile
);
2760 ret
= ventoy_normal_wim_chain_data(wimfile
);
2763 grub_file_close(wimfile
);
2767 int ventoy_chain_file_size(const char *path
)
2772 file
= grub_file_open(path
, VENTOY_FILE_TYPE
);
2773 size
= (int)(file
->size
);
2775 grub_file_close(file
);
2780 int ventoy_chain_file_read(const char *path
, int offset
, int len
, void *buf
)
2785 file
= grub_file_open(path
, VENTOY_FILE_TYPE
);
2786 grub_file_seek(file
, offset
);
2787 size
= grub_file_read(file
, buf
, len
);
2788 grub_file_close(file
);