Ventoy 1.1.18 sources and Paravis patches
No files matched your search
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Background (centered layout) + theme.txt + preview.png"""
|
||||
import argparse
|
||||
import os
|
||||
from psd_tools import PSDImage
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('psd', help='layered PSD with the menu background')
|
||||
parser.add_argument('out', help='output directory')
|
||||
parser.add_argument('--bar', default=None,
|
||||
help='selected-row image (default: <out>/sel_bar.png)')
|
||||
parser.add_argument('--font', default='Montserrat-SemiBold.ttf',
|
||||
help='TTF used for the preview text')
|
||||
args = parser.parse_args()
|
||||
|
||||
SRC = args.psd
|
||||
T = args.out
|
||||
os.makedirs(T, exist_ok=True)
|
||||
|
||||
KEEP_HEADERS = {'главное меню', 'paravis flash', '© paravis.ru'}
|
||||
DROP_PIXELS = {'shape and color'} # frame of the right "additional menu"
|
||||
|
||||
psd = PSDImage.open(SRC)
|
||||
|
||||
|
||||
def walk(layer):
|
||||
for ch in layer:
|
||||
nm = (ch.name or '').strip().lower()
|
||||
if ch.kind == 'group':
|
||||
walk(ch)
|
||||
elif ch.kind == 'type':
|
||||
if nm not in KEEP_HEADERS:
|
||||
ch.visible = False
|
||||
elif ch.kind == 'pixel':
|
||||
if nm in DROP_PIXELS:
|
||||
ch.visible = False
|
||||
|
||||
|
||||
for layer in psd:
|
||||
nm = (layer.name or '')
|
||||
if nm.startswith('ТЕКСТ_БЕЗ_ОБВОДКИ'):
|
||||
layer.visible = False
|
||||
elif nm.startswith('ВЫДЕЛЕНЫЕ'):
|
||||
layer.visible = False
|
||||
else:
|
||||
walk(layer)
|
||||
|
||||
bg = psd.composite().convert('RGB')
|
||||
bg.save(os.path.join(T, 'background.png'))
|
||||
print('background:', bg.size)
|
||||
|
||||
# ---------------------------------------------------------------- geometry
|
||||
LEFT, TOP, WIDTH = 202, 100, 620
|
||||
ITEM_H, SPACING = 46, 4
|
||||
ROWS = [
|
||||
('Super Grub2 (поиск и запуск ОС)', '(1)'),
|
||||
('Поиск и запуск Windows 7-11', '(2)'),
|
||||
('Установка Windows 7, 10, 11 x64', '(3)'),
|
||||
('Ventoy (ISO-образы)', '(4)'),
|
||||
('Kaspersky Rescue Disk 18', '(5)'),
|
||||
None,
|
||||
('Windows 10, 11 PE Sergei Strelec', '(6)'),
|
||||
('Утилиты для диагностики', '(7)'),
|
||||
('Восстановление Windows MSDaRT', '(8)'),
|
||||
('Запуск / Установка Linux', '(9)'),
|
||||
None,
|
||||
('Перезагрузка', '(R)'),
|
||||
('Выключение', '(S)'),
|
||||
]
|
||||
HEIGHT = len(ROWS) * (ITEM_H + SPACING)
|
||||
|
||||
theme = f'''# Paravis Flash - GRUB2 theme (main menu)
|
||||
desktop-image: "background.png"
|
||||
desktop-color: "#e9e9e9"
|
||||
title-text: ""
|
||||
terminal-font: "Unifont Regular 16"
|
||||
|
||||
+ boot_menu {{
|
||||
left = {LEFT}
|
||||
top = {TOP}
|
||||
width = {WIDTH}
|
||||
height = {HEIGHT}
|
||||
item_font = "Montserrat SemiBold 17"
|
||||
item_color = "#2b3a55"
|
||||
selected_item_color = "#ffffff"
|
||||
item_height = {ITEM_H}
|
||||
item_spacing = {SPACING}
|
||||
item_padding = 26
|
||||
item_icon_space = 0
|
||||
icon_width = 0
|
||||
icon_height = 0
|
||||
selected_item_pixmap_style = "sel_*.png"
|
||||
scrollbar = false
|
||||
}}
|
||||
'''
|
||||
open(os.path.join(T, 'theme.txt'), 'w', encoding='utf-8').write(theme)
|
||||
print('theme.txt written')
|
||||
|
||||
# ---------------------------------------------------------------- preview
|
||||
bar_path = args.bar or os.path.join(T, 'sel_bar.png')
|
||||
bar = Image.open(bar_path).convert('RGBA').resize((WIDTH, ITEM_H))
|
||||
font = ImageFont.truetype(args.font, 17)
|
||||
img = bg.copy().convert('RGBA')
|
||||
d = ImageDraw.Draw(img)
|
||||
col = max(len(r[0]) for r in ROWS if r)
|
||||
for i, row in enumerate(ROWS):
|
||||
y = TOP + i * (ITEM_H + SPACING)
|
||||
if row is None:
|
||||
continue
|
||||
label, num = row
|
||||
if i == 0:
|
||||
img.alpha_composite(bar, (LEFT, y))
|
||||
color = (255, 255, 255) if i == 0 else (43, 58, 85)
|
||||
d.text((LEFT + 26, y + ITEM_H / 2), label, font=font, fill=color, anchor='lm')
|
||||
d.text((LEFT + WIDTH - 22, y + ITEM_H / 2), num, font=font, fill=color, anchor='rm')
|
||||
img.convert('RGB').save(os.path.join(T, 'preview.png'))
|
||||
print('preview.png written')
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
F=${1:?usage: patch-ventoy-lang.sh <path-to-vtoyefi/grub/grub.cfg>}
|
||||
python3 - "$F" <<'EOF'
|
||||
import io, sys
|
||||
p = sys.argv[1]
|
||||
s = io.open(p, encoding='utf-8', newline='').read()
|
||||
old = '''if [ -n "$VTOY_MENU_LANGUAGE" ]; then
|
||||
vt_init_menu_lang "$VTOY_MENU_LANGUAGE"
|
||||
else
|
||||
vt_init_menu_lang en_US
|
||||
fi'''
|
||||
new = '''if [ -n "$VTOY_MENU_LANGUAGE" ]; then
|
||||
vt_init_menu_lang "$VTOY_MENU_LANGUAGE"
|
||||
else
|
||||
vt_init_menu_lang ru_RU
|
||||
fi'''
|
||||
if new in s:
|
||||
print("already patched")
|
||||
elif old in s:
|
||||
s = s.replace(old, new, 1)
|
||||
io.open(p, 'w', encoding='utf-8', newline='').write(s)
|
||||
print("patched: default menu language -> ru_RU")
|
||||
else:
|
||||
print("BLOCK NOT FOUND")
|
||||
sys.exit(1)
|
||||
EOF
|
||||
grep -n -A3 'VTOY_MENU_LANGUAGE' "$F" | head -12
|
||||
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Patch Ventoy 1.1.18 grub.cfg for the custom Xorboot layout:
|
||||
|
||||
* data (ISO) partition is detected by marker file /ISO/Ventoy/NOT.DEL
|
||||
instead of being hardcoded to partition 1;
|
||||
* partition numbers are exported to the ventoy GRUB module
|
||||
(VTOY_DATA_PART_IDX / VTOY_EFI_PART_IDX);
|
||||
* user config + custom menu live in /ISO/Ventoy/ instead of /ventoy/.
|
||||
|
||||
Usage:
|
||||
python3 patch_ventoy_grubcfg.py <path-to-vtoyefi/grub/grub.cfg>
|
||||
"""
|
||||
|
||||
import io
|
||||
import sys
|
||||
|
||||
MARK = "# VTOY-CUSTOM-LAYOUT"
|
||||
|
||||
OLD_BLOCK = (
|
||||
" set vtoydev=$vtoy_dev\n"
|
||||
" set vtoy_iso_part=($vtoy_dev,1)\n"
|
||||
" set vtoy_efi_part=($vtoy_dev,2)\n"
|
||||
" \n"
|
||||
" vt_load_file_to_mem \"auto\" $prefix/fonts/unicode.pf2 vtoy_font_mem\n"
|
||||
)
|
||||
|
||||
NEW_BLOCK = (
|
||||
" set vtoydev=$vtoy_dev\n"
|
||||
" set vtoy_iso_part=($vtoy_dev,1)\n"
|
||||
" set VTOY_DATA_PART_IDX=1\n"
|
||||
" set vtoy_efi_part=($vtoy_dev,2)\n"
|
||||
" set VTOY_EFI_PART_IDX=2\n"
|
||||
"\n"
|
||||
" " + MARK + ": data (ISO) partition is the one that contains\n"
|
||||
" # /ISO/Ventoy/NOT.DEL (fallback: partition 1). VTOYEFI stays partition 2.\n"
|
||||
" for vt_part in 1 2 3 4; do\n"
|
||||
" if [ -f ($vtoy_dev,$vt_part)/ISO/Ventoy/NOT.DEL ]; then\n"
|
||||
" set vtoy_iso_part=($vtoy_dev,$vt_part)\n"
|
||||
" set VTOY_DATA_PART_IDX=$vt_part\n"
|
||||
" break\n"
|
||||
" fi\n"
|
||||
" done\n"
|
||||
" export VTOY_DATA_PART_IDX\n"
|
||||
" export VTOY_EFI_PART_IDX\n"
|
||||
"\n"
|
||||
" vt_load_file_to_mem \"auto\" $prefix/fonts/unicode.pf2 vtoy_font_mem\n"
|
||||
)
|
||||
|
||||
REPLACEMENTS = [
|
||||
# plugin json at /ISO/Ventoy/ (both tftp and normal branches)
|
||||
("$vtoy_iso_part/ventoy/ventoy.json", "$vtoy_iso_part/ISO/Ventoy/ventoy.json"),
|
||||
# custom menu file at /ISO/Ventoy/
|
||||
("$vt_plugin_path/ventoy/ventoy_grub.cfg", "$vt_plugin_path/ISO/Ventoy/ventoy_grub.cfg"),
|
||||
# default menu language: Russian (Ventoy opens in Russian unless user picks)
|
||||
(' vt_init_menu_lang en_US\n', ' vt_init_menu_lang ru_RU\n'),
|
||||
# WinPE with a non-standard BCD (Sergei Strelec: SSTR/BCD, WePE: WEPE/B64...).
|
||||
# Ventoy reads the list of wims to patch from BCD files; the x86 wims of such
|
||||
# PEs are only referenced there, so without this the mount under ia32 never
|
||||
# happens. Same set as the legacy branch uses.
|
||||
('for file in "efi/microsoft/boot/bcd"; do',
|
||||
'for file in "efi/microsoft/boot/bcd" "boot/bcd" "SSTR/BCD" "WEPE/B64" "WEPE/B32" "WEPE/BCD" "ISPE/BCD" "ISYL/BCD" "2K10/FONTS/BCD" "2K10/BCD" "boot/uqi/BCD"; do'),
|
||||
('for file in "boot/bcd" "/efi/microsoft/boot/bcd" "SSTR/BCD" "boot/bce"; do',
|
||||
'for file in "boot/bcd" "/efi/microsoft/boot/bcd" "SSTR/BCD" "WEPE/B64" "WEPE/B32" "WEPE/BCD" "ISPE/BCD" "ISYL/BCD" "2K10/FONTS/BCD" "2K10/BCD" "boot/uqi/BCD" "boot/bce"; do'),
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
path = sys.argv[1]
|
||||
src = io.open(path, encoding="utf-8", newline="").read()
|
||||
|
||||
if MARK in src:
|
||||
print("already patched:", path)
|
||||
return
|
||||
|
||||
if src.count(OLD_BLOCK) != 1:
|
||||
raise SystemExit("layout block not found exactly once")
|
||||
|
||||
src = src.replace(OLD_BLOCK, NEW_BLOCK, 1)
|
||||
print("layout block: marker-based data partition")
|
||||
|
||||
for old, new in REPLACEMENTS:
|
||||
n = src.count(old)
|
||||
if n == 0:
|
||||
raise SystemExit("not found: %s" % old)
|
||||
src = src.replace(old, new)
|
||||
print("replaced %d x %s" % (n, old))
|
||||
|
||||
io.open(path, "w", encoding="utf-8", newline="").write(src)
|
||||
print("written:", path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,214 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Patch Ventoy 1.1.18 initramfs hook for a non-standard layout.
|
||||
|
||||
Problem
|
||||
-------
|
||||
VtoyTool/vtoydm.c hardcodes:
|
||||
|
||||
int part = 1; /* ISO partition is assumed to be partition 1 */
|
||||
uint64_t offset = 2048; /* ... starting at sector 2048 */
|
||||
|
||||
so `vtoydm -p/-r` always emits device-mapper tables for `<disk>1`. When the
|
||||
ISO partition is, say, partition 3, the guest kernel rejects the table
|
||||
("sda1 too small for target") and Linux live systems fail to boot.
|
||||
|
||||
Fix
|
||||
---
|
||||
`vtoy_os_param.vtoy_disk_part_id` (packed struct, byte offset 41) already
|
||||
contains the real partition number. The hook library gets two small
|
||||
functions that rewrite the generated tables:
|
||||
|
||||
* chunk table (-p): <disk>1 + (offset + 2048 - part_start) -> <disk>N + (offset - part_start)
|
||||
* raw table (-r): size of <disk>1 -> size of <disk>N, device <disk>N
|
||||
|
||||
Partition 1 layouts are left untouched.
|
||||
|
||||
The script rewrites the newc cpio archives in place (only the changed entry
|
||||
changes), so names, order, modes and timestamps are preserved:
|
||||
|
||||
ventoy.cpio
|
||||
└── ventoy/hook.cpio.xz (xz)
|
||||
└── hook/ventoy-hook-lib.sh (patched)
|
||||
|
||||
Usage:
|
||||
python3 patch_ventoy_hook.py <in.cpio> <out.cpio>
|
||||
"""
|
||||
|
||||
import io
|
||||
import lzma
|
||||
import sys
|
||||
|
||||
MARK = "VTOY-CUSTOM-LAYOUT"
|
||||
|
||||
HELPER = '''# %s: vtoydm assumes the ISO partition is number 1 with offset 2048.
|
||||
# Rewrite generated dm tables when the ISO lives on another partition.
|
||||
ventoy_dm_fix() {
|
||||
vtfile="$1"
|
||||
vtdisk="${2#/dev/}"
|
||||
vtmode="$3"
|
||||
|
||||
[ -f /ventoy/ventoy_os_param ] || return 0
|
||||
vtpart=$($BUSYBOX_PATH/hexdump -s 41 -n 1 -e '1/1 "%%u"' /ventoy/ventoy_os_param 2>/dev/null)
|
||||
[ -z "$vtpart" ] && return 0
|
||||
[ "$vtpart" = "0" ] && return 0
|
||||
[ "$vtpart" = "1" ] && return 0
|
||||
|
||||
case "$vtdisk" in
|
||||
nvme*|mmc*|nbd*) vtsep="p" ;;
|
||||
*) vtsep="" ;;
|
||||
esac
|
||||
vtbase="/sys/class/block/${vtdisk}${vtsep}${vtpart}"
|
||||
[ -d "$vtbase" ] || return 0
|
||||
vtstart=$($CAT "$vtbase/start" 2>/dev/null)
|
||||
vtsize=$($CAT "$vtbase/size" 2>/dev/null)
|
||||
[ -z "$vtstart" ] && return 0
|
||||
|
||||
vtdev="/dev/${vtdisk}${vtsep}${vtpart}"
|
||||
vtold="/dev/${vtdisk}${vtsep}1"
|
||||
|
||||
if [ "$vtmode" = "1" ]; then
|
||||
$AWK -v dev="$vtdev" -v old="$vtold" -v st="$vtstart" '
|
||||
$3 == "linear" && $4 == old { $4 = dev; $5 = $5 + 2048 - st }
|
||||
{ print }
|
||||
' "$vtfile" > "${vtfile}.fix"
|
||||
else
|
||||
$AWK -v dev="$vtdev" -v old="$vtold" -v sz="$vtsize" '
|
||||
$3 == "linear" && $4 == old { $1 = 0; $2 = sz; $4 = dev; $5 = 0 }
|
||||
{ print }
|
||||
' "$vtfile" > "${vtfile}.fix"
|
||||
fi
|
||||
$BUSYBOX_PATH/mv "${vtfile}.fix" "$vtfile"
|
||||
vtlog "dm table fixed: $vtfile dev=$vtdev start=$vtstart part=$vtpart"
|
||||
}
|
||||
|
||||
''' % MARK
|
||||
|
||||
ANCHOR_FUNC = "create_ventoy_device_mapper() {\n"
|
||||
|
||||
CALLS_AFTER = (
|
||||
" $VTOY_PATH/tool/vtoydm -r -f $VTOY_PATH/ventoy_image_map -d $1 > $VTOY_PATH/ventoy_raw_table \n"
|
||||
)
|
||||
|
||||
CALLS_ADD = (
|
||||
" # " + MARK + ": fix dm tables for a non-part1 ISO partition\n"
|
||||
" ventoy_dm_fix $VTOY_PATH/ventoy_dm_table \"$1\" 1\n"
|
||||
" ventoy_dm_fix $VTOY_PATH/ventoy_raw_table \"$1\" 0\n"
|
||||
)
|
||||
|
||||
PERSIST_AFTER = (
|
||||
" $VTOY_PATH/tool/vtoydm -p -f $VTOY_PATH/ventoy_persistent_map -d $1 > $VTOY_PATH/persistent_dm_table \n"
|
||||
)
|
||||
|
||||
PERSIST_ADD = (
|
||||
" ventoy_dm_fix $VTOY_PATH/persistent_dm_table \"$1\" 1\n"
|
||||
)
|
||||
|
||||
|
||||
def parse_newc(data):
|
||||
"""Return list of (fields, name, body) preserving header values."""
|
||||
entries = []
|
||||
pos = 0
|
||||
while pos + 110 <= len(data):
|
||||
hdr = data[pos:pos + 110]
|
||||
if hdr[:6] != b"070701":
|
||||
break
|
||||
f = [int(hdr[6 + i * 8:14 + i * 8], 16) for i in range(13)]
|
||||
namesize = f[11]
|
||||
filesize = f[6]
|
||||
name_start = pos + 110
|
||||
name = data[name_start:name_start + namesize - 1].decode("utf-8", "surrogateescape")
|
||||
p = name_start + namesize
|
||||
p = (p + 3) & ~3
|
||||
body = data[p:p + filesize]
|
||||
p += filesize
|
||||
p = (p + 3) & ~3
|
||||
entries.append({"fields": f, "name": name, "body": body})
|
||||
pos = p
|
||||
if name == "TRAILER!!!":
|
||||
break
|
||||
return entries
|
||||
|
||||
|
||||
def build_newc(entries):
|
||||
out = bytearray()
|
||||
for e in entries:
|
||||
f = list(e["fields"])
|
||||
name = e["name"].encode("utf-8", "surrogateescape") + b"\0"
|
||||
body = e["body"]
|
||||
f[6] = len(body)
|
||||
f[11] = len(name)
|
||||
hdr = b"070701" + b"".join(b"%08X" % (v & 0xFFFFFFFF) for v in f)
|
||||
name_pad = (4 - ((110 + len(name)) % 4)) % 4
|
||||
out += hdr
|
||||
out += name
|
||||
out += b"\0" * name_pad
|
||||
out += body
|
||||
out += b"\0" * ((-len(body)) % 4)
|
||||
return bytes(out)
|
||||
|
||||
|
||||
def patch_hook_sh(text):
|
||||
if MARK in text:
|
||||
return text, False
|
||||
|
||||
if ANCHOR_FUNC not in text:
|
||||
raise SystemExit("anchor create_ventoy_device_mapper not found")
|
||||
text = text.replace(ANCHOR_FUNC, HELPER + ANCHOR_FUNC, 1)
|
||||
|
||||
if CALLS_AFTER not in text:
|
||||
raise SystemExit("anchor vtoydm -r line not found")
|
||||
text = text.replace(CALLS_AFTER, CALLS_AFTER + CALLS_ADD, 1)
|
||||
|
||||
if PERSIST_AFTER in text:
|
||||
text = text.replace(PERSIST_AFTER, PERSIST_AFTER + PERSIST_ADD, 1)
|
||||
else:
|
||||
print(" note: persistent mapper anchor not found (skipped)")
|
||||
|
||||
return text, True
|
||||
|
||||
|
||||
def main():
|
||||
src, dst = sys.argv[1], sys.argv[2]
|
||||
data = open(src, "rb").read()
|
||||
entries = parse_newc(data)
|
||||
print("ventoy.cpio entries:", [e["name"] for e in entries if e["name"] != "TRAILER!!!"][:20])
|
||||
|
||||
hook_idx = None
|
||||
for i, e in enumerate(entries):
|
||||
if e["name"] == "ventoy/hook.cpio.xz":
|
||||
hook_idx = i
|
||||
break
|
||||
if hook_idx is None:
|
||||
raise SystemExit("ventoy/hook.cpio.xz not found")
|
||||
|
||||
hook_cpio = lzma.decompress(entries[hook_idx]["body"])
|
||||
hook_entries = parse_newc(hook_cpio)
|
||||
print("hook.cpio entries:", len(hook_entries))
|
||||
|
||||
target = "hook/ventoy-hook-lib.sh"
|
||||
idx = None
|
||||
for i, e in enumerate(hook_entries):
|
||||
if e["name"] == target:
|
||||
idx = i
|
||||
break
|
||||
if idx is None:
|
||||
raise SystemExit("%s not found" % target)
|
||||
|
||||
text = hook_entries[idx]["body"].decode("utf-8", "surrogateescape")
|
||||
new_text, changed = patch_hook_sh(text)
|
||||
if not changed:
|
||||
print("already patched")
|
||||
return
|
||||
|
||||
hook_entries[idx]["body"] = new_text.encode("utf-8", "surrogateescape")
|
||||
new_hook = build_newc(hook_entries)
|
||||
entries[hook_idx]["body"] = lzma.compress(new_hook, format=lzma.FORMAT_XZ, preset=6)
|
||||
|
||||
out = build_newc(entries)
|
||||
open(dst, "wb").write(out)
|
||||
print("written %s (%d bytes)" % (dst, len(out)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Patch Ventoy 1.1.18 GRUB sources for the custom Xorboot layout:
|
||||
|
||||
* data (ISO) partition is NOT partition 1 any more: it is selected at
|
||||
runtime by grub.cfg (marker file /ISO/Ventoy/NOT.DEL) and passed in
|
||||
VTOY_DATA_PART_IDX; VTOYEFI stays partition 2 (VTOY_EFI_PART_IDX).
|
||||
* the "official device" geometry check is disabled (it hardcodes
|
||||
data=part1 @1MB, VTOYEFI=part2 right after it).
|
||||
* plugin config is read from <data>/ISO/Ventoy/ventoy.json instead of
|
||||
<data>/ventoy/ventoy.json.
|
||||
|
||||
Run inside WSL against the build tree:
|
||||
python3 patch_ventoy_layout.py /root/vtbuild/GRUB2/SRC/grub-2.04/grub-core/ventoy
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
MARK = "/* VTOY-CUSTOM-LAYOUT */"
|
||||
|
||||
|
||||
def patch_cmd(path):
|
||||
src = open(path, encoding="utf-8", errors="surrogateescape").read()
|
||||
changed = False
|
||||
|
||||
# --- 1. disable official-device geometry check ------------------------
|
||||
anchor = " char *label = NULL;\n struct grub_partition *partition;\n\n"
|
||||
early = (
|
||||
" char *label = NULL;\n"
|
||||
" struct grub_partition *partition;\n"
|
||||
"\n"
|
||||
" " + MARK + "\n"
|
||||
" /* Custom layout: ISO partition is found by marker file and VTOYEFI\n"
|
||||
" is partition 2, so the original geometry checks do not apply. */\n"
|
||||
" (void)workaround; (void)file; (void)offset; (void)devname;\n"
|
||||
" (void)fs; (void)mbr; (void)disk; (void)dev2; (void)label;\n"
|
||||
" (void)partition;\n"
|
||||
" return ventoy_set_check_result(0, NULL);\n"
|
||||
"\n"
|
||||
" if (dev->disk == NULL || dev->disk->partition == NULL)\n"
|
||||
)
|
||||
if MARK in src:
|
||||
print(" ventoy_cmd.c: device check already patched")
|
||||
else:
|
||||
if anchor not in src:
|
||||
raise SystemExit("anchor for device check not found")
|
||||
src = src.replace(anchor, early, 1)
|
||||
changed = True
|
||||
print(" ventoy_cmd.c: device check disabled")
|
||||
|
||||
# --- 2. partition size lookup via env --------------------------------
|
||||
old_fn = re.search(
|
||||
r"grub_uint64_t ventoy_get_vtoy_partsize\(int part\)\n\{.*?\n\}\n",
|
||||
src, re.S)
|
||||
if not old_fn:
|
||||
raise SystemExit("ventoy_get_vtoy_partsize not found")
|
||||
|
||||
new_fn = (
|
||||
"grub_uint64_t ventoy_get_vtoy_partsize(int part)\n"
|
||||
"{\n"
|
||||
" grub_uint64_t sectors;\n"
|
||||
" const char *env;\n"
|
||||
" int idx = part;\n"
|
||||
"\n"
|
||||
" " + MARK + "\n"
|
||||
" /* part 0 = data (ISO) partition, part 1 = VTOYEFI.\n"
|
||||
" Real partition numbers come from grub.cfg (1-based). */\n"
|
||||
" env = ventoy_get_env(part == 0 ? \"VTOY_DATA_PART_IDX\" : \"VTOY_EFI_PART_IDX\");\n"
|
||||
" if (env)\n"
|
||||
" {\n"
|
||||
" idx = (int)grub_strtol(env, NULL, 10) - 1;\n"
|
||||
" }\n"
|
||||
" if (idx < 0)\n"
|
||||
" {\n"
|
||||
" idx = 0;\n"
|
||||
" }\n"
|
||||
" if (idx > 3)\n"
|
||||
" {\n"
|
||||
" idx = 3;\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" if (grub_strncmp(g_ventoy_part_info->Head.Signature, \"EFI PART\", 8) == 0)\n"
|
||||
" {\n"
|
||||
" sectors = g_ventoy_part_info->PartTbl[idx].LastLBA + 1 - g_ventoy_part_info->PartTbl[idx].StartLBA;\n"
|
||||
" }\n"
|
||||
" else\n"
|
||||
" {\n"
|
||||
" sectors = g_ventoy_part_info->MBR.PartTbl[idx].SectorCount;\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" return sectors * 512;\n"
|
||||
"}\n"
|
||||
)
|
||||
if marker_in(old_fn.group(0)):
|
||||
print(" ventoy_cmd.c: partsize already patched")
|
||||
else:
|
||||
src = src[:old_fn.start()] + new_fn + src[old_fn.end():]
|
||||
changed = True
|
||||
print(" ventoy_cmd.c: partsize now uses VTOY_DATA_PART_IDX")
|
||||
|
||||
if changed:
|
||||
open(path, "w", encoding="utf-8", errors="surrogateescape").write(src)
|
||||
return changed
|
||||
|
||||
|
||||
def marker_in(text):
|
||||
return MARK in text
|
||||
|
||||
|
||||
def patch_plugin(path):
|
||||
src = open(path, encoding="utf-8", errors="surrogateescape").read()
|
||||
if "ISO/Ventoy/ventoy.json" in src:
|
||||
print(" ventoy_plugin.c: json path already patched")
|
||||
return False
|
||||
|
||||
n = src.count('"%s/ventoy/ventoy.json"')
|
||||
if n != 2:
|
||||
raise SystemExit("expected 2 json path occurrences, found %d" % n)
|
||||
src = src.replace('"%s/ventoy/ventoy.json"', '"%s/ISO/Ventoy/ventoy.json"')
|
||||
src = src.replace(
|
||||
'grub_printf("Plugin json file /ventoy/ventoy.json does NOT exist.\\n");',
|
||||
'grub_printf("Plugin json file /ISO/Ventoy/ventoy.json does NOT exist.\\n");')
|
||||
open(path, "w", encoding="utf-8", errors="surrogateescape").write(src)
|
||||
print(" ventoy_plugin.c: json path -> /ISO/Ventoy/ventoy.json")
|
||||
return True
|
||||
|
||||
|
||||
def patch_vhd(path):
|
||||
"""ventoy_vhd.c: VHD/IMG on the Ventoy data partition used partIndex = 0 (p1)."""
|
||||
src = open(path, encoding="utf-8", errors="surrogateescape").read()
|
||||
if MARK in src:
|
||||
print(" ventoy_vhd.c: already patched")
|
||||
return False
|
||||
|
||||
pat = re.compile(r"(gpt = g_ventoy_part_info;[ \t]*\n)(\s*)partIndex = 0;")
|
||||
m = pat.search(src)
|
||||
if not m:
|
||||
raise SystemExit("vhd partIndex anchor not found")
|
||||
|
||||
ind = m.group(2)
|
||||
new = (
|
||||
m.group(1)
|
||||
+ ind + MARK + "\n"
|
||||
+ ind + "/* data partition number comes from grub.cfg (VTOY_DATA_PART_IDX) */\n"
|
||||
+ ind + "partIndex = 0;\n"
|
||||
+ ind + "{\n"
|
||||
+ ind + " const char *vtEnv = ventoy_get_env(\"VTOY_DATA_PART_IDX\");\n"
|
||||
+ ind + " if (vtEnv)\n"
|
||||
+ ind + " {\n"
|
||||
+ ind + " partIndex = (int)grub_strtol(vtEnv, NULL, 10) - 1;\n"
|
||||
+ ind + " }\n"
|
||||
+ ind + " if (partIndex < 0)\n"
|
||||
+ ind + " {\n"
|
||||
+ ind + " partIndex = 0;\n"
|
||||
+ ind + " }\n"
|
||||
+ ind + " if (partIndex > 3)\n"
|
||||
+ ind + " {\n"
|
||||
+ ind + " partIndex = 3;\n"
|
||||
+ ind + " }\n"
|
||||
+ ind + "}"
|
||||
)
|
||||
src = src[:m.start()] + new + src[m.end():]
|
||||
open(path, "w", encoding="utf-8", errors="surrogateescape").write(src)
|
||||
print(" ventoy_vhd.c: partIndex now uses VTOY_DATA_PART_IDX")
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
d = sys.argv[1] if len(sys.argv) > 1 else "."
|
||||
patch_cmd(os.path.join(d, "ventoy_cmd.c"))
|
||||
patch_plugin(os.path.join(d, "ventoy_plugin.c"))
|
||||
patch_vhd(os.path.join(d, "ventoy_vhd.c"))
|
||||
print("OK")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Patch Ventoy 1.1.18 vtoyjump32.exe / vtoyjump64.exe to skip the "Ventoy disk"
|
||||
MBR marker check (CheckVentoyDisk), so the ISO can be mounted when the USB
|
||||
stick uses a third-party MBR (Xorboot) instead of Ventoy's own MBR.
|
||||
|
||||
CheckVentoyDisk() in vtoyjump.c does:
|
||||
UINT8 check[8] = { 0x56,0x54,0x00,0x47,0x65,0x00,0x48,0x44 };
|
||||
...
|
||||
if (memcmp(SectorBuf + 0x190, check, 8) == 0)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
|
||||
Patches (always return TRUE, code size unchanged):
|
||||
|
||||
vtoyjump64.exe (PE32+, .text VMA 0x140001000, file off 0x400)
|
||||
0x140008D0E 0F 94 C3 sete %bl
|
||||
-> B3 01 90 mov $1,%bl ; nop
|
||||
(ebx is zeroed at function entry, then copied to eax at 0x140008D11)
|
||||
|
||||
vtoyjump32.exe (PE32, .text VMA 0x00401000, file off 0x400)
|
||||
0x00407BEB 75 87 jne -> false
|
||||
-> 90 90 nop nop
|
||||
0x00407BF3 0F 85 7B FF FF FF jne -> false
|
||||
-> 90 90 90 90 90 90 nop x6
|
||||
|
||||
Usage:
|
||||
python3 patch_vtoyjump.py <dir-with-vtoyjump32.exe-and-vtoyjump64.exe>
|
||||
|
||||
Re-running is safe: already patched files are detected and skipped.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
PATCHES = {
|
||||
"vtoyjump64.exe": [
|
||||
(0x810E, bytes([0x0F, 0x94, 0xC3]), bytes([0xB3, 0x01, 0x90])),
|
||||
],
|
||||
"vtoyjump32.exe": [
|
||||
(0x6FEB, bytes([0x75, 0x87]), bytes([0x90, 0x90])),
|
||||
(0x6FF3, bytes([0x0F, 0x85, 0x7B, 0xFF, 0xFF, 0xFF]),
|
||||
bytes([0x90, 0x90, 0x90, 0x90, 0x90, 0x90])),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def patch_file(path, patches):
|
||||
with open(path, "rb") as f:
|
||||
data = bytearray(f.read())
|
||||
|
||||
changed = False
|
||||
for off, orig, new in patches:
|
||||
cur = bytes(data[off:off + len(orig)])
|
||||
if cur == new:
|
||||
print(" %s @0x%X already patched" % (os.path.basename(path), off))
|
||||
continue
|
||||
if cur != orig:
|
||||
raise SystemExit(
|
||||
" %s @0x%X unexpected bytes: %s (expected %s)" % (
|
||||
os.path.basename(path), off, cur.hex(" "), orig.hex(" ")))
|
||||
data[off:off + len(new)] = new
|
||||
print(" %s @0x%X patched: %s -> %s" % (
|
||||
os.path.basename(path), off, orig.hex(" "), new.hex(" ")))
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
with open(path, "wb") as f:
|
||||
f.write(data)
|
||||
return changed
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print(__doc__)
|
||||
return 1
|
||||
|
||||
d = sys.argv[1]
|
||||
rc = 0
|
||||
for name, patches in PATCHES.items():
|
||||
path = os.path.join(d, name)
|
||||
if not os.path.isfile(path):
|
||||
print("MISSING: %s" % path)
|
||||
rc = 1
|
||||
continue
|
||||
print("%s (%d bytes)" % (path, os.path.getsize(path)))
|
||||
try:
|
||||
patch_file(path, patches)
|
||||
except SystemExit as e:
|
||||
print(e)
|
||||
rc = 1
|
||||
|
||||
print("DONE" if rc == 0 else "FAILED")
|
||||
return rc
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2024 The Montserrat.Git Project Authors (https://github.com/JulietaUla/Montserrat.git)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 234 B |
|
After Width: | Height: | Size: 144 B |
|
After Width: | Height: | Size: 1023 B |
|
After Width: | Height: | Size: 428 B |
|
After Width: | Height: | Size: 96 B |
|
After Width: | Height: | Size: 170 B |
|
After Width: | Height: | Size: 157 B |
|
After Width: | Height: | Size: 976 B |
|
After Width: | Height: | Size: 952 B |
|
After Width: | Height: | Size: 963 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 963 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 952 B |
@@ -0,0 +1,88 @@
|
||||
# Paravis Flash - Ventoy theme (1024x768)
|
||||
desktop-image: "background.png"
|
||||
desktop-color: "#e8e8e8"
|
||||
title-text: ""
|
||||
title-color: "#293554"
|
||||
message-color: "#293554"
|
||||
terminal-box: "terminal_box_*.png"
|
||||
|
||||
+ boot_menu {
|
||||
left = 80
|
||||
top = 120
|
||||
width = 864
|
||||
height = 500
|
||||
item_font = "Tahoma Regular 20"
|
||||
item_color = "#293554"
|
||||
selected_item_color = "#ffffff"
|
||||
item_height = 38
|
||||
item_spacing = 3
|
||||
item_padding = 10
|
||||
item_icon_space = 0
|
||||
icon_width = 0
|
||||
icon_height = 0
|
||||
selected_item_pixmap_style = "sel_*.png"
|
||||
scrollbar = true
|
||||
scrollbar_width = 8
|
||||
scrollbar_thumb = "slider_*.png"
|
||||
}
|
||||
|
||||
+ progress_bar {
|
||||
id = "__timeout__"
|
||||
text = "@TIMEOUT_NOTIFICATION_SHORT@"
|
||||
left = 30%
|
||||
width = 20%
|
||||
top = 12%
|
||||
text_color = "#293554"
|
||||
bar_style = "*"
|
||||
highlight_style = "*"
|
||||
}
|
||||
|
||||
+ hbox {
|
||||
left = 4%
|
||||
top = 92%
|
||||
width = 60%
|
||||
height = 20
|
||||
+ label { text = "@VTOY_HOTKEY_TIP@" color = "#293554" align = "left" }
|
||||
}
|
||||
|
||||
|
||||
|
||||
+ hbox {
|
||||
left = 4%
|
||||
top = 86%
|
||||
width = 40%
|
||||
height = 20
|
||||
+ label { text = "@VTOY_MEM_DISK@" color = "#293554" align = "left" }
|
||||
}
|
||||
|
||||
+ hbox {
|
||||
left = 4%
|
||||
top = 83%
|
||||
width = 40%
|
||||
height = 20
|
||||
+ label { text = "@VTOY_ISO_RAW@" color = "#293554" align = "left" }
|
||||
}
|
||||
|
||||
+ hbox {
|
||||
left = 50%
|
||||
top = 83%
|
||||
width = 40%
|
||||
height = 20
|
||||
+ label { text = "@VTOY_GRUB2_MODE@" color = "#293554" align = "left" }
|
||||
}
|
||||
|
||||
+ hbox {
|
||||
left = 50%
|
||||
top = 86%
|
||||
width = 40%
|
||||
height = 20
|
||||
+ label { text = "@VTOY_WIMBOOT_MODE@" color = "#293554" align = "left" }
|
||||
}
|
||||
|
||||
+ hbox {
|
||||
left = 88%
|
||||
top = 10%
|
||||
width = 10%
|
||||
height = 20
|
||||
+ label { text = "@VTOY_ISO_UEFI_DRV@" color = "#293554" align = "left" }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"theme": {
|
||||
"file": "/ISO/Ventoy/theme/theme.txt",
|
||||
"gfxmode": "1024x768",
|
||||
"display_mode": "GUI",
|
||||
"ventoy_left": "76%",
|
||||
"ventoy_top": "95%",
|
||||
"ventoy_color": "#8a8a8a",
|
||||
"fonts": [
|
||||
"/ISO/Ventoy/theme/tahoma20.pf2",
|
||||
"/ISO/Ventoy/theme/tahoma16.pf2",
|
||||
"/ISO/Ventoy/theme/tahoma-bold16.pf2",
|
||||
"/ISO/Ventoy/theme/tahoma-bold14.pf2"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
menuentry "Возврат в главное меню сборки [F7]" --hotkey=f7 --class=vtoyret {
|
||||
if [ "$grub_platform" = "efi" ]; then
|
||||
search --no-floppy --file --set=root /efi/Paravis/Boot/grub2/grub.cfg
|
||||
if [ "$grub_cpu" = "x86_64" ]; then
|
||||
chainloader /efi/Paravis/Boot/grub2/grubx64.efi
|
||||
else
|
||||
chainloader /EFI/Boot/bootia32.efi
|
||||
fi
|
||||
else
|
||||
chainloader (${vtoydev})+1
|
||||
fi
|
||||
boot
|
||||
}
|
||||
|
||||
menuentry "← Назад в меню Ventoy [Esc]" --class=vtoyret VTOY_RET {
|
||||
echo "Return ..."
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
menuentry "← Назад в меню Ventoy [Esc]" --class=vtoyret VTOY_RET {
|
||||
echo "Return ..."
|
||||
}
|
||||