microsoft / microsoft/WSL

wslc container cp silently produces an empty file when the source is a symlink

Open
#41,309 3 comments 0 reactions 1 assignee Claimed by @ptrivedi View on GitHub
wslc
Dominant language
C++
Stars
33.7k
Forks
1.8k
Avg merge
3d 17h
Merged PRs (30d)
116

Description

### Windows Version

Microsoft Windows [Version 10.0.26220.8764]

### WSL Version

2.9.4.0

### Are you using WSL 1 or WSL 2?

- [X] WSL 2
- [ ] WSL 1

### Kernel Version

6.18.35.2-1

### Distro Version

Not a distro install — reproduced against the container image `mcr.microsoft.com/azurelinux/base/core:3.0`.

### Other Software

None. This is `wslc`, WSL's own container CLI.

### Repro Steps

```bash
wslc image pull mcr.microsoft.com/azurelinux/base/core:3.0

wslc container run -d --name repro mcr.microsoft.com/azurelinux/base/core:3.0 \
sh -c "mkdir -p /w && printf 'REAL-CONTENT' > /w/real.txt && ln -s /w/real.txt /w/link.txt && sleep 120"

# In the guest both entries are as expected:
# -rw-r--r-- 1 root root 12 real.txt
# lrwxrwxrwx 1 root root 11 link.txt -> /w/real.txt

wslc container cp repro:/w/real.txt ./real.out # control
wslc container cp repro:/w/link.txt ./link.out # the bug
```

### Expected Behavior

Copying a symlink out of a container should do one of three things: preserve the link, follow it and copy the target's bytes, or fail with a diagnostic. Any of those is workable for a caller. The docker CLI, whose surface `wslc container cp` mirrors, preserves the link entry.

### Actual Behavior

`wslc container cp` exits **0**, writes **nothing to stderr**, and creates a **0-byte regular file**. The result is indistinguishable from a file that was legitimately empty.

```
cp real.txt -> exit=0 stderr=[] size=12 content=[REAL-CONTENT]
cp link.txt -> exit=0 stderr=[] size=0 content=[]
```

Three observations narrow this down:

- `-a` / `--archive` makes no difference.
- It is not a general absence of error reporting. The same command fails correctly elsewhere: a directory copied to a file path returns exit 1 with `Cannot copy a directory to a file path. Use a directory target (with trailing separator) instead. Error code: E_FAIL`, and a nonexistent source returns exit 1 with `Could not find the file /w/nope.txt in container . Error code: ERROR_PATH_NOT_FOUND` and creates no file. Only the symlink case reports success while producing nothing.
- It is not containment. A link pointing *inside* the copied tree behaves identically to one pointing outside it, so this does not look like a deliberate refusal to let a copy escape the container.

The guest has the information needed to act on it: `stat -c '%F %s' /w/link.txt` reports `symbolic link 11`.

The practical impact is that a caller cannot distinguish this from an empty file, so the failure propagates silently into whatever consumes the copy. The only workaround is to `exec` into the container and `stat` the path first, which requires the image to contain a shell — something `cp` itself does not need.

### Diagnostic Logs

None attached; the repro above is deterministic and requires no tracing.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.