# Ventoy Runtime File Injection Process: How the Injection Plugin Modifies Boot Images

> Discover Ventoy's runtime file injection process. Learn how the injection plugin modifies boot images by parsing JSON and extracting archives during boot for a seamless OS loading experience.

- Repository: [longpanda/Ventoy](https://github.com/ventoy/Ventoy)
- Tags: internals
- Published: 2026-03-01

---

**The Ventoy runtime file injection process parses JSON configuration into a linked list during boot initialization, matches ISO paths against exact file or parent directory rules to retrieve archive paths, and extracts those archives into the virtual file system before the operating system starts loading.**

Ventoy is an open-source boot manager that enables users to boot ISO files directly from USB drives without extracting them. The injection plugin, implemented in the GRUB-based boot modules of the `ventoy/Ventoy` repository, provides a powerful mechanism to dynamically add files—such as drivers, scripts, or configuration files—into the boot environment without modifying the original ISO image.

## Understanding the Injection Plugin Architecture

The runtime file injection system operates through three distinct stages implemented across the GRUB core modules. When the boot loader initializes, the plugin validates configuration data, builds an in-memory lookup structure, and later intercepts the boot process to inject archives into the virtual file system.

The implementation spans several key files in `GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/`:
- [`ventoy_plugin.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_plugin.c) handles configuration parsing and lookup logic
- [`ventoy_linux.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_linux.c) manages injection for Linux initrd images  
- [`ventoy_windows.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_windows.c) handles Windows boot archive preparation
- [`vtoyjump.c`](https://github.com/ventoy/Ventoy/blob/main/vtoyjump.c) performs the actual extraction on Windows systems

## Stage 1: Parsing the JSON Configuration

### Configuration Schema

The injection plugin reads rules from the [`ventoy.json`](https://github.com/ventoy/Ventoy/blob/main/ventoy.json) configuration file. Users define injection mappings using either exact file matches or parent directory wildcards:

```json
{
    "injection": [
        {
            "image": "/ISO/Win10.iso",
            "archive": "/ISO/injection_win10.zip"
        },
        {
            "parent": "/ISO/Linux/",
            "archive": "/ISO/injection_linux.tar.gz"
        }
    ]
}

```

- **`image`**: Specifies an exact ISO file path for one-to-one injection mapping
- **`parent`**: Matches any ISO located within the specified directory
- **`archive`**: Defines the ZIP or TAR archive containing files to inject

### Validation and Linked List Construction

During plugin initialization, `ventoy_plugin_injection_check()` in [`ventoy_plugin.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_plugin.c) validates the JSON array. The function verifies that referenced `image` or `parent` paths exist on the USB device and confirms the `archive` file is accessible.

For each valid entry, `ventoy_plugin_injection_entry()` allocates an `injection_config` structure and prepends it to the global `g_injection_head` linked list:

```c
typedef struct injection_config {
    int  type;                // injection_type_file or injection_type_parent
    int  pathlen;             // length of isopath string
    char isopath[256];        // image or parent path (absolute)
    char archive[256];        // archive path to inject
    struct injection_config *next;
} injection_config;

static int ventoy_plugin_injection_entry(VTOY_JSON *json, const char *isodisk)
{
    /* ... create node ... */
    node->type     = type;
    node->pathlen  = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", path);
    grub_snprintf(node->archive, sizeof(node->archive), "%s", archive);
    /* prepend to global list */
    node->next = g_injection_head;
    g_injection_head = node;
}

```

This linked list persists for the entire boot session, enabling O(n) lookup complexity when matching images against rules.

## Stage 2: Runtime Archive Lookup

### The Lookup Algorithm

When preparing a boot entry, the system calls `ventoy_plugin_get_injection()` with the ISO path as the argument. This function, defined in [`ventoy_plugin.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_plugin.c), implements a two-pass matching strategy:

```c
const char *ventoy_plugin_get_injection(const char *isopath)
{
    int len = (int)grub_strlen(isopath);

    /* 1️⃣ Exact file match */
    for (node = g_injection_head; node; node = node->next) {
        if (node->type == injection_type_file &&
            node->pathlen == len &&
            ventoy_strcmp(node->isopath, isopath) == 0)
            return node->archive;                // exact match
    }

    /* 2️⃣ Parent‑directory match */
    for (node = g_injection_head; node; node = node->next) {
        if (node->type == injection_type_parent &&
            node->pathlen < len &&
            ventoy_plugin_is_parent(node->isopath, node->pathlen, isopath))
            return node->archive;                // parent match
    }

    return NULL;                                 // no injection configured
}

```

### Exact vs Parent Directory Matching

The lookup prioritizes **exact file matches** over **parent directory matches**. If the first iteration finds a matching `image` rule with identical path length and string comparison, it returns immediately. Otherwise, the function iterates again seeking parent rules where `ventoy_plugin_is_parent()` verifies that the ISO path starts with the configured directory and contains no additional path separators beyond the match point.

If a match succeeds, the function returns the archive filename; otherwise, it returns `NULL`, indicating no injection should occur for that image.

## Stage 3: Applying the Injection

### Linux Initrd Integration

In [`ventoy_linux.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_linux.c), the boot command handler retrieves the injection archive and embeds it into the initrd (initial RAM disk). When `ventoy_cmd_linux()` processes a Linux boot entry, it calls the lookup function and loads the archive into memory:

```c
/* ventoy_linux.c – handling a Linux boot entry */
static int ventoy_cmd_linux(... ) {
    const char *iso_path = args[1];          // e.g. "/ISO/Win10.iso"
    const char *inject   = ventoy_plugin_get_injection(iso_path);

    if (inject) {
        /* Open the archive, load it into memory */
        file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", iso_root, inject);
        injection_size = file->size;
        injection_buf  = grub_malloc(injection_size);
        grub_file_read(file, injection_buf, injection_size);
        /* ... later packed into initrd via ventoy_cpio_newc_fill_head ... */
    }
    /* continue normal boot */
}

```

The archive contents are appended to the initrd image (around lines 1490-1497 in [`ventoy_linux.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_linux.c)), making the injected files available in the root file system when the Linux kernel initializes.

### Windows Archive Extraction

For Windows boot entries, [`ventoy_windows.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_windows.c) stores the archive path for later extraction by the `vtoyjump` helper:

```c
/* ventoy_windows.c – preparing a Windows boot entry */
script = (char *)ventoy_plugin_get_injection(pos);
if (script) {
    if (ventoy_check_file_exist("%s%s", ventoy_get_env("vtoy_iso_part"), script)) {
        /* Remember the archive name for later decompression */
        grub_snprintf(data->injection_archive,
                     sizeof(data->injection_archive) - 1, "%s", script);
    }
}

```

During the Windows chainload process, [`vtoyjump.c`](https://github.com/ventoy/Ventoy/blob/main/vtoyjump.c) accesses `g_windows_data.injection_archive` to locate and decompress the archive:

```c
/* vtoyjump.c – later during chainload */
if (g_windows_data.injection_archive[0]) {
    sprintf_s(IsoPath, sizeof(IsoPath), "%C:%s",
              VtoyLetter, g_windows_data.injection_archive);
    Log("decompress injection archive %s...", IsoPath);
    /* actual decompression implementation ... */
}

```

This approach places the injected files into the Windows file system before the OS begins its initialization sequence.

## Summary

- **The Ventoy injection plugin** enables runtime file modification without rebuilding ISO images by parsing [`ventoy.json`](https://github.com/ventoy/Ventoy/blob/main/ventoy.json) configuration into a linked list of `injection_config` structures stored in `g_injection_head`.
- **The lookup mechanism** in `ventoy_plugin_get_injection()` prioritizes exact file matches over parent directory matches, returning the associated archive path when rules apply.
- **Linux implementations** embed archives directly into the initrd through [`ventoy_linux.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_linux.c), while **Windows implementations** store archive references for extraction by [`vtoyjump.c`](https://github.com/ventoy/Ventoy/blob/main/vtoyjump.c) during the boot chainload process.
- **Key source files** include [`ventoy_plugin.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_plugin.c) for configuration management, [`ventoy_def.h`](https://github.com/ventoy/Ventoy/blob/main/ventoy_def.h) for API declarations, and OS-specific handlers in [`ventoy_linux.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_linux.c) and [`ventoy_windows.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_windows.c).

## Frequently Asked Questions

### How does Ventoy prioritize multiple injection rules for the same ISO?

**Ventoy evaluates exact file matches before checking parent directory rules.** In `ventoy_plugin_get_injection()`, the function first iterates through `g_injection_head` seeking `injection_type_file` entries with identical path lengths and string matches. Only if no exact match exists does it perform a second iteration for `injection_type_parent` matches, ensuring specific configurations override general directory rules.

### What archive formats does the Ventoy injection plugin support?

**The plugin supports standard ZIP and TAR archive formats.** The source code in [`ventoy_linux.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_linux.c) and [`vtoyjump.c`](https://github.com/ventoy/Ventoy/blob/main/vtoyjump.c) handles these archives through standard decompression routines. While the JSON configuration accepts any filename extension, the extraction logic expects archives compatible with the OS-specific boot loader modules.

### Can I use runtime file injection with Ventoy without modifying the original ISO?

**Yes, this is the primary design goal of the injection plugin.** The `ventoy_plugin_injection_entry()` function stores archive paths separately from the ISO images, and `ventoy_plugin_get_injection()` resolves these at boot time. The original ISO remains unmodified while the boot process dynamically merges the archive contents into the virtual file system visible to the operating system.

### Where does Ventoy store the injection configuration data during the boot process?

**Ventoy maintains injection data in a global linked list called `g_injection_head`.** During plugin initialization in [`ventoy_plugin.c`](https://github.com/ventoy/Ventoy/blob/main/ventoy_plugin.c), each valid JSON entry becomes an `injection_config` node containing the match type (file or parent), path strings, and archive location. This structure persists in memory throughout the GRUB session and is accessed by lookup functions when processing boot entries.