--- /dev/null
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/linux.h>
+#include <grub/misc.h>
+#include <grub/file.h>
+#include <grub/mm.h>
+#include <grub/env.h>
+#include <grub/term.h>
+
+struct newc_head
+{
+ char magic[6];
+ char ino[8];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char nlink[8];
+ char mtime[8];
+ char filesize[8];
+ char devmajor[8];
+ char devminor[8];
+ char rdevmajor[8];
+ char rdevminor[8];
+ char namesize[8];
+ char check[8];
+} GRUB_PACKED;
+
+struct grub_linux_initrd_component
+{
+ grub_file_t file;
+ char *newc_name;
+ grub_off_t size;
+};
+
+struct dir
+{
+ char *name;
+ struct dir *next;
+ struct dir *child;
+};
+
+static char
+hex (grub_uint8_t val)
+{
+ if (val < 10)
+ return '0' + val;
+ return 'a' + val - 10;
+}
+
+static void
+set_field (char *var, grub_uint32_t val)
+{
+ int i;
+ char *ptr = var;
+ for (i = 28; i >= 0; i -= 4)
+ *ptr++ = hex((val >> i) & 0xf);
+}
+
+static grub_uint8_t *
+make_header (grub_uint8_t *ptr,
+ const char *name, grub_size_t len,
+ grub_uint32_t mode,
+ grub_off_t fsize)
+{
+ struct newc_head *head = (struct newc_head *) ptr;
+ grub_uint8_t *optr;
+ grub_size_t oh = 0;
+ grub_memcpy (head->magic, "070701", 6);
+ set_field (head->ino, 0);
+ set_field (head->mode, mode);
+ set_field (head->uid, 0);
+ set_field (head->gid, 0);
+ set_field (head->nlink, 1);
+ set_field (head->mtime, 0);
+ set_field (head->filesize, fsize);
+ set_field (head->devmajor, 0);
+ set_field (head->devminor, 0);
+ set_field (head->rdevmajor, 0);
+ set_field (head->rdevminor, 0);
+ set_field (head->namesize, len);
+ set_field (head->check, 0);
+ optr = ptr;
+ ptr += sizeof (struct newc_head);
+ grub_memcpy (ptr, name, len);
+ ptr += len;
+ oh = ALIGN_UP_OVERHEAD (ptr - optr, 4);
+ grub_memset (ptr, 0, oh);
+ ptr += oh;
+ return ptr;
+}
+
+static void
+free_dir (struct dir *root)
+{
+ if (!root)
+ return;
+ free_dir (root->next);
+ free_dir (root->child);
+ grub_free (root->name);
+ grub_free (root);
+}
+
+static grub_size_t
+insert_dir (const char *name, struct dir **root,
+ grub_uint8_t *ptr)
+{
+ struct dir *cur, **head = root;
+ const char *cb, *ce = name;
+ grub_size_t size = 0;
+ while (1)
+ {
+ for (cb = ce; *cb == '/'; cb++);
+ for (ce = cb; *ce && *ce != '/'; ce++);
+ if (!*ce)
+ break;
+
+ for (cur = *root; cur; cur = cur->next)
+ if (grub_memcmp (cur->name, cb, ce - cb)
+ && cur->name[ce - cb] == 0)
+ break;
+ if (!cur)
+ {
+ struct dir *n;
+ n = grub_zalloc (sizeof (*n));
+ if (!n)
+ return 0;
+ n->next = *head;
+ n->name = grub_strndup (cb, ce - cb);
+ if (ptr)
+ {
+ grub_dprintf ("linux", "Creating directory %s, %s\n", name, ce);
+ ptr = make_header (ptr, name, ce - name,
+ 040777, 0);
+ }
+ size += ALIGN_UP ((ce - (char *) name)
+ + sizeof (struct newc_head), 4);
+ *head = n;
+ cur = n;
+ }
+ root = &cur->next;
+ }
+ return size;
+}
+
+grub_err_t
+grub_initrd_init (int argc, char *argv[],
+ struct grub_linux_initrd_context *initrd_ctx)
+{
+ int i;
+ int newc = 0;
+ struct dir *root = 0;
+
+ initrd_ctx->nfiles = 0;
+ initrd_ctx->components = 0;
+
+ initrd_ctx->components = grub_zalloc (argc
+ * sizeof (initrd_ctx->components[0]));
+ if (!initrd_ctx->components)
+ return grub_errno;
+
+ initrd_ctx->size = 0;
+
+ for (i = 0; i < argc; i++)
+ {
+ const char *fname = argv[i];
+
+ initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
+
+ if (grub_memcmp (argv[i], "newc:", 5) == 0)
+ {
+ const char *ptr, *eptr;
+ ptr = argv[i] + 5;
+ while (*ptr == '/')
+ ptr++;
+ eptr = grub_strchr (ptr, ':');
+ if (eptr)
+ {
+ initrd_ctx->components[i].newc_name = grub_strndup (ptr, eptr - ptr);
+ if (!initrd_ctx->components[i].newc_name)
+ {
+ grub_initrd_close (initrd_ctx);
+ return grub_errno;
+ }
+ initrd_ctx->size
+ += ALIGN_UP (sizeof (struct newc_head)
+ + grub_strlen (initrd_ctx->components[i].newc_name),
+ 4);
+ initrd_ctx->size += insert_dir (initrd_ctx->components[i].newc_name,
+ &root, 0);
+ newc = 1;
+ fname = eptr + 1;
+ }
+ }
+ else if (newc)
+ {
+ initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
+ + sizeof ("TRAILER!!!") - 1, 4);
+ free_dir (root);
+ root = 0;
+ newc = 0;
+ }
+ initrd_ctx->components[i].file = grub_file_open (fname,
+ GRUB_FILE_TYPE_LINUX_INITRD
+ | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (!initrd_ctx->components[i].file)
+ {
+ grub_initrd_close (initrd_ctx);
+ return grub_errno;
+ }
+ initrd_ctx->nfiles++;
+ initrd_ctx->components[i].size
+ = grub_file_size (initrd_ctx->components[i].file);
+ initrd_ctx->size += initrd_ctx->components[i].size;
+ }
+
+ if (newc)
+ {
+ initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
+ initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
+ + sizeof ("TRAILER!!!") - 1, 4);
+ free_dir (root);
+ root = 0;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+grub_size_t
+grub_get_initrd_size (struct grub_linux_initrd_context *initrd_ctx)
+{
+ return initrd_ctx->size;
+}
+
+void
+grub_initrd_close (struct grub_linux_initrd_context *initrd_ctx)
+{
+ int i;
+ if (!initrd_ctx->components)
+ return;
+ for (i = 0; i < initrd_ctx->nfiles; i++)
+ {
+ grub_free (initrd_ctx->components[i].newc_name);
+ grub_file_close (initrd_ctx->components[i].file);
+ }
+ grub_free (initrd_ctx->components);
+ initrd_ctx->components = 0;
+}
+
+extern int ventoy_need_prompt_load_file(void);
+extern grub_ssize_t ventoy_load_file_with_prompt(grub_file_t file, void *buf, grub_ssize_t size);
+grub_err_t
+grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
+ char *argv[], void *target)
+{
+ grub_uint8_t *ptr = target;
+ int i;
+ int newc = 0;
+ struct dir *root = 0;
+ grub_ssize_t cursize = 0;
+ grub_ssize_t readsize = 0;
+
+ for (i = 0; i < initrd_ctx->nfiles; i++)
+ {
+ grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
+ ptr += ALIGN_UP_OVERHEAD (cursize, 4);
+
+ if (initrd_ctx->components[i].newc_name)
+ {
+ ptr += insert_dir (initrd_ctx->components[i].newc_name,
+ &root, ptr);
+ ptr = make_header (ptr, initrd_ctx->components[i].newc_name,
+ grub_strlen (initrd_ctx->components[i].newc_name),
+ 0100777,
+ initrd_ctx->components[i].size);
+ newc = 1;
+ }
+ else if (newc)
+ {
+ ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1,
+ 0, 0);
+ free_dir (root);
+ root = 0;
+ newc = 0;
+ }
+
+ cursize = initrd_ctx->components[i].size;
+ if (ventoy_need_prompt_load_file() && initrd_ctx->components[i].newc_name &&
+ grub_strcmp(initrd_ctx->components[i].newc_name, "boot.wim") == 0)
+ {
+ readsize = ventoy_load_file_with_prompt(initrd_ctx->components[i].file, ptr, cursize);
+ }
+ else
+ {
+ readsize = grub_file_read (initrd_ctx->components[i].file, ptr, cursize);
+ }
+
+ if (readsize != cursize)
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
+ argv[i]);
+ grub_initrd_close (initrd_ctx);
+ return grub_errno;
+ }
+ ptr += cursize;
+ }
+ if (newc)
+ {
+ grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
+ ptr += ALIGN_UP_OVERHEAD (cursize, 4);
+ ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1, 0, 0);
+ }
+ free_dir (root);
+ root = 0;
+ return GRUB_ERR_NONE;
+}
"iso", "wim", "efi", "img", "vhd", "vtoy"
};
+static int g_vtoy_load_prompt = 0;
+static char g_vtoy_prompt_msg[64];
+
static int ventoy_get_fs_type(const char *fs)
{
if (NULL == fs)
return 0;
}
+grub_err_t ventoy_cmd_set_wim_prompt(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ g_vtoy_load_prompt = 0;
+ grub_memset(g_vtoy_prompt_msg, 0, sizeof(g_vtoy_prompt_msg));
+
+ if (argc == 2 && args[0][0] == '1')
+ {
+ g_vtoy_load_prompt = 1;
+ grub_snprintf(g_vtoy_prompt_msg, sizeof(g_vtoy_prompt_msg), "%s", args[1]);
+ }
+
+ VENTOY_CMD_RETURN(GRUB_ERR_NONE);
+}
+
+int ventoy_need_prompt_load_file(void)
+{
+ return g_vtoy_load_prompt;
+}
+
+grub_ssize_t ventoy_load_file_with_prompt(grub_file_t file, void *buf, grub_ssize_t size)
+{
+ grub_uint64_t ro = 0;
+ grub_uint64_t div = 0;
+ grub_ssize_t left = size;
+ char *cur = (char *)buf;
+
+ grub_printf("\r%s 1%% ", g_vtoy_prompt_msg);
+ grub_refresh();
+
+ while (left >= VTOY_SIZE_2MB)
+ {
+ grub_file_read(file, cur, VTOY_SIZE_2MB);
+ cur += VTOY_SIZE_2MB;
+ left -= VTOY_SIZE_2MB;
+
+ div = grub_divmod64((grub_uint64_t)((size - left) * 100), (grub_uint64_t)size, &ro);
+ grub_printf("\r%s %d%% ", g_vtoy_prompt_msg, (int)div);
+ grub_refresh();
+ }
+
+ if (left > 0)
+ {
+ grub_file_read(file, cur, left);
+ }
+
+ grub_printf("\r%s 100%% \n", g_vtoy_prompt_msg);
+ grub_refresh();
+
+ return size;
+}
+
static grub_err_t ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
{
int rc = 1;
return 1;
}
- grub_file_read(file, buf, file->size);
+ if (g_vtoy_load_prompt)
+ {
+ ventoy_load_file_with_prompt(file, buf, file->size);
+ }
+ else
+ {
+ grub_file_read(file, buf, file->size);
+ }
grub_snprintf(name, sizeof(name), "%s_addr", args[2]);
grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
{ "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL },
{ "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL },
{ "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL },
+ { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL },
};