Initial commit

This commit is contained in:
2026-01-19 01:51:08 +02:00
commit 2dbb7e5d7e
18 changed files with 1475 additions and 0 deletions

28
ffs/dreamfile.go Normal file
View File

@@ -0,0 +1,28 @@
package ffs
import (
"context"
"fmt"
"fusetest/furcadia"
"bazil.org/fuse"
)
///////////////////////////////////////////////////////////////////////////////////////////////////
// TYPE: DreamFile ////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
type DreamFile struct {
Dream *furcadia.PounceDream
_attr fuse.Attr
}
func (f *DreamFile) GetName() string {
return f.Dream.ShortURL
}
func (f *DreamFile) Attr(ctx context.Context, a *fuse.Attr) error {
fmt.Printf("[D] DreamFile('%v').Attr()\n", f.GetName())
*a = f._attr
return nil
}

115
ffs/dreamsdir.go Normal file
View File

@@ -0,0 +1,115 @@
package ffs
import (
"context"
"fmt"
"os"
"syscall"
"time"
"bazil.org/fuse"
"bazil.org/fuse/fs"
)
///////////////////////////////////////////////////////////////////////////////////////////////////
// CONSTANTS //////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
const (
DREAMS_DIR_INODE_BASE = 0x2000
DREAMS_DIR_MAX_INODES = 0x1000
)
///////////////////////////////////////////////////////////////////////////////////////////////////
// TYPE: DreamsDir ////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
type DreamsDir struct {
_attr fuse.Attr
_entries []fuse.Dirent
}
func NewDreamsDir(inodeBase uint64, rootUID, rootGID uint32) *DreamsDir {
now := time.Now()
dir := &DreamsDir{
_attr: fuse.Attr{
Inode: inodeBase,
Nlink: 1,
Mode: os.ModeDir | 0500,
Uid: rootUID,
Gid: rootGID,
Atime: now,
Ctime: now,
Mtime: now,
},
}
// add basic entries
dir._entries = append(
dir._entries,
fuse.Dirent{Inode: dir._attr.Inode, Name: ".", Type: fuse.DT_Dir},
fuse.Dirent{Inode: ROOT_INODE, Name: "..", Type: fuse.DT_Dir},
)
return dir
}
func (d *DreamsDir) GetAttr() *fuse.Attr {
return &d._attr
}
func (d *DreamsDir) Attr(ctx context.Context, a *fuse.Attr) error {
*a = d._attr
return nil
}
func (d *DreamsDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
pounce := G_FS._pounce
dreams := pounce.Dreams
items := make([]fuse.Dirent, len(dreams)+2)
items[0] = fuse.Dirent{Inode: d._attr.Inode, Name: ".", Type: fuse.DT_Dir}
items[1] = fuse.Dirent{Inode: ROOT_INODE, Name: "..", Type: fuse.DT_Dir}
i := 2
for shortURL := range dreams {
items[i] = fuse.Dirent{
Inode: uint64(2000 + i),
Name: shortURL,
Type: fuse.DT_File,
}
i++
}
return items, nil
}
func (d *DreamsDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
if name == "." {
return d, nil
}
dreams := G_FS._pounce.Dreams
dream, exists := dreams[name]
if !exists {
fmt.Printf("[D] DreamsDir().Lookup('%v'): ENOENT\n", name)
return nil, syscall.ENOENT
}
fmt.Printf("[D] DreamsDir().Lookup('%v'): OK\n", name)
now := time.Now()
return &DreamFile{
Dream: dream,
_attr: fuse.Attr{
Inode: 0,
Nlink: 1,
Mode: 0400,
Size: 0,
Ctime: now,
Atime: now,
Mtime: now,
Uid: d._attr.Uid,
Gid: d._attr.Gid,
},
}, nil
}

67
ffs/fs.go Normal file
View File

@@ -0,0 +1,67 @@
package ffs
import (
"fusetest/furcadia"
"os"
"time"
"bazil.org/fuse"
"bazil.org/fuse/fs"
)
///////////////////////////////////////////////////////////////////////////////////////////////////
// VAR ////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
var (
// Filesystem context (there should only be one)
G_FS *FurcFS = nil
)
///////////////////////////////////////////////////////////////////////////////////////////////////
// TYPE: FS ///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
type FurcFS struct {
RootDir *RootDir
_pounce *furcadia.PounceList
}
func InitFS(rootUID, rootGID uint32) *FurcFS {
if G_FS != nil {
panic("G_FS already initialized - wtf?")
}
now := time.Now()
fs := &FurcFS{
RootDir: &RootDir{
_nodes: make(map[string]TopLevelDir),
_attr: fuse.Attr{
Inode: ROOT_INODE,
Nlink: 1,
Mode: os.ModeDir | 0500,
Uid: rootUID,
Gid: rootGID,
Atime: now,
Ctime: now,
Mtime: now,
},
},
_pounce: furcadia.NewPounceList(),
}
///////////////////////////////////////////////////////////////////////////
// register root-level items
///////////////////////////////////////////////////////////////////////////
fs.RootDir._nodes["furres"] = NewFurresDir(FURRES_DIR_INODE_BASE, rootUID, rootGID)
fs.RootDir._nodes["dreams"] = NewDreamsDir(DREAMS_DIR_INODE_BASE, rootUID, rootGID)
// FS context is now ready
G_FS = fs
return fs
}
func (fs *FurcFS) Root() (fs.Node, error) {
return fs.RootDir, nil
}

28
ffs/furrefile.go Normal file
View File

@@ -0,0 +1,28 @@
package ffs
import (
"context"
"fmt"
"fusetest/furcadia"
"bazil.org/fuse"
)
///////////////////////////////////////////////////////////////////////////////////////////////////
// TYPE: DreamFile ////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
type FurreFile struct {
Furre *furcadia.PounceFurre
_attr fuse.Attr
}
func (f *FurreFile) GetName() string {
return f.Furre.DisplayName
}
func (f *FurreFile) Attr(ctx context.Context, a *fuse.Attr) error {
fmt.Printf("[D] FurreFile('%v').Attr()\n", f.GetName())
*a = f._attr
return nil
}

133
ffs/furresdir.go Normal file
View File

@@ -0,0 +1,133 @@
package ffs
import (
"context"
"fmt"
"fusetest/furcadia"
"os"
"syscall"
"time"
"bazil.org/fuse"
"bazil.org/fuse/fs"
)
///////////////////////////////////////////////////////////////////////////////////////////////////
// CONSTANTS //////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
const (
FURRES_DIR_INODE_BASE = 0x1000
FURRES_DIR_MAX_INODES = 0x1000
)
///////////////////////////////////////////////////////////////////////////////////////////////////
// TYPE: DreamsDir ////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
type FurresDir struct {
_attr fuse.Attr
_entries []fuse.Dirent
_index map[string]int
}
func NewFurresDir(inodeBase uint64, rootUID, rootGID uint32) *FurresDir {
now := time.Now()
dir := &FurresDir{
_attr: fuse.Attr{
Inode: inodeBase,
Nlink: 1,
Mode: os.ModeDir | 0500,
Uid: rootUID,
Gid: rootGID,
Atime: now,
Ctime: now,
Mtime: now,
},
_index: make(map[string]int),
}
// add basic entries
dir._entries = append(
dir._entries,
fuse.Dirent{Inode: dir._attr.Inode, Name: ".", Type: fuse.DT_Dir},
fuse.Dirent{Inode: ROOT_INODE, Name: "..", Type: fuse.DT_Dir},
)
// add basic entries to the index
for i := range dir._entries {
dirent := &dir._entries[i]
dir._index[dirent.Name] = i
}
return dir
}
func (d *FurresDir) GetAttr() *fuse.Attr {
return &d._attr
}
func (d *FurresDir) Attr(ctx context.Context, a *fuse.Attr) error {
*a = d._attr
return nil
}
func (d *FurresDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
return d._entries, nil
// pounce := G_FS._pounce
// furres := pounce.Furres
// items := make([]fuse.Dirent, len(furres)+2)
// items[0] = fuse.Dirent{Inode: d._attr.Inode, Name: ".", Type: fuse.DT_Dir}
// items[1] = fuse.Dirent{Inode: ROOT_INODE, Name: "..", Type: fuse.DT_Dir}
// var i uint64 = 2
// for _, furre := range furres {
// items[i] = fuse.Dirent{
// Inode: d._attr.Inode + i - 1,
// Name: furre.DisplayName,
// Type: fuse.DT_File,
// }
// i++
// }
// return items, nil
}
func (d *FurresDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
if name == "." {
return d, nil
}
// find dirent for the given name
direntIndex, exists = d._index[name]
if !exists {
return nil, syscall.ENOENT
}
furres := G_FS._pounce.Furres
shortname := furcadia.GetShortName(name)
furre, exists := furres[shortname]
if !exists {
fmt.Printf("[F] FurresDir().Lookup('%v' -> %v): ENOENT\n", name, shortname)
return nil, syscall.ENOENT
}
fmt.Printf("[F] FurresDir().Lookup('%v'): OK\n", name)
now := time.Now()
return &FurreFile{
Furre: furre,
_attr: fuse.Attr{
Inode: 0,
Nlink: 1,
Mode: 0400,
Size: 0,
Ctime: now,
Atime: now,
Mtime: now,
Uid: d._attr.Uid,
Gid: d._attr.Gid,
},
}, nil
}

61
ffs/rootdir.go Normal file
View File

@@ -0,0 +1,61 @@
package ffs
import (
"context"
"fmt"
"syscall"
"bazil.org/fuse"
"bazil.org/fuse/fs"
)
///////////////////////////////////////////////////////////////////////////////////////////////////
// CONSTANTS //////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
const ROOT_INODE = 1
///////////////////////////////////////////////////////////////////////////////////////////////////
// TYPE: RootDir //////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
type RootDir struct {
_attr fuse.Attr
_nodes map[string]TopLevelDir
}
func (d *RootDir) Attr(ctx context.Context, a *fuse.Attr) error {
*a = d._attr
return nil
}
func (d *RootDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
if name == "." {
return d, nil
}
node, exists := d._nodes[name]
if exists {
fmt.Printf("[D] RootDir.Lookup('%v'): OK\n", name)
return node, nil
}
fmt.Printf("[D] RootDir.Lookup('%v'): ENOENT\n", name)
return nil, syscall.ENOENT
}
func (d *RootDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
fmt.Printf("[D] RootDir.ReadDirAll()\n")
items := make([]fuse.Dirent, len(d._nodes))
i := 0
for name, node := range d._nodes {
items[i] = fuse.Dirent{
Inode: node.GetAttr().Inode,
Name: name,
Type: fuse.DT_Dir,
}
i++
}
return items, nil
}

30
ffs/util.go Normal file
View File

@@ -0,0 +1,30 @@
package ffs
import (
"strings"
"bazil.org/fuse"
"bazil.org/fuse/fs"
)
type TopLevelDir interface {
fs.Node
GetAttr() *fuse.Attr
}
func IsValidName(name string) bool {
l := len(name)
if l == 0 || l > 255 {
return false
}
if name == "." || name == ".." {
return false
}
if strings.ContainsRune(name, '/') {
return false
}
return true
}