fortify/sandbox/vfs/unfold.go
Ophestra a11237b158
All checks were successful
Test / Create distribution (push) Successful in 26s
Test / Fortify (push) Successful in 2m42s
Test / Fpkg (push) Successful in 3m40s
Test / Data race detector (push) Successful in 4m15s
Test / Flake checks (push) Successful in 55s
sandbox/vfs: add doc comments
Signed-off-by: Ophestra <cat@gensokyo.uk>
2025-03-24 13:21:55 +09:00

108 lines
2.2 KiB
Go

package vfs
import (
"iter"
"path"
"strings"
"syscall"
)
// MountInfoNode positions a [MountInfoEntry] in its mount hierarchy.
type MountInfoNode struct {
*MountInfoEntry
FirstChild *MountInfoNode `json:"first_child"`
NextSibling *MountInfoNode `json:"next_sibling"`
Clean string `json:"clean"`
Covered bool `json:"covered"`
}
// Collective returns an iterator over visible mountinfo nodes.
func (n *MountInfoNode) Collective() iter.Seq[*MountInfoNode] {
return func(yield func(*MountInfoNode) bool) { n.visit(yield) }
}
func (n *MountInfoNode) visit(yield func(*MountInfoNode) bool) bool {
if !n.Covered && !yield(n) {
return false
}
for cur := n.FirstChild; cur != nil; cur = cur.NextSibling {
if !cur.visit(yield) {
return false
}
}
return true
}
// Unfold unfolds the mount hierarchy and resolves covered paths.
func (d *MountInfoDecoder) Unfold(target string) (*MountInfoNode, error) {
targetClean := path.Clean(target)
var mountinfoSize int
for range d.Entries() {
mountinfoSize++
}
if err := d.Err(); err != nil {
return nil, err
}
mountinfo := make([]*MountInfoNode, mountinfoSize)
// mount ID to index lookup
idIndex := make(map[int]int, mountinfoSize)
// final entry to match target
targetIndex := -1
{
i := 0
for ent := range d.Entries() {
mountinfo[i] = &MountInfoNode{Clean: path.Clean(ent.Target), MountInfoEntry: ent}
idIndex[ent.ID] = i
if mountinfo[i].Clean == targetClean {
targetIndex = i
}
i++
}
}
if targetIndex == -1 {
return nil, syscall.ESTALE
}
for _, cur := range mountinfo {
var parent *MountInfoNode
if p, ok := idIndex[cur.Parent]; !ok {
continue
} else {
parent = mountinfo[p]
}
if !strings.HasPrefix(cur.Clean, targetClean) {
continue
}
if parent.Clean == cur.Clean {
parent.Covered = true
}
covered := false
nsp := &parent.FirstChild
for s := parent.FirstChild; s != nil; s = s.NextSibling {
if strings.HasPrefix(cur.Clean, s.Clean) {
covered = true
break
}
if strings.HasPrefix(s.Clean, cur.Clean) {
*nsp = s.NextSibling
} else {
nsp = &s.NextSibling
}
}
if covered {
continue
}
*nsp = cur
}
return mountinfo[targetIndex], nil
}