statfs.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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 statfs
  15. import (
  16. "os"
  17. "sync"
  18. "golang.org/x/net/context"
  19. "github.com/jacobsa/fuse"
  20. "github.com/jacobsa/fuse/fuseops"
  21. "github.com/jacobsa/fuse/fuseutil"
  22. )
  23. // A file system that allows orchestrating canned responses to statfs ops, for
  24. // testng out OS-specific statfs behavior.
  25. //
  26. // The file system allows opening and writing to any name that is a child of
  27. // the root inode, and keeps track of the most recent write size delivered by
  28. // the kernel (in order to test statfs response block size effects on write
  29. // size, if any).
  30. //
  31. // Safe for concurrent access.
  32. type FS interface {
  33. fuseutil.FileSystem
  34. // Set the canned response to be used for future statfs ops.
  35. SetStatFSResponse(r fuseops.StatFSOp)
  36. // Set the canned response to be used for future stat ops.
  37. SetStatResponse(r fuseops.InodeAttributes)
  38. // Return the size of the most recent write delivered by the kernel, or -1 if
  39. // none.
  40. MostRecentWriteSize() int
  41. }
  42. func New() (fs FS) {
  43. fs = &statFS{
  44. cannedStatResponse: fuseops.InodeAttributes{
  45. Mode: 0666,
  46. },
  47. mostRecentWriteSize: -1,
  48. }
  49. return
  50. }
  51. const childInodeID = fuseops.RootInodeID + 1
  52. type statFS struct {
  53. fuseutil.NotImplementedFileSystem
  54. mu sync.Mutex
  55. cannedResponse fuseops.StatFSOp // GUARDED_BY(mu)
  56. cannedStatResponse fuseops.InodeAttributes // GUARDED_BY(mu)
  57. mostRecentWriteSize int // GUARDED_BY(mu)
  58. }
  59. ////////////////////////////////////////////////////////////////////////
  60. // Helpers
  61. ////////////////////////////////////////////////////////////////////////
  62. func dirAttrs() fuseops.InodeAttributes {
  63. return fuseops.InodeAttributes{
  64. Mode: os.ModeDir | 0777,
  65. }
  66. }
  67. func (fs *statFS) fileAttrs() fuseops.InodeAttributes {
  68. return fs.cannedStatResponse
  69. }
  70. ////////////////////////////////////////////////////////////////////////
  71. // Public interface
  72. ////////////////////////////////////////////////////////////////////////
  73. // LOCKS_EXCLUDED(fs.mu)
  74. func (fs *statFS) SetStatFSResponse(r fuseops.StatFSOp) {
  75. fs.mu.Lock()
  76. defer fs.mu.Unlock()
  77. fs.cannedResponse = r
  78. }
  79. // LOCKS_EXCLUDED(fs.mu)
  80. func (fs *statFS) SetStatResponse(r fuseops.InodeAttributes) {
  81. fs.mu.Lock()
  82. defer fs.mu.Unlock()
  83. fs.cannedStatResponse = r
  84. }
  85. // LOCKS_EXCLUDED(fs.mu)
  86. func (fs *statFS) MostRecentWriteSize() int {
  87. fs.mu.Lock()
  88. defer fs.mu.Unlock()
  89. return fs.mostRecentWriteSize
  90. }
  91. ////////////////////////////////////////////////////////////////////////
  92. // FileSystem methods
  93. ////////////////////////////////////////////////////////////////////////
  94. // LOCKS_EXCLUDED(fs.mu)
  95. func (fs *statFS) StatFS(
  96. ctx context.Context,
  97. op *fuseops.StatFSOp) (err error) {
  98. fs.mu.Lock()
  99. defer fs.mu.Unlock()
  100. *op = fs.cannedResponse
  101. return
  102. }
  103. func (fs *statFS) LookUpInode(
  104. ctx context.Context,
  105. op *fuseops.LookUpInodeOp) (err error) {
  106. // Only the root has children.
  107. if op.Parent != fuseops.RootInodeID {
  108. err = fuse.ENOENT
  109. return
  110. }
  111. op.Entry.Child = childInodeID
  112. op.Entry.Attributes = fs.fileAttrs()
  113. return
  114. }
  115. func (fs *statFS) GetInodeAttributes(
  116. ctx context.Context,
  117. op *fuseops.GetInodeAttributesOp) (err error) {
  118. switch op.Inode {
  119. case fuseops.RootInodeID:
  120. op.Attributes = dirAttrs()
  121. case childInodeID:
  122. op.Attributes = fs.fileAttrs()
  123. default:
  124. err = fuse.ENOENT
  125. }
  126. return
  127. }
  128. func (fs *statFS) SetInodeAttributes(
  129. ctx context.Context,
  130. op *fuseops.SetInodeAttributesOp) (err error) {
  131. // Ignore calls to truncate existing files when opening.
  132. return
  133. }
  134. func (fs *statFS) OpenFile(
  135. ctx context.Context,
  136. op *fuseops.OpenFileOp) (err error) {
  137. return
  138. }
  139. // LOCKS_EXCLUDED(fs.mu)
  140. func (fs *statFS) WriteFile(
  141. ctx context.Context,
  142. op *fuseops.WriteFileOp) (err error) {
  143. fs.mu.Lock()
  144. defer fs.mu.Unlock()
  145. fs.mostRecentWriteSize = len(op.Data)
  146. return
  147. }