Browse Source
Motivated by a make.tcl project deploy failure ("could not delete target
binary") where the locker turned out to be 7-Zip inspecting the exe -
identifying it took several dead ends because Windows has no cheap
file-to-process reverse lookup (name matching and Process.Modules scans
both miss plain file handles; openfiles needs a pre-enabled global flag;
handle.exe is external and elevation-bound).
G-028: a punkboot::utils helper returns the locking processes via the
Windows Restart Manager API (the installers-grade answer to "who is
blocking this file"), with twapi or cffi required lazily at call time -
punkboot::utils stays pure Tcl per the bootsupport no-compiled-extensions
contract, and unavailability degrades to the existing message. make.tcl
kit deploy failures append the locker report when determinable. Recurring
customer: G-023 versioned/dev binaries rewritten every build.
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
2 changed files with 73 additions and 0 deletions
@ -0,0 +1,67 @@
|
||||
# G-028 Name the process locking a file when builds cannot replace a target |
||||
|
||||
Status: proposed |
||||
Scope: src/modules/punkboot/utils-999999.0a1.0.tm (locker-report helper), src/make.tcl (kit deploy failure reporting) |
||||
Acceptance: as in root GOALS.md index (canonical). |
||||
|
||||
## Context |
||||
|
||||
Motivating incident (2026-07-07, tomlish project): `make.tcl project` failed |
||||
with "could not delete target binary at .../bin/tomlish.exe" and no further |
||||
information. The lock turned out to be 7-Zip holding the exe open for archive |
||||
inspection - but identifying that took several dead ends, because Windows has |
||||
no cheap reverse lookup from file to holding process: |
||||
|
||||
- tasklist / Get-Process by name only finds processes *running as* the file. |
||||
- Scanning Process.Modules only sees files mapped as images (loaded EXE/DLLs), |
||||
not plain open handles, and silently skips inaccessible processes. |
||||
- Full handle enumeration (NtQuerySystemInformation) needs elevation and |
||||
per-handle queries; `openfiles` requires a globally pre-enabled tracking |
||||
flag; Sysinternals handle.exe / Resource Monitor are external/manual. |
||||
|
||||
The **Restart Manager API** (RmStartSession/RmRegisterResources/RmGetList) is |
||||
the practical programmatic answer: it is what installers use for the "these |
||||
applications are using this file" dialog, does not require elevation for the |
||||
common cases, and directly answers "who is blocking my replace/delete". It is |
||||
callable from Tcl via twapi or cffi, both already shipped in the punk Windows |
||||
kit. |
||||
|
||||
Deploy-target locks will recur - G-023's versioned/dev binary outputs are |
||||
rewritten every build, and a running or inspected punk8/9-dev.exe is exactly |
||||
the kind of file this fails on. |
||||
|
||||
## Approach |
||||
|
||||
- `punkboot::utils` helper (e.g. file_lockers <path>) returning a list of |
||||
{pid <n> name <procname> ...} records, empty when unlocked. |
||||
- **Constraint: bootsupport carries no compiled extensions** (src/bootsupport |
||||
AGENTS.md). punkboot::utils stays pure Tcl; twapi (RmStartSession et al via |
||||
its API coverage) or cffi (direct Rstrtmgr.dll binding) is package-required |
||||
lazily inside the helper, from the environment's auto_path. Unavailable |
||||
binding, non-Windows platform, or API failure all yield a clean |
||||
'unavailable' result the caller renders as the existing message. |
||||
- make.tcl kit deploy (and any other replace-target failure sites worth |
||||
covering) appends the locker report to its failure output when available. |
||||
- Prefer twapi if its Restart Manager coverage suffices; cffi binding as the |
||||
fallback implementation choice - record the choice here when made. |
||||
|
||||
## Alternatives considered |
||||
|
||||
- Full handle-table enumeration (NtQuerySystemInformation) - rejected: |
||||
elevation-dependent, expensive, and reimplements what Restart Manager |
||||
already provides for the blocking-file case. |
||||
- Shelling out to Sysinternals handle.exe - rejected: external download, |
||||
license prompt on first run, elevation required; not dependable build |
||||
tooling. |
||||
- `openfiles` - rejected: requires a pre-enabled global tracking flag with a |
||||
standing performance cost. |
||||
|
||||
## Notes |
||||
|
||||
- Related: G-023 (versioned binary deploys are the recurring customer), |
||||
G-020 (same optionally-available twapi/cffi pattern for platform features), |
||||
punkboot::utils chicken-and-egg ordering rules in src/bootsupport/AGENTS.md |
||||
apply when adding the helper. |
||||
- Unix analogues (lsof/fuser) could slot behind the same helper interface |
||||
later; out of scope for acceptance (Windows is where the pain is and where |
||||
the API answer is non-obvious). |
||||
Loading…
Reference in new issue