diff --git a/dir.go b/dir.go index a146d6c..81e2198 100644 --- a/dir.go +++ b/dir.go @@ -81,29 +81,29 @@ func (vd *verDir) createDir(name string) (*verDir, error) { node := newVerNode(childPath, vd.node.ver, nil, NodeFlagDir|NodeFlagVer) dir := newVerDir(node, vd) vd.dirs[name] = dir - node.ver.meta.createNode(node.path) + 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 { - return nil, err + return nil, nil, err } 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) 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) - return file, nil + + return file, handle, nil } // Node @@ -137,9 +137,11 @@ func (vd *verDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fus } } else if req.Mode.IsRegular() { 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 - handle = file + handle = handle + resp.Handle = vfh.id } } else { err = errors.New("unsupported filetype") diff --git a/file.go b/file.go index a051a3f..165a055 100644 --- a/file.go +++ b/file.go @@ -23,7 +23,6 @@ package main import ( - "errors" "os" "bazil.org/fuse" @@ -36,14 +35,14 @@ import ( // type verFile struct { - node *verNode - inode uint64 - parent *verDir - handle *os.File + node *verNode + inode uint64 + parent *verDir + handles map[fuse.HandleID]*verFileHandle } 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 { @@ -63,6 +62,30 @@ func (vf *verFile) version() error { 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 func (vf *verFile) Attr(ctx context.Context, attr *fuse.Attr) error { vf.node.attr(attr) @@ -82,54 +105,41 @@ func (vf *verFile) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp * // NodeOpener func (vf *verFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) { - if vf.handle != nil { - 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) + handle, err := vf.open(req.Flags) if err != nil { return nil, err } - vf.handle = handle - return vf, 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 + resp.Handle = handle.id + return handle, nil } // NodeFsyncer func (vf *verFile) Fsync(ctx context.Context, req *fuse.FsyncRequest) error { - if vf.handle == nil { - return errors.New("attempted to sync unopened file") + for _, vfh := range vf.handles { + 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 -func (vf *verFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { - if vf.handle == nil { - return errors.New("attempted to read from unopened file") - } - +func (vfh *verFileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { 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 } @@ -137,18 +147,14 @@ func (vf *verFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.R } // HandleReadAller -func (vf *verFile) ReadAll(ctx context.Context) ([]byte, error) { - if vf.handle == nil { - return nil, errors.New("attempted to read from unopened file") - } - - info, err := os.Stat(vf.node.rebasedPath()) +func (vfh *verFileHandle) ReadAll(ctx context.Context) ([]byte, error) { + info, err := os.Stat(vfh.path) if err != nil { return nil, err } data := make([]byte, info.Size()) - if _, err := vf.handle.Read(data); err != nil { + if _, err := vfh.handle.Read(data); err != nil { return nil, err } @@ -156,12 +162,8 @@ func (vf *verFile) ReadAll(ctx context.Context) ([]byte, error) { } // HandleWriter -func (vf *verFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error { - if vf.handle == nil { - return errors.New("attempted to write to unopened file") - } - - size, err := vf.handle.WriteAt(req.Data, req.Offset) +func (vfh *verFileHandle) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error { + size, err := vfh.handle.WriteAt(req.Data, req.Offset) if err != nil { return err } @@ -169,3 +171,12 @@ func (vf *verFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse resp.Size = size 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 +} diff --git a/util.go b/util.go index 1924432..68c2441 100644 --- a/util.go +++ b/util.go @@ -32,14 +32,20 @@ import ( "strconv" "sync/atomic" "time" + + "bazil.org/fuse" ) -var inodeCnt uint64 +var inodeCnt, handleCnt uint64 func allocInode() uint64 { return atomic.AddUint64(&inodeCnt, 1) } +func allocHandleId() fuse.HandleID { + return fuse.HandleID(atomic.AddUint64(&handleCnt, 1)) +} + func copyFile(src, dst string) (int64, error) { srcFile, err := os.Open(src) if err != nil {