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  }