github.com/hanwen/go-fuse@v1.0.0/fuse/nodefs/fsmount.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  	"log"
     9  	"sync"
    10  	"unsafe"
    11  
    12  	"github.com/hanwen/go-fuse/fuse"
    13  )
    14  
    15  // openedFile stores either an open dir or an open file.
    16  type openedFile struct {
    17  	handled
    18  
    19  	WithFlags
    20  
    21  	dir *connectorDir
    22  }
    23  
    24  type fileSystemMount struct {
    25  	// Node that we were mounted on.
    26  	mountInode *Inode
    27  
    28  	// Parent to the mountInode.
    29  	parentInode *Inode
    30  
    31  	// Options for the mount.
    32  	options *Options
    33  
    34  	// Protects the "children" and "parents" hashmaps of the inodes
    35  	// within the mount.
    36  	// treeLock should be acquired before openFilesLock.
    37  	//
    38  	// If multiple treeLocks must be acquired, the treeLocks
    39  	// closer to the root must be acquired first.
    40  	treeLock sync.RWMutex
    41  
    42  	// Manage filehandles of open files.
    43  	openFiles handleMap
    44  
    45  	Debug bool
    46  
    47  	connector *FileSystemConnector
    48  }
    49  
    50  // Must called with lock for parent held.
    51  func (m *fileSystemMount) mountName() string {
    52  	for k, v := range m.parentInode.children {
    53  		if m.mountInode == v {
    54  			return k
    55  		}
    56  	}
    57  	panic("not found")
    58  }
    59  
    60  func (m *fileSystemMount) setOwner(attr *fuse.Attr) {
    61  	if m.options.Owner != nil {
    62  		attr.Owner = *m.options.Owner
    63  	}
    64  }
    65  
    66  func (m *fileSystemMount) fillEntry(out *fuse.EntryOut) {
    67  	out.SetEntryTimeout(m.options.EntryTimeout)
    68  	out.SetAttrTimeout(m.options.AttrTimeout)
    69  	m.setOwner(&out.Attr)
    70  	if out.Mode&fuse.S_IFDIR == 0 && out.Nlink == 0 {
    71  		out.Nlink = 1
    72  	}
    73  }
    74  
    75  func (m *fileSystemMount) fillAttr(out *fuse.AttrOut, nodeId uint64) {
    76  	out.SetTimeout(m.options.AttrTimeout)
    77  	m.setOwner(&out.Attr)
    78  	if out.Ino == 0 {
    79  		out.Ino = nodeId
    80  	}
    81  }
    82  
    83  func (m *fileSystemMount) getOpenedFile(h uint64) *openedFile {
    84  	var b *openedFile
    85  	if h != 0 {
    86  		b = (*openedFile)(unsafe.Pointer(m.openFiles.Decode(h)))
    87  	}
    88  
    89  	if b != nil && m.connector.debug && b.WithFlags.Description != "" {
    90  		log.Printf("File %d = %q", h, b.WithFlags.Description)
    91  	}
    92  	return b
    93  }
    94  
    95  func (m *fileSystemMount) unregisterFileHandle(handle uint64, node *Inode) *openedFile {
    96  	_, obj := m.openFiles.Forget(handle, 1)
    97  	opened := (*openedFile)(unsafe.Pointer(obj))
    98  	node.openFilesMutex.Lock()
    99  	idx := -1
   100  	for i, v := range node.openFiles {
   101  		if v == opened {
   102  			idx = i
   103  			break
   104  		}
   105  	}
   106  
   107  	l := len(node.openFiles)
   108  	if idx == l-1 {
   109  		node.openFiles[idx] = nil
   110  	} else {
   111  		node.openFiles[idx] = node.openFiles[l-1]
   112  	}
   113  	node.openFiles = node.openFiles[:l-1]
   114  	node.openFilesMutex.Unlock()
   115  
   116  	return opened
   117  }
   118  
   119  // registerFileHandle registers f or dir to have a handle.
   120  //
   121  // The handle is then used as file-handle in communications with kernel.
   122  //
   123  // If dir != nil the handle is registered for OpenDir and the inner file (see
   124  // below) must be nil. If dir = nil the handle is registered for regular open &
   125  // friends.
   126  //
   127  // f can be nil, or a WithFlags that leads to File=nil. For !OpenDir, if that
   128  // is the case, returned handle will be 0 to indicate a handleless open, and
   129  // the filesystem operations on the opened file will be routed to be served by
   130  // the node.
   131  //
   132  // other arguments:
   133  //
   134  //	node  - Inode for which f or dir were opened,
   135  //	flags - file open flags, like O_RDWR.
   136  func (m *fileSystemMount) registerFileHandle(node *Inode, dir *connectorDir, f File, flags uint32) (handle uint64, opened *openedFile) {
   137  	b := &openedFile{
   138  		dir: dir,
   139  		WithFlags: WithFlags{
   140  			File:      f,
   141  			OpenFlags: flags,
   142  		},
   143  	}
   144  
   145  	for {
   146  		withFlags, ok := f.(*WithFlags)
   147  		if !ok {
   148  			break
   149  		}
   150  
   151  		b.WithFlags.File = withFlags.File
   152  		b.WithFlags.FuseFlags |= withFlags.FuseFlags
   153  		b.WithFlags.Description += withFlags.Description
   154  		f = withFlags.File
   155  	}
   156  
   157  	// don't allow both dir and file
   158  	if dir != nil && b.WithFlags.File != nil {
   159  		panic("registerFileHandle: both dir and file are set.")
   160  	}
   161  
   162  	if b.WithFlags.File == nil && dir == nil {
   163  		// it was just WithFlags{...}, but the file itself is nil
   164  		return 0, b
   165  	}
   166  
   167  	if b.WithFlags.File != nil {
   168  		b.WithFlags.File.SetInode(node)
   169  	}
   170  
   171  	node.openFilesMutex.Lock()
   172  	node.openFiles = append(node.openFiles, b)
   173  	handle, _ = m.openFiles.Register(&b.handled)
   174  	node.openFilesMutex.Unlock()
   175  	return handle, b
   176  }
   177  
   178  // Creates a return entry for a non-existent path.
   179  func (m *fileSystemMount) negativeEntry(out *fuse.EntryOut) bool {
   180  	if m.options.NegativeTimeout > 0.0 {
   181  		out.NodeId = 0
   182  		out.SetEntryTimeout(m.options.NegativeTimeout)
   183  		return true
   184  	}
   185  	return false
   186  }