ref: 1833a59599bf67892606916c56da3503be0a1c0a
author: Alex Musolino <alex@musolino.id.au>
date: Thu Dec 29 17:37:11 EST 2022
initial commit
--- /dev/null
+++ b/go.mod
@@ -1,0 +1,8 @@
+module musolino.id.au/mntgen
+
+go 1.19
+
+require (
+ bazil.org/fuse v0.0.0-20221210232012-5a1c75a4f691 // indirect
+ golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 // indirect
+)
--- /dev/null
+++ b/go.sum
@@ -1,0 +1,4 @@
+bazil.org/fuse v0.0.0-20221210232012-5a1c75a4f691 h1:dxU4G/I97qxiXCYzKo9IJBrYUNDjBODU6cTpXMlPb7Y=
+bazil.org/fuse v0.0.0-20221210232012-5a1c75a4f691/go.mod h1:eX+feLR06AMFrTGQBzFnMMDz1vjBv2yHZBFlI9RJeaQ=
+golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 h1:gSbV7h1NRL2G1xTg/owz62CST1oJBmxy4QpMMregXVQ=
+golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
--- /dev/null
+++ b/mntgen.go
@@ -1,0 +1,125 @@
+package main
+
+import (
+ "bazil.org/fuse"
+ "bazil.org/fuse/fs"
+ "context"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "os/signal"
+ "sync/atomic"
+ "syscall"
+ "time"
+)
+
+var inodeCount uint64
+
+type Node interface {
+ fs.Node
+ GetDirentType() fuse.DirentType
+}
+
+type Dir struct {
+ Fs *FS
+ Name string
+ Attributes fuse.Attr
+ Entries map[string]*Dir
+}
+
+func NewDir(fs *FS, name string) *Dir {
+ atomic.AddUint64(&inodeCount, 1)
+ return &Dir{
+ Fs: fs,
+ Name: name,
+ Attributes: fuse.Attr{
+ Inode: inodeCount,
+ Atime: time.Now(),
+ Mtime: time.Now(),
+ Ctime: time.Now(),
+ Mode: os.ModeDir | 0o755,
+ },
+ Entries: make(map[string]*Dir),
+ }
+}
+
+func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) error {
+ *a = d.Attributes
+ return nil
+}
+
+func (d *Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
+ if d == d.Fs.RootDir {
+ if node, ok := d.Entries[name]; ok {
+ return node, nil
+ } else {
+ nd := NewDir(d.Fs, name)
+ d.Entries[name] = nd
+ return nd, nil
+ }
+ }
+ return nil, syscall.ENOENT
+}
+
+func (d *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
+ var entries []fuse.Dirent
+ for k, v := range d.Entries {
+ var a fuse.Attr
+ v.Attr(ctx, &a)
+ entries = append(entries, fuse.Dirent{
+ Inode: a.Inode,
+ Type: fuse.DT_Dir,
+ Name: k,
+ })
+ }
+ return entries, nil
+}
+
+type FS struct {
+ RootDir *Dir
+}
+
+func NewFS() *FS {
+ fs := &FS{}
+ fs.RootDir = NewDir(fs, "")
+ return fs
+}
+
+func (fs FS) Root() (fs.Node, error) {
+ return fs.RootDir, nil
+}
+
+func main() {
+ flag.Usage = func () {
+ fmt.Fprintf(os.Stderr, "usage: %s [ mnt ]\n", os.Args[0])
+ os.Exit(1)
+ }
+ flag.Parse()
+ if flag.NArg() >= 2 {
+ flag.Usage()
+ }
+ mtpt := "/n"
+ if flag.NArg() == 1 {
+ mtpt = flag.Arg(0)
+ }
+ c, err := fuse.Mount(mtpt, fuse.FSName("mntgen"), fuse.Subtype("mntgen"))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer c.Close()
+ sigc := make(chan os.Signal, 1)
+ signal.Notify(sigc, syscall.SIGTERM, syscall.SIGINT)
+ go func() {
+ for {
+ <-sigc
+ if err := fuse.Unmount(mtpt); err != nil {
+ log.Print("unmount failed: ", err)
+ }
+ }
+ }()
+ err = fs.Serve(c, NewFS())
+ if err != nil {
+ log.Fatal(err)
+ }
+}