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  }