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
|
||||
# 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.
|
||||
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
|
||||
:: diskpart rather than the Storage cmdlets. New-Partition and
|
||||
:: Format-Volume need services that are not up yet this early in
|
||||
|
|
@ -248,7 +300,7 @@ in
|
|||
:cleanup
|
||||
del /q C:\Windows\Temp\vmix-dd-assign.txt C:\Windows\Temp\vmix-dd-init.txt 2>nul
|
||||
:done
|
||||
'';
|
||||
'');
|
||||
|
||||
# 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue