vfs: Implement Create support (#13)
* vfs: Implement Create support Signed-off-by: Xuanwo <github@xuanwo.io> * Format code Signed-off-by: Xuanwo <github@xuanwo.io>
This commit is contained in:
parent
0b64b1feef
commit
a1d9d0c129
|
@ -95,6 +95,11 @@ func fillAttrOut(i *vfs.Inode, out *fuse.AttrOut) fuse.Status {
|
||||||
return fuse.OK
|
return fuse.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fillOpenOut(fh *vfs.FileHandle, out *fuse.OpenOut) fuse.Status {
|
||||||
|
out.Fh = fh.ID
|
||||||
|
return fuse.OK
|
||||||
|
}
|
||||||
|
|
||||||
func parseError(err error) fuse.Status {
|
func parseError(err error) fuse.Status {
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, services.ErrObjectNotExist):
|
case errors.Is(err, services.ErrObjectNotExist):
|
||||||
|
@ -303,7 +308,15 @@ func (fs *FS) Create(cancel <-chan struct{}, input *fuse.CreateIn, name string,
|
||||||
return fuse.EINVAL
|
return fuse.EINVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement me
|
i, fh, err := fs.fs.Create(ino.ID, name)
|
||||||
|
if err != nil {
|
||||||
|
fs.logger.Error("create", zap.Error(err))
|
||||||
|
return fuse.EAGAIN
|
||||||
|
}
|
||||||
|
fs.logger.Info("start fill open out")
|
||||||
|
fillOpenOut(fh, &out.OpenOut)
|
||||||
|
fs.logger.Info("start fill entry out")
|
||||||
|
fillEntryOut(i, &out.EntryOut)
|
||||||
return fuse.OK
|
return fuse.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +333,12 @@ func (fs *FS) Open(cancel <-chan struct{}, input *fuse.OpenIn, out *fuse.OpenOut
|
||||||
return fuse.ENOENT
|
return fuse.ENOENT
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("implement me")
|
fh, err := fs.fs.CreateFileHandle(ino)
|
||||||
|
if err != nil {
|
||||||
|
fs.logger.Error("create file handle", zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return fillOpenOut(fh, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FS) Read(cancel <-chan struct{}, input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) {
|
func (fs *FS) Read(cancel <-chan struct{}, input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) {
|
||||||
|
@ -344,7 +362,12 @@ func (fs *FS) SetLkw(cancel <-chan struct{}, input *fuse.LkIn) (code fuse.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FS) Release(cancel <-chan struct{}, input *fuse.ReleaseIn) {
|
func (fs *FS) Release(cancel <-chan struct{}, input *fuse.ReleaseIn) {
|
||||||
panic("implement me")
|
err := fs.fs.DeleteFileHandle(input.Fh)
|
||||||
|
if err != nil {
|
||||||
|
fs.logger.Error("release",
|
||||||
|
zap.Uint64("file_handle", input.Fh),
|
||||||
|
zap.Error(err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FS) Write(cancel <-chan struct{}, input *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) {
|
func (fs *FS) Write(cancel <-chan struct{}, input *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) {
|
||||||
|
@ -356,7 +379,8 @@ func (fs *FS) CopyFileRange(cancel <-chan struct{}, input *fuse.CopyFileRangeIn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FS) Flush(cancel <-chan struct{}, input *fuse.FlushIn) fuse.Status {
|
func (fs *FS) Flush(cancel <-chan struct{}, input *fuse.FlushIn) fuse.Status {
|
||||||
panic("implement me")
|
// FIXME: maybe we need to write data here.
|
||||||
|
return fuse.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FS) Fsync(cancel <-chan struct{}, input *fuse.FsyncIn) (code fuse.Status) {
|
func (fs *FS) Fsync(cancel <-chan struct{}, input *fuse.FsyncIn) (code fuse.Status) {
|
||||||
|
|
|
@ -2,9 +2,11 @@ package vfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/beyondstorage/beyond-fs/meta"
|
|
||||||
"github.com/beyondstorage/go-storage/v4/types"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/beyondstorage/go-storage/v4/types"
|
||||||
|
|
||||||
|
"github.com/beyondstorage/beyond-fs/meta"
|
||||||
)
|
)
|
||||||
|
|
||||||
type dirHandleMap struct {
|
type dirHandleMap struct {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package vfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/beyondstorage/beyond-fs/meta"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fileHandleMap struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
m map[uint64]*FileHandle
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFileHandleMap() *fileHandleMap {
|
||||||
|
return &fileHandleMap{
|
||||||
|
m: make(map[uint64]*FileHandle),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fhm *fileHandleMap) Get(id uint64) *FileHandle {
|
||||||
|
fhm.lock.Lock()
|
||||||
|
defer fhm.lock.Unlock()
|
||||||
|
|
||||||
|
return fhm.m[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fhm *fileHandleMap) Set(id uint64, dh *FileHandle) {
|
||||||
|
fhm.lock.Lock()
|
||||||
|
defer fhm.lock.Unlock()
|
||||||
|
|
||||||
|
fhm.m[id] = dh
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fhm *fileHandleMap) Delete(id uint64) {
|
||||||
|
fhm.lock.Lock()
|
||||||
|
defer fhm.lock.Unlock()
|
||||||
|
|
||||||
|
delete(fhm.m, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileHandle struct {
|
||||||
|
ID uint64
|
||||||
|
|
||||||
|
ino *Inode
|
||||||
|
fs *FS
|
||||||
|
meta meta.Service
|
||||||
|
}
|
57
vfs/fs.go
57
vfs/fs.go
|
@ -1,7 +1,9 @@
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
_ "github.com/beyondstorage/go-service-fs/v3"
|
_ "github.com/beyondstorage/go-service-fs/v3"
|
||||||
_ "github.com/beyondstorage/go-service-s3/v2"
|
_ "github.com/beyondstorage/go-service-s3/v2"
|
||||||
|
@ -32,6 +34,7 @@ type FS struct {
|
||||||
meta meta.Service
|
meta meta.Service
|
||||||
|
|
||||||
dhm *dirHandleMap
|
dhm *dirHandleMap
|
||||||
|
fhm *fileHandleMap
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +60,7 @@ func NewFS(cfg *Config) (fs *FS, err error) {
|
||||||
meta: metaSrv,
|
meta: metaSrv,
|
||||||
|
|
||||||
dhm: newDirHandleMap(),
|
dhm: newDirHandleMap(),
|
||||||
|
fhm: newFileHandleMap(),
|
||||||
logger: cfg.Logger,
|
logger: cfg.Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +75,39 @@ func NewFS(cfg *Config) (fs *FS, err error) {
|
||||||
return fs, err
|
return fs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *FS) Create(parent uint64, name string) (ino *Inode, fh *FileHandle, err error) {
|
||||||
|
// FIXME: we need to handle file exists.
|
||||||
|
p, err := fs.GetInode(parent)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
path := p.GetEntryPath(name)
|
||||||
|
_, err = fs.s.Write(path, bytes.NewReader([]byte{}), 0)
|
||||||
|
if err != nil {
|
||||||
|
fs.logger.Error("write", zap.String("path", path), zap.Error(err))
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
o := fs.s.Create(path)
|
||||||
|
o.Path = path
|
||||||
|
o.Mode = types.ModeRead
|
||||||
|
o.SetContentLength(0)
|
||||||
|
o.SetLastModified(time.Now())
|
||||||
|
|
||||||
|
ino = newInode(parent, o)
|
||||||
|
err = fs.SetInode(ino)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fh, err = fs.CreateFileHandle(ino)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *FS) Delete(parent uint64, name string) (err error) {
|
func (fs *FS) Delete(parent uint64, name string) (err error) {
|
||||||
ino, err := fs.GetEntry(parent, name)
|
ino, err := fs.GetEntry(parent, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -95,6 +132,26 @@ func (fs *FS) DeleteDir(path string) (err error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *FS) CreateFileHandle(ino *Inode) (fh *FileHandle, err error) {
|
||||||
|
fh = &FileHandle{
|
||||||
|
ID: NextHandle(),
|
||||||
|
ino: ino,
|
||||||
|
fs: fs,
|
||||||
|
meta: fs.meta,
|
||||||
|
}
|
||||||
|
fs.fhm.Set(fh.ID, fh)
|
||||||
|
return fh, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FS) GetFileHandle(fhid uint64) (fh *FileHandle, err error) {
|
||||||
|
return fs.fhm.Get(fhid), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FS) DeleteFileHandle(fhid uint64) (err error) {
|
||||||
|
fs.fhm.Delete(fhid)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (fs *FS) CreateDirHandle(ino *Inode) (dh *DirHandle, err error) {
|
func (fs *FS) CreateDirHandle(ino *Inode) (dh *DirHandle, err error) {
|
||||||
it, err := fs.s.List(ino.Path, pairs.WithListMode(types.ListModeDir))
|
it, err := fs.s.List(ino.Path, pairs.WithListMode(types.ListModeDir))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
11
vfs/inode.go
11
vfs/inode.go
|
@ -1,10 +1,12 @@
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/beyondstorage/go-storage/v4/types"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/beyondstorage/go-storage/v4/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run github.com/tinylib/msgp
|
//go:generate go run github.com/tinylib/msgp
|
||||||
|
@ -27,6 +29,13 @@ func (ino *Inode) IsDir() bool {
|
||||||
return ino.Mode&uint32(os.ModeDir) != 0
|
return ino.Mode&uint32(os.ModeDir) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ino *Inode) GetEntryPath(name string) string {
|
||||||
|
if ino.Path == "" {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s/%s", ino.Path, name)
|
||||||
|
}
|
||||||
|
|
||||||
func newInode(parent uint64, o *types.Object) *Inode {
|
func newInode(parent uint64, o *types.Object) *Inode {
|
||||||
ino := &Inode{
|
ino := &Inode{
|
||||||
ID: NextInodeID(),
|
ID: NextInodeID(),
|
||||||
|
|
Loading…
Reference in New Issue