github.com/hanwen/go-fuse@v1.0.0/fuse/nodefs/files.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  
    13  	"github.com/hanwen/go-fuse/fuse"
    14  )
    15  
    16  // DataFile is for implementing read-only filesystems.  This
    17  // assumes we already have the data in memory.
    18  type dataFile struct {
    19  	data []byte
    20  
    21  	File
    22  }
    23  
    24  func (f *dataFile) String() string {
    25  	l := len(f.data)
    26  	if l > 10 {
    27  		l = 10
    28  	}
    29  
    30  	return fmt.Sprintf("dataFile(%x)", f.data[:l])
    31  }
    32  
    33  func (f *dataFile) GetAttr(out *fuse.Attr) fuse.Status {
    34  	out.Mode = fuse.S_IFREG | 0644
    35  	out.Size = uint64(len(f.data))
    36  	return fuse.OK
    37  }
    38  
    39  func NewDataFile(data []byte) File {
    40  	f := new(dataFile)
    41  	f.data = data
    42  	f.File = NewDefaultFile()
    43  	return f
    44  }
    45  
    46  func (f *dataFile) Read(buf []byte, off int64) (res fuse.ReadResult, code fuse.Status) {
    47  	end := int(off) + int(len(buf))
    48  	if end > len(f.data) {
    49  		end = len(f.data)
    50  	}
    51  
    52  	return fuse.ReadResultData(f.data[off:end]), fuse.OK
    53  }
    54  
    55  type devNullFile struct {
    56  	File
    57  }
    58  
    59  // NewDevNullFile returns a file that accepts any write, and always
    60  // returns EOF for reads.
    61  func NewDevNullFile() File {
    62  	return &devNullFile{
    63  		File: NewDefaultFile(),
    64  	}
    65  }
    66  
    67  func (f *devNullFile) Allocate(off uint64, size uint64, mode uint32) (code fuse.Status) {
    68  	return fuse.OK
    69  }
    70  
    71  func (f *devNullFile) String() string {
    72  	return "devNullFile"
    73  }
    74  
    75  func (f *devNullFile) Read(buf []byte, off int64) (fuse.ReadResult, fuse.Status) {
    76  	return fuse.ReadResultData(nil), fuse.OK
    77  }
    78  
    79  func (f *devNullFile) Write(content []byte, off int64) (uint32, fuse.Status) {
    80  	return uint32(len(content)), fuse.OK
    81  }
    82  
    83  func (f *devNullFile) Flush() fuse.Status {
    84  	return fuse.OK
    85  }
    86  
    87  func (f *devNullFile) Fsync(flags int) (code fuse.Status) {
    88  	return fuse.OK
    89  }
    90  
    91  func (f *devNullFile) Truncate(size uint64) (code fuse.Status) {
    92  	return fuse.OK
    93  }
    94  
    95  ////////////////
    96  
    97  // LoopbackFile delegates all operations back to an underlying os.File.
    98  func NewLoopbackFile(f *os.File) File {
    99  	return &loopbackFile{File: f}
   100  }
   101  
   102  type loopbackFile struct {
   103  	File *os.File
   104  
   105  	// os.File is not threadsafe. Although fd themselves are
   106  	// constant during the lifetime of an open file, the OS may
   107  	// reuse the fd number after it is closed. When open races
   108  	// with another close, they may lead to confusion as which
   109  	// file gets written in the end.
   110  	lock sync.Mutex
   111  }
   112  
   113  func (f *loopbackFile) InnerFile() File {
   114  	return nil
   115  }
   116  
   117  func (f *loopbackFile) SetInode(n *Inode) {
   118  }
   119  
   120  func (f *loopbackFile) String() string {
   121  	return fmt.Sprintf("loopbackFile(%s)", f.File.Name())
   122  }
   123  
   124  func (f *loopbackFile) Read(buf []byte, off int64) (res fuse.ReadResult, code fuse.Status) {
   125  	f.lock.Lock()
   126  	// This is not racy by virtue of the kernel properly
   127  	// synchronizing the open/write/close.
   128  	r := fuse.ReadResultFd(f.File.Fd(), off, len(buf))
   129  	f.lock.Unlock()
   130  	return r, fuse.OK
   131  }
   132  
   133  func (f *loopbackFile) Write(data []byte, off int64) (uint32, fuse.Status) {
   134  	f.lock.Lock()
   135  	n, err := f.File.WriteAt(data, off)
   136  	f.lock.Unlock()
   137  	return uint32(n), fuse.ToStatus(err)
   138  }
   139  
   140  func (f *loopbackFile) Release() {
   141  	f.lock.Lock()
   142  	f.File.Close()
   143  	f.lock.Unlock()
   144  }
   145  
   146  func (f *loopbackFile) Flush() fuse.Status {
   147  	f.lock.Lock()
   148  
   149  	// Since Flush() may be called for each dup'd fd, we don't
   150  	// want to really close the file, we just want to flush. This
   151  	// is achieved by closing a dup'd fd.
   152  	newFd, err := syscall.Dup(int(f.File.Fd()))
   153  	f.lock.Unlock()
   154  
   155  	if err != nil {
   156  		return fuse.ToStatus(err)
   157  	}
   158  	err = syscall.Close(newFd)
   159  	return fuse.ToStatus(err)
   160  }
   161  
   162  func (f *loopbackFile) Fsync(flags int) (code fuse.Status) {
   163  	f.lock.Lock()
   164  	r := fuse.ToStatus(syscall.Fsync(int(f.File.Fd())))
   165  	f.lock.Unlock()
   166  
   167  	return r
   168  }
   169  
   170  const (
   171  	F_OFD_GETLK  = 36
   172  	F_OFD_SETLK  = 37
   173  	F_OFD_SETLKW = 38
   174  )
   175  
   176  func (f *loopbackFile) GetLk(owner uint64, lk *fuse.FileLock, flags uint32, out *fuse.FileLock) (code fuse.Status) {
   177  	flk := syscall.Flock_t{}
   178  	lk.ToFlockT(&flk)
   179  	code = fuse.ToStatus(syscall.FcntlFlock(f.File.Fd(), F_OFD_GETLK, &flk))
   180  	out.FromFlockT(&flk)
   181  	return
   182  }
   183  
   184  func (f *loopbackFile) SetLk(owner uint64, lk *fuse.FileLock, flags uint32) (code fuse.Status) {
   185  	return f.setLock(owner, lk, flags, false)
   186  }
   187  
   188  func (f *loopbackFile) SetLkw(owner uint64, lk *fuse.FileLock, flags uint32) (code fuse.Status) {
   189  	return f.setLock(owner, lk, flags, true)
   190  }
   191  
   192  func (f *loopbackFile) setLock(owner uint64, lk *fuse.FileLock, flags uint32, blocking bool) (code fuse.Status) {
   193  	if (flags & fuse.FUSE_LK_FLOCK) != 0 {
   194  		var op int
   195  		switch lk.Typ {
   196  		case syscall.F_RDLCK:
   197  			op = syscall.LOCK_SH
   198  		case syscall.F_WRLCK:
   199  			op = syscall.LOCK_EX
   200  		case syscall.F_UNLCK:
   201  			op = syscall.LOCK_UN
   202  		default:
   203  			return fuse.EINVAL
   204  		}
   205  		if !blocking {
   206  			op |= syscall.LOCK_NB
   207  		}
   208  		return fuse.ToStatus(syscall.Flock(int(f.File.Fd()), op))
   209  	} else {
   210  		flk := syscall.Flock_t{}
   211  		lk.ToFlockT(&flk)
   212  		var op int
   213  		if blocking {
   214  			op = F_OFD_SETLKW
   215  		} else {
   216  			op = F_OFD_SETLK
   217  		}
   218  		return fuse.ToStatus(syscall.FcntlFlock(f.File.Fd(), op, &flk))
   219  	}
   220  }
   221  
   222  func (f *loopbackFile) Truncate(size uint64) fuse.Status {
   223  	f.lock.Lock()
   224  	r := fuse.ToStatus(syscall.Ftruncate(int(f.File.Fd()), int64(size)))
   225  	f.lock.Unlock()
   226  
   227  	return r
   228  }
   229  
   230  func (f *loopbackFile) Chmod(mode uint32) fuse.Status {
   231  	f.lock.Lock()
   232  	r := fuse.ToStatus(f.File.Chmod(os.FileMode(mode)))
   233  	f.lock.Unlock()
   234  
   235  	return r
   236  }
   237  
   238  func (f *loopbackFile) Chown(uid uint32, gid uint32) fuse.Status {
   239  	f.lock.Lock()
   240  	r := fuse.ToStatus(f.File.Chown(int(uid), int(gid)))
   241  	f.lock.Unlock()
   242  
   243  	return r
   244  }
   245  
   246  func (f *loopbackFile) GetAttr(a *fuse.Attr) fuse.Status {
   247  	st := syscall.Stat_t{}
   248  	f.lock.Lock()
   249  	err := syscall.Fstat(int(f.File.Fd()), &st)
   250  	f.lock.Unlock()
   251  	if err != nil {
   252  		return fuse.ToStatus(err)
   253  	}
   254  	a.FromStat(&st)
   255  
   256  	return fuse.OK
   257  }
   258  
   259  // Utimens implemented in files_linux.go
   260  
   261  // Allocate implemented in files_linux.go
   262  
   263  ////////////////////////////////////////////////////////////////
   264  
   265  // NewReadOnlyFile wraps a File so all write operations are denied.
   266  func NewReadOnlyFile(f File) File {
   267  	return &readOnlyFile{File: f}
   268  }
   269  
   270  type readOnlyFile struct {
   271  	File
   272  }
   273  
   274  func (f *readOnlyFile) InnerFile() File {
   275  	return f.File
   276  }
   277  
   278  func (f *readOnlyFile) String() string {
   279  	return fmt.Sprintf("readOnlyFile(%s)", f.File.String())
   280  }
   281  
   282  func (f *readOnlyFile) Write(data []byte, off int64) (uint32, fuse.Status) {
   283  	return 0, fuse.EPERM
   284  }
   285  
   286  func (f *readOnlyFile) Fsync(flag int) (code fuse.Status) {
   287  	return fuse.OK
   288  }
   289  
   290  func (f *readOnlyFile) Truncate(size uint64) fuse.Status {
   291  	return fuse.EPERM
   292  }
   293  
   294  func (f *readOnlyFile) Chmod(mode uint32) fuse.Status {
   295  	return fuse.EPERM
   296  }
   297  
   298  func (f *readOnlyFile) Chown(uid uint32, gid uint32) fuse.Status {
   299  	return fuse.EPERM
   300  }
   301  
   302  func (f *readOnlyFile) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
   303  	return fuse.EPERM
   304  }