Files
ThothII/tools/tht/internal/safeio/private_root.go

70 lines
2.6 KiB
Go

package safeio
import (
"os"
"strings"
"sync"
)
// PrivateDirectoryHandle pins one private directory for the duration of a storage operation.
// Implementations use descriptor-relative operations on POSIX and retained no-delete handles on
// Windows. Callers must close every returned child before releasing its parent.
type PrivateDirectoryHandle interface {
Close() error
Validate() error
OpenChild(name string, ensure bool) (PrivateDirectoryHandle, bool, error)
CreateRegular(name string, contents []byte) (bool, error)
CreateRegularFile(name string) (*os.File, bool, error)
ReadRegular(name string, maximum int64) ([]byte, bool, error)
ReplaceRegular(name string, contents []byte) error
RemoveRegular(name string) (bool, error)
ListPage(maximumEntries int, afterName string, validName func(string) bool, validLinks func(string, uint64) bool) (PrivateDirectoryPage, error)
ClaimRegular(source, claim string) (bool, error)
ReadClaim(source, claim string, maximum int64) ([]byte, bool, error)
RemoveClaim(source, claim string) (bool, error)
}
// OpenPrivateDirectory validates or creates the final private directory while retaining the
// opened canonical directory handle. With ensure=false, found=false means the final component is
// absent but its already-opened parent proves the same operation could safely create it.
func OpenPrivateDirectory(path string, ensure bool) (PrivateDirectoryHandle, bool, error) {
if err := ValidateCanonicalPath(path); err != nil {
return nil, false, ErrUnsafeFile
}
return openPrivateDirectory(path, ensure)
}
func validPrivateLeafName(name string) bool {
return name != "" && name != "." && name != ".." && !strings.ContainsAny(name, "\\/:\x00")
}
var privateDirectoryTestHook struct {
sync.RWMutex
hook func(string)
}
// SetPrivateDirectoryTestHookForTest installs a deterministic race hook for internal package
// tests. It has no production effect unless a test explicitly installs one.
func SetPrivateDirectoryTestHookForTest(hook func(string)) func() {
privateDirectoryTestHook.Lock()
previous := privateDirectoryTestHook.hook
privateDirectoryTestHook.hook = hook
privateDirectoryTestHook.Unlock()
return func() {
privateDirectoryTestHook.Lock()
privateDirectoryTestHook.hook = previous
privateDirectoryTestHook.Unlock()
}
}
// NotifyPrivateDirectoryTestHookForTest marks an internal retained-handle boundary. It is called
// only by storage code and lets tests install deterministic directory replacement races.
func NotifyPrivateDirectoryTestHookForTest(stage string) {
privateDirectoryTestHook.RLock()
hook := privateDirectoryTestHook.hook
privateDirectoryTestHook.RUnlock()
if hook != nil {
hook(stage)
}
}