cmount,vfs: unify Read and Write handles and File and Dir where possible
This commit is contained in:
parent
5634659ea3
commit
22ee839d05
2 changed files with 77 additions and 186 deletions
247
cmd/cmount/fs.go
247
cmd/cmount/fs.go
|
@ -25,10 +25,9 @@ const fhUnset = ^uint64(0)
|
||||||
type FS struct {
|
type FS struct {
|
||||||
VFS *vfs.VFS
|
VFS *vfs.VFS
|
||||||
f fs.Fs
|
f fs.Fs
|
||||||
openDirs *openFiles
|
|
||||||
openFilesWr *openFiles
|
|
||||||
openFilesRd *openFiles
|
|
||||||
ready chan (struct{})
|
ready chan (struct{})
|
||||||
|
mu sync.Mutex // to protect the below
|
||||||
|
handles []vfs.Handle
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFS makes a new FS
|
// NewFS makes a new FS
|
||||||
|
@ -36,86 +35,60 @@ func NewFS(f fs.Fs) *FS {
|
||||||
fsys := &FS{
|
fsys := &FS{
|
||||||
VFS: vfs.New(f, &vfsflags.Opt),
|
VFS: vfs.New(f, &vfsflags.Opt),
|
||||||
f: f,
|
f: f,
|
||||||
openDirs: newOpenFiles(0x01),
|
|
||||||
openFilesWr: newOpenFiles(0x02),
|
|
||||||
openFilesRd: newOpenFiles(0x03),
|
|
||||||
ready: make(chan (struct{})),
|
ready: make(chan (struct{})),
|
||||||
}
|
}
|
||||||
return fsys
|
return fsys
|
||||||
}
|
}
|
||||||
|
|
||||||
type openFiles struct {
|
// Open a handle returning an integer file handle
|
||||||
mu sync.Mutex
|
func (fsys *FS) openHandle(handle vfs.Handle) (fh uint64) {
|
||||||
mark uint8
|
fsys.mu.Lock()
|
||||||
nodes []vfs.Noder
|
defer fsys.mu.Unlock()
|
||||||
}
|
|
||||||
|
|
||||||
func newOpenFiles(mark uint8) *openFiles {
|
|
||||||
return &openFiles{
|
|
||||||
mark: mark,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open a node returning a file handle
|
|
||||||
func (of *openFiles) Open(node vfs.Noder) (fh uint64) {
|
|
||||||
of.mu.Lock()
|
|
||||||
defer of.mu.Unlock()
|
|
||||||
var i int
|
var i int
|
||||||
var oldNode vfs.Noder
|
var oldHandle vfs.Handle
|
||||||
for i, oldNode = range of.nodes {
|
for i, oldHandle = range fsys.handles {
|
||||||
if oldNode == nil {
|
if oldHandle == nil {
|
||||||
of.nodes[i] = node
|
fsys.handles[i] = handle
|
||||||
goto found
|
goto found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
of.nodes = append(of.nodes, node)
|
fsys.handles = append(fsys.handles, handle)
|
||||||
i = len(of.nodes) - 1
|
i = len(fsys.handles) - 1
|
||||||
found:
|
found:
|
||||||
return uint64((i << 8) | int(of.mark))
|
return uint64(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InRange to see if this fh could be one of ours
|
// get the handle for fh, call with the lock held
|
||||||
func (of *openFiles) InRange(fh uint64) bool {
|
func (fsys *FS) _getHandle(fh uint64) (i int, handle vfs.Handle, errc int) {
|
||||||
return uint8(fh) == of.mark
|
if fh > uint64(len(fsys.handles)) {
|
||||||
}
|
|
||||||
|
|
||||||
// get the node for fh, call with the lock held
|
|
||||||
func (of *openFiles) get(fh uint64) (i int, node vfs.Noder, errc int) {
|
|
||||||
receivedMark := uint8(fh)
|
|
||||||
if receivedMark != of.mark {
|
|
||||||
fs.Debugf(nil, "Bad file handle: bad mark 0x%X != 0x%X: 0x%X", receivedMark, of.mark, fh)
|
|
||||||
return i, nil, -fuse.EBADF
|
|
||||||
}
|
|
||||||
i64 := fh >> 8
|
|
||||||
if i64 > uint64(len(of.nodes)) {
|
|
||||||
fs.Debugf(nil, "Bad file handle: too big: 0x%X", fh)
|
fs.Debugf(nil, "Bad file handle: too big: 0x%X", fh)
|
||||||
return i, nil, -fuse.EBADF
|
return i, nil, -fuse.EBADF
|
||||||
}
|
}
|
||||||
i = int(i64)
|
i = int(fh)
|
||||||
node = of.nodes[i]
|
handle = fsys.handles[i]
|
||||||
if node == nil {
|
if handle == nil {
|
||||||
fs.Debugf(nil, "Bad file handle: nil node: 0x%X", fh)
|
fs.Debugf(nil, "Bad file handle: nil handle: 0x%X", fh)
|
||||||
return i, nil, -fuse.EBADF
|
return i, nil, -fuse.EBADF
|
||||||
}
|
}
|
||||||
return i, node, 0
|
return i, handle, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the node for the file handle
|
// Get the handle for the file handle
|
||||||
func (of *openFiles) Get(fh uint64) (node vfs.Noder, errc int) {
|
func (fsys *FS) getHandle(fh uint64) (handle vfs.Handle, errc int) {
|
||||||
of.mu.Lock()
|
fsys.mu.Lock()
|
||||||
_, node, errc = of.get(fh)
|
_, handle, errc = fsys._getHandle(fh)
|
||||||
of.mu.Unlock()
|
fsys.mu.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the node
|
// Close the handle
|
||||||
func (of *openFiles) Close(fh uint64) (errc int) {
|
func (fsys *FS) closeHandle(fh uint64) (errc int) {
|
||||||
of.mu.Lock()
|
fsys.mu.Lock()
|
||||||
i, _, errc := of.get(fh)
|
i, _, errc := fsys._getHandle(fh)
|
||||||
if errc == 0 {
|
if errc == 0 {
|
||||||
of.nodes[i] = nil
|
fsys.handles[i] = nil
|
||||||
}
|
}
|
||||||
of.mu.Unlock()
|
fsys.mu.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,35 +131,13 @@ func (fsys *FS) lookupFile(path string) (file *vfs.File, errc int) {
|
||||||
return file, 0
|
return file, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the underlying openFile handle from the file handle
|
|
||||||
func (fsys *FS) getOpenFilesFromFh(fh uint64) (of *openFiles, errc int) {
|
|
||||||
switch {
|
|
||||||
case fsys.openFilesRd.InRange(fh):
|
|
||||||
return fsys.openFilesRd, 0
|
|
||||||
case fsys.openFilesWr.InRange(fh):
|
|
||||||
return fsys.openFilesWr, 0
|
|
||||||
case fsys.openDirs.InRange(fh):
|
|
||||||
return fsys.openDirs, 0
|
|
||||||
}
|
|
||||||
return nil, -fuse.EBADF
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the underlying handle from the file handle
|
|
||||||
func (fsys *FS) getHandleFromFh(fh uint64) (handle vfs.Noder, errc int) {
|
|
||||||
of, errc := fsys.getOpenFilesFromFh(fh)
|
|
||||||
if errc != 0 {
|
|
||||||
return nil, errc
|
|
||||||
}
|
|
||||||
return of.Get(fh)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get a node from the path or from the fh if not fhUnset
|
// get a node from the path or from the fh if not fhUnset
|
||||||
func (fsys *FS) getNode(path string, fh uint64) (node vfs.Node, errc int) {
|
func (fsys *FS) getNode(path string, fh uint64) (node vfs.Node, errc int) {
|
||||||
if fh == fhUnset {
|
if fh == fhUnset {
|
||||||
node, errc = fsys.lookupNode(path)
|
node, errc = fsys.lookupNode(path)
|
||||||
} else {
|
} else {
|
||||||
var n vfs.Noder
|
var n vfs.Handle
|
||||||
n, errc = fsys.getHandleFromFh(fh)
|
n, errc = fsys.getHandle(fh)
|
||||||
if errc == 0 {
|
if errc == 0 {
|
||||||
node = n.Node()
|
node = n.Node()
|
||||||
}
|
}
|
||||||
|
@ -196,19 +147,14 @@ func (fsys *FS) getNode(path string, fh uint64) (node vfs.Node, errc int) {
|
||||||
|
|
||||||
// stat fills up the stat block for Node
|
// stat fills up the stat block for Node
|
||||||
func (fsys *FS) stat(node vfs.Node, stat *fuse.Stat_t) (errc int) {
|
func (fsys *FS) stat(node vfs.Node, stat *fuse.Stat_t) (errc int) {
|
||||||
var Size uint64
|
Size := uint64(node.Size())
|
||||||
var Blocks uint64
|
Blocks := (Size + 511) / 512
|
||||||
var modTime time.Time
|
modTime := node.ModTime()
|
||||||
var Mode os.FileMode
|
Mode := node.Mode().Perm()
|
||||||
switch x := node.(type) {
|
if node.IsDir() {
|
||||||
case *vfs.Dir:
|
Mode |= fuse.S_IFDIR
|
||||||
modTime = x.ModTime()
|
} else {
|
||||||
Mode = fsys.VFS.Opt.DirPerms | fuse.S_IFDIR
|
Mode |= fuse.S_IFREG
|
||||||
case *vfs.File:
|
|
||||||
modTime = x.ModTime()
|
|
||||||
Size = uint64(x.Size())
|
|
||||||
Blocks = (Size + 511) / 512
|
|
||||||
Mode = fsys.VFS.Opt.FilePerms | fuse.S_IFREG
|
|
||||||
}
|
}
|
||||||
//stat.Dev = 1
|
//stat.Dev = 1
|
||||||
stat.Ino = node.Inode() // FIXME do we need to set the inode number?
|
stat.Ino = node.Inode() // FIXME do we need to set the inode number?
|
||||||
|
@ -255,13 +201,11 @@ func (fsys *FS) Getattr(path string, stat *fuse.Stat_t, fh uint64) (errc int) {
|
||||||
// Opendir opens path as a directory
|
// Opendir opens path as a directory
|
||||||
func (fsys *FS) Opendir(path string) (errc int, fh uint64) {
|
func (fsys *FS) Opendir(path string) (errc int, fh uint64) {
|
||||||
defer fs.Trace(path, "")("errc=%d, fh=0x%X", &errc, &fh)
|
defer fs.Trace(path, "")("errc=%d, fh=0x%X", &errc, &fh)
|
||||||
dir, errc := fsys.lookupDir(path)
|
handle, err := fsys.VFS.OpenFile(path, os.O_RDONLY, 0777)
|
||||||
if errc == 0 {
|
if errc != 0 {
|
||||||
fh = fsys.openDirs.Open(dir)
|
return translateError(err), fhUnset
|
||||||
} else {
|
|
||||||
fh = fhUnset
|
|
||||||
}
|
}
|
||||||
return
|
return 0, fsys.openHandle(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Readdir reads the directory at dirPath
|
// Readdir reads the directory at dirPath
|
||||||
|
@ -272,17 +216,12 @@ func (fsys *FS) Readdir(dirPath string,
|
||||||
itemsRead := -1
|
itemsRead := -1
|
||||||
defer fs.Trace(dirPath, "ofst=%d, fh=0x%X", ofst, fh)("items=%d, errc=%d", &itemsRead, &errc)
|
defer fs.Trace(dirPath, "ofst=%d, fh=0x%X", ofst, fh)("items=%d, errc=%d", &itemsRead, &errc)
|
||||||
|
|
||||||
node, errc := fsys.openDirs.Get(fh)
|
node, errc := fsys.getHandle(fh)
|
||||||
if errc != 0 {
|
if errc != 0 {
|
||||||
return errc
|
return errc
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, ok := node.(*vfs.Dir)
|
items, err := node.Readdir(-1)
|
||||||
if !ok {
|
|
||||||
return -fuse.ENOTDIR
|
|
||||||
}
|
|
||||||
|
|
||||||
items, err := dir.ReadDirAll()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return translateError(err)
|
return translateError(err)
|
||||||
}
|
}
|
||||||
|
@ -303,9 +242,12 @@ func (fsys *FS) Readdir(dirPath string,
|
||||||
fill(".", nil, 0)
|
fill(".", nil, 0)
|
||||||
fill("..", nil, 0)
|
fill("..", nil, 0)
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
name := path.Base(item.DirEntry().Remote())
|
node, ok := item.(vfs.Node)
|
||||||
|
if ok {
|
||||||
|
name := path.Base(node.DirEntry().Remote())
|
||||||
fill(name, nil, 0)
|
fill(name, nil, 0)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
itemsRead = len(items)
|
itemsRead = len(items)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -313,7 +255,7 @@ func (fsys *FS) Readdir(dirPath string,
|
||||||
// Releasedir finished reading the directory
|
// Releasedir finished reading the directory
|
||||||
func (fsys *FS) Releasedir(path string, fh uint64) (errc int) {
|
func (fsys *FS) Releasedir(path string, fh uint64) (errc int) {
|
||||||
defer fs.Trace(path, "fh=0x%X", fh)("errc=%d", &errc)
|
defer fs.Trace(path, "fh=0x%X", fh)("errc=%d", &errc)
|
||||||
return fsys.openDirs.Close(fh)
|
return fsys.closeHandle(fh)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statfs reads overall stats on the filessystem
|
// Statfs reads overall stats on the filessystem
|
||||||
|
@ -346,14 +288,7 @@ func (fsys *FS) Open(path string, flags int) (errc int, fh uint64) {
|
||||||
return translateError(err), fhUnset
|
return translateError(err), fhUnset
|
||||||
}
|
}
|
||||||
|
|
||||||
switch fh := handle.(type) {
|
return 0, fsys.openHandle(handle)
|
||||||
case *vfs.WriteFileHandle:
|
|
||||||
return 0, fsys.openFilesWr.Open(fh)
|
|
||||||
case *vfs.ReadFileHandle:
|
|
||||||
return 0, fsys.openFilesRd.Open(fh)
|
|
||||||
}
|
|
||||||
|
|
||||||
return -fuse.EPERM, fhUnset
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates and opens a file.
|
// Create creates and opens a file.
|
||||||
|
@ -367,7 +302,7 @@ func (fsys *FS) Create(filePath string, flags int, mode uint32) (errc int, fh ui
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return translateError(err), fhUnset
|
return translateError(err), fhUnset
|
||||||
}
|
}
|
||||||
return 0, fsys.openFilesWr.Open(handle)
|
return 0, fsys.openHandle(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Truncate truncates a file to size
|
// Truncate truncates a file to size
|
||||||
|
@ -377,12 +312,8 @@ func (fsys *FS) Truncate(path string, size int64, fh uint64) (errc int) {
|
||||||
if errc != 0 {
|
if errc != 0 {
|
||||||
return errc
|
return errc
|
||||||
}
|
}
|
||||||
file, ok := node.(*vfs.File)
|
|
||||||
if !ok {
|
|
||||||
return -fuse.EIO
|
|
||||||
}
|
|
||||||
// Read the size so far
|
// Read the size so far
|
||||||
currentSize := file.Size()
|
currentSize := node.Size()
|
||||||
fs.Debugf(path, "truncate to %d, currentSize %d", size, currentSize)
|
fs.Debugf(path, "truncate to %d, currentSize %d", size, currentSize)
|
||||||
if int64(currentSize) != size {
|
if int64(currentSize) != size {
|
||||||
fs.Errorf(path, "Can't truncate files")
|
fs.Errorf(path, "Can't truncate files")
|
||||||
|
@ -391,10 +322,10 @@ func (fsys *FS) Truncate(path string, size int64, fh uint64) (errc int) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read data from file handle
|
||||||
func (fsys *FS) Read(path string, buff []byte, ofst int64, fh uint64) (n int) {
|
func (fsys *FS) Read(path string, buff []byte, ofst int64, fh uint64) (n int) {
|
||||||
defer fs.Trace(path, "ofst=%d, fh=0x%X", ofst, fh)("n=%d", &n)
|
defer fs.Trace(path, "ofst=%d, fh=0x%X", ofst, fh)("n=%d", &n)
|
||||||
// FIXME detect seek
|
handle, errc := fsys.getHandle(fh)
|
||||||
handle, errc := fsys.openFilesRd.Get(fh)
|
|
||||||
if errc != 0 {
|
if errc != 0 {
|
||||||
return errc
|
return errc
|
||||||
}
|
}
|
||||||
|
@ -407,19 +338,14 @@ func (fsys *FS) Read(path string, buff []byte, ofst int64, fh uint64) (n int) {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write data to file handle
|
||||||
func (fsys *FS) Write(path string, buff []byte, ofst int64, fh uint64) (n int) {
|
func (fsys *FS) Write(path string, buff []byte, ofst int64, fh uint64) (n int) {
|
||||||
defer fs.Trace(path, "ofst=%d, fh=0x%X", ofst, fh)("n=%d", &n)
|
defer fs.Trace(path, "ofst=%d, fh=0x%X", ofst, fh)("n=%d", &n)
|
||||||
// FIXME detect seek
|
handle, errc := fsys.getHandle(fh)
|
||||||
handle, errc := fsys.openFilesWr.Get(fh)
|
|
||||||
if errc != 0 {
|
if errc != 0 {
|
||||||
return errc
|
return errc
|
||||||
}
|
}
|
||||||
wfh, ok := handle.(*vfs.WriteFileHandle)
|
n, err := handle.WriteAt(buff, ofst)
|
||||||
if !ok {
|
|
||||||
// Can only write to write file handle
|
|
||||||
return -fuse.EIO
|
|
||||||
}
|
|
||||||
n, err := wfh.WriteAt(buff, ofst)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return translateError(err)
|
return translateError(err)
|
||||||
}
|
}
|
||||||
|
@ -429,44 +355,22 @@ func (fsys *FS) Write(path string, buff []byte, ofst int64, fh uint64) (n int) {
|
||||||
// Flush flushes an open file descriptor or path
|
// Flush flushes an open file descriptor or path
|
||||||
func (fsys *FS) Flush(path string, fh uint64) (errc int) {
|
func (fsys *FS) Flush(path string, fh uint64) (errc int) {
|
||||||
defer fs.Trace(path, "fh=0x%X", fh)("errc=%d", &errc)
|
defer fs.Trace(path, "fh=0x%X", fh)("errc=%d", &errc)
|
||||||
handle, errc := fsys.getHandleFromFh(fh)
|
handle, errc := fsys.getHandle(fh)
|
||||||
if errc != 0 {
|
if errc != 0 {
|
||||||
return errc
|
return errc
|
||||||
}
|
}
|
||||||
var err error
|
return translateError(handle.Flush())
|
||||||
switch x := handle.(type) {
|
|
||||||
case *vfs.ReadFileHandle:
|
|
||||||
err = x.Flush()
|
|
||||||
case *vfs.WriteFileHandle:
|
|
||||||
err = x.Flush()
|
|
||||||
default:
|
|
||||||
return -fuse.EIO
|
|
||||||
}
|
|
||||||
return translateError(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release closes the file if still open
|
// Release closes the file if still open
|
||||||
func (fsys *FS) Release(path string, fh uint64) (errc int) {
|
func (fsys *FS) Release(path string, fh uint64) (errc int) {
|
||||||
defer fs.Trace(path, "fh=0x%X", fh)("errc=%d", &errc)
|
defer fs.Trace(path, "fh=0x%X", fh)("errc=%d", &errc)
|
||||||
of, errc := fsys.getOpenFilesFromFh(fh)
|
handle, errc := fsys.getHandle(fh)
|
||||||
if errc != 0 {
|
if errc != 0 {
|
||||||
return errc
|
return errc
|
||||||
}
|
}
|
||||||
handle, errc := of.Get(fh)
|
_ = fsys.closeHandle(fh)
|
||||||
if errc != 0 {
|
return translateError(handle.Release())
|
||||||
return errc
|
|
||||||
}
|
|
||||||
_ = of.Close(fh)
|
|
||||||
var err error
|
|
||||||
switch x := handle.(type) {
|
|
||||||
case *vfs.ReadFileHandle:
|
|
||||||
err = x.Release()
|
|
||||||
case *vfs.WriteFileHandle:
|
|
||||||
err = x.Release()
|
|
||||||
default:
|
|
||||||
return -fuse.EIO
|
|
||||||
}
|
|
||||||
return translateError(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlink removes a file.
|
// Unlink removes a file.
|
||||||
|
@ -503,15 +407,7 @@ func (fsys *FS) Rmdir(dirPath string) (errc int) {
|
||||||
// Rename renames a file.
|
// Rename renames a file.
|
||||||
func (fsys *FS) Rename(oldPath string, newPath string) (errc int) {
|
func (fsys *FS) Rename(oldPath string, newPath string) (errc int) {
|
||||||
defer fs.Trace(oldPath, "newPath=%q", newPath)("errc=%d", &errc)
|
defer fs.Trace(oldPath, "newPath=%q", newPath)("errc=%d", &errc)
|
||||||
oldLeaf, oldParentDir, errc := fsys.lookupParentDir(oldPath)
|
return translateError(fsys.VFS.Rename(oldPath, newPath))
|
||||||
if errc != 0 {
|
|
||||||
return errc
|
|
||||||
}
|
|
||||||
newLeaf, newParentDir, errc := fsys.lookupParentDir(newPath)
|
|
||||||
if errc != 0 {
|
|
||||||
return errc
|
|
||||||
}
|
|
||||||
return translateError(oldParentDir.Rename(oldLeaf, newLeaf, newParentDir))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utimens changes the access and modification times of a file.
|
// Utimens changes the access and modification times of a file.
|
||||||
|
@ -527,14 +423,7 @@ func (fsys *FS) Utimens(path string, tmsp []fuse.Timespec) (errc int) {
|
||||||
} else {
|
} else {
|
||||||
t = tmsp[1].Time()
|
t = tmsp[1].Time()
|
||||||
}
|
}
|
||||||
var err error
|
return translateError(node.SetModTime(t))
|
||||||
switch x := node.(type) {
|
|
||||||
case *vfs.Dir:
|
|
||||||
err = x.SetModTime(t)
|
|
||||||
case *vfs.File:
|
|
||||||
err = x.SetModTime(t)
|
|
||||||
}
|
|
||||||
return translateError(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mknod creates a file node.
|
// Mknod creates a file node.
|
||||||
|
|
|
@ -105,6 +105,7 @@ type Handle interface {
|
||||||
// Additional methods useful for FUSE filesystems
|
// Additional methods useful for FUSE filesystems
|
||||||
Flush() error
|
Flush() error
|
||||||
Release() error
|
Release() error
|
||||||
|
Node() Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// baseHandle implements all the missing methods
|
// baseHandle implements all the missing methods
|
||||||
|
@ -129,6 +130,7 @@ func (h baseHandle) WriteAt(b []byte, off int64) (n int, err error) { retu
|
||||||
func (h baseHandle) WriteString(s string) (n int, err error) { return 0, ENOSYS }
|
func (h baseHandle) WriteString(s string) (n int, err error) { return 0, ENOSYS }
|
||||||
func (h baseHandle) Flush() (err error) { return ENOSYS }
|
func (h baseHandle) Flush() (err error) { return ENOSYS }
|
||||||
func (h baseHandle) Release() (err error) { return ENOSYS }
|
func (h baseHandle) Release() (err error) { return ENOSYS }
|
||||||
|
func (h baseHandle) Node() Node { return nil }
|
||||||
|
|
||||||
// Check interfaces
|
// Check interfaces
|
||||||
var (
|
var (
|
||||||
|
|
Loading…
Reference in a new issue