Hello,
I'm sorry for the delay due to my vacation. Here are details from GH CI.

Jiri

Run .\.github\scripts\debug_environment.ps1
  .\.github\scripts\debug_environment.ps1
  shell: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.EXE -command
". '{0}'"
  env:
    SCOOP: C:\Users\runneradmin\scoop

=================== OS & SYSTEM INFO ===================
Caption         : Microsoft Windows Server 2025 Datacenter
Version         : 10.0.26100
BuildNumber     : 26100
OSArchitecture  : 64-bit
SystemDirectory : C:\Windows\system32
LastBootUpTime  : 9/13/2026 5:27:39 PM
PSVersion        : 5.1.26100.33296
PSEdition        : Desktop
CLRVersion       : 4.0.30319.42000
ProcessorArch    : AMD64
AnsiCodePage     : 1252
LongPathsEnabled : 1
ProbedVolumes    : D:\a\scoop-bucket\scoop-bucket,
C:\Users\runneradmin\scoop
=================== FILESYSTEM INFO ===================
--- volume D: (probe root: D:\a\scoop-bucket\scoop-bucket) ---
DriveLetter        : D
FileSystemLabel    : Temporary Storage
FileSystem         : NTFS
FileSystemType     : NTFS
DriveType          : Fixed
AllocationUnitSize : 4096
Size               : 161059172352
SizeRemaining      : 157865340928
DeviceID                     : D:
VolumeName                   : Temporary Storage
FileSystem                   : NTFS
MaximumComponentLength       : 255
SupportsFileBasedCompression : True
VolumeSerialNumber           : 922614C0
GetVolumeInformationW: label=Temporary Storage fs=NTFS serial=922614C0
maxComponentLength=255 flags=0x03E72EFF
  flags set: FILE_CASE_PRESERVED_NAMES, FILE_UNICODE_ON_DISK,
FILE_FILE_COMPRESSION, FILE_VOLUME_IS_COMPRESSED, , , , , , , ,
--- volume C: (probe root: C:\Users\runneradmin\scoop) ---
DriveLetter        : C
FileSystemLabel    : Windows
FileSystem         : NTFS
FileSystemType     : NTFS
DriveType          : Fixed
AllocationUnitSize : 4096
Size               : 160467759104
SizeRemaining      : 33966383104
DeviceID                     : C:
VolumeName                   : Windows
FileSystem                   : NTFS
MaximumComponentLength       : 255
SupportsFileBasedCompression : True
VolumeSerialNumber           : D6F2A281
GetVolumeInformationW: label=Windows fs=NTFS serial=D6F2A281
maxComponentLength=255 flags=0x03E72EFF
  flags set: FILE_CASE_PRESERVED_NAMES, FILE_UNICODE_ON_DISK,
FILE_FILE_COMPRESSION, FILE_VOLUME_IS_COMPRESSED, , , , , , , ,
=================== C RUNTIME fopen() TRAILING-SEPARATOR TEST
===================
--- volume D:, probe directory
D:\a\scoop-bucket\scoop-bucket\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78
---
ucrtbase
 
fopen("D:\a\scoop-bucket\scoop-bucket\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78\marker_ucrtbase_fwdslash/",
"wb") -> FAILED  errno=22 (Invalid argument)
          -> nothing created on disk
ucrtbase
 
fopen("D:\a\scoop-bucket\scoop-bucket\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78\marker_ucrtbase_backslash\",
"wb") -> FAILED  errno=22 (Invalid argument)
          -> nothing created on disk
ucrtbase
 
fopen("D:\a\scoop-bucket\scoop-bucket\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78\marker_ucrtbase_plain",
"wb") -> OPENED
          -> created: marker_ucrtbase_plain  [FILE, 0 bytes]
 attributes=Archive
msvcrt
 
fopen("D:\a\scoop-bucket\scoop-bucket\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78\marker_msvcrt_fwdslash/",
"wb") -> FAILED  errno=22 (Invalid argument)
          -> nothing created on disk
msvcrt
 
fopen("D:\a\scoop-bucket\scoop-bucket\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78\marker_msvcrt_backslash\",
"wb") -> FAILED  errno=22 (Invalid argument)
          -> nothing created on disk
msvcrt
 
fopen("D:\a\scoop-bucket\scoop-bucket\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78\marker_msvcrt_plain",
"wb") -> OPENED
          -> created: marker_msvcrt_plain  [FILE, 0 bytes]
 attributes=Archive
--- volume C:, probe directory
C:\Users\runneradmin\scoop\ctx-probe-44ee47e2feb14608a2f94c23526a11af ---
ucrtbase
 
fopen("C:\Users\runneradmin\scoop\ctx-probe-44ee47e2feb14608a2f94c23526a11af\marker_ucrtbase_fwdslash/",
"wb") -> FAILED  errno=22 (Invalid argument)
          -> nothing created on disk
ucrtbase
 
fopen("C:\Users\runneradmin\scoop\ctx-probe-44ee47e2feb14608a2f94c23526a11af\marker_ucrtbase_backslash\",
"wb") -> FAILED  errno=22 (Invalid argument)
          -> nothing created on disk
ucrtbase
 
fopen("C:\Users\runneradmin\scoop\ctx-probe-44ee47e2feb14608a2f94c23526a11af\marker_ucrtbase_plain",
"wb") -> OPENED
          -> created: marker_ucrtbase_plain  [FILE, 0 bytes]
 attributes=Archive
msvcrt
 
fopen("C:\Users\runneradmin\scoop\ctx-probe-44ee47e2feb14608a2f94c23526a11af\marker_msvcrt_fwdslash/",
"wb") -> FAILED  errno=22 (Invalid argument)
          -> nothing created on disk
msvcrt
 
fopen("C:\Users\runneradmin\scoop\ctx-probe-44ee47e2feb14608a2f94c23526a11af\marker_msvcrt_backslash\",
"wb") -> FAILED  errno=22 (Invalid argument)
          -> nothing created on disk
msvcrt
 
fopen("C:\Users\runneradmin\scoop\ctx-probe-44ee47e2feb14608a2f94c23526a11af\marker_msvcrt_plain",
"wb") -> OPENED
          -> created: marker_msvcrt_plain  [FILE, 0 bytes]
 attributes=Archive
=================== CONSEQUENCE: DOES A MARKER FILE BLOCK mkdir()?
===================
fopen("D:\a\scoop-bucket\scoop-bucket\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78\web2c/",
"wb") -> FAILED  errno=22 (Invalid argument)
  'web2c' was not created - mkdir() would not be blocked here
fopen("C:\Users\runneradmin\scoop\ctx-probe-44ee47e2feb14608a2f94c23526a11af\web2c/",
"wb") -> FAILED  errno=22 (Invalid argument)
  'web2c' was not created - mkdir() would not be blocked here
=================== LUAMETATEX io.open() TRAILING-SEPARATOR TEST
===================
---
C:\Users\runneradmin\scoop\apps\context\current\tex\texmf-win64\bin\luametatex.exe
--luaonly <probe.lua> (probe directory
D:\a\scoop-bucket\scoop-bucket\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78)
---
lua version: Lua 5.5
io.open("D:\\a\\scoop-bucket\\scoop-bucket\\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78/lua_marker_fwdslash/",
'wb') -> nil
 
err=D:\a\scoop-bucket\scoop-bucket\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78/lua_marker_fwdslash/:
Invalid argument  errno=22
io.open("D:\\a\\scoop-bucket\\scoop-bucket\\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78/lua_marker_backslash\\",
'wb') -> nil
 
err=D:\a\scoop-bucket\scoop-bucket\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78/lua_marker_backslash\:
Invalid argument  errno=22
io.open("D:\\a\\scoop-bucket\\scoop-bucket\\ctx-probe-b967d7f6d6fb4084b0c7a5ecfbafdf78/lua_marker_plain",
'wb') -> file (00007ff90cddda90)  err=nil  errno=nil
  lua_marker_fwdslash -> nothing created on disk
  lua_marker_backslash -> nothing created on disk
  lua_marker_plain -> created: [FILE, 0 bytes] attributes=Archive
=================== SUMMARY ===================
Volume Probe                  Opened Created
------ -----                  ------ -------
D:     ucrtbase fopen(...'/')  False   False
D:     msvcrt fopen(...'/')    False   False
C:     ucrtbase fopen(...'/')  False   False
C:     msvcrt fopen(...'/')    False   False
Reading: "Opened=True, Created=True" means this Windows CRT accepts a path
ending in "/" for writing and materialises a literal 0-byte file under the
separator-stripped name - the behaviour util-zip.lua's unzipdir() relies on
NOT happening (on POSIX the same open fails, making the write a no-op).

On Fri, Sep 4, 2026 at 2:25 PM Hans Hagen via ntg-context <
[email protected]> wrote:

> On 9/4/2026 10:25 AM, Jiri Bělka wrote:
> > Fix util-zip.lua's unzipdir() writing zip directory-marker entries as
> > 0-byte files, which then blocks mkdir() for the real files that belong
> > underneath them (reproducible on Windows; the same code path happens
> > to no-op harmlessly on POSIX, where opening a path ending in "/" for
> > writing simply fails).
> >
> > Upstream: ConTeXt LMTX, tex/context/base/mkiv/util-zip.lua, function
> > unzipdir - bundled (minified, concatenated with other core modules)
> > into bin/mtxrun.lua inside the small bootstrap archive
> > (context-<platform>.zip) that ships from lmtx.pragma-ade.com <http://
> > lmtx.pragma-ade.com>. This
> > patch targets that bundled bin/mtxrun.lua copy, applied with
> > `git apply -p1` from the app's install directory before the first
> > `mtx-install.lua --update` bootstrap run.
> >
> > How this was found
> > -------------------
> > The jirib/scoop-bucket "context" package's own Windows CI (GitHub
> > Actions, windows-latest) failed a fresh `scoop install context` with
> > mtxrun unable to find tex/texmf-context/web2c/contextcnf.lua, and
> > every mtxrun/context script lookup afterwards failing with "unknown
> > script ...". A diagnostic step added to that CI listed the tree after
> > bootstrap: tex/texmf-context had only ~10 entries, and every one of
> > them - including "web2c" - was a 0-byte *file* rather than a
> > directory (`Get-ChildItem` showed `-a----` file-mode entries where
> > directories were expected).
> >
> > To rule out a scoop-specific packaging mistake, the exact same
> > `mtx-install.lua --update` bootstrap was reproduced by hand, fresh,
> > directly against the real upstream context-linux-64.zip /
> > context-win64.zip / texmf-context.zip - on Linux it succeeded on the
> > first try (5723 real files under tex/texmf-context, web2c a real
> > directory); the identical code, same zip, same directory-marker
> > entries, failed only on Windows. Tracing unzipdir()/unzipfile() in the
> > bundled bin/mtxrun.lua explained the split: unzipfile() returns "" for
> > a directory-marker entry (0 compressed bytes), which Lua treats as
> > truthy, so unzipdir() proceeds to mkdirs()+savedata() for it. Writing
> > a file to a path ending in "/" apparently fails silently on POSIX
> > (harmless no-op there) but succeeds on Windows as a literal 0-byte
> > file with that name - which then blocks mkdir() for every real file
> > meant to live underneath it.
> >
> > This patch was applied to bin/mtxrun.lua and verified against a real,
> > fresh `scoop install context` on a GitHub Actions windows-latest
> > runner (jirib/scoop-bucket CI): the bootstrap now completes in ~2
> > minutes (previously it either corrupted the tree, or - with a
> > detect-and-retry workaround instead of this patch - took ~48 minutes
> > falling back to downloading ~6700 files individually), tex/texmf-context
> > contains the correct 5723 files with web2c as a real directory, and
> > `context --version` / `mtxrun --generate` both work.
> >
> > Reported upstream to [email protected] <mailto:[email protected]>.
> >
> > --- a/bin/mtxrun.lua
> > +++ b/bin/mtxrun.lua
> > @@ -16453,7 +16453,8 @@
> >       for i=1,count do
> >        local l=list[i]
> >        local n=l.filename
> > - if not validate or validate(n) then
> > + if n:sub(-1) == "/" then
> > + elseif not validate or validate(n) then
> >         local d=unzipfile(z,n)
> >         if d then
> >          local p=filejoin(path,n)
>
> more like (in util-zip.lua):
>
>                      if find(n,"/$") then
>                       -- mkdirs(dirname(n))
>                      elseif not validate or validate(n) then
>
> and then
>
>         mtxrun --selfmerge
>
> but ... as I never saw this on windows, what file system are you using?
>
> Hans
>
> -----------------------------------------------------------------
>                                            Hans Hagen | PRAGMA ADE
>                Ridderstraat 27 | 8061 GH Hasselt | The Netherlands
>         tel: 038 477 53 69 | www.pragma-ade.nl | www.pragma-pod.nl
> -----------------------------------------------------------------
>
> ___________________________________________________________________________________
> If your question is of interest to others as well, please add an entry to
> the Wiki!
>
> maillist : [email protected] /
> https://mailman.ntg.nl/mailman3/lists/ntg-context.ntg.nl
> webpage  : https://www.pragma-ade.nl / https://context.aanhet.net (mirror)
> archive  : https://github.com/contextgarden/context
> wiki     : https://wiki.contextgarden.net
>
> ___________________________________________________________________________________
>
___________________________________________________________________________________
If your question is of interest to others as well, please add an entry to the 
Wiki!

maillist : [email protected] / 
https://mailman.ntg.nl/mailman3/lists/ntg-context.ntg.nl
webpage  : https://www.pragma-ade.nl / https://context.aanhet.net (mirror)
archive  : https://github.com/contextgarden/context
wiki     : https://wiki.contextgarden.net
___________________________________________________________________________________

Reply via email to