github.com/hanwen/go-fuse@v1.0.0/fuse/nodefs/fsops.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 // This file contains FileSystemConnector's implementation of 8 // RawFileSystem 9 10 import ( 11 "bytes" 12 "fmt" 13 "log" 14 "strings" 15 "time" 16 17 "github.com/hanwen/go-fuse/fuse" 18 ) 19 20 // Returns the RawFileSystem so it can be mounted. 21 func (c *FileSystemConnector) RawFS() fuse.RawFileSystem { 22 return (*rawBridge)(c) 23 } 24 25 type rawBridge FileSystemConnector 26 27 func (c *rawBridge) Fsync(input *fuse.FsyncIn) fuse.Status { 28 node := c.toInode(input.NodeId) 29 opened := node.mount.getOpenedFile(input.Fh) 30 31 if opened != nil { 32 return opened.WithFlags.File.Fsync(int(input.FsyncFlags)) 33 } 34 35 return fuse.ENOSYS 36 } 37 38 func (c *rawBridge) SetDebug(debug bool) { 39 c.fsConn().SetDebug(debug) 40 } 41 42 func (c *rawBridge) FsyncDir(input *fuse.FsyncIn) fuse.Status { 43 return fuse.ENOSYS 44 } 45 46 func (c *rawBridge) fsConn() *FileSystemConnector { 47 return (*FileSystemConnector)(c) 48 } 49 50 func (c *rawBridge) String() string { 51 if c.rootNode == nil || c.rootNode.mount == nil { 52 return "go-fuse:unmounted" 53 } 54 55 name := fmt.Sprintf("%T", c.rootNode.Node()) 56 name = strings.TrimLeft(name, "*") 57 return name 58 } 59 60 func (c *rawBridge) Init(s *fuse.Server) { 61 c.server = s 62 c.rootNode.Node().OnMount((*FileSystemConnector)(c)) 63 } 64 65 func (c *FileSystemConnector) lookupMountUpdate(out *fuse.Attr, mount *fileSystemMount) (node *Inode, code fuse.Status) { 66 code = mount.mountInode.Node().GetAttr(out, nil, nil) 67 if !code.Ok() { 68 log.Println("Root getattr should not return error", code) 69 out.Mode = fuse.S_IFDIR | 0755 70 return mount.mountInode, fuse.OK 71 } 72 73 return mount.mountInode, fuse.OK 74 } 75 76 // internalLookup executes a lookup without affecting NodeId reference counts. 77 func (c *FileSystemConnector) internalLookup(out *fuse.Attr, parent *Inode, name string, header *fuse.InHeader) (node *Inode, code fuse.Status) { 78 79 // We may already know the child because it was created using Create or Mkdir, 80 // from an earlier lookup, or because the nodes were created in advance 81 // (in-memory filesystems). 82 child := parent.GetChild(name) 83 84 if child != nil && child.mountPoint != nil { 85 return c.lookupMountUpdate(out, child.mountPoint) 86 } 87 88 if child != nil && !parent.mount.options.LookupKnownChildren { 89 code = child.fsInode.GetAttr(out, nil, &header.Context) 90 } else { 91 child, code = parent.fsInode.Lookup(out, name, &header.Context) 92 } 93 94 return child, code 95 } 96 97 func (c *rawBridge) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOut) (code fuse.Status) { 98 // Prevent Lookup() and Forget() from running concurrently. 99 c.lookupLock.Lock() 100 defer c.lookupLock.Unlock() 101 102 parent := c.toInode(header.NodeId) 103 if !parent.IsDir() { 104 log.Printf("Lookup %q called on non-Directory node %d", name, header.NodeId) 105 return fuse.ENOTDIR 106 } 107 108 child, code := c.fsConn().internalLookup(&out.Attr, parent, name, header) 109 if code == fuse.ENOENT && parent.mount.negativeEntry(out) { 110 return fuse.OK 111 } 112 if !code.Ok() { 113 return code 114 } 115 if child == nil { 116 log.Println("Lookup returned fuse.OK with nil child", name) 117 } 118 119 child.mount.fillEntry(out) 120 out.NodeId, out.Generation = c.fsConn().lookupUpdate(child) 121 if out.Ino == 0 { 122 out.Ino = out.NodeId 123 } 124 125 return fuse.OK 126 } 127 128 func (c *rawBridge) Forget(nodeID, nlookup uint64) { 129 // Prevent Lookup() and Forget() from running concurrently. 130 c.lookupLock.Lock() 131 defer c.lookupLock.Unlock() 132 133 c.fsConn().forgetUpdate(nodeID, int(nlookup)) 134 } 135 136 func (c *rawBridge) GetAttr(input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) { 137 node := c.toInode(input.NodeId) 138 139 var f File 140 if input.Flags()&fuse.FUSE_GETATTR_FH != 0 { 141 if opened := node.mount.getOpenedFile(input.Fh()); opened != nil { 142 f = opened.WithFlags.File 143 } 144 } 145 146 dest := &out.Attr 147 code = node.fsInode.GetAttr(dest, f, &input.Context) 148 if !code.Ok() { 149 return code 150 } 151 152 if out.Nlink == 0 { 153 // With Nlink == 0, newer kernels will refuse link 154 // operations. 155 out.Nlink = 1 156 } 157 158 node.mount.fillAttr(out, input.NodeId) 159 return fuse.OK 160 } 161 162 func (c *rawBridge) OpenDir(input *fuse.OpenIn, out *fuse.OpenOut) (code fuse.Status) { 163 node := c.toInode(input.NodeId) 164 de := &connectorDir{ 165 inode: node, 166 node: node.Node(), 167 rawFS: c, 168 } 169 h, opened := node.mount.registerFileHandle(node, de, nil, input.Flags) 170 out.OpenFlags = opened.FuseFlags 171 out.Fh = h 172 return fuse.OK 173 } 174 175 func (c *rawBridge) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) fuse.Status { 176 node := c.toInode(input.NodeId) 177 opened := node.mount.getOpenedFile(input.Fh) 178 return opened.dir.ReadDir(input, out) 179 } 180 181 func (c *rawBridge) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) fuse.Status { 182 node := c.toInode(input.NodeId) 183 opened := node.mount.getOpenedFile(input.Fh) 184 return opened.dir.ReadDirPlus(input, out) 185 } 186 187 func (c *rawBridge) Open(input *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) { 188 node := c.toInode(input.NodeId) 189 f, code := node.fsInode.Open(input.Flags, &input.Context) 190 if !code.Ok() { 191 return code 192 } 193 h, opened := node.mount.registerFileHandle(node, nil, f, input.Flags) 194 out.OpenFlags = opened.FuseFlags 195 out.Fh = h 196 return fuse.OK 197 } 198 199 func (c *rawBridge) SetAttr(input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse.Status) { 200 node := c.toInode(input.NodeId) 201 202 var f File 203 if fh, ok := input.GetFh(); ok { 204 if opened := node.mount.getOpenedFile(fh); opened != nil { 205 f = opened.WithFlags.File 206 } 207 } 208 209 if permissions, ok := input.GetMode(); ok { 210 code = node.fsInode.Chmod(f, permissions, &input.Context) 211 } 212 213 uid, uok := input.GetUID() 214 gid, gok := input.GetGID() 215 216 if code.Ok() && (uok || gok) { 217 code = node.fsInode.Chown(f, uid, gid, &input.Context) 218 } 219 if sz, ok := input.GetSize(); code.Ok() && ok { 220 code = node.fsInode.Truncate(f, sz, &input.Context) 221 } 222 223 atime, aok := input.GetATime() 224 mtime, mok := input.GetMTime() 225 if code.Ok() && (aok || mok) { 226 var a, m *time.Time 227 228 if aok { 229 a = &atime 230 } 231 if mok { 232 m = &mtime 233 } 234 235 code = node.fsInode.Utimens(f, a, m, &input.Context) 236 } 237 238 if !code.Ok() { 239 return code 240 } 241 242 // Must call GetAttr(); the filesystem may override some of 243 // the changes we effect here. 244 attr := &out.Attr 245 code = node.fsInode.GetAttr(attr, nil, &input.Context) 246 if code.Ok() { 247 node.mount.fillAttr(out, input.NodeId) 248 } 249 return code 250 } 251 252 func (c *rawBridge) Fallocate(input *fuse.FallocateIn) (code fuse.Status) { 253 n := c.toInode(input.NodeId) 254 opened := n.mount.getOpenedFile(input.Fh) 255 256 return n.fsInode.Fallocate(opened, input.Offset, input.Length, input.Mode, &input.Context) 257 } 258 259 func (c *rawBridge) Readlink(header *fuse.InHeader) (out []byte, code fuse.Status) { 260 n := c.toInode(header.NodeId) 261 return n.fsInode.Readlink(&header.Context) 262 } 263 264 func (c *rawBridge) Mknod(input *fuse.MknodIn, name string, out *fuse.EntryOut) (code fuse.Status) { 265 parent := c.toInode(input.NodeId) 266 267 child, code := parent.fsInode.Mknod(name, input.Mode, uint32(input.Rdev), &input.Context) 268 if code.Ok() { 269 c.childLookup(out, child, &input.Context) 270 code = child.fsInode.GetAttr(&out.Attr, nil, &input.Context) 271 } 272 return code 273 } 274 275 func (c *rawBridge) Mkdir(input *fuse.MkdirIn, name string, out *fuse.EntryOut) (code fuse.Status) { 276 parent := c.toInode(input.NodeId) 277 278 child, code := parent.fsInode.Mkdir(name, input.Mode, &input.Context) 279 if code.Ok() { 280 c.childLookup(out, child, &input.Context) 281 code = child.fsInode.GetAttr(&out.Attr, nil, &input.Context) 282 } 283 return code 284 } 285 286 func (c *rawBridge) Unlink(header *fuse.InHeader, name string) (code fuse.Status) { 287 parent := c.toInode(header.NodeId) 288 return parent.fsInode.Unlink(name, &header.Context) 289 } 290 291 func (c *rawBridge) Rmdir(header *fuse.InHeader, name string) (code fuse.Status) { 292 parent := c.toInode(header.NodeId) 293 return parent.fsInode.Rmdir(name, &header.Context) 294 } 295 296 func (c *rawBridge) Symlink(header *fuse.InHeader, pointedTo string, linkName string, out *fuse.EntryOut) (code fuse.Status) { 297 parent := c.toInode(header.NodeId) 298 299 child, code := parent.fsInode.Symlink(linkName, pointedTo, &header.Context) 300 if code.Ok() { 301 c.childLookup(out, child, &header.Context) 302 code = child.fsInode.GetAttr(&out.Attr, nil, &header.Context) 303 } 304 return code 305 } 306 307 func (c *rawBridge) Rename(input *fuse.RenameIn, oldName string, newName string) (code fuse.Status) { 308 if input.Flags != 0 { 309 return fuse.ENOSYS 310 } 311 oldParent := c.toInode(input.NodeId) 312 313 child := oldParent.GetChild(oldName) 314 if child == nil { 315 return fuse.ENOENT 316 } 317 if child.mountPoint != nil { 318 return fuse.EBUSY 319 } 320 321 newParent := c.toInode(input.Newdir) 322 if oldParent.mount != newParent.mount { 323 return fuse.EXDEV 324 } 325 326 return oldParent.fsInode.Rename(oldName, newParent.fsInode, newName, &input.Context) 327 } 328 329 func (c *rawBridge) Link(input *fuse.LinkIn, name string, out *fuse.EntryOut) (code fuse.Status) { 330 existing := c.toInode(input.Oldnodeid) 331 parent := c.toInode(input.NodeId) 332 333 if existing.mount != parent.mount { 334 return fuse.EXDEV 335 } 336 337 child, code := parent.fsInode.Link(name, existing.fsInode, &input.Context) 338 if code.Ok() { 339 c.childLookup(out, child, &input.Context) 340 code = child.fsInode.GetAttr(&out.Attr, nil, &input.Context) 341 } 342 343 return code 344 } 345 346 func (c *rawBridge) Access(input *fuse.AccessIn) (code fuse.Status) { 347 n := c.toInode(input.NodeId) 348 return n.fsInode.Access(input.Mask, &input.Context) 349 } 350 351 func (c *rawBridge) Create(input *fuse.CreateIn, name string, out *fuse.CreateOut) (code fuse.Status) { 352 parent := c.toInode(input.NodeId) 353 f, child, code := parent.fsInode.Create(name, uint32(input.Flags), input.Mode, &input.Context) 354 if !code.Ok() { 355 return code 356 } 357 358 c.childLookup(&out.EntryOut, child, &input.Context) 359 handle, opened := parent.mount.registerFileHandle(child, nil, f, input.Flags) 360 361 out.OpenOut.OpenFlags = opened.FuseFlags 362 out.OpenOut.Fh = handle 363 return code 364 } 365 366 func (c *rawBridge) Release(input *fuse.ReleaseIn) { 367 if input.Fh != 0 { 368 node := c.toInode(input.NodeId) 369 opened := node.mount.unregisterFileHandle(input.Fh, node) 370 opened.WithFlags.File.Release() 371 } 372 } 373 374 func (c *rawBridge) ReleaseDir(input *fuse.ReleaseIn) { 375 if input.Fh != 0 { 376 node := c.toInode(input.NodeId) 377 node.mount.unregisterFileHandle(input.Fh, node) 378 } 379 } 380 381 func (c *rawBridge) GetXAttrSize(header *fuse.InHeader, attribute string) (sz int, code fuse.Status) { 382 node := c.toInode(header.NodeId) 383 data, errno := node.fsInode.GetXAttr(attribute, &header.Context) 384 return len(data), errno 385 } 386 387 func (c *rawBridge) GetXAttrData(header *fuse.InHeader, attribute string) (data []byte, code fuse.Status) { 388 node := c.toInode(header.NodeId) 389 return node.fsInode.GetXAttr(attribute, &header.Context) 390 } 391 392 func (c *rawBridge) RemoveXAttr(header *fuse.InHeader, attr string) fuse.Status { 393 node := c.toInode(header.NodeId) 394 return node.fsInode.RemoveXAttr(attr, &header.Context) 395 } 396 397 func (c *rawBridge) SetXAttr(input *fuse.SetXAttrIn, attr string, data []byte) fuse.Status { 398 node := c.toInode(input.NodeId) 399 return node.fsInode.SetXAttr(attr, data, int(input.Flags), &input.Context) 400 } 401 402 func (c *rawBridge) ListXAttr(header *fuse.InHeader) (data []byte, code fuse.Status) { 403 node := c.toInode(header.NodeId) 404 attrs, code := node.fsInode.ListXAttr(&header.Context) 405 if code != fuse.OK { 406 return nil, code 407 } 408 409 b := bytes.NewBuffer([]byte{}) 410 for _, v := range attrs { 411 b.Write([]byte(v)) 412 b.WriteByte(0) 413 } 414 415 return b.Bytes(), code 416 } 417 418 //////////////// 419 // files. 420 421 func (c *rawBridge) Write(input *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) { 422 node := c.toInode(input.NodeId) 423 opened := node.mount.getOpenedFile(input.Fh) 424 425 var f File 426 if opened != nil { 427 f = opened.WithFlags.File 428 } 429 430 return node.Node().Write(f, data, int64(input.Offset), &input.Context) 431 } 432 433 func (c *rawBridge) Read(input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) { 434 node := c.toInode(input.NodeId) 435 opened := node.mount.getOpenedFile(input.Fh) 436 437 var f File 438 if opened != nil { 439 f = opened.WithFlags.File 440 } 441 442 return node.Node().Read(f, buf, int64(input.Offset), &input.Context) 443 } 444 445 func (c *rawBridge) GetLk(input *fuse.LkIn, out *fuse.LkOut) (code fuse.Status) { 446 n := c.toInode(input.NodeId) 447 opened := n.mount.getOpenedFile(input.Fh) 448 449 return n.fsInode.GetLk(opened, input.Owner, &input.Lk, input.LkFlags, &out.Lk, &input.Context) 450 } 451 452 func (c *rawBridge) SetLk(input *fuse.LkIn) (code fuse.Status) { 453 n := c.toInode(input.NodeId) 454 opened := n.mount.getOpenedFile(input.Fh) 455 456 return n.fsInode.SetLk(opened, input.Owner, &input.Lk, input.LkFlags, &input.Context) 457 } 458 459 func (c *rawBridge) SetLkw(input *fuse.LkIn) (code fuse.Status) { 460 n := c.toInode(input.NodeId) 461 opened := n.mount.getOpenedFile(input.Fh) 462 463 return n.fsInode.SetLkw(opened, input.Owner, &input.Lk, input.LkFlags, &input.Context) 464 } 465 466 func (c *rawBridge) StatFs(header *fuse.InHeader, out *fuse.StatfsOut) fuse.Status { 467 node := c.toInode(header.NodeId) 468 s := node.Node().StatFs() 469 if s == nil { 470 return fuse.ENOSYS 471 } 472 *out = *s 473 return fuse.OK 474 } 475 476 func (c *rawBridge) Flush(input *fuse.FlushIn) fuse.Status { 477 node := c.toInode(input.NodeId) 478 opened := node.mount.getOpenedFile(input.Fh) 479 480 if opened != nil { 481 return opened.WithFlags.File.Flush() 482 } 483 return fuse.OK 484 }