fuse.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // +build linux
  2. /*
  3. * Rufs - Remote Union File System
  4. *
  5. * Copyright 2017 Matthias Ladkau. All rights reserved.
  6. *
  7. * This Source Code Form is subject to the terms of the MIT
  8. * License, If a copy of the MIT License was not distributed with this
  9. * file, You can obtain one at https://opensource.org/licenses/MIT.
  10. */
  11. /*
  12. Package export contains export bindings for Rufs.
  13. */
  14. package export
  15. /*
  16. This file contains Rufs bindings for FUSE (Filesystem in Userspace) enabling
  17. a user to operate on Rufs as if it was a local file system.
  18. This uses GO-FUSE: https://github.com/hanwen/go-fuse
  19. Distributed under the New BSD License
  20. Copyright (c) 2010 the Go-FUSE Authors. All rights reserved.
  21. */
  22. import (
  23. "log"
  24. "os"
  25. "path"
  26. "path/filepath"
  27. "devt.de/krotik/rufs"
  28. "github.com/hanwen/go-fuse/v2/fuse"
  29. "github.com/hanwen/go-fuse/v2/fuse/nodefs"
  30. "github.com/hanwen/go-fuse/v2/fuse/pathfs"
  31. )
  32. /*
  33. RufsFuse is the Rufs specific FUSE filesystem API that uses paths rather
  34. than inodes.
  35. */
  36. type RufsFuse struct {
  37. pathfs.FileSystem
  38. Tree *rufs.Tree
  39. }
  40. /*
  41. GetAttr is the main entry point, through which FUSE discovers which
  42. files and directories exist.
  43. */
  44. func (rf *RufsFuse) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
  45. if name == "" {
  46. // Mount point is always a directory
  47. return &fuse.Attr{
  48. Mode: fuse.S_IFDIR | 0755,
  49. }, fuse.OK
  50. }
  51. var a *fuse.Attr
  52. status := fuse.ENOENT
  53. // Construct path and filename
  54. name = path.Join("/", name)
  55. dir, file := filepath.Split(name)
  56. // Query the tree
  57. _, fis, err := rf.Tree.Dir(dir, "", false, false)
  58. if err != nil {
  59. log.Print(err)
  60. status = fuse.EIO
  61. }
  62. if len(fis) > 0 {
  63. // Create attribute entries
  64. for _, fi := range fis[0] {
  65. if fi.Name() == file {
  66. a = &fuse.Attr{
  67. Mode: OSModeToFuseMode(fi.Mode()),
  68. Size: uint64(fi.Size()),
  69. }
  70. status = fuse.OK
  71. }
  72. }
  73. }
  74. return a, status
  75. }
  76. /*
  77. OpenDir handles directories.
  78. */
  79. func (rf *RufsFuse) OpenDir(name string,
  80. context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
  81. var c []fuse.DirEntry
  82. // Construct path and filename
  83. name = path.Join("/", name)
  84. status := fuse.ENOENT
  85. // Query the tree
  86. _, fis, err := rf.Tree.Dir(name, "", false, false)
  87. if err != nil {
  88. LogError(err)
  89. return nil, fuse.EIO
  90. }
  91. if len(fis) > 0 {
  92. // Create entries
  93. for _, fi := range fis[0] {
  94. c = append(c, fuse.DirEntry{
  95. Name: fi.Name(),
  96. Mode: OSModeToFuseMode(fi.Mode()),
  97. })
  98. }
  99. status = fuse.OK
  100. }
  101. return c, status
  102. }
  103. /*
  104. Open file handling.
  105. */
  106. func (rf *RufsFuse) Open(name string, flags uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) {
  107. return &RufsFile{nodefs.NewDefaultFile(), path.Join("/", name), rf.Tree}, fuse.OK
  108. }
  109. // File related objects
  110. // ====================
  111. /*
  112. RufsFile models a file of Rufs.
  113. */
  114. type RufsFile struct {
  115. nodefs.File
  116. name string
  117. tree *rufs.Tree
  118. }
  119. /*
  120. Read reads a portion of the file.
  121. */
  122. func (f *RufsFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) {
  123. var res fuse.ReadResult
  124. status := fuse.OK
  125. n, err := f.tree.ReadFile(f.name, buf, off)
  126. if err != nil {
  127. LogError(err)
  128. status = fuse.EIO
  129. } else {
  130. res = &RufsReadResult{buf, n}
  131. }
  132. return res, status
  133. }
  134. /*
  135. RufsReadResult is an implementation of fuse.ReadResult.
  136. */
  137. type RufsReadResult struct {
  138. buf []byte
  139. n int
  140. }
  141. /*
  142. Bytes returns the raw bytes for the read.
  143. */
  144. func (r *RufsReadResult) Bytes(buf []byte) ([]byte, fuse.Status) {
  145. return r.buf, fuse.OK
  146. }
  147. /*
  148. Size returns how many bytes this return value takes at most.
  149. */
  150. func (r *RufsReadResult) Size() int {
  151. return r.n
  152. }
  153. /*
  154. Done is called after sending the data to the kernel.
  155. */
  156. func (r *RufsReadResult) Done() {}
  157. // Helper functions
  158. // ================
  159. /*
  160. OSModeToFuseMode converts a given os.FileMode to a Fuse Mode
  161. */
  162. func OSModeToFuseMode(fm os.FileMode) uint32 {
  163. m := uint32(fm)
  164. m = m & 0x0FFF // Remove special bits
  165. if fm.IsDir() {
  166. m = fuse.S_IFDIR | m
  167. } else {
  168. m = fuse.S_IFREG | m
  169. }
  170. return m
  171. }