127 lines
4.0 KiB
Go
127 lines
4.0 KiB
Go
package fsedsl
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
// File is an open handle to a single named blob.
|
|
type File interface {
|
|
Stat() (os.FileInfo, error)
|
|
Read() ([]byte, error)
|
|
Write(data []byte) error
|
|
BlockingRead(ctx context.Context, base string) (content []byte, nextBase string, err error)
|
|
|
|
// Read-side contracts (mutually exclusive — at most one true):
|
|
// BlockingReadMode — blocks up to 5s for next value, returns it or empty, EOF on 2nd read
|
|
// StreamMode — blocks indefinitely, streams data incrementally, FD lives until EOF
|
|
// RequestRespMode — write blocks until result produced, read returns result once (rdwr)
|
|
BlockingReadMode() bool
|
|
StreamMode() bool
|
|
RequestRespMode() bool
|
|
}
|
|
|
|
// FileTree is a named collection of entries.
|
|
type FileTree interface {
|
|
Stat(name string) (os.FileInfo, error)
|
|
List() ([]os.DirEntry, error)
|
|
Open(name string) (File, error)
|
|
Create(name string) error
|
|
Delete(name string) error
|
|
Rename(oldName, newName string) error
|
|
}
|
|
|
|
// FileConfig implements File via function pointers.
|
|
type FileConfig struct {
|
|
StatFn func() (os.FileInfo, error)
|
|
ReadFn func() ([]byte, error)
|
|
WriteFn func([]byte) error
|
|
BlockingReadFn func(context.Context, string) ([]byte, string, error)
|
|
BlockingRead_ bool // one-shot waiter: block 5s, return once, EOF on 2nd read
|
|
StreamMode_ bool // indefinite stream: block forever, keep FD open
|
|
RequestResp_ bool // rdwr: write blocks on write, read returns result once
|
|
}
|
|
|
|
func (e *FileConfig) Stat() (os.FileInfo, error) { return e.StatFn() }
|
|
func (e *FileConfig) Read() ([]byte, error) { return e.ReadFn() }
|
|
func (e *FileConfig) Write(data []byte) error { return e.WriteFn(data) }
|
|
func (e *FileConfig) BlockingRead(ctx context.Context, base string) ([]byte, string, error) {
|
|
return e.BlockingReadFn(ctx, base)
|
|
}
|
|
func (e *FileConfig) BlockingReadMode() bool { return e.BlockingRead_ }
|
|
func (e *FileConfig) StreamMode() bool { return e.StreamMode_ }
|
|
func (e *FileConfig) RequestRespMode() bool { return e.RequestResp_ }
|
|
|
|
// ValidateReadMode panics if more than one read-side mode is set.
|
|
func (e *FileConfig) ValidateReadMode() {
|
|
n := 0
|
|
if e.BlockingRead_ {
|
|
n++
|
|
}
|
|
if e.StreamMode_ {
|
|
n++
|
|
}
|
|
if e.RequestResp_ {
|
|
n++
|
|
}
|
|
if n > 1 {
|
|
panic("FileConfig: at most one of BlockingReadMode, StreamMode, RequestRespMode may be set")
|
|
}
|
|
}
|
|
|
|
// SyntheticFileInfo implements os.FileInfo for entries with no backing file.
|
|
type SyntheticFileInfo struct {
|
|
Name_ string
|
|
Mode_ os.FileMode
|
|
Size_ int64
|
|
IsDir_ bool
|
|
UID_ string
|
|
GID_ string
|
|
Vers_ uint32
|
|
}
|
|
|
|
func (f *SyntheticFileInfo) Name() string { return f.Name_ }
|
|
func (f *SyntheticFileInfo) Size() int64 { return f.Size_ }
|
|
func (f *SyntheticFileInfo) Mode() os.FileMode { return f.Mode_ }
|
|
func (f *SyntheticFileInfo) ModTime() time.Time { return time.Time{} }
|
|
func (f *SyntheticFileInfo) IsDir() bool { return f.IsDir_ }
|
|
func (f *SyntheticFileInfo) Sys() any { return nil }
|
|
|
|
// SyntheticEntry implements os.DirEntry for entries with no backing file.
|
|
type SyntheticEntry struct {
|
|
Name_ string
|
|
Mode_ os.FileMode
|
|
IsDir_ bool
|
|
}
|
|
|
|
func (e *SyntheticEntry) Name() string { return e.Name_ }
|
|
func (e *SyntheticEntry) IsDir() bool { return e.IsDir_ }
|
|
func (e *SyntheticEntry) Type() os.FileMode {
|
|
if e.IsDir_ {
|
|
return os.ModeDir
|
|
}
|
|
return 0
|
|
}
|
|
func (e *SyntheticEntry) Info() (os.FileInfo, error) {
|
|
return &SyntheticFileInfo{Name_: e.Name_, Mode_: e.Mode_, IsDir_: e.IsDir_}, nil
|
|
}
|
|
|
|
// FileEntry returns a synthetic file DirEntry.
|
|
func FileEntry(name string, mode os.FileMode) os.DirEntry {
|
|
return &SyntheticEntry{Name_: name, Mode_: mode}
|
|
}
|
|
|
|
// DirEntry returns a synthetic directory DirEntry.
|
|
func DirEntry(name string, mode os.FileMode) os.DirEntry {
|
|
return &SyntheticEntry{Name_: name, Mode_: mode, IsDir_: true}
|
|
}
|
|
|
|
// Structural permissions — used by Tree for mounted children and synthetic files.
|
|
const (
|
|
PermChildDir os.FileMode = 0555
|
|
PermIdx os.FileMode = 0444
|
|
PermMkdir os.FileMode = 0755
|
|
PermMkdirPrivate os.FileMode = 0700
|
|
)
|