Unify host and native filesystem acquisition
This commit is contained in:
@@ -2,11 +2,8 @@ package engine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
@@ -42,29 +39,29 @@ func (s *importTraversal) expandImportGlob(basePath string, declaration importDe
|
||||
names = []string{literal}
|
||||
}
|
||||
for _, name := range names {
|
||||
absolute := filepath.Join(candidate.absolute, filepath.FromSlash(name))
|
||||
absolute := s.access.join(candidate.absolute, name)
|
||||
relative := path.Join(candidate.relative, name)
|
||||
if !containedPath(s.rootPath, filepath.Clean(absolute)) {
|
||||
if !s.access.contains(absolute) {
|
||||
return nil, []Diagnostic{importDiagnostic(CodeImportOutsideRoot, "glob traversal is outside the configuration root", &location)}
|
||||
}
|
||||
canonical, err := canonicalExistingPath(absolute)
|
||||
canonical, err := s.access.canonical(absolute)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) && !patterned {
|
||||
continue
|
||||
}
|
||||
return nil, []Diagnostic{globFilesystemDiagnostic(err, "glob match could not be canonicalized", location)}
|
||||
}
|
||||
if !containedPath(s.rootPath, canonical) {
|
||||
if !s.access.contains(canonical) {
|
||||
return nil, []Diagnostic{importDiagnostic(CodeImportOutsideRoot, "glob traversal resolves outside the configuration root", &location)}
|
||||
}
|
||||
if last {
|
||||
next = append(next, globCandidate{absolute: canonical, relative: relative})
|
||||
if len(s.sources)+len(next) > s.limits.sources {
|
||||
if s.accounting.sources+len(next) > s.limits.sources {
|
||||
return nil, []Diagnostic{importDiagnostic(CodeImportLimitExceeded, "glob matches exceed the remaining source-count limit", &location)}
|
||||
}
|
||||
continue
|
||||
}
|
||||
info, err := os.Stat(canonical)
|
||||
info, err := s.access.stat(canonical)
|
||||
if err != nil {
|
||||
return nil, []Diagnostic{globFilesystemDiagnostic(err, "glob traversal target could not be inspected", location)}
|
||||
}
|
||||
@@ -88,56 +85,47 @@ func (s *importTraversal) expandImportGlob(basePath string, declaration importDe
|
||||
}
|
||||
|
||||
func (s *importTraversal) readGlobMatches(directory, pattern string, location Location) ([]string, []Diagnostic) {
|
||||
canonical, err := canonicalExistingPath(directory)
|
||||
canonical, err := s.access.canonical(directory)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, []Diagnostic{globFilesystemDiagnostic(err, "glob directory could not be canonicalized", location)}
|
||||
}
|
||||
if !containedPath(s.rootPath, canonical) {
|
||||
if !s.access.contains(canonical) {
|
||||
return nil, []Diagnostic{importDiagnostic(CodeImportOutsideRoot, "glob directory resolves outside the configuration root", &location)}
|
||||
}
|
||||
relative, err := filepath.Rel(s.rootPath, canonical)
|
||||
if err != nil || filepath.IsAbs(relative) || relative == ".." || strings.HasPrefix(relative, ".."+string(filepath.Separator)) {
|
||||
if _, err := s.access.relative(canonical); err != nil {
|
||||
return nil, []Diagnostic{importDiagnostic(CodeImportOutsideRoot, "glob directory could not be addressed inside the configuration root", &location)}
|
||||
}
|
||||
directoryFile, err := s.root.Open(relative)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, []Diagnostic{globFilesystemDiagnostic(err, "glob directory could not be opened", location)}
|
||||
}
|
||||
|
||||
var matches []string
|
||||
for {
|
||||
entries, readErr := directoryFile.ReadDir(globReadBatch)
|
||||
for _, entry := range entries {
|
||||
s.usedEntries++
|
||||
if s.usedEntries > s.limits.entries {
|
||||
_ = directoryFile.Close()
|
||||
return nil, []Diagnostic{importDiagnostic(CodeImportLimitExceeded, "glob traversal exceeds the directory-entry visit limit", &location)}
|
||||
}
|
||||
matched, matchErr := path.Match(pattern, entry.Name())
|
||||
if matchErr != nil {
|
||||
_ = directoryFile.Close()
|
||||
return nil, []Diagnostic{importDiagnostic(CodeImportInvalid, "import glob pattern is invalid", &location)}
|
||||
}
|
||||
if matched {
|
||||
matches = append(matches, entry.Name())
|
||||
}
|
||||
var problem *Diagnostic
|
||||
err = s.access.readDirectory(canonical, func(entry fs.DirEntry) bool {
|
||||
s.accounting.entries++
|
||||
if s.accounting.entries > s.limits.entries {
|
||||
value := importDiagnostic(CodeImportLimitExceeded, "glob traversal exceeds the directory-entry visit limit", &location)
|
||||
problem = &value
|
||||
return false
|
||||
}
|
||||
if errors.Is(readErr, io.EOF) {
|
||||
break
|
||||
matched, matchErr := path.Match(pattern, entry.Name())
|
||||
if matchErr != nil {
|
||||
value := importDiagnostic(CodeImportInvalid, "import glob pattern is invalid", &location)
|
||||
problem = &value
|
||||
return false
|
||||
}
|
||||
if readErr != nil {
|
||||
_ = directoryFile.Close()
|
||||
return nil, []Diagnostic{globFilesystemDiagnostic(readErr, "glob directory could not be read", location)}
|
||||
if matched {
|
||||
matches = append(matches, entry.Name())
|
||||
}
|
||||
return true
|
||||
})
|
||||
if problem != nil {
|
||||
return nil, []Diagnostic{*problem}
|
||||
}
|
||||
if err := directoryFile.Close(); err != nil {
|
||||
return nil, []Diagnostic{globFilesystemDiagnostic(err, "glob directory could not be closed", location)}
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, []Diagnostic{globFilesystemDiagnostic(err, "glob directory could not be traversed", location)}
|
||||
}
|
||||
slices.Sort(matches)
|
||||
return matches, nil
|
||||
|
||||
Reference in New Issue
Block a user