-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
path/filepath: filepath.Walk does not work on mounted volumes in Windows containers #26033
Comments
You run the walk program outside of the started container, just on the same directory that is also mounted into the container? The directory search works ok when using other (non-Go) programs? Can you check what this C program would output? |
Sorry about the lag in my response. Program is run from the default CWD inside the container. However it's in a mounted directory. To be precise: Step 1 - Launch the container.
Step 2 - From
Using other programs such as Hopefully this clarifies the situation a bit further. |
same issue with mounted docker volume on linux. If i run it from VSCode/command line it works as expected (on the same folder which is not mounted). As long as it's mounted through docker volume, it doesn't work. Logged into docker container to check if folder with files exists inside of it and all is there. Might be permission issues of some sorts? |
I've confirmed the same behaviour with go1.15.5 for junction points outside a container. My use-case is for volume mounts that happen to be a WCOW container image. I mounted a WCOW container image using I suspect the core problem is that The DOS-style path for a volume mount point is of course the volume mount point. The rest of Go handles this as a symlink to itself, rather than like a bind-mount in Linux, for example. The difference is that if you proceed down a symlink to itself, you get an error. If you follow a volume mount point or bind-mount, you see the contents. The question of "is this a directory or a symlink" was asked and answered well before this code is executed though, so it's not easily solved without changing the definition of Unlike a real Symlink, it's not necessarily feasible to call PoC, with package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"syscall"
"github.com/Microsoft/go-winio"
)
func openSymlink(path string) (syscall.Handle, error) {
p, err := syscall.UTF16PtrFromString(path)
if err != nil {
return 0, err
}
attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
// Use FILE_FLAG_OPEN_REPARSE_POINT, otherwise CreateFile will follow symlink.
// See https://docs.microsoft.com/en-us/windows/desktop/FileIO/symbolic-link-effects-on-file-systems-functions#createfile-and-createfiletransacted
attrs |= syscall.FILE_FLAG_OPEN_REPARSE_POINT
h, err := syscall.CreateFile(p, 0, 0, nil, syscall.OPEN_EXISTING, attrs, 0)
if err != nil {
return 0, err
}
return h, nil
}
func readlink(path string) ([]byte, error) {
h, err := openSymlink(path)
if err != nil {
return nil, err
}
defer syscall.CloseHandle(h)
rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
var bytesReturned uint32
err = syscall.DeviceIoControl(h, syscall.FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
if err != nil {
return nil, err
}
return rdbbuf, nil
}
func main() {
path := flag.String("path", "", "path to walk")
flag.Parse()
fmt.Printf("walking path %v\n", *path)
err := filepath.Walk(filepath.Clean(*path), func(path string, info os.FileInfo, err error) error {
if err != nil {
panic(err)
}
fmt.Printf("visiting %v\n", path)
if info.Mode()&os.ModeSymlink == 0 {
return nil
}
name, err := os.Readlink(path)
if err != nil {
panic(err)
}
fmt.Printf("\tpoints to %v\n", name)
buff, err := readlink(name)
if err != nil {
panic(err)
}
rp, err := winio.DecodeReparsePoint(buff)
if err != nil {
panic(err)
}
fmt.Printf("\treally points to %v\n", rp.Target)
return nil
})
if err != nil {
panic(err)
}
} Produces:
Edit: Thinking about this a little, I don't understand why Go treats Volume Mount Points as symlinks, whether they are mounts of So this could be resolved by dropping all the support for Or teaching Looks like this was briefly touched-upon in discussion of the change that introduced it but the discussion wasn't followed up on, except to note that tests that expected to treat mount points as symlinks fail if you don't treat mount points as symlinks... Edit: I realised much later that |
Thinking about this, one rationale for treating an NTFS Mount Point like a Symlink is that, unlike I assume that avoiding infinite recursion is why |
After https://go.dev/cl/463177, the fix here is probably to add a trailing separator to the path passed to |
For the record, the above fix was in Go 1.21. |
Timed out in state WaitingForInfo. Closing. (I am just a bot, though. Please speak up if this is a mistake or you have the requested information.) |
What version of Go are you using (
go version
)?1.10
Does this issue reproduce with the latest release?
Not sure
What operating system and processor architecture are you using (
go env
)?windows 386
What did you do?
Cross compile the following program from osx
GOOS=windows GOARCH=386 go build -o walk.exe main.go
(cross compilation does not really matter, the behaviour outlined below is also consistent even if the binary is produced in a windows)Created a docker container from
microsoft/windowsservercore
What did you expect to see?
List of files and directories in
c:\files
.What did you see instead?
Just the root directory
The text was updated successfully, but these errors were encountered: