Some work on getting cross-version file operations working

This commit is contained in:
Alex Yatskov 2015-06-19 19:20:11 +09:00
parent 00d1c81a6c
commit aeb0822714
3 changed files with 86 additions and 67 deletions

28
dir.go
View File

@ -81,29 +81,29 @@ func (vd *verDir) createDir(name string) (*verDir, error) {
node := newVerNode(childPath, vd.node.ver, nil, NodeFlagDir|NodeFlagVer) node := newVerNode(childPath, vd.node.ver, nil, NodeFlagDir|NodeFlagVer)
dir := newVerDir(node, vd) dir := newVerDir(node, vd)
vd.dirs[name] = dir vd.dirs[name] = dir
node.ver.meta.createNode(node.path) node.ver.meta.createNode(node.path)
return dir, nil return dir, nil
} }
func (vd *verDir) createFile(name string, flags int) (*verFile, error) { func (vd *verDir) createFile(name string, flags fuse.OpenFlags) (*verFile, *verFileHandle, error) {
if err := vd.version(); err != nil { if err := vd.version(); err != nil {
return nil, err return nil, nil, err
} }
childPath := path.Join(vd.node.path, name) childPath := path.Join(vd.node.path, name)
handle, err := os.OpenFile(vd.node.ver.rebasePath(childPath), flags, 0644)
if err != nil {
return nil, err
}
node := newVerNode(childPath, vd.node.ver, nil, NodeFlagVer) node := newVerNode(childPath, vd.node.ver, nil, NodeFlagVer)
file := newVerFile(node, vd) file := newVerFile(node, vd)
file.handle = handle
vd.files[name] = file
handle, err := file.open(flags)
if err != nil {
return nil, nil, err
}
vd.files[name] = file
node.ver.meta.createNode(node.path) node.ver.meta.createNode(node.path)
return file, nil
return file, handle, nil
} }
// Node // Node
@ -137,9 +137,11 @@ func (vd *verDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fus
} }
} else if req.Mode.IsRegular() { } else if req.Mode.IsRegular() {
var file *verFile var file *verFile
if file, err = vd.createFile(req.Name, int(req.Flags)); err == nil { var vfh *verFileHandle
if file, vfh, err = vd.createFile(req.Name, req.Flags); err == nil {
node = file node = file
handle = file handle = handle
resp.Handle = vfh.id
} }
} else { } else {
err = errors.New("unsupported filetype") err = errors.New("unsupported filetype")

111
file.go
View File

@ -23,7 +23,6 @@
package main package main
import ( import (
"errors"
"os" "os"
"bazil.org/fuse" "bazil.org/fuse"
@ -39,11 +38,11 @@ type verFile struct {
node *verNode node *verNode
inode uint64 inode uint64
parent *verDir parent *verDir
handle *os.File handles map[fuse.HandleID]*verFileHandle
} }
func newVerFile(node *verNode, parent *verDir) *verFile { func newVerFile(node *verNode, parent *verDir) *verFile {
return &verFile{node, allocInode(), parent, nil} return &verFile{node, allocInode(), parent, make(map[fuse.HandleID]*verFileHandle)}
} }
func (vf *verFile) version() error { func (vf *verFile) version() error {
@ -63,6 +62,30 @@ func (vf *verFile) version() error {
return nil return nil
} }
func (vf *verFile) open(flags fuse.OpenFlags) (*verFileHandle, error) {
if !flags.IsReadOnly() {
if err := vf.version(); err != nil {
return nil, err
}
}
path := vf.node.rebasedPath()
handle, err := os.OpenFile(path, int(flags), 0644)
if err != nil {
return nil, err
}
id := fuse.HandleID(allocHandleId())
verHandle := &verFileHandle{vf, path, handle, id}
vf.handles[id] = verHandle
return verHandle, nil
}
func (vf *verFile) release(handle fuse.HandleID) {
delete(vf.handles, handle)
}
// Node // Node
func (vf *verFile) Attr(ctx context.Context, attr *fuse.Attr) error { func (vf *verFile) Attr(ctx context.Context, attr *fuse.Attr) error {
vf.node.attr(attr) vf.node.attr(attr)
@ -82,54 +105,41 @@ func (vf *verFile) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *
// NodeOpener // NodeOpener
func (vf *verFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) { func (vf *verFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
if vf.handle != nil { handle, err := vf.open(req.Flags)
return nil, errors.New("attempted to open already opened file")
}
if !req.Flags.IsReadOnly() {
if err := vf.version(); err != nil {
return nil, err
}
}
handle, err := os.OpenFile(vf.node.rebasedPath(), int(req.Flags), 0644)
if err != nil { if err != nil {
return nil, err return nil, err
} }
vf.handle = handle resp.Handle = handle.id
return vf, nil return handle, nil
}
// HandleReleaser
func (vf *verFile) Release(ctx context.Context, req *fuse.ReleaseRequest) error {
if vf.handle == nil {
return errors.New("attempted to release unopened file")
}
vf.handle.Close()
vf.handle = nil
return nil
} }
// NodeFsyncer // NodeFsyncer
func (vf *verFile) Fsync(ctx context.Context, req *fuse.FsyncRequest) error { func (vf *verFile) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
if vf.handle == nil { for _, vfh := range vf.handles {
return errors.New("attempted to sync unopened file") if err := vfh.handle.Sync(); err != nil {
return err
}
} }
return vf.handle.Sync() return nil
}
//
// verFileHandle
//
type verFileHandle struct {
node *verFile
path string
handle *os.File
id fuse.HandleID
} }
// HandleReader // HandleReader
func (vf *verFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { func (vfh *verFileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
if vf.handle == nil {
return errors.New("attempted to read from unopened file")
}
resp.Data = make([]byte, req.Size) resp.Data = make([]byte, req.Size)
if _, err := vf.handle.ReadAt(resp.Data, req.Offset); err != nil { if _, err := vfh.handle.ReadAt(resp.Data, req.Offset); err != nil {
return err return err
} }
@ -137,18 +147,14 @@ func (vf *verFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.R
} }
// HandleReadAller // HandleReadAller
func (vf *verFile) ReadAll(ctx context.Context) ([]byte, error) { func (vfh *verFileHandle) ReadAll(ctx context.Context) ([]byte, error) {
if vf.handle == nil { info, err := os.Stat(vfh.path)
return nil, errors.New("attempted to read from unopened file")
}
info, err := os.Stat(vf.node.rebasedPath())
if err != nil { if err != nil {
return nil, err return nil, err
} }
data := make([]byte, info.Size()) data := make([]byte, info.Size())
if _, err := vf.handle.Read(data); err != nil { if _, err := vfh.handle.Read(data); err != nil {
return nil, err return nil, err
} }
@ -156,12 +162,8 @@ func (vf *verFile) ReadAll(ctx context.Context) ([]byte, error) {
} }
// HandleWriter // HandleWriter
func (vf *verFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error { func (vfh *verFileHandle) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
if vf.handle == nil { size, err := vfh.handle.WriteAt(req.Data, req.Offset)
return errors.New("attempted to write to unopened file")
}
size, err := vf.handle.WriteAt(req.Data, req.Offset)
if err != nil { if err != nil {
return err return err
} }
@ -169,3 +171,12 @@ func (vf *verFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse
resp.Size = size resp.Size = size
return nil return nil
} }
// HandleReleaser
func (vfh *verFileHandle) Release(ctx context.Context, req *fuse.ReleaseRequest) error {
vfh.handle.Close()
vfh.handle = nil
vfh.node.release(req.Handle)
return nil
}

View File

@ -32,14 +32,20 @@ import (
"strconv" "strconv"
"sync/atomic" "sync/atomic"
"time" "time"
"bazil.org/fuse"
) )
var inodeCnt uint64 var inodeCnt, handleCnt uint64
func allocInode() uint64 { func allocInode() uint64 {
return atomic.AddUint64(&inodeCnt, 1) return atomic.AddUint64(&inodeCnt, 1)
} }
func allocHandleId() fuse.HandleID {
return fuse.HandleID(atomic.AddUint64(&handleCnt, 1))
}
func copyFile(src, dst string) (int64, error) { func copyFile(src, dst string) (int64, error) {
srcFile, err := os.Open(src) srcFile, err := os.Open(src)
if err != nil { if err != nil {