fix: directory listing on Go 1.20 windows (#16976)

This commit is contained in:
Klaus Post 2023-04-05 14:36:49 -07:00 committed by GitHub
parent ae011663e8
commit 62c3df0ca3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 46 deletions

View file

@ -20,13 +20,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
go-version: [1.20.x, 1.19.x]
go-version: [1.20.x]
os: [ubuntu-latest, windows-latest]
exclude:
- os: ubuntu-latest
go-version: 1.19.x
- os: windows-latest
go-version: 1.20.x
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3

View file

@ -21,8 +21,8 @@
package cmd
import (
"io"
"os"
"path/filepath"
"syscall"
)
@ -39,38 +39,32 @@ func osMkdirAll(dirPath string, perm os.FileMode) error {
// the directory itself, if the dirPath doesn't exist this function doesn't return
// an error.
func readDirFn(dirPath string, filter func(name string, typ os.FileMode) error) error {
f, err := Open(dirPath)
// Ensure we don't pick up files as directories.
globAll := filepath.Clean(dirPath) + `\*`
globAllP, err := syscall.UTF16PtrFromString(globAll)
if err != nil {
if osErrToFileErr(err) == errFileNotFound {
return nil
}
return osErrToFileErr(err)
return errInvalidArgument
}
defer f.Close()
// Check if file or dir. This is the quickest way.
// Do not remove this check, on windows syscall.FindNextFile
// would throw an exception if Fd() points to a file
// instead of a directory, we need to quickly fail
// in such situations - this workadound is expected.
if _, err = f.Seek(0, io.SeekStart); err == nil {
data := &syscall.Win32finddata{}
handle, err := syscall.FindFirstFile(globAllP, data)
if err != nil {
// Fails on file not found and when not a directory.
return errFileNotFound
}
defer syscall.CloseHandle(handle)
data := &syscall.Win32finddata{}
for {
e := syscall.FindNextFile(syscall.Handle(f.Fd()), data)
if e != nil {
if e == syscall.ERROR_NO_MORE_FILES {
for ; ; err = syscall.FindNextFile(handle, data) {
if err != nil {
if err == syscall.ERROR_NO_MORE_FILES {
break
} else {
if isSysErrPathNotFound(e) {
if isSysErrPathNotFound(err) {
return nil
}
err = osErrToFileErr(&os.PathError{
Op: "FindNextFile",
Path: dirPath,
Err: e,
Err: err,
})
if err == errFileNotFound {
return nil
@ -109,7 +103,7 @@ func readDirFn(dirPath string, filter func(name string, typ os.FileMode) error)
typ = os.ModeDir
}
if e = filter(name, typ); e == errDoneForNow {
if err = filter(name, typ); err == errDoneForNow {
// filtering requested to return by caller.
return nil
}
@ -120,35 +114,30 @@ func readDirFn(dirPath string, filter func(name string, typ os.FileMode) error)
// Return N entries at the directory dirPath.
func readDirWithOpts(dirPath string, opts readDirOpts) (entries []string, err error) {
f, err := Open(dirPath)
// Ensure we don't pick up files as directories.
globAll := filepath.Clean(dirPath) + `\*`
globAllP, err := syscall.UTF16PtrFromString(globAll)
if err != nil {
return nil, osErrToFileErr(err)
return nil, errInvalidArgument
}
defer f.Close()
// Check if file or dir. This is the quickest way.
// Do not remove this check, on windows syscall.FindNextFile
// would throw an exception if Fd() points to a file
// instead of a directory, we need to quickly fail
// in such situations - this workadound is expected.
if _, err = f.Seek(0, io.SeekStart); err == nil {
data := &syscall.Win32finddata{}
handle, err := syscall.FindFirstFile(globAllP, data)
if err != nil {
// Fails on file not found and when not a directory.
return nil, errFileNotFound
}
data := &syscall.Win32finddata{}
handle := syscall.Handle(f.Fd())
defer syscall.CloseHandle(handle)
count := opts.count
for count != 0 {
e := syscall.FindNextFile(handle, data)
if e != nil {
if e == syscall.ERROR_NO_MORE_FILES {
for ; count != 0; err = syscall.FindNextFile(handle, data) {
if err != nil {
if err == syscall.ERROR_NO_MORE_FILES {
break
} else {
return nil, osErrToFileErr(&os.PathError{
Op: "FindNextFile",
Path: dirPath,
Err: e,
Err: err,
})
}
}