package main import ( "context" "log" "path/filepath" "strings" "sync" "syscall" "github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/fuse" ) type configFile struct { fs.MemRegularFile mu sync.Mutex StringData *string } func (f *configFile) Write(ctx context.Context, fh fs.FileHandle, data []byte, off int64) (uint32, syscall.Errno) { f.mu.Lock() defer f.mu.Unlock() end := int64(len(data)) + off if int64(len(f.Data)) < end { n := make([]byte, end) copy(n, f.Data) f.Data = n } copy(f.Data[off:off+int64(len(data))], data) str := string(data) *f.StringData = str return uint32(len(data)), 0 } func (f *configFile) Read(ctx context.Context, fh fs.FileHandle, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { f.mu.Lock() f.Data = []byte(*f.StringData) defer f.mu.Unlock() end := int(off) + len(dest) if end > len(f.Data) { end = len(f.Data) } return fuse.ReadResultData(f.Data[off:end]), fs.OK } // inMemoryFS is the root of the tree type inMemoryFS struct { fs.Inode configs map[string]*string } // Ensure that we implement NodeOnAdder var _ = (fs.NodeOnAdder)((*inMemoryFS)(nil)) // OnAdd is called on mounting the file system. Use it to populate // the file system tree. func (root *inMemoryFS) OnAdd(ctx context.Context) { for name, content := range root.configs { dir, base := filepath.Split(name) p := &root.Inode // Add directories leading up to the file. for _, component := range strings.Split(dir, "/") { if len(component) == 0 { continue } ch := p.GetChild(component) if ch == nil { // Create a directory ch = p.NewPersistentInode(ctx, &fs.Inode{}, fs.StableAttr{Mode: syscall.S_IFDIR}) // Add it p.AddChild(component, ch, true) } p = ch } // Make a file out of the content bytes. This type // provides the open/read/flush methods. embedder := &configFile{StringData: content} embedder.Data = []byte(*content) // Create the file. The Inode must be persistent, // because its life time is not under control of the // kernel. child := p.NewPersistentInode(ctx, embedder, fs.StableAttr{}) // And add it p.AddChild(base, child, true) } } // This demonstrates how to build a file system in memory. The // read/write logic for the file is provided by the MemRegularFile type. func StartFuse(mountPoint string, configs map[string]*string) { root := &inMemoryFS{configs: configs} server, err := fs.Mount(mountPoint, root, &fs.Options{ MountOptions: fuse.MountOptions{Debug: true}, }) if err != nil { log.Panic(err) } log.Printf("Mounted on %s", mountPoint) log.Printf("Unmount by calling 'fusermount -u %s'", mountPoint) // Wait until unmount before exiting server.Wait() }