fix: Bring support for symlink on regular files on NAS (#11383)

fixes #11203
This commit is contained in:
Harshavardhana
2021-02-20 00:30:12 -08:00
committed by GitHub
parent 85d2187c20
commit 8cad407e0b
5 changed files with 155 additions and 23 deletions

View File

@@ -42,6 +42,15 @@ func readDirFn(dirPath string, filter func(name string, typ os.FileMode) error)
}
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 {
return errFileNotFound
}
data := &syscall.Win32finddata{}
for {
e := syscall.FindNextFile(syscall.Handle(f.Fd()), data)
@@ -63,13 +72,33 @@ func readDirFn(dirPath string, filter func(name string, typ os.FileMode) error)
if name == "" || name == "." || name == ".." { // Useless names
continue
}
if data.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
continue
}
var typ os.FileMode = 0 // regular file
if data.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
switch {
case data.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0:
// Reparse point is a symlink
fi, err := os.Stat(pathJoin(dirPath, string(name)))
if err != nil {
// It got deleted in the meantime, not found
// or returns too many symlinks ignore this
// file/directory.
if osIsNotExist(err) || isSysErrPathNotFound(err) ||
isSysErrTooManySymlinks(err) {
continue
}
return err
}
if fi.IsDir() {
// Ignore symlinked directories.
continue
}
typ = fi.Mode()
case data.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0:
typ = os.ModeDir
}
if e = filter(name, typ); e == errDoneForNow {
// filtering requested to return by caller.
return nil
@@ -88,10 +117,14 @@ func readDirN(dirPath string, count int) (entries []string, err error) {
defer f.Close()
// Check if file or dir. This is the quickest way.
_, err = f.Seek(0, io.SeekStart)
if err == nil {
// 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 {
return nil, errFileNotFound
}
data := &syscall.Win32finddata{}
handle := syscall.Handle(f.Fd())
@@ -113,15 +146,33 @@ func readDirN(dirPath string, count int) (entries []string, err error) {
if name == "" || name == "." || name == ".." { // Useless names
continue
}
switch {
case data.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0:
continue
// Reparse point is a symlink
fi, err := os.Stat(pathJoin(dirPath, string(name)))
if err != nil {
// It got deleted in the meantime, not found
// or returns too many symlinks ignore this
// file/directory.
if osIsNotExist(err) || isSysErrPathNotFound(err) ||
isSysErrTooManySymlinks(err) {
continue
}
return nil, err
}
if fi.IsDir() {
// directory symlinks are ignored.
continue
}
case data.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0:
entries = append(entries, name+SlashSeparator)
default:
entries = append(entries, name)
name = name + SlashSeparator
}
count--
entries = append(entries, name)
}
return entries, nil