file_system.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // Copyright 2015 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package fuseutil
  15. import (
  16. "io"
  17. "sync"
  18. "golang.org/x/net/context"
  19. "github.com/jacobsa/fuse"
  20. "github.com/jacobsa/fuse/fuseops"
  21. )
  22. // An interface with a method for each op type in the fuseops package. This can
  23. // be used in conjunction with NewFileSystemServer to avoid writing a "dispatch
  24. // loop" that switches on op types, instead receiving typed method calls
  25. // directly.
  26. //
  27. // The FileSystem implementation should not call Connection.Reply, instead
  28. // returning the error with which the caller should respond.
  29. //
  30. // See NotImplementedFileSystem for a convenient way to embed default
  31. // implementations for methods you don't care about.
  32. type FileSystem interface {
  33. StatFS(context.Context, *fuseops.StatFSOp) error
  34. LookUpInode(context.Context, *fuseops.LookUpInodeOp) error
  35. GetInodeAttributes(context.Context, *fuseops.GetInodeAttributesOp) error
  36. SetInodeAttributes(context.Context, *fuseops.SetInodeAttributesOp) error
  37. ForgetInode(context.Context, *fuseops.ForgetInodeOp) error
  38. MkDir(context.Context, *fuseops.MkDirOp) error
  39. MkNode(context.Context, *fuseops.MkNodeOp) error
  40. CreateFile(context.Context, *fuseops.CreateFileOp) error
  41. CreateSymlink(context.Context, *fuseops.CreateSymlinkOp) error
  42. Rename(context.Context, *fuseops.RenameOp) error
  43. RmDir(context.Context, *fuseops.RmDirOp) error
  44. Unlink(context.Context, *fuseops.UnlinkOp) error
  45. OpenDir(context.Context, *fuseops.OpenDirOp) error
  46. ReadDir(context.Context, *fuseops.ReadDirOp) error
  47. ReleaseDirHandle(context.Context, *fuseops.ReleaseDirHandleOp) error
  48. OpenFile(context.Context, *fuseops.OpenFileOp) error
  49. ReadFile(context.Context, *fuseops.ReadFileOp) error
  50. WriteFile(context.Context, *fuseops.WriteFileOp) error
  51. SyncFile(context.Context, *fuseops.SyncFileOp) error
  52. FlushFile(context.Context, *fuseops.FlushFileOp) error
  53. ReleaseFileHandle(context.Context, *fuseops.ReleaseFileHandleOp) error
  54. ReadSymlink(context.Context, *fuseops.ReadSymlinkOp) error
  55. RemoveXattr(context.Context, *fuseops.RemoveXattrOp) error
  56. GetXattr(context.Context, *fuseops.GetXattrOp) error
  57. ListXattr(context.Context, *fuseops.ListXattrOp) error
  58. SetXattr(context.Context, *fuseops.SetXattrOp) error
  59. // Regard all inodes (including the root inode) as having their lookup counts
  60. // decremented to zero, and clean up any resources associated with the file
  61. // system. No further calls to the file system will be made.
  62. Destroy()
  63. }
  64. // Create a fuse.Server that handles ops by calling the associated FileSystem
  65. // method.Respond with the resulting error. Unsupported ops are responded to
  66. // directly with ENOSYS.
  67. //
  68. // Each call to a FileSystem method is made on its own goroutine, and is free
  69. // to block.
  70. //
  71. // (It is safe to naively process ops concurrently because the kernel
  72. // guarantees to serialize operations that the user expects to happen in order,
  73. // cf. http://goo.gl/jnkHPO, fuse-devel thread "Fuse guarantees on concurrent
  74. // requests").
  75. func NewFileSystemServer(fs FileSystem) fuse.Server {
  76. return &fileSystemServer{
  77. fs: fs,
  78. }
  79. }
  80. type fileSystemServer struct {
  81. fs FileSystem
  82. opsInFlight sync.WaitGroup
  83. }
  84. func (s *fileSystemServer) ServeOps(c *fuse.Connection) {
  85. // When we are done, we clean up by waiting for all in-flight ops then
  86. // destroying the file system.
  87. defer func() {
  88. s.opsInFlight.Wait()
  89. s.fs.Destroy()
  90. }()
  91. for {
  92. ctx, op, err := c.ReadOp()
  93. if err == io.EOF {
  94. break
  95. }
  96. if err != nil {
  97. panic(err)
  98. }
  99. s.opsInFlight.Add(1)
  100. go s.handleOp(c, ctx, op)
  101. }
  102. }
  103. func (s *fileSystemServer) handleOp(
  104. c *fuse.Connection,
  105. ctx context.Context,
  106. op interface{}) {
  107. defer s.opsInFlight.Done()
  108. // Dispatch to the appropriate method.
  109. var err error
  110. switch typed := op.(type) {
  111. default:
  112. err = fuse.ENOSYS
  113. case *fuseops.StatFSOp:
  114. err = s.fs.StatFS(ctx, typed)
  115. case *fuseops.LookUpInodeOp:
  116. err = s.fs.LookUpInode(ctx, typed)
  117. case *fuseops.GetInodeAttributesOp:
  118. err = s.fs.GetInodeAttributes(ctx, typed)
  119. case *fuseops.SetInodeAttributesOp:
  120. err = s.fs.SetInodeAttributes(ctx, typed)
  121. case *fuseops.ForgetInodeOp:
  122. err = s.fs.ForgetInode(ctx, typed)
  123. case *fuseops.MkDirOp:
  124. err = s.fs.MkDir(ctx, typed)
  125. case *fuseops.MkNodeOp:
  126. err = s.fs.MkNode(ctx, typed)
  127. case *fuseops.CreateFileOp:
  128. err = s.fs.CreateFile(ctx, typed)
  129. case *fuseops.CreateSymlinkOp:
  130. err = s.fs.CreateSymlink(ctx, typed)
  131. case *fuseops.RenameOp:
  132. err = s.fs.Rename(ctx, typed)
  133. case *fuseops.RmDirOp:
  134. err = s.fs.RmDir(ctx, typed)
  135. case *fuseops.UnlinkOp:
  136. err = s.fs.Unlink(ctx, typed)
  137. case *fuseops.OpenDirOp:
  138. err = s.fs.OpenDir(ctx, typed)
  139. case *fuseops.ReadDirOp:
  140. err = s.fs.ReadDir(ctx, typed)
  141. case *fuseops.ReleaseDirHandleOp:
  142. err = s.fs.ReleaseDirHandle(ctx, typed)
  143. case *fuseops.OpenFileOp:
  144. err = s.fs.OpenFile(ctx, typed)
  145. case *fuseops.ReadFileOp:
  146. err = s.fs.ReadFile(ctx, typed)
  147. case *fuseops.WriteFileOp:
  148. err = s.fs.WriteFile(ctx, typed)
  149. case *fuseops.SyncFileOp:
  150. err = s.fs.SyncFile(ctx, typed)
  151. case *fuseops.FlushFileOp:
  152. err = s.fs.FlushFile(ctx, typed)
  153. case *fuseops.ReleaseFileHandleOp:
  154. err = s.fs.ReleaseFileHandle(ctx, typed)
  155. case *fuseops.ReadSymlinkOp:
  156. err = s.fs.ReadSymlink(ctx, typed)
  157. case *fuseops.RemoveXattrOp:
  158. err = s.fs.RemoveXattr(ctx, typed)
  159. case *fuseops.GetXattrOp:
  160. err = s.fs.GetXattr(ctx, typed)
  161. case *fuseops.ListXattrOp:
  162. err = s.fs.ListXattr(ctx, typed)
  163. case *fuseops.SetXattrOp:
  164. err = s.fs.SetXattr(ctx, typed)
  165. }
  166. c.Reply(ctx, err)
  167. }