]> glassweightruler.freedombox.rocks Git - Ventoy.git/blobdiff - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
1. Add a new feature to directly boot wim files
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / ventoy / ventoy.c
index 883ca09744e99aaf07043cefda12d1e593d51168..1ad4ebe8b2058d53e6078dc5d8242e5becac144e 100644 (file)
@@ -33,6 +33,7 @@
 #include <grub/datetime.h>
 #include <grub/i18n.h>
 #include <grub/net.h>
+#include <grub/misc.h>
 #ifdef GRUB_MACHINE_EFI
 #include <grub/efi/efi.h>
 #endif
@@ -49,12 +50,15 @@ initrd_info *g_initrd_img_list = NULL;
 initrd_info *g_initrd_img_tail = NULL;
 int g_initrd_img_count = 0;
 int g_valid_initrd_count = 0;
+int g_default_menu_mode = 0;
 int g_filt_dot_underscore_file = 0;
 static grub_file_t g_old_file;
 
+char g_iso_path[256];
 char g_img_swap_tmp_buf[1024];
 img_info g_img_swap_tmp;
 img_info *g_ventoy_img_list = NULL;
+
 int g_ventoy_img_count = 0;
 
 grub_device_t g_enum_dev = NULL;
@@ -75,6 +79,10 @@ ventoy_guid  g_ventoy_guid = VENTOY_GUID;
 
 ventoy_img_chunk_list g_img_chunk_list;
 
+int g_wimboot_enable = 0;
+ventoy_img_chunk_list g_wimiso_chunk_list;
+char *g_wimiso_path = NULL;
+
 static char *g_tree_script_buf = NULL;
 static int g_tree_script_pos = 0;
 
@@ -341,6 +349,44 @@ static grub_err_t ventoy_cmd_file_size(grub_extcmd_context_t ctxt, int argc, cha
     return rc;
 }
 
+static grub_err_t ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+    grub_file_t file;
+    
+    (void)ctxt;
+    (void)argc;
+    (void)args;
+
+    g_wimboot_enable = 0;
+    grub_check_free(g_wimiso_path);
+    grub_check_free(g_wimiso_chunk_list.chunk);
+
+    file = grub_file_open(args[0], VENTOY_FILE_TYPE);
+    if (!file)
+    {
+        return 0;
+    }
+
+    grub_memset(&g_wimiso_chunk_list, 0, sizeof(g_wimiso_chunk_list));
+    g_wimiso_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
+    if (NULL == g_wimiso_chunk_list.chunk)
+    {
+        return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n");
+    }
+    
+    g_wimiso_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
+    g_wimiso_chunk_list.cur_chunk = 0;
+
+    ventoy_get_block_list(file, &g_wimiso_chunk_list, file->device->disk->partition->start);
+
+    g_wimboot_enable = 1;
+    g_wimiso_path = grub_strdup(args[0]);
+    
+    grub_file_close(file);
+
+    return 0;
+}
+
 static grub_err_t ventoy_cmd_load_iso_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
 {
     int rc = 1;
@@ -659,6 +705,8 @@ static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirh
 
 static int ventoy_colect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
 {
+    int i = 0;
+    int type = 0;
     int ignore = 0;
     grub_size_t len;
     img_info *img;
@@ -723,52 +771,89 @@ static int ventoy_colect_img_files(const char *filename, const struct grub_dirho
     else
     {
         debug("Find a file %s\n", filename);
+        if (len <= 4)
+        {
+            return 0;
+        }
 
-        if ((len > 4) && (0 == grub_strcasecmp(filename + len - 4, ".iso")))
+        if (0 == grub_strcasecmp(filename + len - 4, ".iso"))
         {
-            if (!ventoy_img_name_valid(filename, len))
-            {
-                return 0;
-            }
-        
-            img = grub_zalloc(sizeof(img_info));
-            if (img)
+            type = img_type_iso;
+        }
+        else if (g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim")))
+        {
+            type = img_type_wim;
+        }
+        else
+        {
+            return 0;
+        }
+
+        if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_')
+        {
+            return 0;
+        }
+    
+        img = grub_zalloc(sizeof(img_info));
+        if (img)
+        {
+            img->type = type;
+            grub_snprintf(img->name, sizeof(img->name), "%s", filename);
+
+            for (i = 0; i < (int)len; i++)
             {
-                grub_snprintf(img->name, sizeof(img->name), "%s", filename);
-                grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, filename);
-                
-                if (g_ventoy_img_list)
-                {
-                    tail = *(node->tail);
-                    img->prev = tail;
-                    tail->next = img;
-                }
-                else
+                if (filename[i] == ' ' || filename[i] == '\t' || (0 == grub_isprint(filename[i])))
                 {
-                    g_ventoy_img_list = img;
+                    img->name[i] = '*';
+                    img->unsupport = 1;
                 }
+            }
+            
+            grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name);
 
-                img->size = info->size;
-                img->id = g_ventoy_img_count;
-                img->parent = node;
-                if (node && NULL == node->firstiso)
-                {
-                    node->firstiso = img;
-                }
+            img->size = info->size;
+            if (0 == img->size)
+            {
+                img->size = ventoy_grub_get_file_size("%s/%s", g_iso_path, img->path);
+            }
 
-                node->isocnt++;
-                tmp = node->parent;
-                while (tmp)
-                {
-                    tmp->isocnt++;
-                    tmp = tmp->parent;
-                }
-                
-                *((img_info **)(node->tail)) = img;
-                g_ventoy_img_count++;
+            if (img->size < VTOY_FILT_MIN_FILE_SIZE)
+            {
+                debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size);
+                grub_free(img);
+                return 0;
+            }
+            
+            if (g_ventoy_img_list)
+            {
+                tail = *(node->tail);
+                img->prev = tail;
+                tail->next = img;
+            }
+            else
+            {
+                g_ventoy_img_list = img;
+            }
+            
+            img->id = g_ventoy_img_count;
+            img->parent = node;
+            if (node && NULL == node->firstiso)
+            {
+                node->firstiso = img;
+            }
 
-                debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
+            node->isocnt++;
+            tmp = node->parent;
+            while (tmp)
+            {
+                tmp->isocnt++;
+                tmp = tmp->parent;
             }
+            
+            *((img_info **)(node->tail)) = img;
+            g_ventoy_img_count++;
+
+            debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count);
         }
     }
 
@@ -911,11 +996,27 @@ static int ventoy_dynamic_tree_menu(img_iterator_node *node)
         offset = node->parent->dirlen;
     }
 
-    if (node != &g_img_iterator_head)
+    if (node == &g_img_iterator_head)
+    {
+        if (g_default_menu_mode == 0)
+        {
+            vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, 
+                          "menuentry \"%-10s [Return to ListView]\" VTOY_RET {\n  "
+                          "  echo 'return ...' \n"
+                          "}\n", "<--");
+        }
+    }
+    else
     {
         node->dir[node->dirlen - 1] = 0;
-        g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos, 
-                      "submenu \"%-10s [%s]\" {\n", "DIR", node->dir + offset);        
+        vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, 
+                      "submenu \"%-10s [%s]\" {\n", 
+                      "DIR", node->dir + offset);
+
+        vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, 
+                      "menuentry \"%-10s [../]\" VTOY_RET {\n  "
+                      "  echo 'return ...' \n"
+                      "}\n", "<--");
     }
 
     while ((child = ventoy_get_min_child(node)) != NULL)
@@ -925,16 +1026,19 @@ static int ventoy_dynamic_tree_menu(img_iterator_node *node)
 
     while ((img = ventoy_get_min_iso(node)) != NULL)
     {
-        g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos, 
-                  "menuentry \"%-10s %s\" --id=\"VID_%d\" {\n"
-                  "  common_menuentry \n" 
-                  "}\n", 
-                  grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT), img->name, img->id);
+        vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, 
+                      "menuentry \"%-10s %s%s\" --id=\"VID_%d\" {\n"
+                      "  %s_%s \n" 
+                      "}\n", 
+                      grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT), 
+                      img->unsupport ? "[unsupported] " : "", img->name, img->id,
+                      (img->type == img_type_iso) ? "iso" : "wim",
+                      img->unsupport ? "unsupport_menuentry" : "common_menuentry");
     }
 
     if (node != &g_img_iterator_head)
     {
-        g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos, "}\n");        
+        vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "%s", "}\n");
     }
 
     node->done = 1;
@@ -943,6 +1047,7 @@ static int ventoy_dynamic_tree_menu(img_iterator_node *node)
 
 static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
 {
+    int len;
     grub_fs_t fs;
     grub_device_t dev = NULL;
     img_info *cur = NULL;
@@ -992,14 +1097,37 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char
     if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max)
     {
         debug("unsupported fs:<%s>\n", fs->name);
+        ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
         goto fail;
     }
 
+    strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
+    if (strdata && strdata[0] == '1')
+    {
+        g_default_menu_mode = 1;
+    }
+
     grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
 
-    g_img_iterator_head.dirlen = 1;
+    grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]);
+
+    strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
+    if (strdata && strdata[0] == '/')
+    {
+        len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata);
+        if (g_img_iterator_head.dir[len] != '/')
+        {
+            g_img_iterator_head.dir[len++] = '/';
+        }
+        g_img_iterator_head.dirlen = len;
+    }
+    else
+    {
+        g_img_iterator_head.dirlen = 1;
+        grub_strcpy(g_img_iterator_head.dir, "/"); 
+    }
+
     g_img_iterator_head.tail = &tail;
-    grub_strcpy(g_img_iterator_head.dir, "/"); 
 
     for (node = &g_img_iterator_head; node; node = node->next)
     {
@@ -1032,13 +1160,23 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char
         }
     }
 
+    if (g_default_menu_mode == 1)
+    {
+        vtoy_ssprintf(g_list_script_buf, g_list_script_pos, 
+                      "menuentry \"%s [Return to TreeView]\" VTOY_RET {\n  "
+                      "  echo 'return ...' \n"
+                      "}\n", "<--");
+    }
+
     for (cur = g_ventoy_img_list; cur; cur = cur->next)
     {
-        g_list_script_pos += grub_snprintf(g_list_script_buf + g_list_script_pos, VTOY_MAX_SCRIPT_BUF - g_list_script_pos, 
-                  "menuentry \"%s\" --id=\"VID_%d\" {\n"
-                  "  common_menuentry \n" 
+        vtoy_ssprintf(g_list_script_buf, g_list_script_pos,
+                  "menuentry \"%s%s\" --id=\"VID_%d\" {\n"
+                  "  %s_%s \n" 
                   "}\n", 
-                  cur->name, cur->id);
+                  cur->unsupport ? "[unsupported] " : "", cur->name, cur->id,
+                  (cur->type == img_type_iso) ? "iso" : "wim",
+                  cur->unsupport ? "unsupport_menuentry" : "common_menuentry");
     }
     g_list_script_buf[g_list_script_pos] = 0;
 
@@ -1311,9 +1449,9 @@ int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist,
         total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
     }
 
-    if (total != (file->size / 512))
+    if (total != ((file->size + 511) / 512))
     {
-        debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)(file->size / 512));
+        debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)((file->size + 511) / 512));
         return 1;
     }
 
@@ -1417,6 +1555,117 @@ static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, ch
     VENTOY_CMD_RETURN(GRUB_ERR_NONE);
 }
 
+static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+    int i = 0;
+    int pos = 0;
+    char *buf = NULL;
+    char configfile[128];
+    install_template *node = NULL;
+        
+    (void)ctxt;
+    (void)argc;
+    (void)args;
+
+    if (argc < 1)
+    {
+        return 0;
+    }
+
+    node = ventoy_plugin_find_install_template(args[0]);
+    if (!node)
+    {
+        return 0;
+    }
+
+    buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
+    if (!buf)
+    {
+        return 0;
+    }
+
+    vtoy_ssprintf(buf, pos, "menuentry \"Boot without auto installation template\" {\n"
+                  "  echo %s\n}\n", "123");
+
+    for (i = 0; i < node->templatenum; i++)
+    {
+        vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
+                  "  echo 123\n}\n",
+                  node->templatepath[i].path);
+    }
+
+    g_ventoy_menu_esc = 1;
+    g_ventoy_suppress_esc = 1;
+
+    grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
+    grub_script_execute_sourcecode(configfile);
+    
+    g_ventoy_menu_esc = 0;
+    g_ventoy_suppress_esc = 0;
+
+    grub_free(buf);
+
+    node->cursel = g_ventoy_last_entry - 1;
+
+    VENTOY_CMD_RETURN(GRUB_ERR_NONE);
+}
+
+static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+    int i = 0;
+    int pos = 0;
+    char *buf = NULL;
+    char configfile[128];
+    persistence_config *node;
+    
+    (void)ctxt;
+    (void)argc;
+    (void)args;
+
+    if (argc < 1)
+    {
+        return 0;
+    }
+
+    node = ventoy_plugin_find_persistent(args[0]);
+    if (!node)
+    {
+        return 0;
+    }
+
+    buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF);
+    if (!buf)
+    {
+        return 0;
+    }
+
+    vtoy_ssprintf(buf, pos, "menuentry \"Boot without persistence\" {\n"
+                  "  echo %s\n}\n", "123");
+    
+    for (i = 0; i < node->backendnum; i++)
+    {
+        vtoy_ssprintf(buf, pos, "menuentry \"Boot with %s\" {\n"
+                      "  echo 123\n}\n",
+                      node->backendpath[i].path);
+        
+    }
+
+    g_ventoy_menu_esc = 1;
+    g_ventoy_suppress_esc = 1;
+
+    grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos);
+    grub_script_execute_sourcecode(configfile);
+    
+    g_ventoy_menu_esc = 0;
+    g_ventoy_suppress_esc = 0;
+
+    grub_free(buf);
+
+    node->cursel = g_ventoy_last_entry - 1;
+
+    VENTOY_CMD_RETURN(GRUB_ERR_NONE);
+}
+
 static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
 {
     grub_uint32_t i;
@@ -1783,6 +2032,30 @@ static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int a
     return 0;
 }
 
+grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
+{
+    grub_uint64_t size = 0;
+    grub_file_t file;
+    va_list ap;
+    char fullpath[256] = {0};
+
+    va_start (ap, fmt);
+    grub_vsnprintf(fullpath, 255, fmt, ap);
+    va_end (ap);
+    
+    file = grub_file_open(fullpath, VENTOY_FILE_TYPE);
+    if (!file)
+    {
+        debug("grub_file_open failed <%s>\n", fullpath);
+        grub_errno = 0;
+        return 0;
+    }
+
+    size = file->size;
+    grub_file_close(file);
+    return size;
+}
+
 grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
 {
     va_list ap;
@@ -1867,6 +2140,7 @@ static cmd_para ventoy_cmds[] =
     { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL },
     { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
     { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
+    { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
     { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
     { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
     { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
@@ -1874,6 +2148,8 @@ static cmd_para ventoy_cmds[] =
     { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
     { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
     { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL },
+    { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL },
+    { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL },
 
     { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
     { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
@@ -1892,6 +2168,7 @@ static cmd_para ventoy_cmds[] =
     { "vt_windows_reset",      ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
     { "vt_windows_locate_wim", ventoy_cmd_wimdows_locate_wim, 0, NULL, "", "", NULL },
     { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
+    { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL },
 
     { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
     { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata, 0, NULL, "", "", NULL },