Unify host and native filesystem acquisition

This commit is contained in:
2026-09-29 17:29:01 +00:00
parent de28718941
commit 6111cb23a1
8 changed files with 636 additions and 122 deletions

View File

@@ -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