windows/seal: keep the config CD off D:, and win the ProfilesDirectory race
Two first-boot hazards the sealed path hits that the baked path does not, fixed in a configMedium-only variant of the data-disk init (the shared path is byte-identical): - The per-VM config rides an optical drive. On the target's first boot the data disk is still raw and unlettered, so Windows gives the CD D: -- where the profile volume must go. The plain `if exist D:\` guard then sees the CD and skips, stranding ProfilesDirectory on read-only media. Now a marker (not the letter) tracks first boot, and any occupant of D: is parked on Y: before the data disk claims it. - Left to Shell-Setup's FolderLocations, ProfilesDirectory can be evaluated before the disk exists (unordered within specialize) and fall back to C:. It is now written to the registry in the same step that just created the volume, so the volume always exists first. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117qMyjpuXsjpVAcpJbFD8g
This commit is contained in:
parent
702f723e6d
commit
ee002586e5
1 changed files with 54 additions and 2 deletions
|
|
@ -219,7 +219,59 @@ in
|
||||||
# a GPT label, one full-size NTFS partition and the drive letter, while a disk
|
# a GPT label, one full-size NTFS partition and the drive letter, while a disk
|
||||||
# that already holds data keeps it and only has its letter re-asserted. The
|
# that already holds data keeps it and only has its letter re-asserted. The
|
||||||
# OS disk is added to QEMU first and so is always disk 0.
|
# OS disk is added to QEMU first and so is always disk 0.
|
||||||
initDataDiskScript = pkgs.writeText "vmix-init-data-disk.cmd" ''
|
initDataDiskScript = pkgs.writeText "vmix-init-data-disk.cmd" (if configMedium then ''
|
||||||
|
@echo off
|
||||||
|
:: Sealed-image variant. Two extra hazards over the baked path:
|
||||||
|
::
|
||||||
|
:: 1. The per-VM config rides an optical drive, and on the target's first
|
||||||
|
:: boot the raw data disk has no volume yet -- so Windows letters the CD
|
||||||
|
:: as ${dataDriveLetter}:, exactly where the profile volume must go. The
|
||||||
|
:: plain `if exist ${dataDriveLetter}:\` guard would then see the CD and
|
||||||
|
:: skip, leaving ProfilesDirectory pointed at read-only media. So a first
|
||||||
|
:: boot is tracked by a marker, not by the letter, and any occupant of
|
||||||
|
:: ${dataDriveLetter}: is moved aside before the data disk claims it.
|
||||||
|
:: 2. Left to Shell-Setup's FolderLocations, ProfilesDirectory can be
|
||||||
|
:: evaluated before this disk exists (unordered within specialize) and
|
||||||
|
:: silently fall back to C:. Setting it here, in the same step that just
|
||||||
|
:: created the volume, removes that race.
|
||||||
|
if exist C:\vmix-data-initialized goto :ensure
|
||||||
|
|
||||||
|
:: First boot: park whatever holds ${dataDriveLetter}: (the config CD) on Y:
|
||||||
|
:: so the data disk can take the letter. Harmless if the letter is free.
|
||||||
|
> C:\Windows\Temp\vmix-cd.txt echo select volume ${dataDriveLetter}
|
||||||
|
>> C:\Windows\Temp\vmix-cd.txt echo assign letter=Y noerr
|
||||||
|
diskpart /s C:\Windows\Temp\vmix-cd.txt > nul 2>&1
|
||||||
|
|
||||||
|
:: Lay disk 1 (the host zvol) out from scratch and give it the letter.
|
||||||
|
> C:\Windows\Temp\vmix-dd-init.txt echo select disk 1
|
||||||
|
>> C:\Windows\Temp\vmix-dd-init.txt echo clean
|
||||||
|
>> C:\Windows\Temp\vmix-dd-init.txt echo convert gpt
|
||||||
|
>> C:\Windows\Temp\vmix-dd-init.txt echo create partition primary
|
||||||
|
>> C:\Windows\Temp\vmix-dd-init.txt echo format fs=ntfs quick label="${dataLabel}"
|
||||||
|
>> C:\Windows\Temp\vmix-dd-init.txt echo assign letter=${dataDriveLetter}
|
||||||
|
diskpart /s C:\Windows\Temp\vmix-dd-init.txt
|
||||||
|
echo initialized > C:\vmix-data-initialized
|
||||||
|
goto :ensure
|
||||||
|
|
||||||
|
:ensure
|
||||||
|
:: The letter normally persists via MountedDevices; re-assert if it is gone.
|
||||||
|
if exist ${dataDriveLetter}:\ goto :profiledir
|
||||||
|
> C:\Windows\Temp\vmix-dd-assign.txt echo select disk 1
|
||||||
|
>> C:\Windows\Temp\vmix-dd-assign.txt echo select partition 1
|
||||||
|
>> C:\Windows\Temp\vmix-dd-assign.txt echo assign letter=${dataDriveLetter}
|
||||||
|
diskpart /s C:\Windows\Temp\vmix-dd-assign.txt > nul 2>&1
|
||||||
|
|
||||||
|
:profiledir
|
||||||
|
${lib.optionalString (profilesDirectory != null) ''
|
||||||
|
:: Point new profiles at the data volume, now that it exists. REG_EXPAND_SZ
|
||||||
|
:: to match Windows' own ProfilesDirectory type.
|
||||||
|
if exist ${dataDriveLetter}:\ (
|
||||||
|
if not exist "${profilesDirectory}" mkdir "${profilesDirectory}"
|
||||||
|
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" /v ProfilesDirectory /t REG_EXPAND_SZ /d "${profilesDirectory}" /f > nul 2>&1
|
||||||
|
)''}
|
||||||
|
del /q C:\Windows\Temp\vmix-cd.txt C:\Windows\Temp\vmix-dd-init.txt C:\Windows\Temp\vmix-dd-assign.txt 2>nul
|
||||||
|
:done
|
||||||
|
'' else ''
|
||||||
@echo off
|
@echo off
|
||||||
:: diskpart rather than the Storage cmdlets. New-Partition and
|
:: diskpart rather than the Storage cmdlets. New-Partition and
|
||||||
:: Format-Volume need services that are not up yet this early in
|
:: Format-Volume need services that are not up yet this early in
|
||||||
|
|
@ -248,7 +300,7 @@ in
|
||||||
:cleanup
|
:cleanup
|
||||||
del /q C:\Windows\Temp\vmix-dd-assign.txt C:\Windows\Temp\vmix-dd-init.txt 2>nul
|
del /q C:\Windows\Temp\vmix-dd-assign.txt C:\Windows\Temp\vmix-dd-init.txt 2>nul
|
||||||
:done
|
:done
|
||||||
'';
|
'');
|
||||||
|
|
||||||
# PowerShell in its own file, so neither cmd quoting nor Nix's '' need to be
|
# PowerShell in its own file, so neither cmd quoting nor Nix's '' need to be
|
||||||
# fought. If the account's real profile got backed up to a .bak key (the
|
# fought. If the account's real profile got backed up to a .bak key (the
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue