fuse.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "path/filepath"
  6. "strings"
  7. "sync"
  8. "syscall"
  9. "github.com/hanwen/go-fuse/v2/fs"
  10. "github.com/hanwen/go-fuse/v2/fuse"
  11. )
  12. type configFile struct {
  13. fs.MemRegularFile
  14. mu sync.Mutex
  15. StringData *string
  16. }
  17. func (f *configFile) Write(ctx context.Context, fh fs.FileHandle, data []byte, off int64) (uint32, syscall.Errno) {
  18. f.mu.Lock()
  19. defer f.mu.Unlock()
  20. end := int64(len(data)) + off
  21. if int64(len(f.Data)) < end {
  22. n := make([]byte, end)
  23. copy(n, f.Data)
  24. f.Data = n
  25. }
  26. copy(f.Data[off:off+int64(len(data))], data)
  27. str := string(data)
  28. *f.StringData = str
  29. return uint32(len(data)), 0
  30. }
  31. func (f *configFile) Read(ctx context.Context, fh fs.FileHandle, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) {
  32. f.mu.Lock()
  33. f.Data = []byte(*f.StringData)
  34. defer f.mu.Unlock()
  35. end := int(off) + len(dest)
  36. if end > len(f.Data) {
  37. end = len(f.Data)
  38. }
  39. return fuse.ReadResultData(f.Data[off:end]), fs.OK
  40. }
  41. // inMemoryFS is the root of the tree
  42. type inMemoryFS struct {
  43. fs.Inode
  44. configs map[string]*string
  45. }
  46. // Ensure that we implement NodeOnAdder
  47. var _ = (fs.NodeOnAdder)((*inMemoryFS)(nil))
  48. // OnAdd is called on mounting the file system. Use it to populate
  49. // the file system tree.
  50. func (root *inMemoryFS) OnAdd(ctx context.Context) {
  51. for name, content := range root.configs {
  52. dir, base := filepath.Split(name)
  53. p := &root.Inode
  54. // Add directories leading up to the file.
  55. for _, component := range strings.Split(dir, "/") {
  56. if len(component) == 0 {
  57. continue
  58. }
  59. ch := p.GetChild(component)
  60. if ch == nil {
  61. // Create a directory
  62. ch = p.NewPersistentInode(ctx, &fs.Inode{},
  63. fs.StableAttr{Mode: syscall.S_IFDIR})
  64. // Add it
  65. p.AddChild(component, ch, true)
  66. }
  67. p = ch
  68. }
  69. // Make a file out of the content bytes. This type
  70. // provides the open/read/flush methods.
  71. embedder := &configFile{StringData: content}
  72. embedder.Data = []byte(*content)
  73. // Create the file. The Inode must be persistent,
  74. // because its life time is not under control of the
  75. // kernel.
  76. child := p.NewPersistentInode(ctx, embedder, fs.StableAttr{})
  77. // And add it
  78. p.AddChild(base, child, true)
  79. }
  80. }
  81. // This demonstrates how to build a file system in memory. The
  82. // read/write logic for the file is provided by the MemRegularFile type.
  83. func StartFuse(mountPoint string, configs map[string]*string) {
  84. root := &inMemoryFS{configs: configs}
  85. server, err := fs.Mount(mountPoint, root, &fs.Options{
  86. MountOptions: fuse.MountOptions{Debug: true},
  87. })
  88. if err != nil {
  89. log.Panic(err)
  90. }
  91. log.Printf("Mounted on %s", mountPoint)
  92. log.Printf("Unmount by calling 'fusermount -u %s'", mountPoint)
  93. // Wait until unmount before exiting
  94. server.Wait()
  95. }