// Package rootstate opens local authority through root-owned directories. package rootstate import ( "context" "os" "path" "strings" ) const MaxRecord = 1 << 20 // Store retains the directory descriptor. Close it after the last operation. type Store interface { Read(string) ([]byte, error) Write(string, []byte) error Remove(string) error Names() ([]string, error) Lock(context.Context, string) (func(), error) Close() error } // Sync makes a checked directory's visible entries durable. A read-only // projection consumer uses it before acknowledging a newly observed record. func Sync(s Store) error { if d, ok := s.(interface{ Sync() error }); ok { return d.Sync() } return os.ErrPermission } func component(s string) bool { if s == "" || s == "." || s == ".." || len(s) > 255 { return false } for _, r := range s { if !((r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '.' || r == '-' || r == '_') { return false } } return true } func fileMode(public bool) os.FileMode { if public { return 0644 } return 0600 } type FileIdentity struct { Device uint64 Inode uint64 Boot, Filesystem, Handle, MountRoot, MountPoint, MountNamespace string `json:",omitempty"` MountLineage string `json:",omitempty"` HandleType int32 `json:",omitempty"` Mount uint64 `json:",omitempty"` MountUnique, NamespaceUnique uint64 `json:",omitempty"` UID, GID, Mode uint32 `json:",omitempty"` } func (a FileIdentity) Same(b FileIdentity) bool { if a.Boot == "" || b.Boot == "" { return false } if a.Filesystem == "" || a.Handle == "" || a.MountRoot == "" || a.MountPoint == "" || a.MountNamespace == "" || b.MountNamespace == "" { return false } if a.Inode != b.Inode || a.Filesystem != b.Filesystem || a.Handle != b.Handle || a.HandleType != b.HandleType || a.UID != b.UID || a.GID != b.GID || a.Mode != b.Mode || a.MountRoot != b.MountRoot || a.MountPoint != b.MountPoint { return false } if (a.MountLineage != "" || b.MountLineage != "") && (a.MountUnique == 0 || b.MountUnique == 0 || a.NamespaceUnique == 0 || b.NamespaceUnique == 0) { return false } if a.SameMountNamespace(b) && a.MountUnique != b.MountUnique { return false } if a.MountLineage != b.MountLineage && (a.SameMountNamespace(b) || !sameMountLayers(a, b)) { return false } return a.Boot != b.Boot || a.Device == b.Device } func (a FileIdentity) SameMountNamespace(b FileIdentity) bool { return a.Boot != "" && a.Boot == b.Boot && a.NamespaceUnique != 0 && a.NamespaceUnique == b.NamespaceUnique } func sameMountLayers(a, b FileIdentity) bool { layers := func(id FileIdentity) (string, []string, bool) { if id.MountLineage == "" { return "", nil, false } var out strings.Builder rows := strings.Split(strings.TrimSuffix(id.MountLineage, "\n"), "\n") for i, row := range rows { fields := strings.Split(row, "\t") if len(fields) != 2 { return "", nil, false } if fields[1] != id.MountPoint { return out.String(), rows[i:], out.Len() != 0 } out.WriteString(row + "\n") } return out.String(), nil, out.Len() != 0 } left, before, ok1 := layers(a) right, after, ok2 := layers(b) if !ok1 || !ok2 || left != right { return false } for i, row := range before { if len(after) != 0 && row == after[0] { after = after[1:] continue } fields := strings.Split(row, "\t") if len(fields) != 2 || i+1 == len(before) || fields[1] == "/" { return false } parent := strings.Split(before[i+1], "\t") if len(parent) != 2 { return false } for _, name := range append(fields, parent...) { if !path.IsAbs(name) || path.Clean(name) != name { return false } } rel, below := strings.CutPrefix(fields[1], strings.TrimSuffix(parent[1], "/")+"/") if !below || rel == "" || path.Join(parent[0], rel) != fields[0] { return false } } return len(after) == 0 }