containerd/vendor/github.com/hanwen/go-fuse/v2/fs/inode_children.go
Brad Davidson 63272c3b7a
Enable btrfs/fuse-overlayfs/stargz snapshotter plugins
Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
2025-03-20 21:34:00 +00:00

134 lines
3.0 KiB
Go

// Copyright 2023 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fs
import (
"fmt"
"strings"
)
type childEntry struct {
Name string
Inode *Inode
// TODO: store int64 changeCounter of the parent, so we can
// use the changeCounter as a directory offset.
}
// inodeChildren is a hashmap with deterministic ordering. It is
// important to return the children in a deterministic order for 2
// reasons:
//
// 1. if the ordering is non-deterministic, multiple concurrent
// readdirs can lead to cache corruption (see issue #391)
//
// 2. it simplifies the implementation of directory seeking: the NFS
// protocol doesn't open and close directories. Instead, a directory
// read must always be continued from a previously handed out offset.
//
// By storing the entries in insertion order, and marking them with a
// int64 logical timestamp, the logical timestamp can serve as readdir
// cookie.
type inodeChildren struct {
// index into children slice.
childrenMap map[string]int
children []childEntry
}
func (c *inodeChildren) init() {
c.childrenMap = make(map[string]int)
}
func (c *inodeChildren) String() string {
var ss []string
for _, e := range c.children {
ch := e.Inode
ss = append(ss, fmt.Sprintf("%q=i%d[%s]", e.Name, ch.stableAttr.Ino, modeStr(ch.stableAttr.Mode)))
}
return strings.Join(ss, ",")
}
func (c *inodeChildren) get(name string) *Inode {
idx, ok := c.childrenMap[name]
if !ok {
return nil
}
return c.children[idx].Inode
}
func (c *inodeChildren) compact() {
nc := make([]childEntry, 0, 2*len(c.childrenMap)+1)
nm := make(map[string]int, len(c.childrenMap))
for _, e := range c.children {
if e.Inode == nil {
continue
}
nm[e.Name] = len(nc)
nc = append(nc, e)
}
c.childrenMap = nm
c.children = nc
}
func (c *inodeChildren) set(parent *Inode, name string, ch *Inode) {
idx, ok := c.childrenMap[name]
if !ok {
if cap(c.children) == len(c.children) {
c.compact()
}
idx = len(c.children)
c.children = append(c.children, childEntry{})
}
c.childrenMap[name] = idx
c.children[idx] = childEntry{Name: name, Inode: ch}
parent.changeCounter++
ch.parents.add(parentData{name, parent})
ch.changeCounter++
}
func (c *inodeChildren) len() int {
return len(c.childrenMap)
}
func (c *inodeChildren) toMap() map[string]*Inode {
r := make(map[string]*Inode, len(c.childrenMap))
for _, e := range c.children {
if e.Inode != nil {
r[e.Name] = e.Inode
}
}
return r
}
func (c *inodeChildren) del(parent *Inode, name string) {
idx, ok := c.childrenMap[name]
if !ok {
return
}
ch := c.children[idx].Inode
delete(c.childrenMap, name)
c.children[idx] = childEntry{}
ch.parents.delete(parentData{name, parent})
ch.changeCounter++
parent.changeCounter++
}
func (c *inodeChildren) list() []childEntry {
r := make([]childEntry, 0, len(c.childrenMap))
for _, e := range c.children {
if e.Inode != nil {
r = append(r, e)
}
}
return r
}