github.com/hanwen/go-fuse@v1.0.0/fuse/nodefs/memnode.go (about) 1 // Copyright 2016 the Go-FUSE Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package nodefs 6 7 import ( 8 "fmt" 9 "os" 10 "sync" 11 "syscall" 12 "time" 13 14 "github.com/hanwen/go-fuse/fuse" 15 ) 16 17 // NewMemNodeFSRoot creates an in-memory node-based filesystem. Files 18 // are written into a backing store under the given prefix. 19 func NewMemNodeFSRoot(prefix string) Node { 20 fs := &memNodeFs{ 21 backingStorePrefix: prefix, 22 } 23 fs.root = fs.newNode() 24 return fs.root 25 } 26 27 type memNodeFs struct { 28 backingStorePrefix string 29 root *memNode 30 31 mutex sync.Mutex 32 nextFree int 33 } 34 35 func (fs *memNodeFs) String() string { 36 return fmt.Sprintf("MemNodeFs(%s)", fs.backingStorePrefix) 37 } 38 39 func (fs *memNodeFs) Root() Node { 40 return fs.root 41 } 42 43 func (fs *memNodeFs) SetDebug(bool) { 44 } 45 46 func (fs *memNodeFs) OnMount(*FileSystemConnector) { 47 } 48 49 func (fs *memNodeFs) OnUnmount() { 50 } 51 52 func (fs *memNodeFs) newNode() *memNode { 53 fs.mutex.Lock() 54 id := fs.nextFree 55 fs.nextFree++ 56 fs.mutex.Unlock() 57 n := &memNode{ 58 Node: NewDefaultNode(), 59 fs: fs, 60 id: id, 61 } 62 now := time.Now() 63 n.info.SetTimes(&now, &now, &now) 64 n.info.Mode = fuse.S_IFDIR | 0777 65 return n 66 } 67 68 func (fs *memNodeFs) Filename(n *Inode) string { 69 mn := n.Node().(*memNode) 70 return mn.filename() 71 } 72 73 type memNode struct { 74 Node 75 fs *memNodeFs 76 id int 77 78 mu sync.Mutex 79 link string 80 info fuse.Attr 81 } 82 83 func (n *memNode) filename() string { 84 return fmt.Sprintf("%s%d", n.fs.backingStorePrefix, n.id) 85 } 86 87 func (n *memNode) Deletable() bool { 88 return false 89 } 90 91 func (n *memNode) Readlink(c *fuse.Context) ([]byte, fuse.Status) { 92 n.mu.Lock() 93 defer n.mu.Unlock() 94 return []byte(n.link), fuse.OK 95 } 96 97 func (n *memNode) StatFs() *fuse.StatfsOut { 98 return &fuse.StatfsOut{} 99 } 100 101 func (n *memNode) Mkdir(name string, mode uint32, context *fuse.Context) (newNode *Inode, code fuse.Status) { 102 ch := n.fs.newNode() 103 ch.info.Mode = mode | fuse.S_IFDIR 104 n.Inode().NewChild(name, true, ch) 105 return ch.Inode(), fuse.OK 106 } 107 108 func (n *memNode) Unlink(name string, context *fuse.Context) (code fuse.Status) { 109 ch := n.Inode().RmChild(name) 110 if ch == nil { 111 return fuse.ENOENT 112 } 113 return fuse.OK 114 } 115 116 func (n *memNode) Rmdir(name string, context *fuse.Context) (code fuse.Status) { 117 return n.Unlink(name, context) 118 } 119 120 func (n *memNode) Symlink(name string, content string, context *fuse.Context) (newNode *Inode, code fuse.Status) { 121 ch := n.fs.newNode() 122 ch.info.Mode = fuse.S_IFLNK | 0777 123 ch.link = content 124 n.Inode().NewChild(name, false, ch) 125 return ch.Inode(), fuse.OK 126 } 127 128 func (n *memNode) Rename(oldName string, newParent Node, newName string, context *fuse.Context) (code fuse.Status) { 129 ch := n.Inode().RmChild(oldName) 130 newParent.Inode().RmChild(newName) 131 newParent.Inode().AddChild(newName, ch) 132 return fuse.OK 133 } 134 135 func (n *memNode) Link(name string, existing Node, context *fuse.Context) (*Inode, fuse.Status) { 136 n.Inode().AddChild(name, existing.Inode()) 137 return existing.Inode(), fuse.OK 138 } 139 140 func (n *memNode) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file File, node *Inode, code fuse.Status) { 141 ch := n.fs.newNode() 142 ch.info.Mode = mode | fuse.S_IFREG 143 144 f, err := os.Create(ch.filename()) 145 if err != nil { 146 return nil, nil, fuse.ToStatus(err) 147 } 148 n.Inode().NewChild(name, false, ch) 149 return ch.newFile(f), ch.Inode(), fuse.OK 150 } 151 152 type memNodeFile struct { 153 File 154 node *memNode 155 } 156 157 func (n *memNodeFile) String() string { 158 return fmt.Sprintf("memNodeFile(%s)", n.File.String()) 159 } 160 161 func (n *memNodeFile) InnerFile() File { 162 return n.File 163 } 164 165 func (n *memNodeFile) Flush() fuse.Status { 166 code := n.File.Flush() 167 168 if !code.Ok() { 169 return code 170 } 171 172 st := syscall.Stat_t{} 173 err := syscall.Stat(n.node.filename(), &st) 174 175 n.node.mu.Lock() 176 defer n.node.mu.Unlock() 177 n.node.info.Size = uint64(st.Size) 178 n.node.info.Blocks = uint64(st.Blocks) 179 return fuse.ToStatus(err) 180 } 181 182 func (n *memNode) newFile(f *os.File) File { 183 return &memNodeFile{ 184 File: NewLoopbackFile(f), 185 node: n, 186 } 187 } 188 189 func (n *memNode) Open(flags uint32, context *fuse.Context) (file File, code fuse.Status) { 190 f, err := os.OpenFile(n.filename(), int(flags), 0666) 191 if err != nil { 192 return nil, fuse.ToStatus(err) 193 } 194 195 return n.newFile(f), fuse.OK 196 } 197 198 func (n *memNode) GetAttr(fi *fuse.Attr, file File, context *fuse.Context) (code fuse.Status) { 199 n.mu.Lock() 200 defer n.mu.Unlock() 201 202 *fi = n.info 203 return fuse.OK 204 } 205 206 func (n *memNode) Truncate(file File, size uint64, context *fuse.Context) (code fuse.Status) { 207 if file != nil { 208 code = file.Truncate(size) 209 } else { 210 err := os.Truncate(n.filename(), int64(size)) 211 code = fuse.ToStatus(err) 212 } 213 if code.Ok() { 214 now := time.Now() 215 216 n.mu.Lock() 217 defer n.mu.Unlock() 218 219 n.info.SetTimes(nil, nil, &now) 220 // TODO - should update mtime too? 221 n.info.Size = size 222 } 223 return code 224 } 225 226 func (n *memNode) Utimens(file File, atime *time.Time, mtime *time.Time, context *fuse.Context) (code fuse.Status) { 227 c := time.Now() 228 n.mu.Lock() 229 defer n.mu.Unlock() 230 231 n.info.SetTimes(atime, mtime, &c) 232 return fuse.OK 233 } 234 235 func (n *memNode) Chmod(file File, perms uint32, context *fuse.Context) (code fuse.Status) { 236 n.info.Mode = (n.info.Mode &^ 07777) | perms 237 now := time.Now() 238 n.mu.Lock() 239 defer n.mu.Unlock() 240 n.info.SetTimes(nil, nil, &now) 241 return fuse.OK 242 } 243 244 func (n *memNode) Chown(file File, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) { 245 n.info.Uid = uid 246 n.info.Gid = gid 247 now := time.Now() 248 n.mu.Lock() 249 defer n.mu.Unlock() 250 n.info.SetTimes(nil, nil, &now) 251 return fuse.OK 252 }