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 5package nodefs 6 7// This file contains FileSystemConnector's implementation of 8// RawFileSystem 9 10import ( 11 "fmt" 12 "log" 13 "strings" 14 "time" 15 16 "github.com/hanwen/go-fuse/v2/fuse" 17) 18 19// Returns the RawFileSystem so it can be mounted. 20func (c *FileSystemConnector) RawFS() fuse.RawFileSystem { 21 return (*rawBridge)(c) 22} 23 24type rawBridge FileSystemConnector 25 26func (c *rawBridge) Fsync(cancel <-chan struct{}, input *fuse.FsyncIn) fuse.Status { 27 node := c.toInode(input.NodeId) 28 opened := node.mount.getOpenedFile(input.Fh) 29 30 if opened != nil { 31 return opened.WithFlags.File.Fsync(int(input.FsyncFlags)) 32 } 33 34 return fuse.ENOSYS 35} 36 37func (c *rawBridge) SetDebug(debug bool) { 38 c.fsConn().SetDebug(debug) 39} 40 41func (c *rawBridge) FsyncDir(cancel <-chan struct{}, input *fuse.FsyncIn) fuse.Status { 42 return fuse.ENOSYS 43} 44 45func (c *rawBridge) fsConn() *FileSystemConnector { 46 return (*FileSystemConnector)(c) 47} 48 49func (c *rawBridge) String() string { 50 if c.rootNode == nil || c.rootNode.mount == nil { 51 return "go-fuse:unmounted" 52 } 53 54 name := fmt.Sprintf("%T", c.rootNode.Node()) 55 name = strings.TrimLeft(name, "*") 56 return name 57} 58 59func (c *rawBridge) Init(s *fuse.Server) { 60 c.server = s 61 c.rootNode.Node().OnMount((*FileSystemConnector)(c)) 62} 63 64func (c *FileSystemConnector) lookupMountUpdate(out *fuse.Attr, mount *fileSystemMount) (node *Inode, code fuse.Status) { 65 code = mount.mountInode.Node().GetAttr(out, nil, nil) 66 if !code.Ok() { 67 log.Println("Root getattr should not return error", code) 68 out.Mode = fuse.S_IFDIR | 0755 69 return mount.mountInode, fuse.OK 70 } 71 72 return mount.mountInode, fuse.OK 73} 74 75// internalLookup executes a lookup without affecting NodeId reference counts. 76func (c *FileSystemConnector) internalLookup(cancel <-chan struct{}, out *fuse.Attr, parent *Inode, name string, header *fuse.InHeader) (node *Inode, code fuse.Status) { 77 78 // We may already know the child because it was created using Create or Mkdir, 79 // from an earlier lookup, or because the nodes were created in advance 80 // (in-memory filesystems). 81 child := parent.GetChild(name) 82 83 if child != nil && child.mountPoint != nil { 84 return c.lookupMountUpdate(out, child.mountPoint) 85 } 86 87 if child != nil && !parent.mount.options.LookupKnownChildren { 88 code = child.fsInode.GetAttr(out, nil, &fuse.Context{Caller: header.Caller, Cancel: cancel}) 89 } else { 90 child, code = parent.fsInode.Lookup(out, name, &fuse.Context{Caller: header.Caller, Cancel: cancel}) 91 } 92 93 return child, code 94} 95 96func (c *rawBridge) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name string, out *fuse.EntryOut) (code fuse.Status) { 97 // Prevent Lookup() and Forget() from running concurrently. 98 // Allow several Lookups to be run simultaneously. 99 c.lookupLock.RLock() 100 defer c.lookupLock.RUnlock() 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(cancel, &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 128func (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 136func (c *rawBridge) GetAttr(cancel <-chan struct{}, 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, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 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 162func (c *rawBridge) OpenDir(cancel <-chan struct{}, 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 175func (c *rawBridge) ReadDir(cancel <-chan struct{}, 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(cancel, input, out) 179} 180 181func (c *rawBridge) ReadDirPlus(cancel <-chan struct{}, 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(cancel, input, out) 185} 186 187func (c *rawBridge) Open(cancel <-chan struct{}, input *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) { 188 node := c.toInode(input.NodeId) 189 f, code := node.fsInode.Open(input.Flags, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 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 199func (c *rawBridge) SetAttr(cancel <-chan struct{}, 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, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 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, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 218 } 219 if sz, ok := input.GetSize(); code.Ok() && ok { 220 code = node.fsInode.Truncate(f, sz, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 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, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 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, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 246 if code.Ok() { 247 node.mount.fillAttr(out, input.NodeId) 248 } 249 return code 250} 251 252func (c *rawBridge) Fallocate(cancel <-chan struct{}, 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, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 257} 258 259func (c *rawBridge) Readlink(cancel <-chan struct{}, header *fuse.InHeader) (out []byte, code fuse.Status) { 260 n := c.toInode(header.NodeId) 261 return n.fsInode.Readlink(&fuse.Context{Caller: header.Caller, Cancel: cancel}) 262} 263 264func (c *rawBridge) Mknod(cancel <-chan struct{}, 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), &fuse.Context{Caller: input.Caller, Cancel: cancel}) 268 if code.Ok() { 269 c.childLookup(out, child, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 270 code = child.fsInode.GetAttr(&out.Attr, nil, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 271 } 272 return code 273} 274 275func (c *rawBridge) Mkdir(cancel <-chan struct{}, 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, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 279 if code.Ok() { 280 c.childLookup(out, child, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 281 code = child.fsInode.GetAttr(&out.Attr, nil, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 282 } 283 return code 284} 285 286func (c *rawBridge) Unlink(cancel <-chan struct{}, header *fuse.InHeader, name string) (code fuse.Status) { 287 parent := c.toInode(header.NodeId) 288 return parent.fsInode.Unlink(name, &fuse.Context{Caller: header.Caller, Cancel: cancel}) 289} 290 291func (c *rawBridge) Rmdir(cancel <-chan struct{}, header *fuse.InHeader, name string) (code fuse.Status) { 292 parent := c.toInode(header.NodeId) 293 return parent.fsInode.Rmdir(name, &fuse.Context{Caller: header.Caller, Cancel: cancel}) 294} 295 296func (c *rawBridge) Symlink(cancel <-chan struct{}, 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, &fuse.Context{Caller: header.Caller, Cancel: cancel}) 300 if code.Ok() { 301 c.childLookup(out, child, &fuse.Context{Caller: header.Caller, Cancel: cancel}) 302 code = child.fsInode.GetAttr(&out.Attr, nil, &fuse.Context{Caller: header.Caller, Cancel: cancel}) 303 } 304 return code 305} 306 307func (c *rawBridge) Rename(cancel <-chan struct{}, 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, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 327} 328 329func (c *rawBridge) Link(cancel <-chan struct{}, 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, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 338 if code.Ok() { 339 c.childLookup(out, child, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 340 code = child.fsInode.GetAttr(&out.Attr, nil, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 341 } 342 343 return code 344} 345 346func (c *rawBridge) Access(cancel <-chan struct{}, input *fuse.AccessIn) (code fuse.Status) { 347 n := c.toInode(input.NodeId) 348 return n.fsInode.Access(input.Mask, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 349} 350 351func (c *rawBridge) Create(cancel <-chan struct{}, 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, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 354 if !code.Ok() { 355 return code 356 } 357 358 c.childLookup(&out.EntryOut, child, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 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 366func (c *rawBridge) Release(cancel <-chan struct{}, 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 374func (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} 380func (c *rawBridge) GetXAttr(cancel <-chan struct{}, header *fuse.InHeader, attribute string, dest []byte) (sz uint32, code fuse.Status) { 381 node := c.toInode(header.NodeId) 382 data, errno := node.fsInode.GetXAttr(attribute, &fuse.Context{Caller: header.Caller, Cancel: cancel}) 383 384 if len(data) > len(dest) { 385 return uint32(len(data)), fuse.ERANGE 386 } 387 copy(dest, data) 388 return uint32(len(data)), errno 389} 390 391func (c *rawBridge) GetXAttrData(cancel <-chan struct{}, header *fuse.InHeader, attribute string) (data []byte, code fuse.Status) { 392 node := c.toInode(header.NodeId) 393 return node.fsInode.GetXAttr(attribute, &fuse.Context{Caller: header.Caller, Cancel: cancel}) 394} 395 396func (c *rawBridge) RemoveXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string) fuse.Status { 397 node := c.toInode(header.NodeId) 398 return node.fsInode.RemoveXAttr(attr, &fuse.Context{Caller: header.Caller, Cancel: cancel}) 399} 400 401func (c *rawBridge) SetXAttr(cancel <-chan struct{}, input *fuse.SetXAttrIn, attr string, data []byte) fuse.Status { 402 node := c.toInode(input.NodeId) 403 return node.fsInode.SetXAttr(attr, data, int(input.Flags), &fuse.Context{Caller: input.Caller, Cancel: cancel}) 404} 405 406func (c *rawBridge) ListXAttr(cancel <-chan struct{}, header *fuse.InHeader, dest []byte) (uint32, fuse.Status) { 407 node := c.toInode(header.NodeId) 408 attrs, code := node.fsInode.ListXAttr(&fuse.Context{Caller: header.Caller, Cancel: cancel}) 409 if code != fuse.OK { 410 return 0, code 411 } 412 413 var sz uint32 414 for _, v := range attrs { 415 sz += uint32(len(v)) + 1 416 } 417 418 if int(sz) > len(dest) { 419 return sz, fuse.ERANGE 420 } 421 422 dest = dest[:0] 423 for _, v := range attrs { 424 dest = append(dest, v...) 425 dest = append(dest, 0) 426 } 427 428 return sz, code 429} 430 431//////////////// 432// files. 433 434func (c *rawBridge) Write(cancel <-chan struct{}, input *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) { 435 node := c.toInode(input.NodeId) 436 opened := node.mount.getOpenedFile(input.Fh) 437 438 var f File 439 if opened != nil { 440 f = opened.WithFlags.File 441 } 442 443 return node.Node().Write(f, data, int64(input.Offset), &fuse.Context{Caller: input.Caller, Cancel: cancel}) 444} 445 446func (c *rawBridge) Read(cancel <-chan struct{}, input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) { 447 node := c.toInode(input.NodeId) 448 opened := node.mount.getOpenedFile(input.Fh) 449 450 var f File 451 if opened != nil { 452 f = opened.WithFlags.File 453 } 454 455 return node.Node().Read(f, buf, int64(input.Offset), &fuse.Context{Caller: input.Caller, Cancel: cancel}) 456} 457 458func (c *rawBridge) GetLk(cancel <-chan struct{}, input *fuse.LkIn, out *fuse.LkOut) (code fuse.Status) { 459 n := c.toInode(input.NodeId) 460 opened := n.mount.getOpenedFile(input.Fh) 461 462 return n.fsInode.GetLk(opened, input.Owner, &input.Lk, input.LkFlags, &out.Lk, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 463} 464 465func (c *rawBridge) SetLk(cancel <-chan struct{}, input *fuse.LkIn) (code fuse.Status) { 466 n := c.toInode(input.NodeId) 467 opened := n.mount.getOpenedFile(input.Fh) 468 469 return n.fsInode.SetLk(opened, input.Owner, &input.Lk, input.LkFlags, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 470} 471 472func (c *rawBridge) SetLkw(cancel <-chan struct{}, input *fuse.LkIn) (code fuse.Status) { 473 n := c.toInode(input.NodeId) 474 opened := n.mount.getOpenedFile(input.Fh) 475 476 return n.fsInode.SetLkw(opened, input.Owner, &input.Lk, input.LkFlags, &fuse.Context{Caller: input.Caller, Cancel: cancel}) 477} 478 479func (c *rawBridge) StatFs(cancel <-chan struct{}, header *fuse.InHeader, out *fuse.StatfsOut) fuse.Status { 480 node := c.toInode(header.NodeId) 481 s := node.Node().StatFs() 482 if s == nil { 483 return fuse.ENOSYS 484 } 485 *out = *s 486 return fuse.OK 487} 488 489func (c *rawBridge) Flush(cancel <-chan struct{}, input *fuse.FlushIn) fuse.Status { 490 node := c.toInode(input.NodeId) 491 opened := node.mount.getOpenedFile(input.Fh) 492 493 if opened != nil { 494 return opened.WithFlags.File.Flush() 495 } 496 return fuse.OK 497} 498 499func (c *rawBridge) CopyFileRange(cancel <-chan struct{}, input *fuse.CopyFileRangeIn) (written uint32, code fuse.Status) { 500 return 0, fuse.ENOSYS 501} 502 503func (fs *rawBridge) Lseek(cancel <-chan struct{}, in *fuse.LseekIn, out *fuse.LseekOut) fuse.Status { 504 return fuse.ENOSYS 505} 506