Browse Source

初步实现fusefs的接口

gitlink
Sydonian 9 months ago
parent
commit
686a08e7c5
9 changed files with 796 additions and 0 deletions
  1. +112
    -0
      client2/internal/mount/dir_handle.go
  2. +206
    -0
      client2/internal/mount/dir_node.go
  3. +119
    -0
      client2/internal/mount/file_handle.go
  4. +121
    -0
      client2/internal/mount/file_node.go
  5. +72
    -0
      client2/internal/mount/node.go
  6. +69
    -0
      client2/internal/mount/types.go
  7. +90
    -0
      client2/internal/mount/vfs.go
  8. +1
    -0
      go.mod
  9. +6
    -0
      go.sum

+ 112
- 0
client2/internal/mount/dir_handle.go View File

@@ -0,0 +1,112 @@
package mount

import (
"io"
"os"
"time"
)

// 目录从设计上来说不需要打开操作,所以dirHandle就是fusefs的DirHandle接口的完整实现。
type dirHandle struct {
dir FsDir
dirReader DirReader
}

func newDirHandle(dir FsDir, dirReader DirReader) *dirHandle {
return &dirHandle{dir: dir, dirReader: dirReader}
}

// Readdir reads the contents of the directory associated with file and returns
// a slice of up to n FileInfo values, as would be returned by Lstat, in
// directory order. Subsequent calls on the same file will yield further
// FileInfos.
//
// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
// Readdir returns an empty slice, it will return a non-nil error explaining
// why. At the end of a directory, the error is io.EOF.
//
// If n <= 0, Readdir returns all the FileInfo from the directory in a single
// slice. In this case, if Readdir succeeds (reads all the way to the end of
// the directory), it returns the slice and a nil error. If it encounters an
// error before the end of the directory, Readdir returns the FileInfo read
// until that point and a non-nil error.
func (fh *dirHandle) Readdir(n int) (fis []os.FileInfo, err error) {
entries, err := fh.dirReader.Next(n)
if err != nil {
return nil, err
}

if len(entries) == 0 {
return nil, io.EOF
}

var infos []os.FileInfo
for _, entry := range entries {
infos = append(infos, &fileInfo{entry})
}

return infos, nil
}

// Readdirnames reads and returns a slice of names from the directory f.
//
// If n > 0, Readdirnames returns at most n names. In this case, if
// Readdirnames returns an empty slice, it will return a non-nil error
// explaining why. At the end of a directory, the error is io.EOF.
//
// If n <= 0, Readdirnames returns all the names from the directory in a single
// slice. In this case, if Readdirnames succeeds (reads all the way to the end
// of the directory), it returns the slice and a nil error. If it encounters an
// error before the end of the directory, Readdirnames returns the names read
// until that point and a non-nil error.
func (fh *dirHandle) Readdirnames(n int) (names []string, err error) {
entries, err := fh.dirReader.Next(n)
if err != nil {
return nil, err
}

if len(entries) == 0 {
return nil, io.EOF
}

for _, entry := range entries {
names = append(names, entry.Name())
}

return names, nil
}

// Close closes the handle
func (fh *dirHandle) Close() (err error) {
fh.dirReader.Close()
return nil
}

type fileInfo struct {
entry FsEntry
}

func (fi *fileInfo) Name() string {
return fi.entry.Name()
}

func (fi *fileInfo) Size() int64 {
return fi.entry.Size()
}

func (fi *fileInfo) Mode() os.FileMode {
return os.FileMode(fi.entry.Mode())
}

// ModTime returns the modification time of the file
func (fi *fileInfo) ModTime() time.Time {
return fi.entry.ModTime()
}

func (fi *fileInfo) IsDir() bool {
return fi.entry.IsDir()
}

func (fi *fileInfo) Sys() interface{} {
return nil
}

+ 206
- 0
client2/internal/mount/dir_node.go View File

@@ -0,0 +1,206 @@
package mount

import (
"context"
"os"
"syscall"

fusefs "github.com/hanwen/go-fuse/v2/fs"
"github.com/hanwen/go-fuse/v2/fuse"
)

type DirNode struct {
NodeBase
dir FsDir
}

func newDirNode(vfs *Vfs, dir FsDir) *DirNode {
return &DirNode{NodeBase: NodeBase{vfs: vfs}, dir: dir}
}

func (n *DirNode) Getattr(ctx context.Context, f fusefs.FileHandle, out *fuse.AttrOut) syscall.Errno {
n.vfs.fillAttrOut(n.dir, out)
return 0
}

// Setattr sets attributes for an Inode.
func (n *DirNode) Setattr(ctx context.Context, f fusefs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) (errno syscall.Errno) {
n.vfs.fillAttrOut(n.dir, out)

_, ok := in.GetSize()
if ok {
return syscall.ENOSYS
}

modTime, ok := in.GetMTime()
if ok {
err := n.dir.SetModTime(modTime)
if err != nil {
return translateError(err)
}
out.Mtime = uint64(modTime.Unix())
out.Mtimensec = uint32(modTime.Nanosecond())
}

return 0
}

var _ = (fusefs.NodeSetattrer)((*DirNode)(nil))

// accessModeMask masks off the read modes from the flags
const accessModeMask = (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)

// Open opens an Inode (of regular file type) for reading. It
// is optional but recommended to return a FileHandle.
func (n *DirNode) Open(ctx context.Context, flags uint32) (fh fusefs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
rdwrMode := int(flags) & accessModeMask
if rdwrMode != os.O_RDONLY {
return nil, 0, syscall.EPERM
}

reader, err := n.dir.ReadChildren()
if err != nil {
return nil, 0, translateError(err)
}

return newDirHandle(n.dir, reader), 0, 0
}

var _ = (fusefs.NodeOpener)((*DirNode)(nil))

func (n *DirNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (inode *fusefs.Inode, errno syscall.Errno) {
child, err := n.dir.Child(ctx, name)
if err != nil {
return nil, translateError(err)
}

switch child := child.(type) {
case FsDir:
node := newDirNode(n.vfs, child)
n.vfs.fillEntryOut(child, out)

return node.NewInode(ctx, node, fusefs.StableAttr{
Mode: out.Attr.Mode,
}), 0

case FsFile:
node := newFileNode(n.vfs, child)
n.vfs.fillEntryOut(child, out)

return node.NewInode(ctx, node, fusefs.StableAttr{
Mode: out.Attr.Mode,
}), 0

default:
return nil, syscall.EINVAL
}
}

var _ = (fusefs.NodeLookuper)((*DirNode)(nil))

func (n *DirNode) Opendir(ctx context.Context) syscall.Errno {
return 0
}

var _ = (fusefs.NodeOpendirer)((*DirNode)(nil))

type dirStream struct {
reader DirReader
vfs *Vfs
}

func (s *dirStream) HasNext() bool {
return s.reader.HasNext()
}

func (s *dirStream) Next() (fuse.DirEntry, syscall.Errno) {
entries, err := s.reader.Next(1)
if err != nil {
return fuse.DirEntry{}, translateError(err)
}
entry := entries[0]

return fuse.DirEntry{
Name: entry.Name(),
Mode: s.vfs.getMode(entry),
}, 0
}

func (s *dirStream) Close() {
s.reader.Close()
}

func (n *DirNode) Readdir(ctx context.Context) (ds fusefs.DirStream, errno syscall.Errno) {
reader, err := n.dir.ReadChildren()
if err != nil {
return nil, translateError(err)
}

return &dirStream{reader: reader, vfs: n.vfs}, 0
}

var _ = (fusefs.NodeReaddirer)((*DirNode)(nil))

func (n *DirNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.EntryOut) (inode *fusefs.Inode, errno syscall.Errno) {
newDir, err := n.dir.NewDir(ctx, name)
if err != nil {
return nil, translateError(err)
}

node := newDirNode(n.vfs, newDir)
n.vfs.fillEntryOut(newDir, out)

return node.NewInode(ctx, node, fusefs.StableAttr{
Mode: out.Attr.Mode,
}), 0
}

var _ = (fusefs.NodeMkdirer)((*DirNode)(nil))

func (n *DirNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (node *fusefs.Inode, fh fusefs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
newFile, err := n.dir.NewFile(ctx, name, flags)
if err != nil {
return nil, nil, 0, translateError(err)
}

hd, err := newFile.Open(flags)
if err != nil {
return nil, nil, 0, translateError(err)
}

n.vfs.fillEntryOut(newFile, out)

fileNode := newFileNode(n.vfs, newFile)
return fileNode.NewInode(ctx, fileNode, fusefs.StableAttr{
Mode: out.Attr.Mode,
}), hd, 0, 0
}

var _ = (fusefs.NodeCreater)((*DirNode)(nil))

// Unlink should remove a child from this directory. If the
// return status is OK, the Inode is removed as child in the
// FS tree automatically. Default is to return EROFS.
func (n *DirNode) Unlink(ctx context.Context, name string) (errno syscall.Errno) {
return translateError(n.dir.RemoveChild(ctx, name))
}

var _ = (fusefs.NodeUnlinker)((*DirNode)(nil))

// Rmdir is like Unlink but for directories.
// Default is to return EROFS.
func (n *DirNode) Rmdir(ctx context.Context, name string) (errno syscall.Errno) {
return translateError(n.dir.RemoveChild(ctx, name))
}

var _ = (fusefs.NodeRmdirer)((*DirNode)(nil))

func (n *DirNode) Rename(ctx context.Context, oldName string, newParent fusefs.InodeEmbedder, newName string, flags uint32) (errno syscall.Errno) {
newParentNode, ok := newParent.(*DirNode)
if !ok {
return syscall.ENOTDIR
}
return translateError(n.dir.MoveChild(ctx, oldName, newName, newParentNode.dir))
}

var _ = (fusefs.NodeRenamer)((*DirNode)(nil))

+ 119
- 0
client2/internal/mount/file_handle.go View File

@@ -0,0 +1,119 @@
package mount

import (
"context"
"io"
"syscall"

fusefs "github.com/hanwen/go-fuse/v2/fs"
"github.com/hanwen/go-fuse/v2/fuse"
)

// 作为本模块的FileHandle与fusefs.FileHandle的桥梁,用于实现fusefs.FileHandle接口
type fileHandle struct {
hd FileHandle
file FsFile
vfs *Vfs
}

func newFileHandle(hd FileHandle, file FsFile, vfs *Vfs) *fileHandle {
return &fileHandle{
hd: hd,
file: file,
vfs: vfs,
}
}

// Read data from a file. The data should be returned as
// ReadResult, which may be constructed from the incoming
// `dest` buffer.
func (f *fileHandle) Read(ctx context.Context, dest []byte, off int64) (res fuse.ReadResult, errno syscall.Errno) {
var n int
var err error
n, err = f.hd.ReadAt(dest, off)
if err == io.EOF {
err = nil
}
return fuse.ReadResultData(dest[:n]), translateError(err)
}

var _ fusefs.FileReader = (*fileHandle)(nil)

// Write the data into the file handle at given offset. After
// returning, the data will be reused and may not referenced.
func (f *fileHandle) Write(ctx context.Context, data []byte, off int64) (written uint32, errno syscall.Errno) {
var n int
var err error
n, err = f.hd.WriteAt(data, off)
return uint32(n), translateError(err)
}

var _ fusefs.FileWriter = (*fileHandle)(nil)

// Flush is called for the close(2) call on a file descriptor. In case
// of a descriptor that was duplicated using dup(2), it may be called
// more than once for the same fileHandle.
func (f *fileHandle) Flush(ctx context.Context) syscall.Errno {
return translateError(f.hd.Close())
}

var _ fusefs.FileFlusher = (*fileHandle)(nil)

// Release is called to before a fileHandle is forgotten. The
// kernel ignores the return value of this method,
// so any cleanup that requires specific synchronization or
// could fail with I/O errors should happen in Flush instead.
func (f *fileHandle) Release(ctx context.Context) syscall.Errno {
return translateError(f.hd.Release())
}

var _ fusefs.FileReleaser = (*fileHandle)(nil)

// Fsync is a signal to ensure writes to the Inode are flushed
// to stable storage.
func (f *fileHandle) Fsync(ctx context.Context, flags uint32) (errno syscall.Errno) {
return translateError(f.hd.Sync())
}

var _ fusefs.FileFsyncer = (*fileHandle)(nil)

// Getattr reads attributes for an Inode. The library will ensure that
// Mode and Ino are set correctly. For files that are not opened with
// FOPEN_DIRECTIO, Size should be set so it can be read correctly. If
// returning zeroed permissions, the default behavior is to change the
// mode of 0755 (directory) or 0644 (files). This can be switched off
// with the Options.NullPermissions setting. If blksize is unset, 4096
// is assumed, and the 'blocks' field is set accordingly.
func (f *fileHandle) Getattr(ctx context.Context, out *fuse.AttrOut) (errno syscall.Errno) {
f.vfs.fillAttrOut(f.file, out)
return 0
}

var _ fusefs.FileGetattrer = (*fileHandle)(nil)

// Setattr sets attributes for an Inode.
func (f *fileHandle) Setattr(ctx context.Context, in *fuse.SetAttrIn, out *fuse.AttrOut) (errno syscall.Errno) {
var err error
f.vfs.fillAttrOut(f.file, out)
size, ok := in.GetSize()
if ok {
err = f.file.Truncate(size)
if err != nil {
return translateError(err)
}
out.Attr.Size = size
}

mtime, ok := in.GetMTime()
if ok {
err = f.file.SetModTime(mtime)
if err != nil {
return translateError(err)
}
out.Attr.Mtime = uint64(mtime.Unix())
out.Attr.Mtimensec = uint32(mtime.Nanosecond())
}
return 0
}

var _ fusefs.FileSetattrer = (*fileHandle)(nil)

+ 121
- 0
client2/internal/mount/file_node.go View File

@@ -0,0 +1,121 @@
package mount

import (
"context"
"syscall"

fusefs "github.com/hanwen/go-fuse/v2/fs"
"github.com/hanwen/go-fuse/v2/fuse"
)

type FileNode struct {
NodeBase
file FsFile
}

func newFileNode(vfs *Vfs, file FsFile) *FileNode {
return &FileNode{
NodeBase: NodeBase{vfs: vfs},
file: file,
}
}

func (n *FileNode) Getattr(ctx context.Context, f fusefs.FileHandle, out *fuse.AttrOut) syscall.Errno {
n.vfs.fillAttrOut(n.file, out)
return 0
}

func (n *FileNode) Setattr(ctx context.Context, f fusefs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) (errno syscall.Errno) {
n.vfs.fillAttrOut(n.file, out)

size, ok := in.GetSize()
if ok {
err := n.file.Truncate(size)
if err != nil {
return translateError(err)
}
out.Size = size
}

modTime, ok := in.GetMTime()
if ok {
err := n.file.SetModTime(modTime)
if err != nil {
return translateError(err)
}
out.Mtime = uint64(modTime.Unix())
out.Mtimensec = uint32(modTime.Nanosecond())
}

return 0
}

var _ = (fusefs.NodeSetattrer)((*FileNode)(nil))

func (n *FileNode) Open(ctx context.Context, flags uint32) (fh fusefs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
// 只支持以下标志:
// os.O_RDONLY
// os.O_WRONLY
// os.O_RDWR
// os.O_APPEND
// os.O_TRUNC
// os.O_SYNC
// 忽略其他标志位

hd, err := n.file.Open(flags)
if err != nil {
return nil, 0, translateError(err)
}

return hd, 0, 0
}

var _ = (fusefs.NodeOpener)((*FileNode)(nil))

func (n *FileNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (inode *fusefs.Inode, errno syscall.Errno) {
return nil, syscall.ENOTDIR
}

var _ = (fusefs.NodeLookuper)((*FileNode)(nil))

func (n *FileNode) Opendir(ctx context.Context) syscall.Errno {
return syscall.ENOTDIR
}

var _ = (fusefs.NodeOpendirer)((*FileNode)(nil))

func (n *FileNode) Readdir(ctx context.Context) (ds fusefs.DirStream, errno syscall.Errno) {
return nil, syscall.ENOTDIR
}

var _ = (fusefs.NodeReaddirer)((*FileNode)(nil))

func (n *FileNode) Mkdir(ctx context.Context, name string, mode uint32, out *fuse.EntryOut) (inode *fusefs.Inode, errno syscall.Errno) {
return nil, syscall.ENOTDIR
}

var _ = (fusefs.NodeMkdirer)((*FileNode)(nil))

func (n *FileNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (node *fusefs.Inode, fh fusefs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
return nil, nil, 0, syscall.ENOTDIR
}

var _ = (fusefs.NodeCreater)((*FileNode)(nil))

func (n *FileNode) Unlink(ctx context.Context, name string) (errno syscall.Errno) {
return syscall.ENOTDIR
}

var _ = (fusefs.NodeUnlinker)((*FileNode)(nil))

func (n *FileNode) Rmdir(ctx context.Context, name string) (errno syscall.Errno) {
return syscall.ENOTDIR
}

var _ = (fusefs.NodeRmdirer)((*FileNode)(nil))

func (n *FileNode) Rename(ctx context.Context, oldName string, newParent fusefs.InodeEmbedder, newName string, flags uint32) (errno syscall.Errno) {
return syscall.ENOTDIR
}

var _ = (fusefs.NodeRenamer)((*FileNode)(nil))

+ 72
- 0
client2/internal/mount/node.go View File

@@ -0,0 +1,72 @@
package mount

import (
"context"
"syscall"

fusefs "github.com/hanwen/go-fuse/v2/fs"
"github.com/hanwen/go-fuse/v2/fuse"
)

type NodeBase struct {
fusefs.Inode
vfs *Vfs
}

// Statfs implements statistics for the filesystem that holds this
// Inode. If not defined, the `out` argument will zeroed with an OK
// result. This is because OSX filesystems must Statfs, or the mount
// will not work.
func (n *NodeBase) Statfs(ctx context.Context, out *fuse.StatfsOut) syscall.Errno {
const blockSize = 4096

stats := n.vfs.fs.Stats()

// total, _, free := n.fsys.VFS.Statfs()
out.Blocks = uint64(stats.TotalDataBytes) / blockSize // Total data blocks in file system.
out.Bfree = 1e9 // Free blocks in file system.
out.Bavail = out.Bfree // Free blocks in file system if you're not root.
out.Files = uint64(stats.TotalObjectCount) // Total files in file system.
out.Ffree = 1e9 // Free files in file system.
out.Bsize = blockSize // Block size
out.NameLen = 255 // Maximum file name length?
out.Frsize = blockSize // Fragment size, smallest addressable data size in the file system.
return 0
}

// Getxattr should read data for the given attribute into
// `dest` and return the number of bytes. If `dest` is too
// small, it should return ERANGE and the size of the attribute.
// If not defined, Getxattr will return ENOATTR.
func (n *NodeBase) Getxattr(ctx context.Context, attr string, dest []byte) (uint32, syscall.Errno) {
return 0, syscall.ENOSYS // we never implement this
}

var _ fusefs.NodeGetxattrer = (*NodeBase)(nil)

// Setxattr should store data for the given attribute. See
// setxattr(2) for information about flags.
// If not defined, Setxattr will return ENOATTR.
func (n *NodeBase) Setxattr(ctx context.Context, attr string, data []byte, flags uint32) syscall.Errno {
return syscall.ENOSYS // we never implement this
}

var _ fusefs.NodeSetxattrer = (*NodeBase)(nil)

// Removexattr should delete the given attribute.
// If not defined, Removexattr will return ENOATTR.
func (n *NodeBase) Removexattr(ctx context.Context, attr string) syscall.Errno {
return syscall.ENOSYS // we never implement this
}

var _ fusefs.NodeRemovexattrer = (*NodeBase)(nil)

// Listxattr should read all attributes (null terminated) into
// `dest`. If the `dest` buffer is too small, it should return ERANGE
// and the correct size. If not defined, return an empty list and
// success.
func (n *NodeBase) Listxattr(ctx context.Context, dest []byte) (uint32, syscall.Errno) {
return 0, syscall.ENOSYS // we never implement this
}

var _ fusefs.NodeListxattrer = (*NodeBase)(nil)

+ 69
- 0
client2/internal/mount/types.go View File

@@ -0,0 +1,69 @@
package mount

import (
"context"
"errors"
"os"
"time"
)

var (
ErrNotExists = os.ErrNotExist
ErrExists = os.ErrExist
ErrNotEmpty = errors.New("directory not empty")
ErrPermission = os.ErrPermission
)

type Fs interface {
Stats() FsStats
}

type FsStats struct {
TotalDataBytes int64 // 存储的总数据量
TotalObjectCount int64 // 存储的总对象数量
}

type FsEntry interface {
Name() string
Size() int64
Mode() os.FileMode
ModTime() time.Time
CreateTime() time.Time
IsDir() bool
}

type FsDir interface {
FsEntry

// 如果不存在,应该返回ErrNotExists
SetModTime(time time.Time) error
Child(ctx context.Context, name string) (FsEntry, error)
Children(ctx context.Context) ([]FsEntry, error)
ReadChildren() (DirReader, error)
NewDir(ctx context.Context, name string) (FsDir, error)
NewFile(ctx context.Context, name string, flags uint32) (FsFile, error)
RemoveChild(ctx context.Context, name string) error
MoveChild(ctx context.Context, oldName string, newName string, newParent FsDir) error
}

type FsFile interface {
FsEntry

Truncate(size uint64) error
SetModTime(time time.Time) error
Open(flags uint32) (FileHandle, error)
}

type DirReader interface {
HasNext() bool
Next(n int) ([]FsEntry, error)
Close()
}

type FileHandle interface {
ReadAt(buf []byte, off int64) (int, error)
WriteAt(buf []byte, off int64) (int, error)
Sync() error
Close() error
Release() error
}

+ 90
- 0
client2/internal/mount/vfs.go View File

@@ -0,0 +1,90 @@
package mount

import (
"os"
"syscall"
"time"

"github.com/hanwen/go-fuse/v2/fuse"
)

type Config struct {
GID uint32 `json:"gid"`
UID uint32 `json:"uid"`
AttrTimeout time.Duration `json:"attrTimeout"`
}

type Vfs struct {
fs Fs
config Config
}

func translateError(err error) syscall.Errno {
switch err {
case nil:
return 0

case ErrNotExists, os.ErrNotExist:
return syscall.ENOENT

case ErrExists, os.ErrExist:
return syscall.EEXIST

case ErrPermission, os.ErrPermission:
return syscall.EACCES

case ErrNotEmpty:
return syscall.ENOTEMPTY

default:
return syscall.EIO
}
}

// get the Mode from a vfs Node
func (v *Vfs) getMode(node FsEntry) uint32 {
Mode := node.Mode().Perm()
if node.IsDir() {
Mode |= fuse.S_IFDIR
} else {
Mode |= fuse.S_IFREG
}
return uint32(Mode)
}

// fill in attr from node
func (v *Vfs) fillAttr(node FsEntry, attr *fuse.Attr) {
Size := uint64(node.Size())
const BlockSize = 512
Blocks := (Size + BlockSize - 1) / BlockSize
attr.Owner.Gid = v.config.GID
attr.Owner.Uid = v.config.UID
attr.Mode = v.getMode(node)
attr.Size = Size
attr.Nlink = 1
attr.Blocks = Blocks
// attr.Blksize = BlockSize // not supported in freebsd/darwin, defaults to 4k if not set

createTime := node.CreateTime()
modTime := node.ModTime()

attr.Atime = uint64(modTime.Unix())
attr.Atimensec = uint32(modTime.Nanosecond())

attr.Mtime = uint64(modTime.Unix())
attr.Mtimensec = uint32(modTime.Nanosecond())

attr.Ctime = uint64(createTime.Unix())
attr.Ctimensec = uint32(createTime.Nanosecond())
}

func (v *Vfs) fillAttrOut(node FsEntry, out *fuse.AttrOut) {
v.fillAttr(node, &out.Attr)
out.SetTimeout(v.config.AttrTimeout)
}

func (v *Vfs) fillEntryOut(node FsEntry, out *fuse.EntryOut) {
v.fillAttr(node, &out.Attr)
out.SetAttrTimeout(v.config.AttrTimeout)
out.SetEntryTimeout(v.config.AttrTimeout)
}

+ 1
- 0
go.mod View File

@@ -13,6 +13,7 @@ require (
github.com/gin-gonic/gin v1.7.7 github.com/gin-gonic/gin v1.7.7
github.com/go-co-op/gocron/v2 v2.15.0 github.com/go-co-op/gocron/v2 v2.15.0
github.com/go-sql-driver/mysql v1.8.1 github.com/go-sql-driver/mysql v1.8.1
github.com/hanwen/go-fuse/v2 v2.7.2
github.com/hashicorp/golang-lru/v2 v2.0.5 github.com/hashicorp/golang-lru/v2 v2.0.5
github.com/huaweicloud/huaweicloud-sdk-go-obs v3.24.9+incompatible github.com/huaweicloud/huaweicloud-sdk-go-obs v3.24.9+incompatible
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.131 github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.131


+ 6
- 0
go.sum View File

@@ -98,6 +98,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
github.com/hanwen/go-fuse/v2 v2.7.2 h1:SbJP1sUP+n1UF8NXBA14BuojmTez+mDgOk0bC057HQw=
github.com/hanwen/go-fuse/v2 v2.7.2/go.mod h1:ugNaD/iv5JYyS1Rcvi57Wz7/vrLQJo10mmketmoef48=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -141,6 +143,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
@@ -156,6 +160,8 @@ github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=


Loading…
Cancel
Save