]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_windows.c
e4c9aa6a93f2dfd2316e83cecab7451a1109b3ce
[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
379 grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, size);
380 grub_script_execute_sourcecode(configfile);
381
382 g_ventoy_menu_esc = 0;
383 g_ventoy_suppress_esc = 0;
384
385 grub_free(buf);
386
387 if (g_ventoy_last_entry == 0)
388 {
389 debug("last entry=%d %s=32\n", g_ventoy_last_entry, args[0]);
390 grub_env_set(args[0], "32");
391 }
392 else
393 {
394 debug("last entry=%d %s=64\n", g_ventoy_last_entry, args[0]);
395 grub_env_set(args[0], "64");
396 }
397
398 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
399 }
400
401 grub_err_t ventoy_cmd_wimdows_reset(grub_extcmd_context_t ctxt, int argc, char **args)
402 {
403 wim_patch *next = NULL;
404 wim_patch *node = g_wim_patch_head;
405
406 (void)ctxt;
407 (void)argc;
408 (void)args;
409
410 while (node)
411 {
412 next = node->next;
413 grub_free(node);
414 node = next;
415 }
416
417 g_wim_patch_head = NULL;
418 g_wim_total_patch_count = 0;
419 g_wim_valid_patch_count = 0;
420
421 return 0;
422 }
423
424 static int ventoy_load_jump_exe(const char *path, grub_uint8_t **data, grub_uint32_t *size, wim_hash *hash)
425 {
426 grub_uint32_t i;
427 grub_uint32_t align;
428 grub_file_t file;
429
430 debug("windows load jump %s\n", path);
431
432 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", path);
433 if (!file)
434 {
435 debug("Can't open file %s\n", path);
436 return 1;
437 }
438
439 align = ventoy_align((int)file->size, 2048);
440
441 debug("file %s size:%d align:%u\n", path, (int)file->size, align);
442
443 *size = (grub_uint32_t)file->size;
444 *data = (grub_uint8_t *)grub_malloc(align);
445 if ((*data) == NULL)
446 {
447 debug("Failed to alloc memory size %u\n", align);
448 goto end;
449 }
450
451 grub_file_read(file, (*data), file->size);
452
453 if (hash)
454 {
455 grub_crypto_hash(GRUB_MD_SHA1, hash->sha1, (*data), file->size);
456
457 if (g_ventoy_debug)
458 {
459 debug("%s", "jump bin 64 hash: ");
460 for (i = 0; i < sizeof(hash->sha1); i++)
461 {
462 ventoy_debug("%02x ", hash->sha1[i]);
463 }
464 ventoy_debug("\n");
465 }
466 }
467
468 end:
469
470 grub_file_close(file);
471 return 0;
472 }
473
474 static int ventoy_get_override_info(grub_file_t file, wim_tail *wim_data)
475 {
476 grub_uint32_t start_block;
477 grub_uint64_t file_offset;
478 grub_uint64_t override_offset;
479 grub_uint32_t override_len;
480 grub_uint64_t fe_entry_size_offset;
481
482 if (grub_strcmp(file->fs->name, "iso9660") == 0)
483 {
484 g_iso_fs_type = wim_data->iso_type = 0;
485 override_len = sizeof(ventoy_iso9660_override);
486 override_offset = grub_iso9660_get_last_file_dirent_pos(file) + 2;
487
488 grub_file_read(file, &start_block, 1); // just read for hook trigger
489 file_offset = grub_iso9660_get_last_read_pos(file);
490
491 debug("iso9660 wim size:%llu override_offset:%llu file_offset:%llu\n",
492 (ulonglong)file->size, (ulonglong)override_offset, (ulonglong)file_offset);
493 }
494 else
495 {
496 g_iso_fs_type = wim_data->iso_type = 1;
497 override_len = sizeof(ventoy_udf_override);
498 override_offset = grub_udf_get_last_file_attr_offset(file, &start_block, &fe_entry_size_offset);
499
500 file_offset = grub_udf_get_file_offset(file);
501
502 debug("UDF wim size:%llu override_offset:%llu file_offset:%llu start_block=%u\n",
503 (ulonglong)file->size, (ulonglong)override_offset, (ulonglong)file_offset, start_block);
504 }
505
506 wim_data->file_offset = file_offset;
507 wim_data->udf_start_block = start_block;
508 wim_data->fe_entry_size_offset = fe_entry_size_offset;
509 wim_data->override_offset = override_offset;
510 wim_data->override_len = override_len;
511
512 return 0;
513 }
514
515 static int ventoy_read_resource(grub_file_t fp, wim_header *wimhdr, wim_resource_header *head, void **buffer)
516 {
517 int decompress_len = 0;
518 int total_decompress = 0;
519 grub_uint32_t i = 0;
520 grub_uint32_t chunk_num = 0;
521 grub_uint32_t chunk_size = 0;
522 grub_uint32_t last_chunk_size = 0;
523 grub_uint32_t last_decompress_size = 0;
524 grub_uint32_t cur_offset = 0;
525 grub_uint8_t *cur_dst = NULL;
526 grub_uint8_t *buffer_compress = NULL;
527 grub_uint8_t *buffer_decompress = NULL;
528 grub_uint32_t *chunk_offset = NULL;
529
530 buffer_decompress = (grub_uint8_t *)grub_malloc(head->raw_size + head->size_in_wim);
531 if (NULL == buffer_decompress)
532 {
533 return 0;
534 }
535
536 grub_file_seek(fp, head->offset);
537
538 if (head->size_in_wim == head->raw_size)
539 {
540 grub_file_read(fp, buffer_decompress, head->size_in_wim);
541 *buffer = buffer_decompress;
542 return 0;
543 }
544
545 buffer_compress = buffer_decompress + head->raw_size;
546 grub_file_read(fp, buffer_compress, head->size_in_wim);
547
548 chunk_num = (head->raw_size + WIM_CHUNK_LEN - 1) / WIM_CHUNK_LEN;
549 cur_offset = (chunk_num - 1) * 4;
550 chunk_offset = (grub_uint32_t *)buffer_compress;
551
552 //debug("%llu %llu chunk_num=%lu", (ulonglong)head->size_in_wim, (ulonglong)head->raw_size, chunk_num);
553
554 cur_dst = buffer_decompress;
555
556 for (i = 0; i < chunk_num - 1; i++)
557 {
558 chunk_size = (i == 0) ? chunk_offset[i] : chunk_offset[i] - chunk_offset[i - 1];
559
560 if (WIM_CHUNK_LEN == chunk_size)
561 {
562 grub_memcpy(cur_dst, buffer_compress + cur_offset, chunk_size);
563 decompress_len = (int)chunk_size;
564 }
565 else
566 {
567 if (wimhdr->flags & FLAG_HEADER_COMPRESS_XPRESS)
568 {
569 decompress_len = (int)xca_decompress(buffer_compress + cur_offset, chunk_size, cur_dst);
570 }
571 else
572 {
573 decompress_len = (int)lzx_decompress(buffer_compress + cur_offset, chunk_size, cur_dst);
574 }
575 }
576
577 //debug("chunk_size:%u decompresslen:%d\n", chunk_size, decompress_len);
578
579 total_decompress += decompress_len;
580 cur_dst += decompress_len;
581 cur_offset += chunk_size;
582 }
583
584 /* last chunk */
585 last_chunk_size = (grub_uint32_t)(head->size_in_wim - cur_offset);
586 last_decompress_size = head->raw_size - total_decompress;
587
588 if (last_chunk_size < WIM_CHUNK_LEN && last_chunk_size == last_decompress_size)
589 {
590 debug("Last chunk %u uncompressed\n", last_chunk_size);
591 grub_memcpy(cur_dst, buffer_compress + cur_offset, last_chunk_size);
592 decompress_len = (int)last_chunk_size;
593 }
594 else
595 {
596 if (wimhdr->flags & FLAG_HEADER_COMPRESS_XPRESS)
597 {
598 decompress_len = (int)xca_decompress(buffer_compress + cur_offset, head->size_in_wim - cur_offset, cur_dst);
599 }
600 else
601 {
602 decompress_len = (int)lzx_decompress(buffer_compress + cur_offset, head->size_in_wim - cur_offset, cur_dst);
603 }
604 }
605
606 cur_dst += decompress_len;
607 total_decompress += decompress_len;
608
609 //debug("last chunk_size:%u decompresslen:%d tot:%d\n", last_chunk_size, decompress_len, total_decompress);
610
611 if (cur_dst != buffer_decompress + head->raw_size)
612 {
613 debug("head->size_in_wim:%llu head->raw_size:%llu cur_dst:%p buffer_decompress:%p total_decompress:%d\n",
614 (ulonglong)head->size_in_wim, (ulonglong)head->raw_size, cur_dst, buffer_decompress, total_decompress);
615 grub_free(buffer_decompress);
616 return 1;
617 }
618
619 *buffer = buffer_decompress;
620 return 0;
621 }
622
623
624 static wim_directory_entry * search_wim_dirent(wim_directory_entry *dir, const char *search_name)
625 {
626 do
627 {
628 if (dir->len && dir->name_len)
629 {
630 if (wim_name_cmp(search_name, (grub_uint16_t *)(dir + 1), dir->name_len / 2) == 0)
631 {
632 return dir;
633 }
634 }
635 dir = (wim_directory_entry *)((grub_uint8_t *)dir + dir->len);
636 } while(dir->len);
637
638 return NULL;
639 }
640
641 static wim_directory_entry * search_full_wim_dirent
642 (
643 void *meta_data,
644 wim_directory_entry *dir,
645 const char **path
646 )
647 {
648 wim_directory_entry *subdir = NULL;
649 wim_directory_entry *search = dir;
650
651 while (*path)
652 {
653 subdir = (wim_directory_entry *)((char *)meta_data + search->subdir);
654 search = search_wim_dirent(subdir, *path);
655 path++;
656 }
657
658 return search;
659 }
660
661
662
663 static wim_lookup_entry * ventoy_find_look_entry(wim_header *header, wim_lookup_entry *lookup, wim_hash *hash)
664 {
665 grub_uint32_t i = 0;
666
667 for (i = 0; i < (grub_uint32_t)header->lookup.raw_size / sizeof(wim_lookup_entry); i++)
668 {
669 if (grub_memcmp(&lookup[i].hash, hash, sizeof(wim_hash)) == 0)
670 {
671 return lookup + i;
672 }
673 }
674
675 return NULL;
676 }
677
678 static int parse_registry_setup_cmdline
679 (
680 grub_file_t file,
681 wim_header *head,
682 wim_lookup_entry *lookup,
683 void *meta_data,
684 wim_directory_entry *dir,
685 char *buf,
686 grub_uint32_t buflen
687 )
688 {
689 char c;
690 int ret = 0;
691 grub_uint32_t i = 0;
692 grub_uint32_t reglen = 0;
693 wim_hash zerohash;
694 reg_vk *regvk = NULL;
695 wim_lookup_entry *look = NULL;
696 wim_directory_entry *wim_dirent = NULL;
697 char *decompress_data = NULL;
698 const char *reg_path[] = { "Windows", "System32", "config", "SYSTEM", NULL };
699
700 wim_dirent = search_full_wim_dirent(meta_data, dir, reg_path);
701 debug("search reg SYSTEM %p\n", wim_dirent);
702 if (!wim_dirent)
703 {
704 return 1;
705 }
706
707 grub_memset(&zerohash, 0, sizeof(zerohash));
708 if (grub_memcmp(&zerohash, wim_dirent->hash.sha1, sizeof(wim_hash)) == 0)
709 {
710 return 2;
711 }
712
713 look = ventoy_find_look_entry(head, lookup, &wim_dirent->hash);
714 if (!look)
715 {
716 return 3;
717 }
718
719 reglen = (grub_uint32_t)look->resource.raw_size;
720 debug("find system lookup entry_id:%ld raw_size:%u\n",
721 ((long)look - (long)lookup) / sizeof(wim_lookup_entry), reglen);
722
723 if (0 != ventoy_read_resource(file, head, &(look->resource), (void **)&(decompress_data)))
724 {
725 return 4;
726 }
727
728 if (grub_strncmp(decompress_data + 0x1000, "hbin", 4))
729 {
730 ret_goto_end(5);
731 }
732
733 for (i = 0x1000; i + sizeof(reg_vk) < reglen; i += 8)
734 {
735 regvk = (reg_vk *)(decompress_data + i);
736 if (regvk->sig == 0x6B76 && regvk->namesize == 7 &&
737 regvk->datatype == 1 && regvk->flag == 1)
738 {
739 if (grub_strncasecmp((char *)(regvk + 1), "cmdline", 7) == 0)
740 {
741 debug("find registry cmdline i:%u offset:(0x%x)%u size:(0x%x)%u\n",
742 i, regvk->dataoffset, regvk->dataoffset, regvk->datasize, regvk->datasize);
743 break;
744 }
745 }
746 }
747
748 if (i + sizeof(reg_vk) >= reglen || regvk == NULL)
749 {
750 ret_goto_end(6);
751 }
752
753 if (regvk->datasize == 0 || (regvk->datasize & 0x80000000) > 0 ||
754 regvk->dataoffset == 0 || regvk->dataoffset == 0xFFFFFFFF)
755 {
756 ret_goto_end(7);
757 }
758
759 if (regvk->datasize / 2 >= buflen)
760 {
761 ret_goto_end(8);
762 }
763
764 debug("start offset is 0x%x(%u)\n", 0x1000 + regvk->dataoffset + 4, 0x1000 + regvk->dataoffset + 4);
765
766 for (i = 0; i < regvk->datasize; i+=2)
767 {
768 c = (char)(*(grub_uint16_t *)(decompress_data + 0x1000 + regvk->dataoffset + 4 + i));
769 *buf++ = c;
770 }
771
772 ret = 0;
773
774 end:
775 grub_check_free(decompress_data);
776 return ret;
777 }
778
779 static int parse_custom_setup_path(char *cmdline, const char **path, char *exefile)
780 {
781 int i = 0;
782 int len = 0;
783 char *pos1 = NULL;
784 char *pos2 = NULL;
785
786 if ((cmdline[0] == 'x' || cmdline[0] == 'X') && cmdline[1] == ':')
787 {
788 pos1 = pos2 = cmdline + 3;
789
790 while (i < VTOY_MAX_DIR_DEPTH && *pos2)
791 {
792 while (*pos2 && *pos2 != '\\' && *pos2 != '/')
793 {
794 pos2++;
795 }
796
797 path[i++] = pos1;
798
799 if (*pos2 == 0)
800 {
801 break;
802 }
803
804 *pos2 = 0;
805 pos1 = pos2 + 1;
806 pos2 = pos1;
807 }
808
809 if (i == 0 || i >= VTOY_MAX_DIR_DEPTH)
810 {
811 return 1;
812 }
813 }
814 else
815 {
816 path[i++] = "Windows";
817 path[i++] = "System32";
818 path[i++] = cmdline;
819 }
820
821 pos1 = (char *)path[i - 1];
822 while (*pos1 != ' ' && *pos1 != '\t' && *pos1)
823 {
824 pos1++;
825 }
826 *pos1 = 0;
827
828 len = (int)grub_strlen(path[i - 1]);
829 if (len < 4 || grub_strcasecmp(path[i - 1] + len - 4, ".exe") != 0)
830 {
831 grub_snprintf(exefile, 256, "%s.exe", path[i - 1]);
832 path[i - 1] = exefile;
833 }
834
835
836 debug("custom setup: %d <%s>\n", i, path[i - 1]);
837 return 0;
838 }
839
840 static wim_directory_entry * search_replace_wim_dirent
841 (
842 grub_file_t file,
843 wim_header *head,
844 wim_lookup_entry *lookup,
845 void *meta_data,
846 wim_directory_entry *dir
847 )
848 {
849 int ret;
850 char exefile[256] = {0};
851 char cmdline[256] = {0};
852 wim_directory_entry *wim_dirent = NULL;
853 wim_directory_entry *pecmd_dirent = NULL;
854 const char *peset_path[] = { "Windows", "System32", "peset.exe", NULL };
855 const char *pecmd_path[] = { "Windows", "System32", "pecmd.exe", NULL };
856 const char *winpeshl_path[] = { "Windows", "System32", "winpeshl.exe", NULL };
857 const char *custom_path[VTOY_MAX_DIR_DEPTH + 1] = { NULL };
858
859 pecmd_dirent = search_full_wim_dirent(meta_data, dir, pecmd_path);
860 debug("search pecmd.exe %p\n", pecmd_dirent);
861
862 if (pecmd_dirent)
863 {
864 ret = parse_registry_setup_cmdline(file, head, lookup, meta_data, dir, cmdline, sizeof(cmdline) - 1);
865 if (0 == ret)
866 {
867 debug("registry setup cmdline:<%s>\n", cmdline);
868
869 if (grub_strncasecmp(cmdline, "PECMD", 5) == 0)
870 {
871 wim_dirent = pecmd_dirent;
872 }
873 else if (grub_strncasecmp(cmdline, "PESET", 5) == 0)
874 {
875 wim_dirent = search_full_wim_dirent(meta_data, dir, peset_path);
876 debug("search peset.exe %p\n", wim_dirent);
877 }
878 else if (grub_strncasecmp(cmdline, "WINPESHL", 8) == 0)
879 {
880 wim_dirent = search_full_wim_dirent(meta_data, dir, winpeshl_path);
881 debug("search winpeshl.exe %p\n", wim_dirent);
882 }
883 else if (0 == parse_custom_setup_path(cmdline, custom_path, exefile))
884 {
885 wim_dirent = search_full_wim_dirent(meta_data, dir, custom_path);
886 debug("search custom path %p\n", wim_dirent);
887 }
888
889 if (wim_dirent)
890 {
891 return wim_dirent;
892 }
893 }
894 else
895 {
896 debug("registry setup cmdline failed : %d\n", ret);
897 }
898 }
899
900 wim_dirent = pecmd_dirent;
901 if (wim_dirent)
902 {
903 return wim_dirent;
904 }
905
906 wim_dirent = search_full_wim_dirent(meta_data, dir, winpeshl_path);
907 debug("search winpeshl.exe %p\n", wim_dirent);
908 if (wim_dirent)
909 {
910 return wim_dirent;
911 }
912
913 return NULL;
914 }
915
916
917 static wim_lookup_entry * ventoy_find_meta_entry(wim_header *header, wim_lookup_entry *lookup)
918 {
919 grub_uint32_t i = 0;
920 grub_uint32_t index = 0;;
921
922 if ((header == NULL) || (lookup == NULL))
923 {
924 return NULL;
925 }
926
927 for (i = 0; i < (grub_uint32_t)header->lookup.raw_size / sizeof(wim_lookup_entry); i++)
928 {
929 if (lookup[i].resource.flags & RESHDR_FLAG_METADATA)
930 {
931 index++;
932 if (index == header->boot_index)
933 {
934 return lookup + i;
935 }
936 }
937 }
938
939 return NULL;
940 }
941
942 static grub_uint64_t ventoy_get_stream_len(wim_directory_entry *dir)
943 {
944 grub_uint16_t i;
945 grub_uint64_t offset = 0;
946 wim_stream_entry *stream = (wim_stream_entry *)((char *)dir + dir->len);
947
948 for (i = 0; i < dir->streams; i++)
949 {
950 offset += stream->len;
951 stream = (wim_stream_entry *)((char *)stream + stream->len);
952 }
953
954 return offset;
955 }
956
957 static int ventoy_update_stream_hash(wim_patch *patch, wim_directory_entry *dir)
958 {
959 grub_uint16_t i;
960 grub_uint64_t offset = 0;
961 wim_stream_entry *stream = (wim_stream_entry *)((char *)dir + dir->len);
962
963 for (i = 0; i < dir->streams; i++)
964 {
965 if (grub_memcmp(stream->hash.sha1, patch->old_hash.sha1, sizeof(wim_hash)) == 0)
966 {
967 debug("find target stream %u, name_len:%u upadte hash\n", i, stream->name_len);
968 grub_memcpy(stream->hash.sha1, &(patch->wim_data.bin_hash), sizeof(wim_hash));
969 }
970
971 offset += stream->len;
972 stream = (wim_stream_entry *)((char *)stream + stream->len);
973 }
974
975 return offset;
976 }
977
978 static int ventoy_update_all_hash(wim_patch *patch, void *meta_data, wim_directory_entry *dir)
979 {
980 if ((meta_data == NULL) || (dir == NULL))
981 {
982 return 0;
983 }
984
985 if (dir->len < sizeof(wim_directory_entry))
986 {
987 return 0;
988 }
989
990 do
991 {
992 if (dir->subdir == 0 && grub_memcmp(dir->hash.sha1, patch->old_hash.sha1, sizeof(wim_hash)) == 0)
993 {
994 debug("find target file, name_len:%u upadte hash\n", dir->name_len);
995 grub_memcpy(dir->hash.sha1, &(patch->wim_data.bin_hash), sizeof(wim_hash));
996 }
997
998 if (dir->subdir)
999 {
1000 ventoy_update_all_hash(patch, meta_data, (wim_directory_entry *)((char *)meta_data + dir->subdir));
1001 }
1002
1003 if (dir->streams)
1004 {
1005 ventoy_update_stream_hash(patch, dir);
1006 dir = (wim_directory_entry *)((char *)dir + dir->len + ventoy_get_stream_len(dir));
1007 }
1008 else
1009 {
1010 dir = (wim_directory_entry *)((char *)dir + dir->len);
1011 }
1012 } while (dir->len >= sizeof(wim_directory_entry));
1013
1014 return 0;
1015 }
1016
1017 static int ventoy_cat_exe_file_data(wim_tail *wim_data, grub_uint32_t exe_len, grub_uint8_t *exe_data)
1018 {
1019 int pe64 = 0;
1020 char file[256];
1021 grub_uint32_t jump_len = 0;
1022 grub_uint32_t jump_align = 0;
1023 grub_uint8_t *jump_data = NULL;
1024
1025 pe64 = ventoy_is_pe64(exe_data);
1026
1027 grub_snprintf(file, sizeof(file), "%s/vtoyjump%d.exe", grub_env_get("vtoy_path"), pe64 ? 64 : 32);
1028 ventoy_load_jump_exe(file, &jump_data, &jump_len, NULL);
1029 jump_align = ventoy_align(jump_len, 16);
1030
1031 wim_data->jump_exe_len = jump_len;
1032 wim_data->bin_raw_len = jump_align + sizeof(ventoy_os_param) + sizeof(ventoy_windows_data) + exe_len;
1033 wim_data->bin_align_len = ventoy_align(wim_data->bin_raw_len, 2048);
1034
1035 wim_data->jump_bin_data = grub_malloc(wim_data->bin_align_len);
1036 if (wim_data->jump_bin_data)
1037 {
1038 grub_memcpy(wim_data->jump_bin_data, jump_data, jump_len);
1039 grub_memcpy(wim_data->jump_bin_data + jump_align + sizeof(ventoy_os_param) + sizeof(ventoy_windows_data), exe_data, exe_len);
1040 }
1041
1042 debug("jump_exe_len:%u bin_raw_len:%u bin_align_len:%u\n",
1043 wim_data->jump_exe_len, wim_data->bin_raw_len, wim_data->bin_align_len);
1044
1045 return 0;
1046 }
1047
1048 int ventoy_fill_windows_rtdata(void *buf, char *isopath)
1049 {
1050 char *pos = NULL;
1051 char *script = NULL;
1052 ventoy_windows_data *data = (ventoy_windows_data *)buf;
1053
1054 grub_memset(data, 0, sizeof(ventoy_windows_data));
1055
1056 pos = grub_strstr(isopath, "/");
1057 if (!pos)
1058 {
1059 return 1;
1060 }
1061
1062 script = ventoy_plugin_get_cur_install_template(pos);
1063 if (script)
1064 {
1065 debug("auto install script <%s>\n", script);
1066 grub_snprintf(data->auto_install_script, sizeof(data->auto_install_script) - 1, "%s", script);
1067 }
1068 else
1069 {
1070 debug("auto install script skipped or not configed %s\n", pos);
1071 }
1072
1073 script = (char *)ventoy_plugin_get_injection(pos);
1074 if (script)
1075 {
1076 if (ventoy_check_file_exist("%s%s", ventoy_get_env("vtoy_iso_part"), script))
1077 {
1078 debug("injection archive <%s> OK\n", script);
1079 grub_snprintf(data->injection_archive, sizeof(data->injection_archive) - 1, "%s", script);
1080 }
1081 else
1082 {
1083 debug("injection archive <%s> NOT exist\n", script);
1084 }
1085 }
1086 else
1087 {
1088 debug("injection archive not configed %s\n", pos);
1089 }
1090
1091 return 0;
1092 }
1093
1094 static int ventoy_update_before_chain(ventoy_os_param *param, char *isopath)
1095 {
1096 grub_uint32_t jump_align = 0;
1097 wim_lookup_entry *meta_look = NULL;
1098 wim_security_header *security = NULL;
1099 wim_directory_entry *rootdir = NULL;
1100 wim_header *head = NULL;
1101 wim_lookup_entry *lookup = NULL;
1102 wim_patch *node = NULL;
1103 wim_tail *wim_data = NULL;
1104
1105 for (node = g_wim_patch_head; node; node = node->next)
1106 {
1107 if (0 == node->valid)
1108 {
1109 continue;
1110 }
1111
1112 wim_data = &node->wim_data;
1113 head = &wim_data->wim_header;
1114 lookup = (wim_lookup_entry *)wim_data->new_lookup_data;
1115
1116 jump_align = ventoy_align(wim_data->jump_exe_len, 16);
1117 if (wim_data->jump_bin_data)
1118 {
1119 grub_memcpy(wim_data->jump_bin_data + jump_align, param, sizeof(ventoy_os_param));
1120 ventoy_fill_windows_rtdata(wim_data->jump_bin_data + jump_align + sizeof(ventoy_os_param), isopath);
1121 }
1122
1123 grub_crypto_hash(GRUB_MD_SHA1, wim_data->bin_hash.sha1, wim_data->jump_bin_data, wim_data->bin_raw_len);
1124
1125 security = (wim_security_header *)wim_data->new_meta_data;
1126 if (security->len > 0)
1127 {
1128 rootdir = (wim_directory_entry *)(wim_data->new_meta_data + ((security->len + 7) & 0xFFFFFFF8U));
1129 }
1130 else
1131 {
1132 rootdir = (wim_directory_entry *)(wim_data->new_meta_data + 8);
1133 }
1134
1135 /* update all winpeshl.exe dirent entry's hash */
1136 ventoy_update_all_hash(node, wim_data->new_meta_data, rootdir);
1137
1138 /* update winpeshl.exe lookup entry data (hash/offset/length) */
1139 if (node->replace_look)
1140 {
1141 debug("update replace lookup entry_id:%ld\n", ((long)node->replace_look - (long)lookup) / sizeof(wim_lookup_entry));
1142 node->replace_look->resource.raw_size = wim_data->bin_raw_len;
1143 node->replace_look->resource.size_in_wim = wim_data->bin_raw_len;
1144 node->replace_look->resource.flags = 0;
1145 node->replace_look->resource.offset = wim_data->wim_align_size;
1146
1147 grub_memcpy(node->replace_look->hash.sha1, wim_data->bin_hash.sha1, sizeof(wim_hash));
1148 }
1149
1150 /* update metadata's hash */
1151 meta_look = ventoy_find_meta_entry(head, lookup);
1152 if (meta_look)
1153 {
1154 debug("find meta lookup entry_id:%ld\n", ((long)meta_look - (long)lookup) / sizeof(wim_lookup_entry));
1155 grub_memcpy(&meta_look->resource, &head->metadata, sizeof(wim_resource_header));
1156 grub_crypto_hash(GRUB_MD_SHA1, meta_look->hash.sha1, wim_data->new_meta_data, wim_data->new_meta_len);
1157 }
1158 }
1159
1160 return 0;
1161 }
1162
1163 static int ventoy_wimdows_locate_wim(const char *disk, wim_patch *patch)
1164 {
1165 int rc;
1166 grub_uint16_t i;
1167 grub_file_t file;
1168 grub_uint32_t exe_len;
1169 grub_uint8_t *exe_data = NULL;
1170 grub_uint8_t *decompress_data = NULL;
1171 wim_lookup_entry *lookup = NULL;
1172 wim_security_header *security = NULL;
1173 wim_directory_entry *rootdir = NULL;
1174 wim_directory_entry *search = NULL;
1175 wim_stream_entry *stream = NULL;
1176 wim_header *head = &(patch->wim_data.wim_header);
1177 wim_tail *wim_data = &patch->wim_data;
1178
1179 debug("windows locate wim start %s\n", patch->path);
1180
1181 g_ventoy_case_insensitive = 1;
1182 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", disk, patch->path);
1183 g_ventoy_case_insensitive = 0;
1184
1185 if (!file)
1186 {
1187 debug("File %s%s NOT exist\n", disk, patch->path);
1188 return 1;
1189 }
1190
1191 ventoy_get_override_info(file, &patch->wim_data);
1192
1193 grub_file_seek(file, 0);
1194 grub_file_read(file, head, sizeof(wim_header));
1195
1196 if (grub_memcmp(head->signature, WIM_HEAD_SIGNATURE, sizeof(head->signature)))
1197 {
1198 debug("Not a valid wim file %s\n", (char *)head->signature);
1199 grub_file_close(file);
1200 return 1;
1201 }
1202
1203 if (head->flags & FLAG_HEADER_COMPRESS_LZMS)
1204 {
1205 debug("LZMS compress is not supported 0x%x\n", head->flags);
1206 grub_file_close(file);
1207 return 1;
1208 }
1209
1210 rc = ventoy_read_resource(file, head, &head->metadata, (void **)&decompress_data);
1211 if (rc)
1212 {
1213 grub_printf("failed to read meta data %d\n", rc);
1214 grub_file_close(file);
1215 return 1;
1216 }
1217
1218 security = (wim_security_header *)decompress_data;
1219 if (security->len > 0)
1220 {
1221 rootdir = (wim_directory_entry *)(decompress_data + ((security->len + 7) & 0xFFFFFFF8U));
1222 }
1223 else
1224 {
1225 rootdir = (wim_directory_entry *)(decompress_data + 8);
1226 }
1227
1228
1229 debug("read lookup offset:%llu size:%llu\n", (ulonglong)head->lookup.offset, (ulonglong)head->lookup.raw_size);
1230 lookup = grub_malloc(head->lookup.raw_size);
1231 grub_file_seek(file, head->lookup.offset);
1232 grub_file_read(file, lookup, head->lookup.raw_size);
1233
1234
1235
1236 /* search winpeshl.exe dirent entry */
1237 search = search_replace_wim_dirent(file, head, lookup, decompress_data, rootdir);
1238 if (!search)
1239 {
1240 debug("Failed to find replace file %p\n", search);
1241 grub_file_close(file);
1242 return 1;
1243 }
1244
1245 debug("find replace file at %p\n", search);
1246
1247 grub_memset(&patch->old_hash, 0, sizeof(wim_hash));
1248 if (grub_memcmp(&patch->old_hash, search->hash.sha1, sizeof(wim_hash)) == 0)
1249 {
1250 debug("search hash all 0, now do deep search\n");
1251 stream = (wim_stream_entry *)((char *)search + search->len);
1252 for (i = 0; i < search->streams; i++)
1253 {
1254 if (stream->name_len == 0)
1255 {
1256 grub_memcpy(&patch->old_hash, stream->hash.sha1, sizeof(wim_hash));
1257 debug("new search hash: %02x %02x %02x %02x %02x %02x %02x %02x\n",
1258 ventoy_varg_8(patch->old_hash.sha1));
1259 break;
1260 }
1261 stream = (wim_stream_entry *)((char *)stream + stream->len);
1262 }
1263 }
1264 else
1265 {
1266 grub_memcpy(&patch->old_hash, search->hash.sha1, sizeof(wim_hash));
1267 }
1268
1269
1270 /* find and extact winpeshl.exe */
1271 patch->replace_look = ventoy_find_look_entry(head, lookup, &patch->old_hash);
1272 if (patch->replace_look)
1273 {
1274 exe_len = (grub_uint32_t)patch->replace_look->resource.raw_size;
1275 debug("find replace lookup entry_id:%ld raw_size:%u\n",
1276 ((long)patch->replace_look - (long)lookup) / sizeof(wim_lookup_entry), exe_len);
1277
1278 if (0 == ventoy_read_resource(file, head, &(patch->replace_look->resource), (void **)&(exe_data)))
1279 {
1280 ventoy_cat_exe_file_data(wim_data, exe_len, exe_data);
1281 grub_free(exe_data);
1282 }
1283 else
1284 {
1285 debug("failed to read replace file meta data %u\n", exe_len);
1286 }
1287 }
1288 else
1289 {
1290 debug("failed to find lookup entry for replace file %02x %02x %02x %02x\n",
1291 ventoy_varg_4(patch->old_hash.sha1));
1292 }
1293
1294 wim_data->wim_raw_size = (grub_uint32_t)file->size;
1295 wim_data->wim_align_size = ventoy_align(wim_data->wim_raw_size, 2048);
1296
1297 grub_check_free(wim_data->new_meta_data);
1298 wim_data->new_meta_data = decompress_data;
1299 wim_data->new_meta_len = head->metadata.raw_size;
1300 wim_data->new_meta_align_len = ventoy_align(wim_data->new_meta_len, 2048);
1301
1302 grub_check_free(wim_data->new_lookup_data);
1303 wim_data->new_lookup_data = (grub_uint8_t *)lookup;
1304 wim_data->new_lookup_len = (grub_uint32_t)head->lookup.raw_size;
1305 wim_data->new_lookup_align_len = ventoy_align(wim_data->new_lookup_len, 2048);
1306
1307 head->metadata.flags = RESHDR_FLAG_METADATA;
1308 head->metadata.offset = wim_data->wim_align_size + wim_data->bin_align_len;
1309 head->metadata.size_in_wim = wim_data->new_meta_len;
1310 head->metadata.raw_size = wim_data->new_meta_len;
1311
1312 head->lookup.flags = 0;
1313 head->lookup.offset = head->metadata.offset + wim_data->new_meta_align_len;
1314 head->lookup.size_in_wim = wim_data->new_lookup_len;
1315 head->lookup.raw_size = wim_data->new_lookup_len;
1316
1317 grub_file_close(file);
1318
1319 debug("%s", "windows locate wim finish\n");
1320 return 0;
1321 }
1322
1323 grub_err_t ventoy_cmd_locate_wim_patch(grub_extcmd_context_t ctxt, int argc, char **args)
1324 {
1325 wim_patch *node = g_wim_patch_head;
1326
1327 (void)ctxt;
1328 (void)argc;
1329 (void)args;
1330
1331 while (node)
1332 {
1333 if (0 == ventoy_wimdows_locate_wim(args[0], node))
1334 {
1335 node->valid = 1;
1336 g_wim_valid_patch_count++;
1337 }
1338
1339 node = node->next;
1340 }
1341
1342 return 0;
1343 }
1344
1345 static grub_uint32_t ventoy_get_override_chunk_num(void)
1346 {
1347 grub_uint32_t chunk_num = 0;
1348
1349 if (g_iso_fs_type == 0)
1350 {
1351 /* ISO9660: */
1352 /* per wim */
1353 /* 1: file_size and file_offset */
1354 /* 2: new wim file header */
1355 chunk_num = g_wim_valid_patch_count * 2;
1356 }
1357 else
1358 {
1359 /* UDF: */
1360 /* global: */
1361 /* 1: block count in Partition Descriptor */
1362
1363 /* per wim */
1364 /* 1: file_size in file_entry or extend_file_entry */
1365 /* 2: data_size and position in extend data short ad */
1366 /* 3: new wim file header */
1367 chunk_num = g_wim_valid_patch_count * 3 + 1;
1368 }
1369
1370 if (g_suppress_wincd_override_offset > 0)
1371 {
1372 chunk_num++;
1373 }
1374
1375 return chunk_num;
1376 }
1377
1378 static void ventoy_fill_suppress_wincd_override_data(void *override)
1379 {
1380 ventoy_override_chunk *cur = (ventoy_override_chunk *)override;
1381
1382 cur->override_size = 4;
1383 cur->img_offset = g_suppress_wincd_override_offset;
1384 grub_memcpy(cur->override_data, &g_suppress_wincd_override_data, cur->override_size);
1385 }
1386
1387 static void ventoy_windows_fill_override_data_iso9660( grub_uint64_t isosize, void *override)
1388 {
1389 grub_uint64_t sector;
1390 grub_uint32_t new_wim_size;
1391 ventoy_override_chunk *cur;
1392 wim_patch *node = NULL;
1393 wim_tail *wim_data = NULL;
1394 ventoy_iso9660_override *dirent = NULL;
1395
1396 sector = (isosize + 2047) / 2048;
1397
1398 cur = (ventoy_override_chunk *)override;
1399
1400 if (g_suppress_wincd_override_offset > 0)
1401 {
1402 ventoy_fill_suppress_wincd_override_data(cur);
1403 cur++;
1404 }
1405
1406 debug("ventoy_windows_fill_override_data_iso9660 %lu\n", (ulong)isosize);
1407
1408 for (node = g_wim_patch_head; node; node = node->next)
1409 {
1410 wim_data = &node->wim_data;
1411 if (0 == node->valid)
1412 {
1413 continue;
1414 }
1415
1416 new_wim_size = wim_data->wim_align_size + wim_data->bin_align_len +
1417 wim_data->new_meta_align_len + wim_data->new_lookup_align_len;
1418
1419 dirent = (ventoy_iso9660_override *)wim_data->override_data;
1420
1421 dirent->first_sector = (grub_uint32_t)sector;
1422 dirent->size = new_wim_size;
1423 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
1424 dirent->size_be = grub_swap_bytes32(dirent->size);
1425
1426 sector += (new_wim_size / 2048);
1427
1428 /* override 1: position and length in dirent */
1429 cur->img_offset = wim_data->override_offset;
1430 cur->override_size = wim_data->override_len;
1431 grub_memcpy(cur->override_data, wim_data->override_data, cur->override_size);
1432 cur++;
1433
1434 /* override 2: new wim file header */
1435 cur->img_offset = wim_data->file_offset;
1436 cur->override_size = sizeof(wim_header);
1437 grub_memcpy(cur->override_data, &(wim_data->wim_header), cur->override_size);
1438 cur++;
1439 }
1440
1441 return;
1442 }
1443
1444 static int ventoy_windows_fill_udf_short_ad(grub_file_t isofile, grub_uint32_t curpos,
1445 wim_tail *wim_data, grub_uint32_t new_wim_size)
1446 {
1447 int i;
1448 grub_uint32_t total = 0;
1449 grub_uint32_t left_size = 0;
1450 ventoy_udf_override *udf = NULL;
1451 ventoy_udf_override tmp[4];
1452
1453 grub_memset(tmp, 0, sizeof(tmp));
1454 grub_file_seek(isofile, wim_data->override_offset);
1455 grub_file_read(isofile, tmp, sizeof(tmp));
1456
1457 left_size = new_wim_size;
1458 udf = (ventoy_udf_override *)wim_data->override_data;
1459
1460 for (i = 0; i < 4; i++)
1461 {
1462 total += tmp[i].length;
1463 if (total >= wim_data->wim_raw_size)
1464 {
1465 udf->length = left_size;
1466 udf->position = curpos;
1467 return 0;
1468 }
1469 else
1470 {
1471 udf->length = tmp[i].length;
1472 udf->position = curpos;
1473 }
1474
1475 left_size -= tmp[i].length;
1476 curpos += udf->length / 2048;
1477 udf++;
1478 wim_data->override_len += sizeof(ventoy_udf_override);
1479 }
1480
1481 debug("######## Too many udf ad ######\n");
1482 return 1;
1483 }
1484
1485 static void ventoy_windows_fill_override_data_udf(grub_file_t isofile, void *override)
1486 {
1487 grub_uint32_t data32;
1488 grub_uint64_t data64;
1489 grub_uint64_t sector;
1490 grub_uint32_t new_wim_size;
1491 grub_uint64_t total_wim_size = 0;
1492 grub_uint32_t udf_start_block = 0;
1493 ventoy_override_chunk *cur;
1494 wim_patch *node = NULL;
1495 wim_tail *wim_data = NULL;
1496
1497 sector = (isofile->size + 2047) / 2048;
1498
1499 cur = (ventoy_override_chunk *)override;
1500
1501 if (g_suppress_wincd_override_offset > 0)
1502 {
1503 ventoy_fill_suppress_wincd_override_data(cur);
1504 cur++;
1505 }
1506
1507 debug("ventoy_windows_fill_override_data_udf %lu\n", (ulong)isofile->size);
1508
1509 for (node = g_wim_patch_head; node; node = node->next)
1510 {
1511 wim_data = &node->wim_data;
1512 if (node->valid)
1513 {
1514 if (udf_start_block == 0)
1515 {
1516 udf_start_block = wim_data->udf_start_block;
1517 }
1518 new_wim_size = wim_data->wim_align_size + wim_data->bin_align_len +
1519 wim_data->new_meta_align_len + wim_data->new_lookup_align_len;
1520 total_wim_size += new_wim_size;
1521 }
1522 }
1523
1524 //override 1: sector number in pd data
1525 cur->img_offset = grub_udf_get_last_pd_size_offset();
1526 cur->override_size = 4;
1527 data32 = sector - udf_start_block + (total_wim_size / 2048);
1528 grub_memcpy(cur->override_data, &(data32), 4);
1529
1530 for (node = g_wim_patch_head; node; node = node->next)
1531 {
1532 wim_data = &node->wim_data;
1533 if (0 == node->valid)
1534 {
1535 continue;
1536 }
1537
1538 new_wim_size = wim_data->wim_align_size + wim_data->bin_align_len +
1539 wim_data->new_meta_align_len + wim_data->new_lookup_align_len;
1540
1541 //override 2: filesize in file_entry
1542 cur++;
1543 cur->img_offset = wim_data->fe_entry_size_offset;
1544 cur->override_size = 8;
1545 data64 = new_wim_size;
1546 grub_memcpy(cur->override_data, &(data64), 8);
1547
1548 /* override 3: position and length in extend data */
1549 ventoy_windows_fill_udf_short_ad(isofile, (grub_uint32_t)sector - udf_start_block, wim_data, new_wim_size);
1550
1551 sector += (new_wim_size / 2048);
1552
1553 cur++;
1554 cur->img_offset = wim_data->override_offset;
1555 cur->override_size = wim_data->override_len;
1556 grub_memcpy(cur->override_data, wim_data->override_data, cur->override_size);
1557
1558 /* override 4: new wim file header */
1559 cur++;
1560 cur->img_offset = wim_data->file_offset;
1561 cur->override_size = sizeof(wim_header);
1562 grub_memcpy(cur->override_data, &(wim_data->wim_header), cur->override_size);
1563 }
1564
1565 return;
1566 }
1567
1568 static grub_uint32_t ventoy_windows_get_virt_data_size(void)
1569 {
1570 grub_uint32_t size = 0;
1571 wim_tail *wim_data = NULL;
1572 wim_patch *node = g_wim_patch_head;
1573
1574 while (node)
1575 {
1576 if (node->valid)
1577 {
1578 wim_data = &node->wim_data;
1579 size += sizeof(ventoy_virt_chunk) + wim_data->bin_align_len +
1580 wim_data->new_meta_align_len + wim_data->new_lookup_align_len;
1581 }
1582 node = node->next;
1583 }
1584
1585 return size;
1586 }
1587
1588 static void ventoy_windows_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain)
1589 {
1590 grub_uint64_t sector;
1591 grub_uint32_t offset;
1592 grub_uint32_t wim_secs;
1593 grub_uint32_t mem_secs;
1594 char *override = NULL;
1595 ventoy_virt_chunk *cur = NULL;
1596 wim_tail *wim_data = NULL;
1597 wim_patch *node = NULL;
1598
1599 sector = (isosize + 2047) / 2048;
1600 offset = sizeof(ventoy_virt_chunk) * g_wim_valid_patch_count;
1601
1602 override = (char *)chain + chain->virt_chunk_offset;
1603 cur = (ventoy_virt_chunk *)override;
1604
1605 for (node = g_wim_patch_head; node; node = node->next)
1606 {
1607 if (0 == node->valid)
1608 {
1609 continue;
1610 }
1611
1612 wim_data = &node->wim_data;
1613
1614 wim_secs = wim_data->wim_align_size / 2048;
1615 mem_secs = (wim_data->bin_align_len + wim_data->new_meta_align_len + wim_data->new_lookup_align_len) / 2048;
1616
1617 cur->remap_sector_start = sector;
1618 cur->remap_sector_end = cur->remap_sector_start + wim_secs;
1619 cur->org_sector_start = (grub_uint32_t)(wim_data->file_offset / 2048);
1620
1621 cur->mem_sector_start = cur->remap_sector_end;
1622 cur->mem_sector_end = cur->mem_sector_start + mem_secs;
1623 cur->mem_sector_offset = offset;
1624
1625 sector += wim_secs + mem_secs;
1626 cur++;
1627
1628 grub_memcpy(override + offset, wim_data->jump_bin_data, wim_data->bin_raw_len);
1629 offset += wim_data->bin_align_len;
1630
1631 grub_memcpy(override + offset, wim_data->new_meta_data, wim_data->new_meta_len);
1632 offset += wim_data->new_meta_align_len;
1633
1634 grub_memcpy(override + offset, wim_data->new_lookup_data, wim_data->new_lookup_len);
1635 offset += wim_data->new_lookup_align_len;
1636
1637 chain->virt_img_size_in_bytes += wim_data->wim_align_size +
1638 wim_data->bin_align_len +
1639 wim_data->new_meta_align_len +
1640 wim_data->new_lookup_align_len;
1641 }
1642
1643 return;
1644 }
1645
1646 static int ventoy_windows_drive_map(ventoy_chain_head *chain)
1647 {
1648 grub_disk_t disk;
1649
1650 debug("drive map begin <%p> ...\n", chain);
1651
1652 if (chain->disk_drive == 0x80)
1653 {
1654 disk = grub_disk_open("hd1");
1655 if (disk)
1656 {
1657 grub_disk_close(disk);
1658 debug("drive map needed %p\n", disk);
1659 chain->drive_map = 0x81;
1660 }
1661 else
1662 {
1663 debug("failed to open disk %s\n", "hd1");
1664 }
1665 }
1666 else
1667 {
1668 debug("no need to map 0x%x\n", chain->disk_drive);
1669 }
1670
1671 return 0;
1672 }
1673
1674 static int ventoy_suppress_windows_cd_prompt(void)
1675 {
1676 int rc = 1;
1677 const char *cdprompt = NULL;
1678 grub_uint64_t readpos = 0;
1679 grub_file_t file = NULL;
1680 grub_uint8_t data[32];
1681
1682 cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
1683 if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0)
1684 {
1685 debug("VTOY_WINDOWS_CD_PROMPT:<%s>\n", cdprompt);
1686 return 0;
1687 }
1688
1689 g_ventoy_case_insensitive = 1;
1690 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/boot/bootfix.bin", "(loop)");
1691 g_ventoy_case_insensitive = 0;
1692
1693 if (!file)
1694 {
1695 debug("Failed to open %s\n", "bootfix.bin");
1696 goto end;
1697 }
1698
1699 grub_file_read(file, data, 32);
1700
1701 if (file->fs && file->fs->name && grub_strcmp(file->fs->name, "udf") == 0)
1702 {
1703 readpos = grub_udf_get_file_offset(file);
1704 }
1705 else
1706 {
1707 readpos = grub_iso9660_get_last_read_pos(file);
1708 }
1709
1710 debug("bootfix.bin readpos:%lu (sector:%lu) data: %02x %02x %02x %02x\n",
1711 (ulong)readpos, (ulong)readpos / 2048, data[24], data[25], data[26], data[27]);
1712
1713 if (*(grub_uint32_t *)(data + 24) == 0x13cd0080)
1714 {
1715 g_suppress_wincd_override_offset = readpos + 24;
1716 g_suppress_wincd_override_data = 0x13cd00fd;
1717
1718 rc = 0;
1719 }
1720
1721 debug("g_suppress_wincd_override_offset:%lu\n", (ulong)g_suppress_wincd_override_offset);
1722
1723 end:
1724 check_free(file, grub_file_close);
1725
1726 return rc;
1727 }
1728
1729 grub_err_t ventoy_cmd_windows_wimboot_data(grub_extcmd_context_t ctxt, int argc, char **args)
1730 {
1731 grub_uint32_t size = 0;
1732 const char *addr = NULL;
1733 ventoy_chain_head *chain = NULL;
1734 ventoy_os_param *param = NULL;
1735 char envbuf[64];
1736
1737 (void)ctxt;
1738 (void)argc;
1739 (void)args;
1740
1741 addr = grub_env_get("vtoy_chain_mem_addr");
1742 if (!addr)
1743 {
1744 debug("Failed to find vtoy_chain_mem_addr\n");
1745 return 1;
1746 }
1747
1748 chain = (ventoy_chain_head *)(void *)grub_strtoul(addr, NULL, 16);
1749
1750 if (grub_memcmp(&g_ventoy_guid, &chain->os_param.guid, 16) != 0)
1751 {
1752 debug("os_param.guid not match\n");
1753 return 1;
1754 }
1755
1756 size = sizeof(ventoy_os_param) + sizeof(ventoy_windows_data);
1757 param = (ventoy_os_param *)grub_zalloc(size);
1758 if (!param)
1759 {
1760 return 1;
1761 }
1762
1763 grub_memcpy(param, &chain->os_param, sizeof(ventoy_os_param));
1764 ventoy_fill_windows_rtdata(param + 1, param->vtoy_img_path);
1765
1766 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)param);
1767 grub_env_set("vtoy_wimboot_mem_addr", envbuf);
1768 debug("vtoy_wimboot_mem_addr: %s\n", envbuf);
1769
1770 grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
1771 grub_env_set("vtoy_wimboot_mem_size", envbuf);
1772 debug("vtoy_wimboot_mem_size: %s\n", envbuf);
1773
1774 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1775 }
1776
1777 grub_err_t ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
1778 {
1779 int unknown_image = 0;
1780 int ventoy_compatible = 0;
1781 grub_uint32_t size = 0;
1782 grub_uint64_t isosize = 0;
1783 grub_uint32_t boot_catlog = 0;
1784 grub_uint32_t img_chunk_size = 0;
1785 grub_uint32_t override_size = 0;
1786 grub_uint32_t virt_chunk_size = 0;
1787 grub_file_t file;
1788 grub_disk_t disk;
1789 const char *pLastChain = NULL;
1790 const char *compatible;
1791 ventoy_chain_head *chain;
1792 char envbuf[64];
1793
1794 (void)ctxt;
1795 (void)argc;
1796
1797 debug("chain data begin <%s> ...\n", args[0]);
1798
1799 compatible = grub_env_get("ventoy_compatible");
1800 if (compatible && compatible[0] == 'Y')
1801 {
1802 ventoy_compatible = 1;
1803 }
1804
1805 if (NULL == g_img_chunk_list.chunk)
1806 {
1807 grub_printf("ventoy not ready\n");
1808 return 1;
1809 }
1810
1811 if (0 == ventoy_compatible && g_wim_valid_patch_count == 0)
1812 {
1813 unknown_image = 1;
1814 debug("Warning: %s was not recognized by Ventoy\n", args[0]);
1815 }
1816
1817 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
1818 if (!file)
1819 {
1820 return 1;
1821 }
1822
1823 isosize = file->size;
1824
1825 boot_catlog = ventoy_get_iso_boot_catlog(file);
1826 if (boot_catlog)
1827 {
1828 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
1829 {
1830 grub_env_set("LoadIsoEfiDriver", "on");
1831 }
1832 }
1833 else
1834 {
1835 if (ventoy_is_efi_os())
1836 {
1837 grub_env_set("LoadIsoEfiDriver", "on");
1838 }
1839 else
1840 {
1841 return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
1842 }
1843 }
1844
1845 g_suppress_wincd_override_offset = 0;
1846 if (!ventoy_is_efi_os()) /* legacy mode */
1847 {
1848 ventoy_suppress_windows_cd_prompt();
1849 }
1850
1851 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1852
1853 if (ventoy_compatible || unknown_image)
1854 {
1855 override_size = g_suppress_wincd_override_offset > 0 ? sizeof(ventoy_override_chunk) : 0;
1856 size = sizeof(ventoy_chain_head) + img_chunk_size + override_size;
1857 }
1858 else
1859 {
1860 override_size = ventoy_get_override_chunk_num() * sizeof(ventoy_override_chunk);
1861 virt_chunk_size = ventoy_windows_get_virt_data_size();
1862 size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size;
1863 }
1864
1865 pLastChain = grub_env_get("vtoy_chain_mem_addr");
1866 if (pLastChain)
1867 {
1868 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
1869 if (chain)
1870 {
1871 debug("free last chain memory %p\n", chain);
1872 grub_free(chain);
1873 }
1874 }
1875
1876 chain = grub_malloc(size);
1877 if (!chain)
1878 {
1879 grub_printf("Failed to alloc chain memory size %u\n", size);
1880 grub_file_close(file);
1881 return 1;
1882 }
1883
1884 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
1885 grub_env_set("vtoy_chain_mem_addr", envbuf);
1886 grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
1887 grub_env_set("vtoy_chain_mem_size", envbuf);
1888
1889 grub_memset(chain, 0, sizeof(ventoy_chain_head));
1890
1891 /* part 1: os parameter */
1892 g_ventoy_chain_type = ventoy_chain_windows;
1893 ventoy_fill_os_param(file, &(chain->os_param));
1894
1895 if (0 == unknown_image)
1896 {
1897 ventoy_update_before_chain(&(chain->os_param), args[0]);
1898 }
1899
1900 /* part 2: chain head */
1901 disk = file->device->disk;
1902 chain->disk_drive = disk->id;
1903 chain->disk_sector_size = (1 << disk->log_sector_size);
1904 chain->real_img_size_in_bytes = file->size;
1905 chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048;
1906 chain->boot_catalog = boot_catlog;
1907
1908 if (!ventoy_is_efi_os())
1909 {
1910 grub_file_seek(file, boot_catlog * 2048);
1911 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
1912 }
1913
1914 /* part 3: image chunk */
1915 chain->img_chunk_offset = sizeof(ventoy_chain_head);
1916 chain->img_chunk_num = g_img_chunk_list.cur_chunk;
1917 grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
1918
1919 if (ventoy_compatible || unknown_image)
1920 {
1921 if (g_suppress_wincd_override_offset > 0)
1922 {
1923 chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
1924 chain->override_chunk_num = 1;
1925 ventoy_fill_suppress_wincd_override_data((char *)chain + chain->override_chunk_offset);
1926 }
1927
1928 return 0;
1929 }
1930
1931 if (0 == g_wim_valid_patch_count)
1932 {
1933 return 0;
1934 }
1935
1936 /* part 4: override chunk */
1937 chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
1938 chain->override_chunk_num = ventoy_get_override_chunk_num();
1939
1940 if (g_iso_fs_type == 0)
1941 {
1942 ventoy_windows_fill_override_data_iso9660(isosize, (char *)chain + chain->override_chunk_offset);
1943 }
1944 else
1945 {
1946 ventoy_windows_fill_override_data_udf(file, (char *)chain + chain->override_chunk_offset);
1947 }
1948
1949 /* part 5: virt chunk */
1950 chain->virt_chunk_offset = chain->override_chunk_offset + override_size;
1951 chain->virt_chunk_num = g_wim_valid_patch_count;
1952 ventoy_windows_fill_virt_data(isosize, chain);
1953
1954 if (ventoy_is_efi_os() == 0)
1955 {
1956 ventoy_windows_drive_map(chain);
1957 }
1958
1959 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1960 }
1961
1962 static grub_uint32_t ventoy_get_wim_iso_offset(const char *filepath)
1963 {
1964 grub_uint32_t imgoffset;
1965 grub_file_t file;
1966 char cmdbuf[128];
1967
1968 grub_snprintf(cmdbuf, sizeof(cmdbuf), "loopback wimiso \"%s\"", filepath);
1969 grub_script_execute_sourcecode(cmdbuf);
1970
1971 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(wimiso)/boot/boot.wim");
1972 if (!file)
1973 {
1974 grub_printf("Failed to open boot.wim file in the image file\n");
1975 return 0;
1976 }
1977
1978 imgoffset = (grub_uint32_t)grub_iso9660_get_last_file_dirent_pos(file) + 2;
1979
1980 debug("wimiso wim direct offset: %u\n", imgoffset);
1981
1982 grub_file_close(file);
1983
1984 grub_script_execute_sourcecode("loopback -d wimiso");
1985
1986 return imgoffset;
1987 }
1988
1989 static int ventoy_get_wim_chunklist(const char *filename, ventoy_img_chunk_list *wimchunk, grub_uint64_t *wimsize)
1990 {
1991 grub_file_t wimfile;
1992
1993 wimfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", filename);
1994 if (!wimfile)
1995 {
1996 return 1;
1997 }
1998
1999 grub_memset(wimchunk, 0, sizeof(ventoy_img_chunk_list));
2000 wimchunk->chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
2001 if (NULL == wimchunk->chunk)
2002 {
2003 grub_file_close(wimfile);
2004 return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
2005 }
2006
2007 wimchunk->max_chunk = DEFAULT_CHUNK_NUM;
2008 wimchunk->cur_chunk = 0;
2009
2010 ventoy_get_block_list(wimfile, wimchunk, wimfile->device->disk->partition->start);
2011
2012 *wimsize = wimfile->size;
2013 grub_file_close(wimfile);
2014
2015 return 0;
2016 }
2017
2018 grub_err_t ventoy_cmd_wim_check_bootable(grub_extcmd_context_t ctxt, int argc, char **args)
2019 {
2020 grub_uint32_t boot_index;
2021 grub_file_t file = NULL;
2022 wim_header *wimhdr = NULL;
2023
2024 (void)ctxt;
2025 (void)argc;
2026
2027 wimhdr = grub_zalloc(sizeof(wim_header));
2028 if (!wimhdr)
2029 {
2030 return 1;
2031 }
2032
2033 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
2034 if (!file)
2035 {
2036 grub_free(wimhdr);
2037 return 1;
2038 }
2039
2040 grub_file_read(file, wimhdr, sizeof(wim_header));
2041 grub_file_close(file);
2042 boot_index = wimhdr->boot_index;
2043 grub_free(wimhdr);
2044
2045 if (boot_index == 0)
2046 {
2047 return 1;
2048 }
2049
2050 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2051 }
2052
2053 grub_err_t ventoy_cmd_wim_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
2054 {
2055 grub_uint32_t i = 0;
2056 grub_uint32_t imgoffset = 0;
2057 grub_uint32_t size = 0;
2058 grub_uint32_t isosector = 0;
2059 grub_uint64_t wimsize = 0;
2060 grub_uint32_t boot_catlog = 0;
2061 grub_uint32_t img_chunk1_size = 0;
2062 grub_uint32_t img_chunk2_size = 0;
2063 grub_uint32_t override_size = 0;
2064 grub_file_t file;
2065 grub_disk_t disk;
2066 const char *pLastChain = NULL;
2067 ventoy_chain_head *chain;
2068 ventoy_iso9660_override *dirent;
2069 ventoy_img_chunk *chunknode;
2070 ventoy_override_chunk *override;
2071 ventoy_img_chunk_list wimchunk;
2072 char envbuf[128];
2073
2074 (void)ctxt;
2075 (void)argc;
2076
2077 debug("wim chain data begin <%s> ...\n", args[0]);
2078
2079 if (NULL == g_wimiso_chunk_list.chunk || NULL == g_wimiso_path)
2080 {
2081 grub_printf("ventoy not ready\n");
2082 return 1;
2083 }
2084
2085 imgoffset = ventoy_get_wim_iso_offset(g_wimiso_path);
2086 if (imgoffset == 0)
2087 {
2088 grub_printf("image offset not found\n");
2089 return 1;
2090 }
2091
2092 if (0 != ventoy_get_wim_chunklist(args[0], &wimchunk, &wimsize))
2093 {
2094 grub_printf("Failed to get wim chunklist\n");
2095 return 1;
2096 }
2097
2098 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", g_wimiso_path);
2099 if (!file)
2100 {
2101 return 1;
2102 }
2103
2104 boot_catlog = ventoy_get_iso_boot_catlog(file);
2105
2106 img_chunk1_size = g_wimiso_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
2107 img_chunk2_size = wimchunk.cur_chunk * sizeof(ventoy_img_chunk);
2108 override_size = sizeof(ventoy_override_chunk);
2109
2110 size = sizeof(ventoy_chain_head) + img_chunk1_size + img_chunk2_size + override_size;
2111
2112 pLastChain = grub_env_get("vtoy_chain_mem_addr");
2113 if (pLastChain)
2114 {
2115 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
2116 if (chain)
2117 {
2118 debug("free last chain memory %p\n", chain);
2119 grub_free(chain);
2120 }
2121 }
2122
2123 chain = grub_malloc(size);
2124 if (!chain)
2125 {
2126 grub_printf("Failed to alloc chain memory size %u\n", size);
2127 grub_file_close(file);
2128 return 1;
2129 }
2130
2131 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
2132 grub_env_set("vtoy_chain_mem_addr", envbuf);
2133 grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
2134 grub_env_set("vtoy_chain_mem_size", envbuf);
2135
2136 grub_memset(chain, 0, sizeof(ventoy_chain_head));
2137
2138 /* part 1: os parameter */
2139 g_ventoy_chain_type = ventoy_chain_wim;
2140 ventoy_fill_os_param(file, &(chain->os_param));
2141
2142 /* part 2: chain head */
2143 disk = file->device->disk;
2144 chain->disk_drive = disk->id;
2145 chain->disk_sector_size = (1 << disk->log_sector_size);
2146 chain->real_img_size_in_bytes = ventoy_align_2k(file->size) + ventoy_align_2k(wimsize);
2147 chain->virt_img_size_in_bytes = chain->real_img_size_in_bytes;
2148 chain->boot_catalog = boot_catlog;
2149
2150 if (!ventoy_is_efi_os())
2151 {
2152 grub_file_seek(file, boot_catlog * 2048);
2153 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
2154 }
2155
2156 /* part 3: image chunk */
2157 chain->img_chunk_offset = sizeof(ventoy_chain_head);
2158 chain->img_chunk_num = g_wimiso_chunk_list.cur_chunk + wimchunk.cur_chunk;
2159 grub_memcpy((char *)chain + chain->img_chunk_offset, g_wimiso_chunk_list.chunk, img_chunk1_size);
2160
2161 /* fs cluster size >= 2048, so don't need to proc align */
2162
2163 /* align by 2048 */
2164 chunknode = wimchunk.chunk + wimchunk.cur_chunk - 1;
2165 i = (chunknode->disk_end_sector + 1 - chunknode->disk_start_sector) % 4;
2166 if (i)
2167 {
2168 chunknode->disk_end_sector += 4 - i;
2169 }
2170
2171 isosector = (grub_uint32_t)((file->size + 2047) / 2048);
2172 for (i = 0; i < wimchunk.cur_chunk; i++)
2173 {
2174 chunknode = wimchunk.chunk + i;
2175 chunknode->img_start_sector = isosector;
2176 chunknode->img_end_sector = chunknode->img_start_sector +
2177 ((chunknode->disk_end_sector + 1 - chunknode->disk_start_sector) / 4) - 1;
2178 isosector = chunknode->img_end_sector + 1;
2179 }
2180
2181 grub_memcpy((char *)chain + chain->img_chunk_offset + img_chunk1_size, wimchunk.chunk, img_chunk2_size);
2182
2183 /* part 4: override chunk */
2184 chain->override_chunk_offset = chain->img_chunk_offset + img_chunk1_size + img_chunk2_size;
2185 chain->override_chunk_num = 1;
2186
2187 override = (ventoy_override_chunk *)((char *)chain + chain->override_chunk_offset);
2188 override->img_offset = imgoffset;
2189 override->override_size = sizeof(ventoy_iso9660_override);
2190
2191 dirent = (ventoy_iso9660_override *)(override->override_data);
2192 dirent->first_sector = (grub_uint32_t)((file->size + 2047) / 2048);
2193 dirent->size = (grub_uint32_t)(wimsize);
2194 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
2195 dirent->size_be = grub_swap_bytes32(dirent->size);
2196
2197 debug("imgoffset=%u first_sector=0x%x size=0x%x\n", imgoffset, dirent->first_sector, dirent->size);
2198
2199 if (ventoy_is_efi_os() == 0)
2200 {
2201 ventoy_windows_drive_map(chain);
2202 }
2203
2204 grub_file_close(file);
2205
2206 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
2207 }
2208
2209 int ventoy_chain_file_size(const char *path)
2210 {
2211 int size;
2212 grub_file_t file;
2213
2214 file = grub_file_open(path, VENTOY_FILE_TYPE);
2215 size = (int)(file->size);
2216
2217 grub_file_close(file);
2218
2219 return size;
2220 }
2221
2222 int ventoy_chain_file_read(const char *path, int offset, int len, void *buf)
2223 {
2224 int size;
2225 grub_file_t file;
2226
2227 file = grub_file_open(path, VENTOY_FILE_TYPE);
2228 grub_file_seek(file, offset);
2229 size = grub_file_read(file, buf, len);
2230 grub_file_close(file);
2231
2232 return size;
2233 }
2234