Memoize completed native link dependencies

This commit is contained in:
2026-10-25 21:43:26 +00:00
parent 8aba43da38
commit 7bf2f0c687
3 changed files with 235 additions and 51 deletions

View File

@@ -126,6 +126,69 @@ type importLinkFrame struct {
link string
}
type importLinkOperations struct {
lstat func(string) (fs.FileInfo, error)
readlink func(string) (string, error)
normalizeTarget func(string, string) (string, error)
}
func resolveImportLinkPath(name string, operations importLinkOperations) (string, error) {
frames := []importLinkFrame{{pending: strings.Split(name, "/")}}
resolved := ""
active := make(map[string]struct{})
completed := make(map[string]string)
for len(frames) > 0 {
frame := &frames[len(frames)-1]
if len(frame.pending) == 0 {
if frame.link != "" {
if resolved == "" {
resolved = "."
}
completed[frame.link] = resolved
delete(active, frame.link)
}
frames = frames[:len(frames)-1]
continue
}
segment := frame.pending[0]
frame.pending = frame.pending[1:]
candidate := path.Join(resolved, segment)
if candidate == "" {
candidate = "."
}
info, err := operations.lstat(candidate)
if err != nil {
return "", err
}
if info.Mode()&fs.ModeSymlink == 0 {
resolved = candidate
continue
}
if target, ok := completed[candidate]; ok {
resolved = target
continue
}
if _, exists := active[candidate]; exists {
return "", errImportDirectoryLinkCycle
}
target, err := operations.readlink(candidate)
if err != nil {
return "", err
}
targetPath, err := operations.normalizeTarget(candidate, target)
if err != nil {
return "", err
}
active[candidate] = struct{}{}
frames = append(frames, importLinkFrame{pending: strings.Split(targetPath, "/"), link: candidate})
resolved = ""
}
if resolved == "" {
resolved = "."
}
return resolved, nil
}
func resolveHostImportPath(access *filesystemAccess, name string) (string, error) {
frames := []importLinkFrame{{pending: strings.Split(filepath.ToSlash(name), "/")}}
resolved := ""
@@ -189,57 +252,27 @@ func resolveNativeImportPath(access *filesystemAccess, filesystem fs.ReadLinkFS,
if !fs.ValidPath(name) || !access.contains(name) {
return "", fs.ErrInvalid
}
frames := []importLinkFrame{{pending: strings.Split(name, "/")}}
resolved := ""
activeLinks := make(map[string]struct{})
for len(frames) > 0 {
frame := &frames[len(frames)-1]
if len(frame.pending) == 0 {
delete(activeLinks, frame.link)
frames = frames[:len(frames)-1]
continue
}
segment := frame.pending[0]
frame.pending = frame.pending[1:]
candidate := path.Join(resolved, segment)
if candidate == "" {
candidate = "."
}
// Ancestors of a multi-component root are resolution prefixes, not
// selected targets. Complete paths and link targets remain contained.
if !access.contains(candidate) && !strings.HasPrefix(access.rootPath, candidate+"/") {
return "", errImportPathOutsideRoot
}
info, err := filesystem.Lstat(candidate)
if err != nil {
return "", err
}
if info.Mode()&fs.ModeSymlink == 0 {
resolved = candidate
continue
}
if _, exists := activeLinks[candidate]; exists {
return "", errImportDirectoryLinkCycle
}
activeLinks[candidate] = struct{}{}
target, err := filesystem.ReadLink(candidate)
if err != nil {
return "", err
}
if target == "" || strings.HasPrefix(target, "/") {
return "", errImportPathOutsideRoot
}
targetPath := path.Clean(path.Join(path.Dir(candidate), target))
if !fs.ValidPath(targetPath) || !access.contains(targetPath) {
return "", errImportPathOutsideRoot
}
frames = append(frames, importLinkFrame{pending: strings.Split(targetPath, "/"), link: candidate})
resolved = ""
}
if resolved == "" {
resolved = "."
}
return resolved, nil
return resolveImportLinkPath(name, importLinkOperations{
lstat: func(candidate string) (fs.FileInfo, error) {
// Ancestors of a multi-component root are resolution prefixes, not
// selected targets. Complete paths and link targets remain contained.
if !access.contains(candidate) && !strings.HasPrefix(access.rootPath, candidate+"/") {
return nil, errImportPathOutsideRoot
}
return filesystem.Lstat(candidate)
},
readlink: filesystem.ReadLink,
normalizeTarget: func(candidate, target string) (string, error) {
if target == "" || strings.HasPrefix(target, "/") {
return "", errImportPathOutsideRoot
}
targetPath := path.Clean(path.Join(path.Dir(candidate), target))
if !fs.ValidPath(targetPath) || !access.contains(targetPath) {
return "", errImportPathOutsideRoot
}
return targetPath, nil
},
})
}
func isImportLinkCycle(err error) bool {