Skip to content

Populate PrintName in junction reparse point#33

Merged
tesuji merged 3 commits intotesuji:mainfrom
zanieb:zb/print-name
Feb 24, 2026
Merged

Populate PrintName in junction reparse point#33
tesuji merged 3 commits intotesuji:mainfrom
zanieb:zb/print-name

Conversation

@zanieb
Copy link
Contributor

@zanieb zanieb commented Feb 18, 2026

When creating a junction, the PrintName field in the reparse data buffer was left empty.

The empty PrintName causes junctions to break in Windows Containers (WCoW) during layer serialization, which can be encountered, e.g., by creating and consuming a junction across container build steps:

FROM mcr.microsoft.com/windows/servercore:ltsc2022

# Create a junction
RUN ...

# Reading the junction errors
RUN ...

WCoW uses microsoft/hcsshim for layer serialization which in turn uses microsoft/go-winio for encoding and decoding reparse points. They only read PrintName, and discard SubstituteName. When the junction is re-encoded, the empty PrintName results in a broken junction.

You could argue this is a bug there, I think, but it seems reasonable to write the PrintName here too.

This was reported downstream in astral-sh/uv#17966 (comment).

I wrote a janky test binary and WCoW build in GitHub Actions to reproduce the reported failure and validated that this change resolves it. Disclosure — I'm far from an expert on junctions and relied on Claude Opus to diagnose and fix this issue.

When creating a junction, the `PrintName` field in the [reparse data buffer](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/ca069dad-ed16-42aa-b057-b6b207f447cc) was left empty, which diverges from  `mklink /j`.

The empty `PrintName` causes junctions to break in Windows Containers (WCoW) during layer serialization, which can be encountered, e.g., by creating and consuming a junction across container build steps:

```dockerfile
FROM mcr.microsoft.com/windows/servercore:ltsc2022

RUN ...

RUN ...
```

WCoW uses [`microsoft/hcsshim`](https://github.com/microsoft/hcsshim) for layer serialization which in turn uses [`microsoft/go-winio`](https://github.com/microsoft/go-winio) for encoding and decoding reparse points. They [only read `PrintName`](https://github.com/microsoft/go-winio/blob/75610162e7da1816cf16fe88f0da73dea994ea50/reparse.go#L70-L82), and discard `SubstituteName`. When the junction is re-encoded, the empty `PrintName` results in a broken junction.

You could argue this is a bug there, I think, but it seems reasonable to write the `PrintName` here too.

This was reported downstream in astral-sh/uv#17966 (comment).

I wrote a janky test binary and WCoW build in GitHub Actions to reproduce the reported failure and validated that this change resolves it. Disclosure — I'm far from an expert on junctions and relied on Claude Opus to diagnose and fix this issue.
@zanieb
Copy link
Contributor Author

zanieb commented Feb 18, 2026

This was also just reported upstream in microsoft/go-winio#340

@tesuji
Copy link
Owner

tesuji commented Feb 21, 2026

Interesting, however the new added test failed.

@zanieb
Copy link
Contributor Author

zanieb commented Feb 22, 2026

I'll look at that.

The test opened an exclusive handle (share_mode(0)) to the junction and
held it while calling get_target(), which tries to open its own handle.
Scope the file handle into a block so it is dropped before the second open.
Copy link
Owner

@tesuji tesuji left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm minus one minor styling issue

Copy link
Owner

@tesuji tesuji left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm. Ty.

@tesuji tesuji merged commit bce02fc into tesuji:main Feb 24, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants