github.com/scaleoutsean/fusego@v0.0.0-20220224074057-4a6429e46bb8/samples/errorfs/error_fs.go (about) 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 15 package errorfs 16 17 import ( 18 "context" 19 "fmt" 20 "os" 21 "reflect" 22 "sync" 23 "syscall" 24 25 "github.com/scaleoutsean/fusego/fuseops" 26 "github.com/scaleoutsean/fusego/fuseutil" 27 ) 28 29 const FooContents = "xxxx" 30 31 const fooInodeID = fuseops.RootInodeID + 1 32 33 var fooAttrs = fuseops.InodeAttributes{ 34 Nlink: 1, 35 Size: uint64(len(FooContents)), 36 Mode: 0444, 37 } 38 39 // A file system whose sole contents are a file named "foo" containing the 40 // string defined by FooContents. 41 // 42 // The file system can be configured to returned canned errors for particular 43 // operations using the method SetError. 44 type FS interface { 45 fuseutil.FileSystem 46 47 // Cause the file system to return the supplied error for all future 48 // operations matching the supplied type. 49 SetError(t reflect.Type, err syscall.Errno) 50 } 51 52 func New() (FS, error) { 53 return &errorFS{ 54 errors: make(map[reflect.Type]syscall.Errno), 55 }, nil 56 } 57 58 type errorFS struct { 59 fuseutil.NotImplementedFileSystem 60 61 mu sync.Mutex 62 63 // GUARDED_BY(mu) 64 errors map[reflect.Type]syscall.Errno 65 } 66 67 // LOCKS_EXCLUDED(fs.mu) 68 func (fs *errorFS) SetError(t reflect.Type, err syscall.Errno) { 69 fs.mu.Lock() 70 defer fs.mu.Unlock() 71 72 fs.errors[t] = err 73 } 74 75 // LOCKS_EXCLUDED(fs.mu) 76 func (fs *errorFS) transformError(op interface{}, err *error) bool { 77 fs.mu.Lock() 78 defer fs.mu.Unlock() 79 80 cannedErr, ok := fs.errors[reflect.TypeOf(op)] 81 if ok { 82 *err = cannedErr 83 return true 84 } 85 86 return false 87 } 88 89 //////////////////////////////////////////////////////////////////////// 90 // File system methods 91 //////////////////////////////////////////////////////////////////////// 92 93 // LOCKS_EXCLUDED(fs.mu) 94 func (fs *errorFS) GetInodeAttributes( 95 ctx context.Context, 96 op *fuseops.GetInodeAttributesOp) error { 97 var err error 98 if fs.transformError(op, &err) { 99 return err 100 } 101 102 // Figure out which inode the request is for. 103 switch { 104 case op.Inode == fuseops.RootInodeID: 105 op.Attributes = fuseops.InodeAttributes{ 106 Mode: os.ModeDir | 0777, 107 } 108 109 case op.Inode == fooInodeID: 110 op.Attributes = fooAttrs 111 112 default: 113 return fmt.Errorf("Unknown inode: %d", op.Inode) 114 } 115 116 return nil 117 } 118 119 func (fs *errorFS) StatFS( 120 ctx context.Context, 121 op *fuseops.StatFSOp) error { 122 return nil 123 } 124 125 // LOCKS_EXCLUDED(fs.mu) 126 func (fs *errorFS) LookUpInode( 127 ctx context.Context, 128 op *fuseops.LookUpInodeOp) error { 129 var err error 130 if fs.transformError(op, &err) { 131 return err 132 } 133 134 // Is this a known inode? 135 if !(op.Parent == fuseops.RootInodeID && op.Name == "foo") { 136 return syscall.ENOENT 137 } 138 139 op.Entry.Child = fooInodeID 140 op.Entry.Attributes = fooAttrs 141 142 return nil 143 } 144 145 // LOCKS_EXCLUDED(fs.mu) 146 func (fs *errorFS) OpenFile( 147 ctx context.Context, 148 op *fuseops.OpenFileOp) error { 149 var err error 150 if fs.transformError(op, &err) { 151 return err 152 } 153 154 if op.Inode != fooInodeID { 155 return fmt.Errorf("Unsupported inode ID: %d", op.Inode) 156 } 157 158 return nil 159 } 160 161 // LOCKS_EXCLUDED(fs.mu) 162 func (fs *errorFS) ReadFile( 163 ctx context.Context, 164 op *fuseops.ReadFileOp) error { 165 var err error 166 if fs.transformError(op, &err) { 167 return err 168 } 169 170 if op.Inode != fooInodeID || op.Offset != 0 { 171 return fmt.Errorf("Unexpected request: %#v", op) 172 } 173 174 op.BytesRead = copy(op.Dst, FooContents) 175 176 return nil 177 } 178 179 // LOCKS_EXCLUDED(fs.mu) 180 func (fs *errorFS) OpenDir( 181 ctx context.Context, 182 op *fuseops.OpenDirOp) error { 183 var err error 184 if fs.transformError(op, &err) { 185 return err 186 } 187 188 if op.Inode != fuseops.RootInodeID { 189 return fmt.Errorf("Unsupported inode ID: %d", op.Inode) 190 } 191 192 return nil 193 } 194 195 // LOCKS_EXCLUDED(fs.mu) 196 func (fs *errorFS) ReadDir( 197 ctx context.Context, 198 op *fuseops.ReadDirOp) error { 199 var err error 200 if fs.transformError(op, &err) { 201 return err 202 } 203 204 if op.Inode != fuseops.RootInodeID || op.Offset != 0 { 205 return fmt.Errorf("Unexpected request: %#v", op) 206 } 207 208 op.BytesRead = fuseutil.WriteDirent( 209 op.Dst, 210 fuseutil.Dirent{ 211 Offset: 0, 212 Inode: fooInodeID, 213 Name: "foo", 214 Type: fuseutil.DT_File, 215 }) 216 217 return nil 218 }