#include <grub/dl.h>
#include <grub/types.h>
#include <grub/fshelp.h>
+#include <grub/ventoy.h>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
-\f
+static int g_ventoy_block_count;
/* Check is a = b^x for some x. */
static inline int
start = grub_le_to_cpu16 (ext[i].start_hi);
start = (start << 32) + grub_le_to_cpu32 (ext[i].start);
+ g_ventoy_block_count = (int)(grub_le_to_cpu16 (ext[i].len) - fileblock);
ret = fileblock + start;
}
}
}
+int grub_ext_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list)
+{
+ int blocksize;
+ int log2blocksize;
+ grub_disk_t disk;
+ grub_disk_addr_t i = 0;
+ grub_disk_addr_t blockcnt;
+ grub_disk_addr_t blknr;
+ grub_fshelp_node_t node = NULL;
+
+ disk = file->device->disk;
+ node = &(((struct grub_ext2_data *)file->data)->diropen);
+
+ log2blocksize = LOG2_EXT2_BLOCK_SIZE (node->data);
+ blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS);
+ blockcnt = (file->size + blocksize - 1) >> (log2blocksize + GRUB_DISK_SECTOR_BITS);
+
+ while (i < blockcnt)
+ {
+ g_ventoy_block_count = 1;
+ blknr = grub_ext2_read_block(node, i);
+ if (blknr == 0)
+ {
+ return 0;
+ }
+
+ i += g_ventoy_block_count;
+ blknr = blknr << log2blocksize;
+ grub_disk_blocklist_read(chunk_list, blknr, g_ventoy_block_count * blocksize, disk->log_sector_size);
+ }
+
+ for (i = 0; i < chunk_list->cur_chunk; i++)
+ {
+ chunk_list->chunk[i].disk_start_sector += part_start;
+ chunk_list->chunk[i].disk_end_sector += part_start;
+ }
+
+ return 0;
+}
-\f
static struct grub_fs grub_ext2_fs =
{
.name = "ext2",
--- /dev/null
+/* fshelp.c -- Filesystem helper functions */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2004,2005,2006,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/disk.h>
+#include <grub/fshelp.h>
+#include <grub/dl.h>
+#include <grub/i18n.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+typedef int (*iterate_dir_func) (grub_fshelp_node_t dir,
+ grub_fshelp_iterate_dir_hook_t hook,
+ void *data);
+typedef grub_err_t (*lookup_file_func) (grub_fshelp_node_t dir,
+ const char *name,
+ grub_fshelp_node_t *foundnode,
+ enum grub_fshelp_filetype *foundtype);
+typedef char *(*read_symlink_func) (grub_fshelp_node_t node);
+
+struct stack_element {
+ struct stack_element *parent;
+ grub_fshelp_node_t node;
+ enum grub_fshelp_filetype type;
+};
+
+/* Context for grub_fshelp_find_file. */
+struct grub_fshelp_find_file_ctx
+{
+ /* Inputs. */
+ const char *path;
+ grub_fshelp_node_t rootnode;
+
+ /* Global options. */
+ int symlinknest;
+
+ /* Current file being traversed and its parents. */
+ struct stack_element *currnode;
+};
+
+/* Helper for find_file_iter. */
+static void
+free_node (grub_fshelp_node_t node, struct grub_fshelp_find_file_ctx *ctx)
+{
+ if (node != ctx->rootnode)
+ grub_free (node);
+}
+
+static void
+pop_element (struct grub_fshelp_find_file_ctx *ctx)
+{
+ struct stack_element *el;
+ el = ctx->currnode;
+ ctx->currnode = el->parent;
+ free_node (el->node, ctx);
+ grub_free (el);
+}
+
+static void
+free_stack (struct grub_fshelp_find_file_ctx *ctx)
+{
+ while (ctx->currnode)
+ pop_element (ctx);
+}
+
+static void
+go_up_a_level (struct grub_fshelp_find_file_ctx *ctx)
+{
+ if (!ctx->currnode->parent)
+ return;
+ pop_element (ctx);
+}
+
+static grub_err_t
+push_node (struct grub_fshelp_find_file_ctx *ctx, grub_fshelp_node_t node, enum grub_fshelp_filetype filetype)
+{
+ struct stack_element *nst;
+ nst = grub_malloc (sizeof (*nst));
+ if (!nst)
+ return grub_errno;
+ nst->node = node;
+ nst->type = filetype & ~GRUB_FSHELP_CASE_INSENSITIVE;
+ nst->parent = ctx->currnode;
+ ctx->currnode = nst;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+go_to_root (struct grub_fshelp_find_file_ctx *ctx)
+{
+ free_stack (ctx);
+ return push_node (ctx, ctx->rootnode, GRUB_FSHELP_DIR);
+}
+
+struct grub_fshelp_find_file_iter_ctx
+{
+ const char *name;
+ grub_fshelp_node_t *foundnode;
+ enum grub_fshelp_filetype *foundtype;
+};
+
+/* Helper for grub_fshelp_find_file. */
+static int
+find_file_iter (const char *filename, enum grub_fshelp_filetype filetype,
+ grub_fshelp_node_t node, void *data)
+{
+ struct grub_fshelp_find_file_iter_ctx *ctx = data;
+
+ if (filetype == GRUB_FSHELP_UNKNOWN ||
+ ((filetype & GRUB_FSHELP_CASE_INSENSITIVE)
+ ? grub_strcasecmp (ctx->name, filename)
+ : grub_strcmp (ctx->name, filename)))
+ {
+ grub_free (node);
+ return 0;
+ }
+
+ /* The node is found, stop iterating over the nodes. */
+ *ctx->foundnode = node;
+ *ctx->foundtype = filetype;
+ return 1;
+}
+
+static grub_err_t
+directory_find_file (grub_fshelp_node_t node, const char *name, grub_fshelp_node_t *foundnode,
+ enum grub_fshelp_filetype *foundtype, iterate_dir_func iterate_dir)
+{
+ int found;
+ struct grub_fshelp_find_file_iter_ctx ctx = {
+ .foundnode = foundnode,
+ .foundtype = foundtype,
+ .name = name
+ };
+ found = iterate_dir (node, find_file_iter, &ctx);
+ if (! found)
+ {
+ if (grub_errno)
+ return grub_errno;
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+find_file (char *currpath,
+ iterate_dir_func iterate_dir, lookup_file_func lookup_file,
+ read_symlink_func read_symlink,
+ struct grub_fshelp_find_file_ctx *ctx)
+{
+ char *name, *next;
+ grub_err_t err;
+ for (name = currpath; ; name = next)
+ {
+ char c;
+ grub_fshelp_node_t foundnode = NULL;
+ enum grub_fshelp_filetype foundtype = 0;
+
+ /* Remove all leading slashes. */
+ while (*name == '/')
+ name++;
+
+ /* Found the node! */
+ if (! *name)
+ return 0;
+
+ /* Extract the actual part from the pathname. */
+ for (next = name; *next && *next != '/'; next++);
+
+ /* At this point it is expected that the current node is a
+ directory, check if this is true. */
+ if (ctx->currnode->type != GRUB_FSHELP_DIR)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
+
+ /* Don't rely on fs providing actual . in the listing. */
+ if (next - name == 1 && name[0] == '.')
+ continue;
+
+ /* Don't rely on fs providing actual .. in the listing. */
+ if (next - name == 2 && name[0] == '.' && name[1] == '.')
+ {
+ go_up_a_level (ctx);
+ continue;
+ }
+
+ /* Iterate over the directory. */
+ c = *next;
+ *next = '\0';
+ if (lookup_file)
+ err = lookup_file (ctx->currnode->node, name, &foundnode, &foundtype);
+ else
+ err = directory_find_file (ctx->currnode->node, name, &foundnode, &foundtype, iterate_dir);
+ *next = c;
+
+ if (err)
+ return err;
+
+ if (!foundnode)
+ break;
+
+ push_node (ctx, foundnode, foundtype);
+
+ /* Read in the symlink and follow it. */
+ if (ctx->currnode->type == GRUB_FSHELP_SYMLINK)
+ {
+ char *symlink;
+
+ /* Test if the symlink does not loop. */
+ if (++ctx->symlinknest == 8)
+ return grub_error (GRUB_ERR_SYMLINK_LOOP,
+ N_("too deep nesting of symlinks"));
+
+ symlink = read_symlink (ctx->currnode->node);
+
+ if (!symlink)
+ return grub_errno;
+
+ /* The symlink is an absolute path, go back to the root inode. */
+ if (symlink[0] == '/')
+ {
+ err = go_to_root (ctx);
+ if (err)
+ return err;
+ }
+ else
+ {
+ /* Get from symlink to containing directory. */
+ go_up_a_level (ctx);
+ }
+
+
+ /* Lookup the node the symlink points to. */
+ find_file (symlink, iterate_dir, lookup_file, read_symlink, ctx);
+ grub_free (symlink);
+
+ if (grub_errno)
+ return grub_errno;
+ }
+ }
+
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"),
+ ctx->path);
+}
+
+static grub_err_t
+grub_fshelp_find_file_real (const char *path, grub_fshelp_node_t rootnode,
+ grub_fshelp_node_t *foundnode,
+ iterate_dir_func iterate_dir,
+ lookup_file_func lookup_file,
+ read_symlink_func read_symlink,
+ enum grub_fshelp_filetype expecttype)
+{
+ struct grub_fshelp_find_file_ctx ctx = {
+ .path = path,
+ .rootnode = rootnode,
+ .symlinknest = 0,
+ .currnode = 0
+ };
+ grub_err_t err;
+ enum grub_fshelp_filetype foundtype;
+ char *duppath;
+
+ if (!path || path[0] != '/')
+ {
+ return grub_error (GRUB_ERR_BAD_FILENAME, N_("invalid file name `%s'"), path);
+ }
+
+ err = go_to_root (&ctx);
+ if (err)
+ return err;
+
+ duppath = grub_strdup (path);
+ if (!duppath)
+ return grub_errno;
+ err = find_file (duppath, iterate_dir, lookup_file, read_symlink, &ctx);
+ grub_free (duppath);
+ if (err)
+ {
+ free_stack (&ctx);
+ return err;
+ }
+
+ *foundnode = ctx.currnode->node;
+ foundtype = ctx.currnode->type;
+ /* Avoid the node being freed. */
+ ctx.currnode->node = 0;
+ free_stack (&ctx);
+
+ /* Check if the node that was found was of the expected type. */
+ if (expecttype == GRUB_FSHELP_REG && foundtype != expecttype)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file"));
+ else if (expecttype == GRUB_FSHELP_DIR && foundtype != expecttype)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
+
+ return 0;
+}
+
+/* Lookup the node PATH. The node ROOTNODE describes the root of the
+ directory tree. The node found is returned in FOUNDNODE, which is
+ either a ROOTNODE or a new malloc'ed node. ITERATE_DIR is used to
+ iterate over all directory entries in the current node.
+ READ_SYMLINK is used to read the symlink if a node is a symlink.
+ EXPECTTYPE is the type node that is expected by the called, an
+ error is generated if the node is not of the expected type. */
+grub_err_t
+grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
+ grub_fshelp_node_t *foundnode,
+ iterate_dir_func iterate_dir,
+ read_symlink_func read_symlink,
+ enum grub_fshelp_filetype expecttype)
+{
+ return grub_fshelp_find_file_real (path, rootnode, foundnode,
+ iterate_dir, NULL,
+ read_symlink, expecttype);
+
+}
+
+grub_err_t
+grub_fshelp_find_file_lookup (const char *path, grub_fshelp_node_t rootnode,
+ grub_fshelp_node_t *foundnode,
+ lookup_file_func lookup_file,
+ read_symlink_func read_symlink,
+ enum grub_fshelp_filetype expecttype)
+{
+ return grub_fshelp_find_file_real (path, rootnode, foundnode,
+ NULL, lookup_file,
+ read_symlink, expecttype);
+
+}
+
+/* Read LEN bytes from the file NODE on disk DISK into the buffer BUF,
+ beginning with the block POS. READ_HOOK should be set before
+ reading a block from the file. READ_HOOK_DATA is passed through as
+ the DATA argument to READ_HOOK. GET_BLOCK is used to translate
+ file blocks to disk blocks. The file is FILESIZE bytes big and the
+ blocks have a size of LOG2BLOCKSIZE (in log2). */
+grub_ssize_t
+grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node,
+ grub_disk_read_hook_t read_hook, void *read_hook_data,
+ grub_off_t pos, grub_size_t len, char *buf,
+ grub_disk_addr_t (*get_block) (grub_fshelp_node_t node,
+ grub_disk_addr_t block),
+ grub_off_t filesize, int log2blocksize,
+ grub_disk_addr_t blocks_start)
+{
+ grub_disk_addr_t i, blockcnt;
+ int blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS);
+
+ if (pos > filesize)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("attempt to read past the end of file"));
+ return -1;
+ }
+
+ /* Adjust LEN so it we can't read past the end of the file. */
+ if (pos + len > filesize)
+ len = filesize - pos;
+
+ blockcnt = ((len + pos) + blocksize - 1) >> (log2blocksize + GRUB_DISK_SECTOR_BITS);
+
+ for (i = pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS); i < blockcnt; i++)
+ {
+ grub_disk_addr_t blknr;
+ int blockoff = pos & (blocksize - 1);
+ int blockend = blocksize;
+
+ int skipfirst = 0;
+
+ blknr = get_block (node, i);
+ if (grub_errno)
+ return -1;
+
+ blknr = blknr << log2blocksize;
+
+ /* Last block. */
+ if (i == blockcnt - 1)
+ {
+ blockend = (len + pos) & (blocksize - 1);
+
+ /* The last portion is exactly blocksize. */
+ if (! blockend)
+ blockend = blocksize;
+ }
+
+ /* First block. */
+ if (i == (pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS)))
+ {
+ skipfirst = blockoff;
+ blockend -= skipfirst;
+ }
+
+ /* If the block number is 0 this block is not stored on disk but
+ is zero filled instead. */
+ if (blknr)
+ {
+ disk->read_hook = read_hook;
+ disk->read_hook_data = read_hook_data;
+
+ grub_disk_read (disk, blknr + blocks_start, skipfirst,
+ blockend, buf);
+ disk->read_hook = 0;
+ if (grub_errno)
+ return -1;
+ }
+ else if (read_hook != (grub_disk_read_hook_t)grub_disk_blocklist_read)
+ grub_memset (buf, 0, blockend);
+
+ buf += blocksize - skipfirst;
+ }
+
+ return len;
+}
{
return ventoy_fs_udf;
}
+ else if (grub_strncmp(fs, "fat", 3) == 0)
+ {
+ return ventoy_fs_fat;
+ }
return ventoy_fs_max;
}
return;
}
-static int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
+int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
+{
+ grub_uint32_t i = 0;
+ grub_uint64_t total = 0;
+ ventoy_img_chunk *chunk = NULL;
+
+ for (i = 0; i < chunklist->cur_chunk; i++)
+ {
+ chunk = chunklist->chunk + i;
+
+ if (chunk->disk_start_sector <= start)
+ {
+ debug("%u disk start invalid %lu\n", i, (ulong)start);
+ return 1;
+ }
+
+ total += chunk->disk_end_sector + 1 - chunk->disk_start_sector;
+ }
+
+ if (total != (file->size / 512))
+ {
+ debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)(file->size / 512));
+ return 1;
+ }
+
+ return 0;
+}
+
+int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start)
{
int fs_type;
grub_uint32_t i = 0;
{
grub_fat_get_file_chunk(start, file, chunklist);
}
+ else if (fs_type == ventoy_fs_ext)
+ {
+ grub_ext_get_file_chunk(start, file, chunklist);
+ }
else
{
file->read_hook = (grub_disk_read_hook_t)grub_disk_blocklist_read;
static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args)
{
+ int rc;
grub_file_t file;
+ grub_disk_addr_t start;
(void)ctxt;
(void)argc;
g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM;
g_img_chunk_list.cur_chunk = 0;
- ventoy_get_block_list(file, &g_img_chunk_list, file->device->disk->partition->start);
+ start = file->device->disk->partition->start;
+ ventoy_get_block_list(file, &g_img_chunk_list, start);
+
+ rc = ventoy_check_block_list(file, &g_img_chunk_list, start);
grub_file_close(file);
+
+ if (rc)
+ {
+ return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported chunk list.\n");
+ }
grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
-
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
chunklist.cur_chunk = 0;
ventoy_get_block_list(file, &chunklist, 0);
-
- grub_file_close(file);
+
+ if (0 != ventoy_check_block_list(file, &chunklist, 0))
+ {
+ grub_printf("########## UNSUPPORTED ###############\n");
+ }
grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk);
}
grub_printf("\n==================================\n");
+
for (i = 0; i < chunklist.cur_chunk; i++)
{
grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i,
}
grub_free(chunklist.chunk);
+ grub_file_close(file);
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
return 0;
}
+static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ ventoy_plugin_dump_persistence();
+
+ return 0;
+}
+
static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
{
(void)ctxt;
{ "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
{ "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_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
{ "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
struct install_template *next;
}install_template;
+typedef struct persistence_config
+{
+ char isopath[256];
+ char filepath[256];
+
+ struct persistence_config *next;
+}persistence_config;
+
extern int g_ventoy_last_entry;
extern int g_ventoy_memdisk_mode;
extern int g_ventoy_iso_raw;
char * ventoy_plugin_get_install_template(const char *isopath);
void ventoy_plugin_dump_auto_install(void);
int ventoy_fill_windows_rtdata(void *buf, char *isopath);
-
+int ventoy_plugin_get_persistent_chunklist(const char *isopath, ventoy_img_chunk_list *chunk_list);
+int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start);
+int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start);
+void ventoy_plugin_dump_persistence(void);
#endif /* __VENTOY_DEF_H__ */
grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **args)
{
+ int rc;
char *template_file = NULL;
char *template_buf = NULL;
+ char *persistent_buf = NULL;
grub_uint8_t *buf = NULL;
grub_uint32_t mod;
grub_uint32_t headlen;
grub_uint32_t padlen;
grub_uint32_t img_chunk_size;
grub_uint32_t template_size = 0;
+ grub_uint32_t persistent_size = 0;
grub_file_t file;
grub_file_t scriptfile;
-
+ ventoy_img_chunk_list chunk_list;
+
(void)ctxt;
(void)argc;
g_ventoy_cpio_size = 0;
}
+ rc = ventoy_plugin_get_persistent_chunklist(args[1], &chunk_list);
+ if (rc == 0 && chunk_list.cur_chunk > 0 && chunk_list.chunk)
+ {
+ persistent_size = chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
+ persistent_buf = (char *)(chunk_list.chunk);
+ }
+
template_file = ventoy_plugin_get_install_template(args[1]);
if (template_file)
{
}
}
- g_ventoy_cpio_buf = grub_malloc(file->size + 4096 + template_size + img_chunk_size);
+ g_ventoy_cpio_buf = grub_malloc(file->size + 4096 + template_size + persistent_size + img_chunk_size);
if (NULL == g_ventoy_cpio_buf)
{
grub_file_close(file);
buf += headlen + ventoy_align(template_size, 4);
}
+ if (persistent_size > 0 && persistent_buf)
+ {
+ headlen = ventoy_cpio_newc_fill_head(buf, persistent_size, persistent_buf, "ventoy/ventoy_persistent_map");
+ buf += headlen + ventoy_align(persistent_size, 4);
+
+ grub_free(persistent_buf);
+ persistent_buf = NULL;
+ }
+
/* step2: insert os param to cpio */
headlen = ventoy_cpio_newc_fill_head(buf, 0, NULL, "ventoy/ventoy_os_param");
padlen = sizeof(ventoy_os_param);
GRUB_MOD_LICENSE ("GPLv3+");
+static char g_iso_disk_name[128];
static install_template *g_install_template_head = NULL;
+static persistence_config *g_persistence_head = NULL;
static int ventoy_plugin_control_entry(VTOY_JSON *json, const char *isodisk)
{
debug("vtoy_gfxmode %s\n", value);
grub_env_set("vtoy_gfxmode", value);
}
+
+ value = vtoy_json_get_string_ex(json->pstChild, "ventoy_left");
+ if (value)
+ {
+ grub_env_set("VTLE_LFT", value);
+ }
+
+ value = vtoy_json_get_string_ex(json->pstChild, "ventoy_top");
+ if (value)
+ {
+ grub_env_set("VTLE_TOP", value);
+ }
+
+ value = vtoy_json_get_string_ex(json->pstChild, "ventoy_color");
+ if (value)
+ {
+ grub_env_set("VTLE_CLR", value);
+ }
return 0;
}
}
+static int ventoy_plugin_persistence_entry(VTOY_JSON *json, const char *isodisk)
+{
+ const char *iso = NULL;
+ const char *persist = NULL;
+ VTOY_JSON *pNode = NULL;
+ persistence_config *node = NULL;
+ persistence_config *next = NULL;
+
+ (void)isodisk;
+
+ if (json->enDataType != JSON_TYPE_ARRAY)
+ {
+ debug("Not array %d\n", json->enDataType);
+ return 0;
+ }
+
+ if (g_persistence_head)
+ {
+ for (node = g_persistence_head; node; node = next)
+ {
+ next = node->next;
+ grub_free(node);
+ }
+
+ g_persistence_head = NULL;
+ }
+
+ for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
+ {
+ iso = vtoy_json_get_string_ex(pNode->pstChild, "image");
+ if (iso && iso[0] == '/')
+ {
+ persist = vtoy_json_get_string_ex(pNode->pstChild, "backend");
+ if (persist && persist[0] == '/')
+ {
+ node = grub_zalloc(sizeof(persistence_config));
+ if (node)
+ {
+ grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso);
+ grub_snprintf(node->filepath, sizeof(node->filepath), "%s", persist);
+
+ if (g_persistence_head)
+ {
+ node->next = g_persistence_head;
+ }
+
+ g_persistence_head = node;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
static plugin_entry g_plugin_entries[] =
{
{ "control", ventoy_plugin_control_entry },
{ "theme", ventoy_plugin_theme_entry },
{ "auto_install", ventoy_plugin_auto_install_entry },
+ { "persistence", ventoy_plugin_persistence_entry },
};
static int ventoy_parse_plugin_config(VTOY_JSON *json, const char *isodisk)
int i;
VTOY_JSON *cur = json;
+ grub_snprintf(g_iso_disk_name, sizeof(g_iso_disk_name), "%s", isodisk);
+
while (cur)
{
for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++)
return;
}
+void ventoy_plugin_dump_persistence(void)
+{
+ int rc;
+ persistence_config *node = NULL;
+ ventoy_img_chunk_list chunk_list;
+
+ for (node = g_persistence_head; node; node = node->next)
+ {
+ grub_printf("IMAGE:<%s>\n", node->isopath);
+ grub_printf("PERSIST:<%s>", node->filepath);
+
+ rc = ventoy_plugin_get_persistent_chunklist(node->isopath, &chunk_list);
+ if (rc == 0)
+ {
+ grub_printf(" [ SUCCESS ]\n\n");
+ grub_free(chunk_list.chunk);
+ }
+ else
+ {
+ grub_printf(" [ FAILED ]\n\n");
+ }
+ }
+
+ return;
+}
+
char * ventoy_plugin_get_install_template(const char *isopath)
{
return NULL;
}
+int ventoy_plugin_get_persistent_chunklist(const char *isopath, ventoy_img_chunk_list *chunk_list)
+{
+ int rc = 1;
+ grub_uint64_t start = 0;
+ grub_file_t file = NULL;
+ persistence_config *node = NULL;
+
+ for (node = g_persistence_head; node; node = node->next)
+ {
+ if (grub_strcmp(node->isopath, isopath) == 0)
+ {
+ break;
+ }
+ }
+
+ if (NULL == node)
+ {
+ goto end;
+ }
+
+ file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", g_iso_disk_name, node->filepath);
+ if (!file)
+ {
+ debug("Failed to open file %s%s\n", g_iso_disk_name, node->filepath);
+ goto end;
+ }
+
+ grub_memset(chunk_list, 0, sizeof(ventoy_img_chunk_list));
+ chunk_list->chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM);
+ if (NULL == chunk_list->chunk)
+ {
+ goto end;
+ }
+
+ chunk_list->max_chunk = DEFAULT_CHUNK_NUM;
+ chunk_list->cur_chunk = 0;
+
+ start = file->device->disk->partition->start;
+ ventoy_get_block_list(file, chunk_list, start);
+
+ if (0 != ventoy_check_block_list(file, chunk_list, start))
+ {
+ grub_free(chunk_list->chunk);
+ chunk_list->chunk = NULL;
+ goto end;
+ }
+
+ rc = 0;
+
+end:
+ if (file)
+ grub_file_close(file);
+
+ return rc;
+}
+
ventoy_fs_ext, /* 2: ext2/ext3/ext4 */
ventoy_fs_xfs, /* 3: XFS */
ventoy_fs_udf, /* 4: UDF */
+ ventoy_fs_fat, /* 5: FAT */
ventoy_fs_max
}ventoy_fs_type;
#pragma pack()
-
+int grub_ext_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list);
int grub_fat_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list);
grub_uint64_t grub_iso9660_get_last_read_pos(grub_file_t file);
grub_uint64_t grub_iso9660_get_last_file_dirent_pos(grub_file_t file);
$SED -i "/_search_for_boot_device_/a\ $BUSYBOX_PATH/sh $VTOY_PATH/hook/debian/antix-disk.sh" /init
+if [ -f $VTOY_PATH/ventoy_persistent_map ]; then
+ $SED 's#for param in $cmdline#for param in persist_all $cmdline#g' -i /init
+fi
+
# for debug
#$SED -i "/^linuxfs_error/a\exec $VTOY_PATH/busybox/sh" /init
fi
fi
+
# OK finish
set_ventoy_hook_finish
fi
}
+create_persistent_device_mapper() {
+ vtlog "create_persistent_device_mapper $*"
+
+ VT_DM_BIN=$(ventoy_find_bin_path dmsetup)
+ if [ -z "$VT_DM_BIN" ]; then
+ vtlog "no dmsetup avaliable, lastly try inbox dmsetup"
+ VT_DM_BIN=$VTOY_PATH/tool/dmsetup
+ fi
+
+ vtlog "dmsetup avaliable in system $VT_DM_BIN"
+
+ if ventoy_check_dm_module "$1"; then
+ vtlog "device-mapper module check success"
+ else
+ vterr "Error: no dm module avaliable"
+ fi
+
+ $VTOY_PATH/tool/vtoydm -p -f $VTOY_PATH/ventoy_persistent_map -d $1 > $VTOY_PATH/persistent_dm_table
+ $VT_DM_BIN create vtoy_persistent $VTOY_PATH/persistent_dm_table >>$VTLOG 2>&1
+}
+
+
+
wait_for_ventoy_dm_disk_label() {
DM=$($BUSYBOX_PATH/readlink $VTOY_DM_PATH)
vtlog "wait_for_ventoy_dm_disk_label $DM ..."
fi
}
+# create link for device-mapper
+ventoy_create_persistent_link() {
+ blkdev_num=$($VTOY_PATH/tool/dmsetup ls | grep vtoy_persistent | sed 's/.*(\([0-9][0-9]*\),.*\([0-9][0-9]*\).*/\1:\2/')
+ vtDM=$(ventoy_find_dm_id ${blkdev_num})
+
+ if ! [ -d /dev/disk/by-label ]; then
+ mkdir -p /dev/disk/by-label
+ fi
+
+ VTLABEL=$($BUSYBOX_PATH/blkid /dev/$vtDM | $SED 's/.*LABEL="\([^"]*\)".*/\1/')
+ if [ -z "$VTLABEL" ]; then
+ VTLABEL=casper-rw
+ fi
+
+ vtlog "Persistent Label: ##${VTLABEL}##"
+
+ if ! [ -e /dev/disk/by-label/$VTLABEL ]; then
+ vtOldDir=$PWD
+ cd /dev/disk/by-label
+ ln -s ../../$vtDM $VTLABEL
+ cd $vtOldDir
+ fi
+}
+
ventoy_udev_disk_common_hook() {
VTDISK="${1:0:-1}"
else
ventoy_copy_device_mapper "/dev/$1"
fi
+
+ if [ -f $VTOY_PATH/ventoy_persistent_map ]; then
+ create_persistent_device_mapper "/dev/$VTDISK"
+ ventoy_create_persistent_link
+ fi
}
+
is_inotify_ventoy_part() {
if echo $1 | grep -q "2$"; then
if ! [ -e /sys/block/$1 ]; then
$BUSYBOX_PATH/rm -rf /proc
fi
+if [ -f $VTOY_PATH/ventoy_persistent_map ]; then
+ export PERSISTENT='YES'
+ export PERSISTENCE='true'
+fi
+
cd /
unset VTOY_PATH VTLOG FIND GREP EGREP CAT AWK SED SLEEP HEAD
fi
grep "^$DISK" /proc/mounts | while read mtline; do
- mtpnt=$(echo $mtline | awk '{print $DISK}')
+ mtpnt=$(echo $mtline | awk '{print $2}')
vtdebug "Trying to umount $mtpnt ..."
umount $mtpnt >/dev/null 2>&1
done
+if swapon -s | grep -q "^${DISK}[0-9]"; then
+ swapon -s | grep "^${DISK}[0-9]" | awk '{print $1}' | while read line; do
+ vtdebug "Trying to swapoff $line ..."
+ swapoff $line
+ done
+fi
+
+
if grep "$DISK" /proc/mounts; then
vterr "$DISK is already mounted, please umount it first!"
cd $OLDDIR
exit 1
fi
+if swapon -s | grep -q "^${DISK}[0-9]"; then
+ vterr "$DISK is used as swap, please swapoff it first!"
+ cd $OLDDIR
+ exit 1
+fi
+
if [ "$MODE" = "install" ]; then
vtdebug "install ventoy ..."
vtinfo "esp partition processing ..."
+ sleep 1
+ mtpnt=$(grep "^${DISK}2" /proc/mounts | awk '{print $2}')
+ if [ -n "$mtpnt" ]; then
+ umount $mtpnt >/dev/null 2>&1
+ fi
+
if [ "$SECUREBOOT" != "YES" ]; then
mkdir ./tmp_mnt
vtdebug "mounting part2 success"
break
fi
+
+ mtpnt=$(grep "^${DISK}2" /proc/mounts | awk '{print $2}')
+ if [ -n "$mtpnt" ]; then
+ umount $mtpnt >/dev/null 2>&1
+ fi
sleep 2
done
-
+
rm -f ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
rm -f ./tmp_mnt/EFI/BOOT/grubx64.efi
rm -f ./tmp_mnt/EFI/BOOT/MokManager.efi
fi
}
+
function distro_specify_initrd_file_phase2 {
if [ -f (loop)/boot/initrd.img ]; then
vt_linux_specify_initrd_file /boot/initrd.img
vt_linux_specify_initrd_file /boot/iniramfs.igz
elif [ -f (loop)/initrd-x86_64 ]; then
vt_linux_specify_initrd_file /initrd-x86_64
+ elif [ -f (loop)/live/initrd.img ]; then
+ vt_linux_specify_initrd_file /live/initrd.img
fi
}
#############################################################
#############################################################
-set VENTOY_VERSION="1.0.10"
+set VENTOY_VERSION="1.0.11"
# Default menu display mode, you can change it as you want.
# 0: List mode
--- /dev/null
+Ventoy Logo was downloaded from https://www.easyicon.net/29165-usb_icon.html
+As descripted in the website:
+
+Author: Ahmad Hania
+License: Creative Commons (Attribution-Noncommercial-Share Alike 3.0 Unported)
{
sector_start = chunk[i].img_start_sector;
sector_num = chunk[i].img_end_sector - chunk[i].img_start_sector + 1;
-
+
+ /* TBD: to be more flexible */
+ #if 0
printf("%u %u linear %s %llu\n",
(sector_start << 2), (sector_num << 2),
diskname, (unsigned long long)chunk[i].disk_start_sector);
+ #else
+ printf("%u %u linear %s1 %llu\n",
+ (sector_start << 2), (sector_num << 2),
+ diskname, (unsigned long long)chunk[i].disk_start_sector - 2048);
+ #endif
}
free(chunk);
ventoy_fs_ext, /* 2: ext2/ext3/ext4 */
ventoy_fs_xfs, /* 3: XFS */
ventoy_fs_udf, /* 4: UDF */
+ ventoy_fs_fat, /* 5: FAT */
ventoy_fs_max
}ventoy_fs_type;
static const char *g_ventoy_fs[ventoy_fs_max] =
{
- "exfat", "ntfs", "ext*", "xfs", "udf"
+ "exfat", "ntfs", "ext*", "xfs", "udf", "fat"
};
static int vtoy_check_os_param(ventoy_os_param *param)