]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_windows.c
8105e0e3562d64f36d3a0dcf9b56df51a97185bc
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / ventoy / ventoy_windows.c
1 /******************************************************************************
2 * ventoy_windows.c
3 *
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 */
20
21 #include <grub/types.h>
22 #include <grub/misc.h>
23 #include <grub/mm.h>
24 #include <grub/err.h>
25 #include <grub/dl.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>
35 #include <grub/net.h>
36 #include <grub/time.h>
37 #include <grub/crypto.h>
38 #include <grub/ventoy.h>
39 #include "ventoy_def.h"
40
41 GRUB_MOD_LICENSE ("GPLv3+");
42
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;
47
48 static grub_uint64_t g_suppress_wincd_override_offset = 0;
49 static grub_uint32_t g_suppress_wincd_override_data = 0;
50
51 grub_uint8_t g_temp_buf[512];
52
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 );
55
56 static wim_patch *ventoy_find_wim_patch(const char *path)
57 {
58 int len = (int)grub_strlen(path);
59 wim_patch *node = g_wim_patch_head;
60
61 while (node)
62 {
63 if (len == node->pathlen && 0 == grub_strcmp(path, node->path))
64 {
65 return node;
66 }
67 node = node->next;
68 }
69
70 return NULL;
71 }
72
73 static int ventoy_collect_wim_patch(const char *bcdfile)
74 {
75 int i, j, k;
76 int rc = 1;
77 grub_uint64_t magic;
78 grub_file_t file = NULL;
79 char *buf = NULL;
80 wim_patch *node = NULL;
81 char c;
82 grub_uint8_t byte;
83 char valid;
84 char path[256];
85
86 g_ventoy_case_insensitive = 1;
87 file = grub_file_open(bcdfile, VENTOY_FILE_TYPE);
88 g_ventoy_case_insensitive = 0;
89 if (!file)
90 {
91 debug("Failed to open file %s\n", bcdfile);
92 grub_errno = 0;
93 goto end;
94 }
95
96 buf = grub_malloc(file->size + 8);
97 if (!buf)
98 {
99 goto end;
100 }
101
102 grub_file_read(file, buf, file->size);
103
104 for (i = 0; i < (int)file->size - 8; i++)
105 {
106 if (buf[i + 8] != 0)
107 {
108 continue;
109 }
110
111 magic = *(grub_uint64_t *)(buf + i);
112
113 /* .wim .WIM .Wim */
114 if ((magic == 0x006D00690077002EULL) ||
115 (magic == 0x004D00490057002EULL) ||
116 (magic == 0x006D00690057002EULL))
117 {
118 for (j = i; j > 0; j-= 2)
119 {
120 if (*(grub_uint16_t *)(buf + j) == 0)
121 {
122 break;
123 }
124 }
125
126 if (j > 0)
127 {
128 byte = (grub_uint8_t)(*(grub_uint16_t *)(buf + j + 2));
129 if (byte != '/' && byte != '\\')
130 {
131 continue;
132 }
133
134 valid = 1;
135 for (k = 0, j += 2; k < (int)sizeof(path) - 1 && j < i + 8; j += 2)
136 {
137 byte = (grub_uint8_t)(*(grub_uint16_t *)(buf + j));
138 c = (char)byte;
139 if (byte > '~' || byte < ' ') /* not printable */
140 {
141 valid = 0;
142 break;
143 }
144 else if (c == '\\')
145 {
146 c = '/';
147 }
148
149 path[k++] = c;
150 }
151 path[k++] = 0;
152
153 debug("@@@@ Find wim flag:<%s>\n", path);
154
155 if (0 == valid)
156 {
157 debug("Invalid wim file %d\n", k);
158 }
159 else if (NULL == ventoy_find_wim_patch(path))
160 {
161 node = grub_zalloc(sizeof(wim_patch));
162 if (node)
163 {
164 node->pathlen = grub_snprintf(node->path, sizeof(node->path), "%s", path);
165
166 debug("add patch <%s>\n", path);
167
168 if (g_wim_patch_head)
169 {
170 node->next = g_wim_patch_head;
171 }
172 g_wim_patch_head = node;
173
174 g_wim_total_patch_count++;
175 }
176 }
177 else
178 {
179 debug("wim <%s> already exist\n", path);
180 }
181 }
182 }
183 }
184
185 end:
186 check_free(file, grub_file_close);
187 grub_check_free(buf);
188 return rc;
189 }
190
191 grub_err_t ventoy_cmd_wim_patch_count(grub_extcmd_context_t ctxt, int argc, char **args)
192 {
193 char buf[32];
194
195 (void)ctxt;
196 (void)argc;
197 (void)args;
198
199 if (argc == 1)
200 {
201 grub_snprintf(buf, sizeof(buf), "%d", g_wim_total_patch_count);
202 ventoy_set_env(args[0], buf);
203 }
204
205 return 0;
206 }
207
208 grub_err_t ventoy_cmd_collect_wim_patch(grub_extcmd_context_t ctxt, int argc, char **args)
209 {
210 wim_patch *node = NULL;
211
212 (void)ctxt;
213 (void)argc;
214 (void)args;
215
216 if (argc != 2)
217 {
218 return 1;
219 }
220
221 debug("ventoy_cmd_collect_wim_patch %s %s\n", args[0], args[1]);
222
223 if (grub_strcmp(args[0], "bcd") == 0)
224 {
225 ventoy_collect_wim_patch(args[1]);
226 return 0;
227 }
228
229 if (NULL == ventoy_find_wim_patch(args[1]))
230 {
231 node = grub_zalloc(sizeof(wim_patch));
232 if (node)
233 {
234 node->pathlen = grub_snprintf(node->path, sizeof(node->path), "%s", args[1]);
235
236 debug("add patch <%s>\n", args[1]);
237
238 if (g_wim_patch_head)
239 {
240 node->next = g_wim_patch_head;
241 }
242 g_wim_patch_head = node;
243
244 g_wim_total_patch_count++;
245 }
246 }
247
248 return 0;
249 }
250
251
252 grub_err_t ventoy_cmd_dump_wim_patch(grub_extcmd_context_t ctxt, int argc, char **args)
253 {
254 int i = 0;
255 wim_patch *node = NULL;
256
257 (void)ctxt;
258 (void)argc;
259 (void)args;
260
261 for (node = g_wim_patch_head; node; node = node->next)
262 {
263 grub_printf("%d %s [%s]\n", i++, node->path, node->valid ? "SUCCESS" : "FAIL");
264 }
265
266 return 0;
267 }
268
269
270 static int wim_name_cmp(const char *search, grub_uint16_t *name, grub_uint16_t namelen)
271 {
272 char c1 = vtoy_to_upper(*search);
273 char c2 = vtoy_to_upper(*name);
274
275 while (namelen > 0 && (c1 == c2))
276 {
277 search++;
278 name++;
279 namelen--;
280
281 c1 = vtoy_to_upper(*search);
282 c2 = vtoy_to_upper(*name);
283 }
284
285 if (namelen == 0 && *search == 0)
286 {
287 return 0;
288 }
289
290 return 1;
291 }
292
293 static int ventoy_is_pe64(grub_uint8_t *buffer)
294 {
295 grub_uint32_t pe_off;
296
297 if (buffer[0] != 'M' || buffer[1] != 'Z')
298 {
299 return 0;
300 }
301
302 pe_off = *(grub_uint32_t *)(buffer + 60);
303
304 if (buffer[pe_off] != 'P' || buffer[pe_off + 1] != 'E')
305 {
306 return 0;
307 }
308
309 if (*(grub_uint16_t *)(buffer + pe_off + 24) == 0x020b)
310 {
311 return 1;
312 }
313
314 return 0;
315 }
316
317 grub_err_t ventoy_cmd_is_pe64(grub_extcmd_context_t ctxt, int argc, char **args)
318 {
319 int ret = 1;
320 grub_file_t file;
321 grub_uint8_t buf[512];
322
323 (void)ctxt;
324 (void)argc;
325
326 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
327 if (!file)
328 {
329 return 1;
330 }
331
332 grub_memset(buf, 0, 512);
333 grub_file_read(file, buf, 512);
334 if (ventoy_is_pe64(buf))
335 {
336 debug("%s is PE64\n", args[0]);
337 ret = 0;
338 }
339 else
340 {
341 debug("%s is PE32\n", args[0]);
342 }
343 grub_file_close(file);
344
345 return ret;
346 }
347
348 grub_err_t ventoy_cmd_sel_wimboot(grub_extcmd_context_t ctxt, int argc, char **args)
349 {
350 int size;
351 char *buf = NULL;
352 char configfile[128];
353
354 (void)ctxt;
355 (void)argc;
356 (void)args;
357
358 debug("select wimboot argc:%d\n", argc);
359
360 buf = (char *)grub_malloc(8192);
361 if (!buf)
362 {
363 return 0;
364 }
365
366 size = (int)grub_snprintf(buf, 8192,
367 "menuentry \"Windows Setup (32-bit)\" {\n"
368 " set vtoy_wimboot_sel=32\n"
369 "}\n"
370 "menuentry \"Windows Setup (64-bit)\" {\n"
371 " set vtoy_wimboot_sel=64\n"
372 "}\n"
373 );
374 buf[size] = 0;
375
376 g_ventoy_menu_esc = 1;
377 g_ventoy_suppress_esc = 1;
378 g_ventoy_suppress_esc_default = 1;
379
380 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, size);
381 grub_script_execute_sourcecode(configfile);
382
383 g_ventoy_menu_esc = 0;
384 g_ventoy_suppress_esc = 0;
385
386 grub_free(buf);
387
388 if (g_ventoy_last_entry == 0)
389 {
390 debug("last entry=%d %s=32\n", g_ventoy_last_entry, args[0]);
391 grub_env_set(args[0], "32");
392 }
393 else
394 {
395 debug("last entry=%d %s=64\n", g_ventoy_last_entry, args[0]);
396 grub_env_set(args[0], "64");
397 }
398
399 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
400 }
401
402 grub_err_t ventoy_cmd_wimdows_reset(grub_extcmd_context_t ctxt, int argc, char **args)
403 {
404 wim_patch *next = NULL;
405 wim_patch *node = g_wim_patch_head;
406
407 (void)ctxt;
408 (void)argc;
409 (void)args;
410
411 while (node)
412 {
413 next = node->next;
414 grub_free(node);
415 node = next;
416 }
417
418 g_wim_patch_head = NULL;
419 g_wim_total_patch_count = 0;
420 g_wim_valid_patch_count = 0;
421
422 return 0;
423 }
424
425 static int ventoy_load_jump_exe(const char *path, grub_uint8_t **data, grub_uint32_t *size, wim_hash *hash)
426 {
427 grub_uint32_t i;
428 grub_uint32_t align;
429 grub_file_t file;
430
431 debug("windows load jump %s\n", path);
432
433 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", path);
434 if (!file)
435 {
436 debug("Can't open file %s\n", path);
437 return 1;
438 }
439
440 align = ventoy_align((int)file->size, 2048);
441
442 debug("file %s size:%d align:%u\n", path, (int)file->size, align);
443
444 *size = (grub_uint32_t)file->size;
445 *data = (grub_uint8_t *)grub_malloc(align);
446 if ((*data) == NULL)
447 {
448 debug("Failed to alloc memory size %u\n", align);
449 goto end;
450 }
451
452 grub_file_read(file, (*data), file->size);
453
454 if (hash)
455 {
456 grub_crypto_hash(GRUB_MD_SHA1, hash->sha1, (*data), file->size);
457
458 if (g_ventoy_debug)
459 {
460 debug("%s", "jump bin 64 hash: ");
461 for (i = 0; i < sizeof(hash->sha1); i++)
462 {
463 ventoy_debug("%02x ", hash->sha1[i]);
464 }
465 ventoy_debug("\n");
466 }
467 }
468
469 end:
470
471 grub_file_close(file);
472 return 0;
473 }
474
475 static int ventoy_get_override_info(grub_file_t file, wim_tail *wim_data)
476 {
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;
482
483 if (grub_strcmp(file->fs->name, "iso9660") == 0)
484 {
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;
488
489 grub_file_read(file, &start_block, 1); // just read for hook trigger
490 file_offset = grub_iso9660_get_last_read_pos(file);
491
492 debug("iso9660 wim size:%llu override_offset:%llu file_offset:%llu\n",
493 (ulonglong)file->size, (ulonglong)override_offset, (ulonglong)file_offset);
494 }
495 else
496 {
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);
500
501 file_offset = grub_udf_get_file_offset(file);
502
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);
505 }
506
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;
512
513 return 0;
514 }
515
516 static int ventoy_read_resource(grub_file_t fp, wim_header *wimhdr, wim_resource_header *head, void **buffer)
517 {
518 int decompress_len = 0;
519 int total_decompress = 0;
520 grub_uint32_t i = 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;
530
531 buffer_decompress = (grub_uint8_t *)grub_malloc(head->raw_size + head->size_in_wim);
532 if (NULL == buffer_decompress)
533 {
534 return 0;
535 }
536
537 grub_file_seek(fp, head->offset);
538
539 if (head->size_in_wim == head->raw_size)
540 {
541 grub_file_read(fp, buffer_decompress, head->size_in_wim);
542 *buffer = buffer_decompress;
543 return 0;
544 }
545
546 buffer_compress = buffer_decompress + head->raw_size;
547 grub_file_read(fp, buffer_compress, head->size_in_wim);
548
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;
552
553 //debug("%llu %llu chunk_num=%lu", (ulonglong)head->size_in_wim, (ulonglong)head->raw_size, chunk_num);
554
555 cur_dst = buffer_decompress;
556
557 for (i = 0; i < chunk_num - 1; i++)
558 {
559 chunk_size = (i == 0) ? chunk_offset[i] : chunk_offset[i] - chunk_offset[i - 1];
560
561 if (WIM_CHUNK_LEN == chunk_size)
562 {
563 grub_memcpy(cur_dst, buffer_compress + cur_offset, chunk_size);
564 decompress_len = (int)chunk_size;
565 }
566 else
567 {
568 if (wimhdr->flags & FLAG_HEADER_COMPRESS_XPRESS)
569 {
570 decompress_len = (int)xca_decompress(buffer_compress + cur_offset, chunk_size, cur_dst);
571 }
572 else
573 {
574 decompress_len = (int)lzx_decompress(buffer_compress + cur_offset, chunk_size, cur_dst);
575 }
576 }
577
578 //debug("chunk_size:%u decompresslen:%d\n", chunk_size, decompress_len);
579
580 total_decompress += decompress_len;
581 cur_dst += decompress_len;
582 cur_offset += chunk_size;
583 }
584
585 /* last chunk */
586 last_chunk_size = (grub_uint32_t)(head->size_in_wim - cur_offset);
587 last_decompress_size = head->raw_size - total_decompress;
588
589 if (last_chunk_size < WIM_CHUNK_LEN && last_chunk_size == last_decompress_size)
590 {
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;
594 }
595 else
596 {
597 if (wimhdr->flags & FLAG_HEADER_COMPRESS_XPRESS)
598 {
599 decompress_len = (int)xca_decompress(buffer_compress + cur_offset, head->size_in_wim - cur_offset, cur_dst);
600 }
601 else
602 {
603 decompress_len = (int)lzx_decompress(buffer_compress + cur_offset, head->size_in_wim - cur_offset, cur_dst);
604 }
605 }
606
607 cur_dst += decompress_len;
608 total_decompress += decompress_len;
609
610 //debug("last chunk_size:%u decompresslen:%d tot:%d\n", last_chunk_size, decompress_len, total_decompress);
611
612 if (cur_dst != buffer_decompress + head->raw_size)
613 {
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);
617 return 1;
618 }
619
620 *buffer = buffer_decompress;
621 return 0;
622 }
623
624
625 static wim_directory_entry * search_wim_dirent(wim_directory_entry *dir, const char *search_name)
626 {
627 do
628 {
629 if (dir->len && dir->name_len)
630 {
631 if (wim_name_cmp(search_name, (grub_uint16_t *)(dir + 1), dir->name_len / 2) == 0)
632 {
633 return dir;
634 }
635 }
636 dir = (wim_directory_entry *)((grub_uint8_t *)dir + dir->len);
637 } while(dir->len);
638
639 return NULL;
640 }
641
642 static wim_directory_entry * search_full_wim_dirent
643 (
644 void *meta_data,
645 wim_directory_entry *dir,
646 const char **path
647 )
648 {
649 wim_directory_entry *subdir = NULL;
650 wim_directory_entry *search = dir;
651
652 while (*path)
653 {
654 subdir = (wim_directory_entry *)((char *)meta_data + search->subdir);
655 search = search_wim_dirent(subdir, *path);
656 path++;
657 }
658
659 return search;
660 }
661
662
663
664 static wim_lookup_entry * ventoy_find_look_entry(wim_header *header, wim_lookup_entry *lookup, wim_hash *hash)
665 {
666 grub_uint32_t i = 0;
667
668 for (i = 0; i < (grub_uint32_t)header->lookup.raw_size / sizeof(wim_lookup_entry); i++)
669 {
670 if (grub_memcmp(&lookup[i].hash, hash, sizeof(wim_hash)) == 0)
671 {
672 return lookup + i;
673 }
674 }
675
676 return NULL;
677 }
678
679 static int parse_registry_setup_cmdline
680 (
681 grub_file_t file,
682 wim_header *head,
683 wim_lookup_entry *lookup,
684 void *meta_data,
685 wim_directory_entry *dir,
686 char *buf,
687 grub_uint32_t buflen
688 )
689 {
690 char c;
691 int ret = 0;
692 grub_uint32_t i = 0;
693 grub_uint32_t reglen = 0;
694 wim_hash zerohash;
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 };
700
701 wim_dirent = search_full_wim_dirent(meta_data, dir, reg_path);
702 debug("search reg SYSTEM %p\n", wim_dirent);
703 if (!wim_dirent)
704 {
705 return 1;
706 }
707
708 grub_memset(&zerohash, 0, sizeof(zerohash));
709 if (grub_memcmp(&zerohash, wim_dirent->hash.sha1, sizeof(wim_hash)) == 0)
710 {
711 return 2;
712 }
713
714 look = ventoy_find_look_entry(head, lookup, &wim_dirent->hash);
715 if (!look)
716 {
717 return 3;
718 }
719
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);
723
724 if (0 != ventoy_read_resource(file, head, &(look->resource), (void **)&(decompress_data)))
725 {
726 return 4;
727 }
728
729 if (grub_strncmp(decompress_data + 0x1000, "hbin", 4))
730 {
731 ret_goto_end(5);
732 }
733
734 for (i = 0x1000; i + sizeof(reg_vk) < reglen; i += 8)
735 {
736 regvk = (reg_vk *)(decompress_data + i);
737 if (regvk->sig == 0x6B76 && regvk->namesize == 7 &&
738 regvk->datatype == 1 && regvk->flag == 1)
739 {
740 if (grub_strncasecmp((char *)(regvk + 1), "cmdline", 7) == 0)
741 {
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);
744 break;
745 }
746 }
747 }
748
749 if (i + sizeof(reg_vk) >= reglen || regvk == NULL)
750 {
751 ret_goto_end(6);
752 }
753
754 if (regvk->datasize == 0 || (regvk->datasize & 0x80000000) > 0 ||
755 regvk->dataoffset == 0 || regvk->dataoffset == 0xFFFFFFFF)
756 {
757 ret_goto_end(7);
758 }
759
760 if (regvk->datasize / 2 >= buflen)
761 {
762 ret_goto_end(8);
763 }
764
765 debug("start offset is 0x%x(%u)\n", 0x1000 + regvk->dataoffset + 4, 0x1000 + regvk->dataoffset + 4);
766
767 for (i = 0; i < regvk->datasize; i+=2)
768 {
769 c = (char)(*(grub_uint16_t *)(decompress_data + 0x1000 + regvk->dataoffset + 4 + i));
770 *buf++ = c;
771 }
772
773 ret = 0;
774
775 end:
776 grub_check_free(decompress_data);
777 return ret;
778 }
779
780 static int parse_custom_setup_path(char *cmdline, const char **path, char *exefile)
781 {
782 int i = 0;
783 int len = 0;
784 char *pos1 = NULL;
785 char *pos2 = NULL;
786
787 if ((cmdline[0] == 'x' || cmdline[0] == 'X') && cmdline[1] == ':')
788 {
789 pos1 = pos2 = cmdline + 3;
790
791 while (i < VTOY_MAX_DIR_DEPTH && *pos2)
792 {
793 while (*pos2 && *pos2 != '\\' && *pos2 != '/')
794 {
795 pos2++;
796 }
797
798 path[i++] = pos1;
799
800 if (*pos2 == 0)
801 {
802 break;
803 }
804
805 *pos2 = 0;
806 pos1 = pos2 + 1;
807 pos2 = pos1;
808 }
809
810 if (i == 0 || i >= VTOY_MAX_DIR_DEPTH)
811 {
812 return 1;
813 }
814 }
815 else
816 {
817 path[i++] = "Windows";
818 path[i++] = "System32";
819 path[i++] = cmdline;
820 }
821
822 pos1 = (char *)path[i - 1];
823 while (*pos1 != ' ' && *pos1 != '\t' && *pos1)
824 {
825 pos1++;
826 }
827 *pos1 = 0;
828
829 len = (int)grub_strlen(path[i - 1]);
830 if (len < 4 || grub_strcasecmp(path[i - 1] + len - 4, ".exe") != 0)
831 {
832 grub_snprintf(exefile, 256, "%s.exe", path[i - 1]);
833 path[i - 1] = exefile;
834 }
835
836
837 debug("custom setup: %d <%s>\n", i, path[i - 1]);
838 return 0;
839 }
840
841 static wim_directory_entry * search_replace_wim_dirent
842 (
843 grub_file_t file,
844 wim_header *head,
845 wim_lookup_entry *lookup,
846 void *meta_data,
847 wim_directory_entry *dir
848 )
849 {
850 int ret;
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 };
859
860 pecmd_dirent = search_full_wim_dirent(meta_data, dir, pecmd_path);
861 debug("search pecmd.exe %p\n", pecmd_dirent);
862
863 if (pecmd_dirent)
864 {
865 ret = parse_registry_setup_cmdline(file, head, lookup, meta_data, dir, cmdline, sizeof(cmdline) - 1);
866 if (0 == ret)
867 {
868 debug("registry setup cmdline:<%s>\n", cmdline);
869
870 if (grub_strncasecmp(cmdline, "PECMD", 5) == 0)
871 {
872 wim_dirent = pecmd_dirent;
873 }
874 else if (grub_strncasecmp(cmdline, "PESET", 5) == 0)
875 {
876 wim_dirent = search_full_wim_dirent(meta_data, dir, peset_path);
877 debug("search peset.exe %p\n", wim_dirent);
878 }
879 else if (grub_strncasecmp(cmdline, "WINPESHL", 8) == 0)
880 {
881 wim_dirent = search_full_wim_dirent(meta_data, dir, winpeshl_path);
882 debug("search winpeshl.exe %p\n", wim_dirent);
883 }
884 else if (0 == parse_custom_setup_path(cmdline, custom_path, exefile))
885 {
886 wim_dirent = search_full_wim_dirent(meta_data, dir, custom_path);
887 debug("search custom path %p\n", wim_dirent);
888 }
889
890 if (wim_dirent)
891 {
892 return wim_dirent;
893 }
894 }
895 else
896 {
897 debug("registry setup cmdline failed : %d\n", ret);
898 }
899 }
900
901 wim_dirent = pecmd_dirent;
902 if (wim_dirent)
903 {
904 return wim_dirent;
905 }
906
907 wim_dirent = search_full_wim_dirent(meta_data, dir, winpeshl_path);
908 debug("search winpeshl.exe %p\n", wim_dirent);
909 if (wim_dirent)
910 {
911 return wim_dirent;
912 }
913
914 return NULL;
915 }
916
917
918 static wim_lookup_entry * ventoy_find_meta_entry(wim_header *header, wim_lookup_entry *lookup)
919 {
920 grub_uint32_t i = 0;
921 grub_uint32_t index = 0;;
922
923 if ((header == NULL) || (lookup == NULL))
924 {
925 return NULL;
926 }
927
928 for (i = 0; i < (grub_uint32_t)header->lookup.raw_size / sizeof(wim_lookup_entry); i++)
929 {
930 if (lookup[i].resource.flags & RESHDR_FLAG_METADATA)
931 {
932 index++;
933 if (index == header->boot_index)
934 {
935 return lookup + i;
936 }
937 }
938 }
939
940 return NULL;
941 }
942
943 static grub_uint64_t ventoy_get_stream_len(wim_directory_entry *dir)
944 {
945 grub_uint16_t i;
946 grub_uint64_t offset = 0;
947 wim_stream_entry *stream = (wim_stream_entry *)((char *)dir + dir->len);
948
949 for (i = 0; i < dir->streams; i++)
950 {
951 offset += stream->len;
952 stream = (wim_stream_entry *)((char *)stream + stream->len);
953 }
954
955 return offset;
956 }
957
958 static int ventoy_update_stream_hash(wim_patch *patch, wim_directory_entry *dir)
959 {
960 grub_uint16_t i;
961 grub_uint64_t offset = 0;
962 wim_stream_entry *stream = (wim_stream_entry *)((char *)dir + dir->len);
963
964 for (i = 0; i < dir->streams; i++)
965 {
966 if (grub_memcmp(stream->hash.sha1, patch->old_hash.sha1, sizeof(wim_hash)) == 0)
967 {
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));
970 }
971
972 offset += stream->len;
973 stream = (wim_stream_entry *)((char *)stream + stream->len);
974 }
975
976 return offset;
977 }
978
979 static int ventoy_update_all_hash(wim_patch *patch, void *meta_data, wim_directory_entry *dir)
980 {
981 if ((meta_data == NULL) || (dir == NULL))
982 {
983 return 0;
984 }
985
986 if (dir->len < sizeof(wim_directory_entry))
987 {
988 return 0;
989 }
990
991 do
992 {
993 if (dir->subdir == 0 && grub_memcmp(dir->hash.sha1, patch->old_hash.sha1, sizeof(wim_hash)) == 0)
994 {
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));
997 }
998
999 if (dir->subdir)
1000 {
1001 ventoy_update_all_hash(patch, meta_data, (wim_directory_entry *)((char *)meta_data + dir->subdir));
1002 }
1003
1004 if (dir->streams)
1005 {
1006 ventoy_update_stream_hash(patch, dir);
1007 dir = (wim_directory_entry *)((char *)dir + dir->len + ventoy_get_stream_len(dir));
1008 }
1009 else
1010 {
1011 dir = (wim_directory_entry *)((char *)dir + dir->len);
1012 }
1013 } while (dir->len >= sizeof(wim_directory_entry));
1014
1015 return 0;
1016 }
1017
1018 static int ventoy_cat_exe_file_data(wim_tail *wim_data, grub_uint32_t exe_len, grub_uint8_t *exe_data, int windatalen)
1019 {
1020 int pe64 = 0;
1021 char file[256];
1022 grub_uint32_t jump_len = 0;
1023 grub_uint32_t jump_align = 0;
1024 grub_uint8_t *jump_data = NULL;
1025
1026 pe64 = ventoy_is_pe64(exe_data);
1027
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);
1031
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);
1035
1036 wim_data->jump_bin_data = grub_malloc(wim_data->bin_align_len);
1037 if (wim_data->jump_bin_data)
1038 {
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);
1041 }
1042
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);
1045
1046 return 0;
1047 }
1048
1049 static int ventoy_get_windows_rtdata_len(const char *iso, int *flag)
1050 {
1051 int size = 0;
1052 int template_file_len = 0;
1053 char *pos = NULL;
1054 char *script = NULL;
1055 install_template *template_node = NULL;
1056
1057 *flag = 0;
1058 size = (int)sizeof(ventoy_windows_data);
1059
1060 pos = grub_strstr(iso, "/");
1061 if (!pos)
1062 {
1063 return size;
1064 }
1065
1066 script = ventoy_plugin_get_cur_install_template(pos, &template_node);
1067 if (script)
1068 {
1069 (*flag) |= WINDATA_FLAG_TEMPLATE;
1070 template_file_len = template_node->filelen;
1071 }
1072
1073 return size + template_file_len;
1074 }
1075
1076 static int ventoy_fill_windows_rtdata(void *buf, char *isopath, int dataflag)
1077 {
1078 int template_len = 0;
1079 char *pos = NULL;
1080 char *end = NULL;
1081 char *script = NULL;
1082 const char *env = NULL;
1083 install_template *template_node = NULL;
1084 ventoy_windows_data *data = (ventoy_windows_data *)buf;
1085
1086 grub_memset(data, 0, sizeof(ventoy_windows_data));
1087
1088 env = grub_env_get("VTOY_WIN11_BYPASS_CHECK");
1089 if (env && env[0] == '1' && env[1] == 0)
1090 {
1091 data->windows11_bypass_check = 1;
1092 }
1093
1094 pos = grub_strstr(isopath, "/");
1095 if (!pos)
1096 {
1097 return 1;
1098 }
1099
1100 if (dataflag & WINDATA_FLAG_TEMPLATE)
1101 {
1102 script = ventoy_plugin_get_cur_install_template(pos, &template_node);
1103 if (script)
1104 {
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);
1110 }
1111 }
1112 else
1113 {
1114 debug("auto install script skipped or not configed %s\n", pos);
1115 }
1116
1117 script = (char *)ventoy_plugin_get_injection(pos);
1118 if (script)
1119 {
1120 if (ventoy_check_file_exist("%s%s", ventoy_get_env("vtoy_iso_part"), script))
1121 {
1122 debug("injection archive <%s> OK\n", script);
1123 grub_snprintf(data->injection_archive, sizeof(data->injection_archive) - 1, "%s", script);
1124 }
1125 else
1126 {
1127 debug("injection archive <%s> NOT exist\n", script);
1128 }
1129 }
1130 else
1131 {
1132 debug("injection archive not configed %s\n", pos);
1133 }
1134
1135 return 0;
1136 }
1137
1138 static int ventoy_update_before_chain(ventoy_os_param *param, char *isopath)
1139 {
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;
1148
1149 for (node = g_wim_patch_head; node; node = node->next)
1150 {
1151 if (0 == node->valid)
1152 {
1153 continue;
1154 }
1155
1156 wim_data = &node->wim_data;
1157 head = &wim_data->wim_header;
1158 lookup = (wim_lookup_entry *)wim_data->new_lookup_data;
1159
1160 jump_align = ventoy_align(wim_data->jump_exe_len, 16);
1161 if (wim_data->jump_bin_data)
1162 {
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);
1165 }
1166
1167 grub_crypto_hash(GRUB_MD_SHA1, wim_data->bin_hash.sha1, wim_data->jump_bin_data, wim_data->bin_raw_len);
1168
1169 security = (wim_security_header *)wim_data->new_meta_data;
1170 if (security->len > 0)
1171 {
1172 rootdir = (wim_directory_entry *)(wim_data->new_meta_data + ((security->len + 7) & 0xFFFFFFF8U));
1173 }
1174 else
1175 {
1176 rootdir = (wim_directory_entry *)(wim_data->new_meta_data + 8);
1177 }
1178
1179 /* update all winpeshl.exe dirent entry's hash */
1180 ventoy_update_all_hash(node, wim_data->new_meta_data, rootdir);
1181
1182 /* update winpeshl.exe lookup entry data (hash/offset/length) */
1183 if (node->replace_look)
1184 {
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;
1190
1191 grub_memcpy(node->replace_look->hash.sha1, wim_data->bin_hash.sha1, sizeof(wim_hash));
1192 }
1193
1194 /* update metadata's hash */
1195 meta_look = ventoy_find_meta_entry(head, lookup);
1196 if (meta_look)
1197 {
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);
1201 }
1202 }
1203
1204 return 0;
1205 }
1206
1207 static int ventoy_wimdows_locate_wim(const char *disk, wim_patch *patch, int windatalen)
1208 {
1209 int rc;
1210 grub_uint16_t i;
1211 grub_file_t file;
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;
1222
1223 debug("windows locate wim start %s\n", patch->path);
1224
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;
1228
1229 if (!file)
1230 {
1231 debug("File %s%s NOT exist\n", disk, patch->path);
1232 return 1;
1233 }
1234
1235 ventoy_get_override_info(file, &patch->wim_data);
1236
1237 grub_file_seek(file, 0);
1238 grub_file_read(file, head, sizeof(wim_header));
1239
1240 if (grub_memcmp(head->signature, WIM_HEAD_SIGNATURE, sizeof(head->signature)))
1241 {
1242 debug("Not a valid wim file %s\n", (char *)head->signature);
1243 grub_file_close(file);
1244 return 1;
1245 }
1246
1247 if (head->flags & FLAG_HEADER_COMPRESS_LZMS)
1248 {
1249 debug("LZMS compress is not supported 0x%x\n", head->flags);
1250 grub_file_close(file);
1251 return 1;
1252 }
1253
1254 rc = ventoy_read_resource(file, head, &head->metadata, (void **)&decompress_data);
1255 if (rc)
1256 {
1257 grub_printf("failed to read meta data %d\n", rc);
1258 grub_file_close(file);
1259 return 1;
1260 }
1261
1262 security = (wim_security_header *)decompress_data;
1263 if (security->len > 0)
1264 {
1265 rootdir = (wim_directory_entry *)(decompress_data + ((security->len + 7) & 0xFFFFFFF8U));
1266 }
1267 else
1268 {
1269 rootdir = (wim_directory_entry *)(decompress_data + 8);
1270 }
1271
1272
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);
1277
1278
1279
1280 /* search winpeshl.exe dirent entry */
1281 search = search_replace_wim_dirent(file, head, lookup, decompress_data, rootdir);
1282 if (!search)
1283 {
1284 debug("Failed to find replace file %p\n", search);
1285 grub_file_close(file);
1286 return 1;
1287 }
1288
1289 debug("find replace file at %p\n", search);
1290
1291 grub_memset(&patch->old_hash, 0, sizeof(wim_hash));
1292 if (grub_memcmp(&patch->old_hash, search->hash.sha1, sizeof(wim_hash)) == 0)
1293 {
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++)
1297 {
1298 if (stream->name_len == 0)
1299 {
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));
1303 break;
1304 }
1305 stream = (wim_stream_entry *)((char *)stream + stream->len);
1306 }
1307 }
1308 else
1309 {
1310 grub_memcpy(&patch->old_hash, search->hash.sha1, sizeof(wim_hash));
1311 }
1312
1313
1314 /* find and extact winpeshl.exe */
1315 patch->replace_look = ventoy_find_look_entry(head, lookup, &patch->old_hash);
1316 if (patch->replace_look)
1317 {
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);
1321
1322 if (0 == ventoy_read_resource(file, head, &(patch->replace_look->resource), (void **)&(exe_data)))
1323 {
1324 ventoy_cat_exe_file_data(wim_data, exe_len, exe_data, windatalen);
1325 grub_free(exe_data);
1326 }
1327 else
1328 {
1329 debug("failed to read replace file meta data %u\n", exe_len);
1330 }
1331 }
1332 else
1333 {
1334 debug("failed to find lookup entry for replace file %02x %02x %02x %02x\n",
1335 ventoy_varg_4(patch->old_hash.sha1));
1336 }
1337
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);
1340
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);
1345
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);
1350
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;
1355
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;
1360
1361 grub_file_close(file);
1362
1363 debug("%s", "windows locate wim finish\n");
1364 return 0;
1365 }
1366
1367 grub_err_t ventoy_cmd_sel_winpe_wim(grub_extcmd_context_t ctxt, int argc, char **args)
1368 {
1369 int i = 0;
1370 int pos = 0;
1371 int len = 0;
1372 int find = 0;
1373 char *cmd = NULL;
1374 wim_patch *node = NULL;
1375 wim_patch *tmp = NULL;
1376 grub_file_t file = NULL;
1377 wim_header *head = NULL;
1378 char cfgfile[128];
1379
1380 (void)ctxt;
1381 (void)argc;
1382
1383 len = 8 * VTOY_SIZE_1KB;
1384 cmd = (char *)grub_malloc(len + sizeof(wim_header));
1385 if (!cmd)
1386 {
1387 return 1;
1388 }
1389
1390 head = (wim_header *)(cmd + len);
1391 grub_env_unset("vtoy_pe_wim_path");
1392
1393 for (node = g_wim_patch_head; node; node = node->next)
1394 {
1395 find = 0;
1396 for (tmp = g_wim_patch_head; tmp != node; tmp = tmp->next)
1397 {
1398 if (tmp->valid && grub_strcasecmp(tmp->path, node->path) == 0)
1399 {
1400 find = 1;
1401 break;
1402 }
1403 }
1404
1405 if (find)
1406 {
1407 continue;
1408 }
1409
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;
1413 if (!file)
1414 {
1415 debug("File %s%s NOT exist\n", args[0], node->path);
1416 continue;
1417 }
1418
1419 grub_file_read(file, head, sizeof(wim_header));
1420 if (grub_memcmp(head->signature, WIM_HEAD_SIGNATURE, sizeof(head->signature)))
1421 {
1422 debug("Not a valid wim file %s\n", (char *)head->signature);
1423 grub_file_close(file);
1424 continue;
1425 }
1426
1427 if (head->flags & FLAG_HEADER_COMPRESS_LZMS)
1428 {
1429 debug("LZMS compress is not supported 0x%x\n", head->flags);
1430 grub_file_close(file);
1431 continue;
1432 }
1433
1434 grub_file_close(file);
1435 node->valid = 1;
1436
1437 vtoy_len_ssprintf(cmd, pos, len, "menuentry \"%s\" --class=\"sel_wim\" {\n echo \"\"\n}\n", node->path);
1438 }
1439
1440 if (pos > 0)
1441 {
1442 g_ventoy_menu_esc = 1;
1443 g_ventoy_suppress_esc = 1;
1444 g_ventoy_suppress_esc_default = 0;
1445
1446 grub_snprintf(cfgfile, sizeof(cfgfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)cmd, pos);
1447 grub_script_execute_sourcecode(cfgfile);
1448
1449 g_ventoy_menu_esc = 0;
1450 g_ventoy_suppress_esc = 0;
1451 g_ventoy_suppress_esc_default = 1;
1452
1453 for (node = g_wim_patch_head; node; node = node->next)
1454 {
1455 if (node->valid)
1456 {
1457 if (i == g_ventoy_last_entry)
1458 {
1459 grub_env_set("vtoy_pe_wim_path", node->path);
1460 break;
1461 }
1462 i++;
1463 }
1464 }
1465 }
1466
1467 grub_free(cmd);
1468 return 0;
1469 }
1470
1471 grub_err_t ventoy_cmd_locate_wim_patch(grub_extcmd_context_t ctxt, int argc, char **args)
1472 {
1473 int datalen = 0;
1474 int dataflag = 0;
1475 wim_patch *node = g_wim_patch_head;
1476
1477 (void)ctxt;
1478 (void)argc;
1479 (void)args;
1480
1481 datalen = ventoy_get_windows_rtdata_len(args[1], &dataflag);
1482
1483 while (node)
1484 {
1485 node->wim_data.windata_flag = dataflag;
1486 if (0 == ventoy_wimdows_locate_wim(args[0], node, datalen))
1487 {
1488 node->valid = 1;
1489 g_wim_valid_patch_count++;
1490 }
1491
1492 node = node->next;
1493 }
1494
1495 return 0;
1496 }
1497
1498 static grub_uint32_t ventoy_get_override_chunk_num(void)
1499 {
1500 grub_uint32_t chunk_num = 0;
1501
1502 if (g_iso_fs_type == 0)
1503 {
1504 /* ISO9660: */
1505 /* per wim */
1506 /* 1: file_size and file_offset */
1507 /* 2: new wim file header */
1508 chunk_num = g_wim_valid_patch_count * 2;
1509 }
1510 else
1511 {
1512 /* UDF: */
1513 /* global: */
1514 /* 1: block count in Partition Descriptor */
1515
1516 /* per wim */
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;
1521 }
1522
1523 if (g_suppress_wincd_override_offset > 0)
1524 {
1525 chunk_num++;
1526 }
1527
1528 return chunk_num;
1529 }
1530
1531 static void ventoy_fill_suppress_wincd_override_data(void *override)
1532 {
1533 ventoy_override_chunk *cur = (ventoy_override_chunk *)override;
1534
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);
1538 }
1539
1540 static void ventoy_windows_fill_override_data_iso9660( grub_uint64_t isosize, void *override)
1541 {
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;
1548
1549 sector = (isosize + 2047) / 2048;
1550
1551 cur = (ventoy_override_chunk *)override;
1552
1553 if (g_suppress_wincd_override_offset > 0)
1554 {
1555 ventoy_fill_suppress_wincd_override_data(cur);
1556 cur++;
1557 }
1558
1559 debug("ventoy_windows_fill_override_data_iso9660 %lu\n", (ulong)isosize);
1560
1561 for (node = g_wim_patch_head; node; node = node->next)
1562 {
1563 wim_data = &node->wim_data;
1564 if (0 == node->valid)
1565 {
1566 continue;
1567 }
1568
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;
1571
1572 dirent = (ventoy_iso9660_override *)wim_data->override_data;
1573
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);
1578
1579 sector += (new_wim_size / 2048);
1580
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);
1585 cur++;
1586
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);
1591 cur++;
1592 }
1593
1594 return;
1595 }
1596
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)
1599 {
1600 int i;
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];
1605
1606 grub_memset(tmp, 0, sizeof(tmp));
1607 grub_file_seek(isofile, wim_data->override_offset);
1608 grub_file_read(isofile, tmp, sizeof(tmp));
1609
1610 left_size = new_wim_size;
1611 udf = (ventoy_udf_override *)wim_data->override_data;
1612
1613 for (i = 0; i < 4; i++)
1614 {
1615 total += tmp[i].length;
1616 if (total >= wim_data->wim_raw_size)
1617 {
1618 udf->length = left_size;
1619 udf->position = curpos;
1620 return 0;
1621 }
1622 else
1623 {
1624 udf->length = tmp[i].length;
1625 udf->position = curpos;
1626 }
1627
1628 left_size -= tmp[i].length;
1629 curpos += udf->length / 2048;
1630 udf++;
1631 wim_data->override_len += sizeof(ventoy_udf_override);
1632 }
1633
1634 debug("######## Too many udf ad ######\n");
1635 return 1;
1636 }
1637
1638 static void ventoy_windows_fill_override_data_udf(grub_file_t isofile, void *override)
1639 {
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;
1649
1650 sector = (isofile->size + 2047) / 2048;
1651
1652 cur = (ventoy_override_chunk *)override;
1653
1654 if (g_suppress_wincd_override_offset > 0)
1655 {
1656 ventoy_fill_suppress_wincd_override_data(cur);
1657 cur++;
1658 }
1659
1660 debug("ventoy_windows_fill_override_data_udf %lu\n", (ulong)isofile->size);
1661
1662 for (node = g_wim_patch_head; node; node = node->next)
1663 {
1664 wim_data = &node->wim_data;
1665 if (node->valid)
1666 {
1667 if (udf_start_block == 0)
1668 {
1669 udf_start_block = wim_data->udf_start_block;
1670 }
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;
1674 }
1675 }
1676
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);
1682
1683 for (node = g_wim_patch_head; node; node = node->next)
1684 {
1685 wim_data = &node->wim_data;
1686 if (0 == node->valid)
1687 {
1688 continue;
1689 }
1690
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;
1693
1694 //override 2: filesize in file_entry
1695 cur++;
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);
1700
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);
1703
1704 sector += (new_wim_size / 2048);
1705
1706 cur++;
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);
1710
1711 /* override 4: new wim file header */
1712 cur++;
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);
1716 }
1717
1718 return;
1719 }
1720
1721 static grub_uint32_t ventoy_windows_get_virt_data_size(void)
1722 {
1723 grub_uint32_t size = 0;
1724 wim_tail *wim_data = NULL;
1725 wim_patch *node = g_wim_patch_head;
1726
1727 while (node)
1728 {
1729 if (node->valid)
1730 {
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;
1734 }
1735 node = node->next;
1736 }
1737
1738 return size;
1739 }
1740
1741 static void ventoy_windows_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain)
1742 {
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;
1751
1752 sector = (isosize + 2047) / 2048;
1753 offset = sizeof(ventoy_virt_chunk) * g_wim_valid_patch_count;
1754
1755 override = (char *)chain + chain->virt_chunk_offset;
1756 cur = (ventoy_virt_chunk *)override;
1757
1758 for (node = g_wim_patch_head; node; node = node->next)
1759 {
1760 if (0 == node->valid)
1761 {
1762 continue;
1763 }
1764
1765 wim_data = &node->wim_data;
1766
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;
1769
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);
1773
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;
1777
1778 sector += wim_secs + mem_secs;
1779 cur++;
1780
1781 grub_memcpy(override + offset, wim_data->jump_bin_data, wim_data->bin_raw_len);
1782 offset += wim_data->bin_align_len;
1783
1784 grub_memcpy(override + offset, wim_data->new_meta_data, wim_data->new_meta_len);
1785 offset += wim_data->new_meta_align_len;
1786
1787 grub_memcpy(override + offset, wim_data->new_lookup_data, wim_data->new_lookup_len);
1788 offset += wim_data->new_lookup_align_len;
1789
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;
1794 }
1795
1796 return;
1797 }
1798
1799 static int ventoy_windows_drive_map(ventoy_chain_head *chain, int vlnk)
1800 {
1801 int hd1 = 0;
1802 grub_disk_t disk;
1803
1804 debug("drive map begin <%p> <%d> ...\n", chain, vlnk);
1805
1806 disk = grub_disk_open("hd1");
1807 if (disk)
1808 {
1809 grub_disk_close(disk);
1810 hd1 = 1;
1811 debug("BIOS hd1 exist\n");
1812 }
1813 else
1814 {
1815 debug("failed to open disk %s\n", "hd1");
1816 }
1817
1818 if (vlnk)
1819 {
1820 if (g_ventoy_disk_bios_id == 0x80 && hd1)
1821 {
1822 debug("drive map needed vlnk %p\n", disk);
1823 chain->drive_map = 0x81;
1824 }
1825 }
1826 else if (chain->disk_drive == 0x80)
1827 {
1828 if (hd1)
1829 {
1830 debug("drive map needed normal %p\n", disk);
1831 chain->drive_map = 0x81;
1832 }
1833 }
1834 else
1835 {
1836 debug("no need to map 0x%x\n", chain->disk_drive);
1837 }
1838
1839 return 0;
1840 }
1841
1842 static int ventoy_suppress_windows_cd_prompt(void)
1843 {
1844 int rc = 1;
1845 const char *cdprompt = NULL;
1846 grub_uint64_t readpos = 0;
1847 grub_file_t file = NULL;
1848 grub_uint8_t data[32];
1849
1850 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
1851 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
1852 {
1853 debug("VTOY_WINDOWS_CD_PROMPT:<%s>\n", cdprompt);
1854 return 0;
1855 }
1856
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;
1860
1861 if (!file)
1862 {
1863 debug("Failed to open %s\n", "bootfix.bin");
1864 goto end;
1865 }
1866
1867 grub_file_read(file, data, 32);
1868
1869 if (file->fs && file->fs->name && grub_strcmp(file->fs->name, "udf") == 0)
1870 {
1871 readpos = grub_udf_get_file_offset(file);
1872 }
1873 else
1874 {
1875 readpos = grub_iso9660_get_last_read_pos(file);
1876 }
1877
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]);
1880
1881 if (*(grub_uint32_t *)(data + 24) == 0x13cd0080)
1882 {
1883 g_suppress_wincd_override_offset = readpos + 24;
1884 g_suppress_wincd_override_data = 0x13cd00fd;
1885
1886 rc = 0;
1887 }
1888
1889 debug("g_suppress_wincd_override_offset:%lu\n", (ulong)g_suppress_wincd_override_offset);
1890
1891 end:
1892 check_free(file, grub_file_close);
1893
1894 return rc;
1895 }
1896
1897 static int ventoy_extract_init_exe(char *wimfile, grub_uint8_t **pexe_data, grub_uint32_t *pexe_len, char *exe_name)
1898 {
1899 int rc;
1900 int ret = 1;
1901 grub_uint16_t i;
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;
1914 wim_header wimhdr;
1915 wim_hash hashdata;
1916
1917 head = &wimhdr;
1918
1919 file = grub_file_open(wimfile, VENTOY_FILE_TYPE);
1920 if (!file)
1921 {
1922 goto out;
1923 }
1924
1925 grub_file_read(file, head, sizeof(wim_header));
1926 rc = ventoy_read_resource(file, head, &head->metadata, (void **)&decompress_data);
1927 if (rc)
1928 {
1929 grub_printf("failed to read meta data %d\n", rc);
1930 goto out;
1931 }
1932
1933 security = (wim_security_header *)decompress_data;
1934 if (security->len > 0)
1935 {
1936 rootdir = (wim_directory_entry *)(decompress_data + ((security->len + 7) & 0xFFFFFFF8U));
1937 }
1938 else
1939 {
1940 rootdir = (wim_directory_entry *)(decompress_data + 8);
1941 }
1942
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);
1947
1948 /* search winpeshl.exe dirent entry */
1949 search = search_replace_wim_dirent(file, head, lookup, decompress_data, rootdir);
1950 if (!search)
1951 {
1952 debug("Failed to find replace file %p\n", search);
1953 goto out;
1954 }
1955
1956 uname = (grub_uint16_t *)(search + 1);
1957 for (i = 0; i < search->name_len / 2 && i < 200; i++)
1958 {
1959 exe_name[i] = (char)uname[i];
1960 }
1961 exe_name[i] = 0;
1962 debug("find replace file at %p <%s>\n", search, exe_name);
1963
1964 grub_memset(&hashdata, 0, sizeof(wim_hash));
1965 if (grub_memcmp(&hashdata, search->hash.sha1, sizeof(wim_hash)) == 0)
1966 {
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++)
1970 {
1971 if (stream->name_len == 0)
1972 {
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));
1976 break;
1977 }
1978 stream = (wim_stream_entry *)((char *)stream + stream->len);
1979 }
1980 }
1981 else
1982 {
1983 grub_memcpy(&hashdata, search->hash.sha1, sizeof(wim_hash));
1984 }
1985
1986 /* find and extact winpeshl.exe */
1987 replace_look = ventoy_find_look_entry(head, lookup, &hashdata);
1988 if (replace_look)
1989 {
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);
1993
1994 if (0 != ventoy_read_resource(file, head, &(replace_look->resource), (void **)&(exe_data)))
1995 {
1996 exe_len = 0;
1997 exe_data = NULL;
1998 debug("failed to read replace file meta data %u\n", exe_len);
1999 }
2000 }
2001 else
2002 {
2003 debug("failed to find lookup entry for replace file %02x %02x %02x %02x\n",
2004 ventoy_varg_4(hashdata.sha1));
2005 }
2006
2007 if (exe_data)
2008 {
2009 ret = 0;
2010 *pexe_data = exe_data;
2011 *pexe_len = exe_len;
2012 }
2013
2014 out:
2015
2016 grub_check_free(lookup);
2017 grub_check_free(decompress_data);
2018 check_free(file, grub_file_close);
2019
2020 return ret;
2021 }
2022
2023 grub_err_t ventoy_cmd_windows_wimboot_data(grub_extcmd_context_t ctxt, int argc, char **args)
2024 {
2025 int rc = 0;
2026 int wim64 = 0;
2027 int datalen = 0;
2028 int dataflag = 0;
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};
2038 wim_tail wim_data;
2039
2040 (void)ctxt;
2041 (void)argc;
2042
2043 addr = grub_env_get("vtoy_chain_mem_addr");
2044 if (!addr)
2045 {
2046 debug("Failed to find vtoy_chain_mem_addr\n");
2047 return 1;
2048 }
2049
2050 chain = (ventoy_chain_head *)(void *)grub_strtoul(addr, NULL, 16);
2051
2052 if (grub_memcmp(&g_ventoy_guid, &chain->os_param.guid, 16) != 0)
2053 {
2054 debug("os_param.guid not match\n");
2055 return 1;
2056 }
2057
2058 datalen = ventoy_get_windows_rtdata_len(chain->os_param.vtoy_img_path, &dataflag);
2059
2060 rc = ventoy_extract_init_exe(args[0], &exe_data, &exe_len, exename);
2061 if (rc)
2062 {
2063 return 1;
2064 }
2065 wim64 = ventoy_is_pe64(exe_data);
2066
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);
2070
2071 jump_align = ventoy_align(wim_data.jump_exe_len, 16);
2072 param = wim_data.jump_bin_data;
2073
2074 grub_memcpy(param + jump_align, &chain->os_param, sizeof(ventoy_os_param));
2075
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);
2078
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);
2082
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);
2086
2087 grub_env_set(args[1], exename);
2088 grub_env_set(args[2], wim64 ? "64" : "32");
2089
2090 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2091 }
2092
2093 grub_err_t ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
2094 {
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;
2103 grub_file_t file;
2104 grub_disk_t disk;
2105 const char *pLastChain = NULL;
2106 const char *compatible;
2107 ventoy_chain_head *chain;
2108 char envbuf[64];
2109
2110 (void)ctxt;
2111 (void)argc;
2112
2113 debug("chain data begin <%s> ...\n", args[0]);
2114
2115 compatible = grub_env_get("ventoy_compatible");
2116 if (compatible && compatible[0] == 'Y')
2117 {
2118 ventoy_compatible = 1;
2119 }
2120
2121 if (NULL == g_img_chunk_list.chunk)
2122 {
2123 grub_printf("ventoy not ready\n");
2124 return 1;
2125 }
2126
2127 if (0 == ventoy_compatible && g_wim_valid_patch_count == 0)
2128 {
2129 unknown_image = 1;
2130 if (!g_ventoy_wimboot_mode)
2131 {
2132 debug("Warning: %s was not recognized by Ventoy\n", args[0]);
2133 }
2134 }
2135
2136 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2137 if (!file)
2138 {
2139 return 1;
2140 }
2141
2142 isosize = file->size;
2143
2144 boot_catlog = ventoy_get_iso_boot_catlog(file);
2145 if (boot_catlog)
2146 {
2147 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
2148 {
2149 grub_env_set("LoadIsoEfiDriver", "on");
2150 }
2151 }
2152 else
2153 {
2154 if (ventoy_is_efi_os())
2155 {
2156 grub_env_set("LoadIsoEfiDriver", "on");
2157 }
2158 else
2159 {
2160 return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
2161 }
2162 }
2163
2164 g_suppress_wincd_override_offset = 0;
2165 if (!ventoy_is_efi_os()) /* legacy mode */
2166 {
2167 ventoy_suppress_windows_cd_prompt();
2168 }
2169
2170 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
2171
2172 if (ventoy_compatible || unknown_image)
2173 {
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;
2176 }
2177 else
2178 {
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;
2182 }
2183
2184 pLastChain = grub_env_get("vtoy_chain_mem_addr");
2185 if (pLastChain)
2186 {
2187 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
2188 if (chain)
2189 {
2190 debug("free last chain memory %p\n", chain);
2191 grub_free(chain);
2192 }
2193 }
2194
2195 chain = ventoy_alloc_chain(size);
2196 if (!chain)
2197 {
2198 grub_printf("Failed to alloc chain win1 memory size %u\n", size);
2199 grub_file_close(file);
2200 return 1;
2201 }
2202
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);
2207
2208 grub_memset(chain, 0, sizeof(ventoy_chain_head));
2209
2210 /* part 1: os parameter */
2211 g_ventoy_chain_type = ventoy_chain_windows;
2212 ventoy_fill_os_param(file, &(chain->os_param));
2213
2214 if (0 == unknown_image)
2215 {
2216 ventoy_update_before_chain(&(chain->os_param), args[0]);
2217 }
2218
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;
2226
2227 if (!ventoy_is_efi_os())
2228 {
2229 grub_file_seek(file, boot_catlog * 2048);
2230 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
2231 }
2232
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);
2237
2238 if (ventoy_compatible || unknown_image)
2239 {
2240 if (g_suppress_wincd_override_offset > 0)
2241 {
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);
2245 }
2246
2247 return 0;
2248 }
2249
2250 if (0 == g_wim_valid_patch_count)
2251 {
2252 return 0;
2253 }
2254
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();
2258
2259 if (g_iso_fs_type == 0)
2260 {
2261 ventoy_windows_fill_override_data_iso9660(isosize, (char *)chain + chain->override_chunk_offset);
2262 }
2263 else
2264 {
2265 ventoy_windows_fill_override_data_udf(file, (char *)chain + chain->override_chunk_offset);
2266 }
2267
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);
2272
2273 if (ventoy_is_efi_os() == 0)
2274 {
2275 ventoy_windows_drive_map(chain, file->vlnk);
2276 }
2277
2278 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2279 }
2280
2281 static grub_uint32_t ventoy_get_wim_iso_offset(const char *filepath)
2282 {
2283 grub_uint32_t imgoffset;
2284 grub_file_t file;
2285 char cmdbuf[128];
2286
2287 grub_snprintf(cmdbuf, sizeof(cmdbuf), "loopback wimiso \"%s\"", filepath);
2288 grub_script_execute_sourcecode(cmdbuf);
2289
2290 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(wimiso)/boot/boot.wim");
2291 if (!file)
2292 {
2293 grub_printf("Failed to open boot.wim file in the image file\n");
2294 return 0;
2295 }
2296
2297 imgoffset = (grub_uint32_t)grub_iso9660_get_last_file_dirent_pos(file) + 2;
2298
2299 debug("wimiso wim direct offset: %u\n", imgoffset);
2300
2301 grub_file_close(file);
2302
2303 grub_script_execute_sourcecode("loopback -d wimiso");
2304
2305 return imgoffset;
2306 }
2307
2308 static int ventoy_get_wim_chunklist(grub_file_t wimfile, ventoy_img_chunk_list *wimchunk)
2309 {
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)
2313 {
2314 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2315 }
2316
2317 wimchunk->max_chunk = DEFAULT_CHUNK_NUM;
2318 wimchunk->cur_chunk = 0;
2319
2320 ventoy_get_block_list(wimfile, wimchunk, wimfile->device->disk->partition->start);
2321
2322 return 0;
2323 }
2324
2325 grub_err_t ventoy_cmd_is_standard_winiso(grub_extcmd_context_t ctxt, int argc, char **args)
2326 {
2327 int i;
2328 int ret = 1;
2329 char prefix[32] = {0};
2330 const char *chkfile[] =
2331 {
2332 "boot/bcd", "boot/boot.sdi", NULL
2333 };
2334
2335 (void)ctxt;
2336 (void)argc;
2337
2338 if (ventoy_check_file_exist("%s/sources/boot.wim", args[0]))
2339 {
2340 prefix[0] = 0;
2341 }
2342 else if (ventoy_check_file_exist("%s/x86/sources/boot.wim", args[0]))
2343 {
2344 grub_snprintf(prefix, sizeof(prefix), "/x86");
2345 }
2346 else if (ventoy_check_file_exist("%s/x64/sources/boot.wim", args[0]))
2347 {
2348 grub_snprintf(prefix, sizeof(prefix), "/x64");
2349 }
2350 else
2351 {
2352 debug("No boot.wim found.\n");
2353 goto out;
2354 }
2355
2356 for (i = 0; chkfile[i]; i++)
2357 {
2358 if (!ventoy_check_file_exist("%s%s/%s", args[0], prefix, chkfile[i]))
2359 {
2360 debug("%s not found.\n", chkfile[i]);
2361 goto out;
2362 }
2363 }
2364
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)))
2367 {
2368 debug("No install.wim(esd) found.\n");
2369 goto out;
2370 }
2371
2372 if (!ventoy_check_file_exist("%s/setup.exe", args[0]))
2373 {
2374 debug("No setup.exe found.\n");
2375 goto out;
2376 }
2377
2378 ret = 0;
2379 debug("This is standard Windows ISO.\n");
2380
2381 out:
2382
2383 return ret;
2384 }
2385
2386 grub_err_t ventoy_cmd_wim_check_bootable(grub_extcmd_context_t ctxt, int argc, char **args)
2387 {
2388 grub_uint32_t boot_index;
2389 grub_file_t file = NULL;
2390 wim_header *wimhdr = NULL;
2391
2392 (void)ctxt;
2393 (void)argc;
2394
2395 wimhdr = grub_zalloc(sizeof(wim_header));
2396 if (!wimhdr)
2397 {
2398 return 1;
2399 }
2400
2401 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2402 if (!file)
2403 {
2404 grub_free(wimhdr);
2405 return 1;
2406 }
2407
2408 grub_file_read(file, wimhdr, sizeof(wim_header));
2409 grub_file_close(file);
2410 boot_index = wimhdr->boot_index;
2411 grub_free(wimhdr);
2412
2413 if (boot_index == 0)
2414 {
2415 return 1;
2416 }
2417
2418 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2419 }
2420
2421 static grub_err_t ventoy_vlnk_wim_chain_data(grub_file_t wimfile)
2422 {
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;
2432 grub_file_t file;
2433 grub_disk_t disk;
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;
2440 char envbuf[128];
2441
2442 debug("vlnk wim chain data begin <%s> ...\n", wimfile->name);
2443
2444 if (NULL == g_wimiso_chunk_list.chunk || NULL == g_wimiso_path)
2445 {
2446 grub_printf("ventoy not ready\n");
2447 return 1;
2448 }
2449
2450 imgoffset = ventoy_get_wim_iso_offset(g_wimiso_path);
2451 if (imgoffset == 0)
2452 {
2453 grub_printf("image offset not found\n");
2454 return 1;
2455 }
2456
2457 if (0 != ventoy_get_wim_chunklist(wimfile, &wimchunk))
2458 {
2459 grub_printf("Failed to get wim chunklist\n");
2460 return 1;
2461 }
2462 wimsize = wimfile->size;
2463
2464 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", g_wimiso_path);
2465 if (!file)
2466 {
2467 return 1;
2468 }
2469
2470 boot_catlog = ventoy_get_iso_boot_catlog(file);
2471
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;
2475
2476 size = sizeof(ventoy_chain_head) + img_chunk1_size + img_chunk2_size + override_size;
2477
2478 pLastChain = grub_env_get("vtoy_chain_mem_addr");
2479 if (pLastChain)
2480 {
2481 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
2482 if (chain)
2483 {
2484 debug("free last chain memory %p\n", chain);
2485 grub_free(chain);
2486 }
2487 }
2488
2489 chain = ventoy_alloc_chain(size);
2490 if (!chain)
2491 {
2492 grub_printf("Failed to alloc chain win2 memory size %u\n", size);
2493 grub_file_close(file);
2494 return 1;
2495 }
2496
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);
2501
2502 grub_memset(chain, 0, sizeof(ventoy_chain_head));
2503
2504 /* part 1: os parameter */
2505 g_ventoy_chain_type = ventoy_chain_wim;
2506 ventoy_fill_os_param(wimfile, &(chain->os_param));
2507
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;
2515
2516 if (!ventoy_is_efi_os())
2517 {
2518 grub_file_seek(file, boot_catlog * 2048);
2519 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
2520 }
2521
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);
2526
2527 chunknode = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
2528 for (i = 0; i < g_wimiso_chunk_list.cur_chunk; i++)
2529 {
2530 chunknode->disk_end_sector = chunknode->disk_end_sector - chunknode->disk_start_sector;
2531 chunknode->disk_start_sector = 0;
2532 chunknode++;
2533 }
2534
2535 /* fs cluster size >= 2048, so don't need to proc align */
2536
2537 /* align by 2048 */
2538 chunknode = wimchunk.chunk + wimchunk.cur_chunk - 1;
2539 i = (chunknode->disk_end_sector + 1 - chunknode->disk_start_sector) % 4;
2540 if (i)
2541 {
2542 chunknode->disk_end_sector += 4 - i;
2543 }
2544
2545 isosector = (grub_uint32_t)((file->size + 2047) / 2048);
2546 for (i = 0; i < wimchunk.cur_chunk; i++)
2547 {
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;
2553 }
2554
2555 grub_memcpy((char *)chain + chain->img_chunk_offset + img_chunk1_size, wimchunk.chunk, img_chunk2_size);
2556
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;
2560
2561 override = (ventoy_override_chunk *)((char *)chain + chain->override_chunk_offset);
2562 override->img_offset = 0;
2563 override->override_size = g_wimiso_size;
2564
2565 grub_file_seek(file, 0);
2566 grub_file_read(file, override->override_data, file->size);
2567
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);
2573
2574 debug("imgoffset=%u first_sector=0x%x size=0x%x\n", imgoffset, dirent->first_sector, dirent->size);
2575
2576 if (ventoy_is_efi_os() == 0)
2577 {
2578 ventoy_windows_drive_map(chain, 0);
2579 }
2580
2581 grub_file_close(file);
2582
2583 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2584 }
2585
2586 static grub_err_t ventoy_normal_wim_chain_data(grub_file_t wimfile)
2587 {
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;
2597 grub_file_t file;
2598 grub_disk_t disk;
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;
2605 char envbuf[128];
2606
2607 debug("normal wim chain data begin <%s> ...\n", wimfile->name);
2608
2609 if (NULL == g_wimiso_chunk_list.chunk || NULL == g_wimiso_path)
2610 {
2611 grub_printf("ventoy not ready\n");
2612 return 1;
2613 }
2614
2615 imgoffset = ventoy_get_wim_iso_offset(g_wimiso_path);
2616 if (imgoffset == 0)
2617 {
2618 grub_printf("image offset not found\n");
2619 return 1;
2620 }
2621
2622 if (0 != ventoy_get_wim_chunklist(wimfile, &wimchunk))
2623 {
2624 grub_printf("Failed to get wim chunklist\n");
2625 return 1;
2626 }
2627 wimsize = wimfile->size;
2628
2629 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", g_wimiso_path);
2630 if (!file)
2631 {
2632 return 1;
2633 }
2634
2635 boot_catlog = ventoy_get_iso_boot_catlog(file);
2636
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);
2640
2641 size = sizeof(ventoy_chain_head) + img_chunk1_size + img_chunk2_size + override_size;
2642
2643 pLastChain = grub_env_get("vtoy_chain_mem_addr");
2644 if (pLastChain)
2645 {
2646 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
2647 if (chain)
2648 {
2649 debug("free last chain memory %p\n", chain);
2650 grub_free(chain);
2651 }
2652 }
2653
2654 chain = ventoy_alloc_chain(size);
2655 if (!chain)
2656 {
2657 grub_printf("Failed to alloc chain win3 memory size %u\n", size);
2658 grub_file_close(file);
2659 return 1;
2660 }
2661
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);
2666
2667 grub_memset(chain, 0, sizeof(ventoy_chain_head));
2668
2669 /* part 1: os parameter */
2670 g_ventoy_chain_type = ventoy_chain_wim;
2671 ventoy_fill_os_param(file, &(chain->os_param));
2672
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;
2680
2681 if (!ventoy_is_efi_os())
2682 {
2683 grub_file_seek(file, boot_catlog * 2048);
2684 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
2685 }
2686
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);
2691
2692 /* fs cluster size >= 2048, so don't need to proc align */
2693
2694 /* align by 2048 */
2695 chunknode = wimchunk.chunk + wimchunk.cur_chunk - 1;
2696 i = (chunknode->disk_end_sector + 1 - chunknode->disk_start_sector) % 4;
2697 if (i)
2698 {
2699 chunknode->disk_end_sector += 4 - i;
2700 }
2701
2702 isosector = (grub_uint32_t)((file->size + 2047) / 2048);
2703 for (i = 0; i < wimchunk.cur_chunk; i++)
2704 {
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;
2710 }
2711
2712 grub_memcpy((char *)chain + chain->img_chunk_offset + img_chunk1_size, wimchunk.chunk, img_chunk2_size);
2713
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;
2717
2718 override = (ventoy_override_chunk *)((char *)chain + chain->override_chunk_offset);
2719 override->img_offset = imgoffset;
2720 override->override_size = sizeof(ventoy_iso9660_override);
2721
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);
2727
2728 debug("imgoffset=%u first_sector=0x%x size=0x%x\n", imgoffset, dirent->first_sector, dirent->size);
2729
2730 if (ventoy_is_efi_os() == 0)
2731 {
2732 ventoy_windows_drive_map(chain, 0);
2733 }
2734
2735 grub_file_close(file);
2736
2737 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2738 }
2739
2740 grub_err_t ventoy_cmd_wim_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
2741 {
2742 grub_err_t ret;
2743 grub_file_t wimfile;
2744
2745 (void)ctxt;
2746 (void)argc;
2747
2748 wimfile = grub_file_open(args[0], VENTOY_FILE_TYPE);
2749 if (!wimfile)
2750 {
2751 return 1;
2752 }
2753
2754 if (wimfile->vlnk)
2755 {
2756 ret = ventoy_vlnk_wim_chain_data(wimfile);
2757 }
2758 else
2759 {
2760 ret = ventoy_normal_wim_chain_data(wimfile);
2761 }
2762
2763 grub_file_close(wimfile);
2764 return ret;
2765 }
2766
2767 int ventoy_chain_file_size(const char *path)
2768 {
2769 int size;
2770 grub_file_t file;
2771
2772 file = grub_file_open(path, VENTOY_FILE_TYPE);
2773 size = (int)(file->size);
2774
2775 grub_file_close(file);
2776
2777 return size;
2778 }
2779
2780 int ventoy_chain_file_read(const char *path, int offset, int len, void *buf)
2781 {
2782 int size;
2783 grub_file_t file;
2784
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);
2789
2790 return size;
2791 }
2792