Work in progress

This commit is contained in:
Alex Yatskov 2015-06-17 16:41:43 +09:00
parent 4de3dcc799
commit 466ac8ec26
5 changed files with 80 additions and 116 deletions

View File

@ -57,7 +57,7 @@ func (this *database) load(dir string) error {
} }
if err := buildNewVersion(this.base); err != nil { if err := buildNewVersion(this.base); err != nil {
return nil return err
} }
this.vers, err = this.buildVersions(this.base) this.vers, err = this.buildVersions(this.base)
@ -109,10 +109,10 @@ func (this *database) buildVersions(base string) (versionList, error) {
sort.Sort(vers) sort.Sort(vers)
var parentVer *version var parVer *version
for _, ver := range vers { for _, ver := range vers {
ver.parent = parentVer ver.parent = parVer
parentVer = ver parVer = ver
} }
return vers, nil return vers, nil

38
dir.go
View File

@ -51,23 +51,17 @@ func newVersionedDir(node *versionedNode, parent *versionedDir) *versionedDir {
} }
func (this *versionedDir) version() error { func (this *versionedDir) version() error {
if this.node.versioned { if this.node.flags&NodeFlagVer == NodeFlagVer {
return nil return nil
} }
version := this.node.ver.db.lastVersion() node := newVersionedNode(this.node.path, this.node.ver.db.lastVersion(), this.node, NodeFlagDir|NodeFlagVer)
if err := os.MkdirAll(version.rebasePath(this.node.path), 0755); err != nil {
if err := os.MkdirAll(node.rebasedPath(), 0755); err != nil {
return err return err
} }
node, err := newVersionedNode(this.node.path, version, this.node)
if err != nil {
return err
}
node.versioned = true
this.node = node this.node = node
return nil return nil
} }
@ -81,11 +75,7 @@ func (this *versionedDir) createDir(name string) (*versionedDir, error) {
return nil, err return nil, err
} }
node, err := newVersionedNode(childPath, this.node.ver, nil) node := newVersionedNode(childPath, this.node.ver, nil, NodeFlagDir)
if err != nil {
return nil, err
}
dir := newVersionedDir(node, this) dir := newVersionedDir(node, this)
this.dirs[name] = dir this.dirs[name] = dir
@ -103,11 +93,7 @@ func (this *versionedDir) createFile(name string, flags int) (*versionedFile, er
return nil, err return nil, err
} }
node, err := newVersionedNode(childPath, this.node.ver, nil) node := newVersionedNode(childPath, this.node.ver, nil, 0)
if err != nil {
return nil, err
}
file := newVersionedFile(node, this) file := newVersionedFile(node, this)
file.handle = handle file.handle = handle
this.files[name] = file this.files[name] = file
@ -116,18 +102,16 @@ func (this *versionedDir) createFile(name string, flags int) (*versionedFile, er
} }
func (this *versionedDir) Attr(ctx context.Context, attr *fuse.Attr) error { func (this *versionedDir) Attr(ctx context.Context, attr *fuse.Attr) error {
this.node.attr(attr) if err := this.node.attr(attr); err != nil {
return err
}
attr.Inode = this.inode attr.Inode = this.inode
return nil return nil
} }
func (this *versionedDir) Getattr(ctx context.Context, req *fuse.GetattrRequest, resp *fuse.GetattrResponse) error { func (this *versionedDir) Getattr(ctx context.Context, req *fuse.GetattrRequest, resp *fuse.GetattrResponse) error {
if err := this.node.sync(); err != nil { return this.Attr(ctx, &resp.Attr)
return err
}
this.Attr(ctx, &resp.Attr)
return nil
} }
func (this *versionedDir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error { func (this *versionedDir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {

28
file.go
View File

@ -47,23 +47,17 @@ func newVersionedFile(node *versionedNode, parent *versionedDir) *versionedFile
} }
func (this *versionedFile) version() error { func (this *versionedFile) version() error {
if this.node.versioned { if this.node.flags&NodeFlagVer == NodeFlagVer {
return nil return nil
} }
version := this.node.ver.db.lastVersion() node := newVersionedNode(this.node.path, this.node.ver.db.lastVersion(), this.node, NodeFlagVer)
if _, err := fileCopy(this.node.rebasedPath(), version.rebasePath(this.node.path)); err != nil {
if _, err := fileCopy(this.node.rebasedPath(), node.rebasedPath()); err != nil {
return err return err
} }
node, err := newVersionedNode(this.node.path, version, this.node)
if err != nil {
return err
}
node.versioned = true
this.node = node this.node = node
return nil return nil
} }
@ -94,12 +88,7 @@ func (this *versionedFile) Attr(ctx context.Context, attr *fuse.Attr) error {
} }
func (this *versionedFile) Getattr(ctx context.Context, req *fuse.GetattrRequest, resp *fuse.GetattrResponse) error { func (this *versionedFile) Getattr(ctx context.Context, req *fuse.GetattrRequest, resp *fuse.GetattrResponse) error {
if err := this.node.sync(); err != nil { return this.Attr(ctx, &resp.Attr)
return err
}
this.Attr(ctx, &resp.Attr)
return nil
} }
func (this *versionedFile) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error { func (this *versionedFile) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {
@ -124,7 +113,12 @@ func (this *versionedFile) ReadAll(ctx context.Context) ([]byte, error) {
return nil, errors.New("attempted to read from unopened file") return nil, errors.New("attempted to read from unopened file")
} }
data := make([]byte, this.node.info.Size()) info, err := os.Stat(this.node.rebasedPath())
if err != nil {
return nil, err
}
data := make([]byte, info.Size())
if _, err := this.handle.Read(data); err != nil { if _, err := this.handle.Read(data); err != nil {
return nil, err return nil, err
} }

93
node.go
View File

@ -33,84 +33,68 @@ import (
// versionedNode // versionedNode
// //
const (
NodeFlagDir = 1 << iota
NodeFlagVer
)
type versionedNode struct { type versionedNode struct {
path string path string
info os.FileInfo ver *version
ver *version parent *versionedNode
parent *versionedNode flags int
versioned bool
} }
func newVersionedNode(path string, ver *version, parent *versionedNode) (*versionedNode, error) { func newVersionedNode(path string, ver *version, parent *versionedNode, flags int) *versionedNode {
info, err := os.Stat(ver.rebasePath(path)) return &versionedNode{path, ver, parent, flags}
if err != nil {
return nil, err
}
return newVersionedNodeStat(path, ver, parent, info), nil
}
func newVersionedNodeStat(path string, ver *version, parent *versionedNode, info os.FileInfo) *versionedNode {
return &versionedNode{path, info, ver, parent, false}
} }
func (this *versionedNode) setAttr(req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error { func (this *versionedNode) setAttr(req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {
if err := this.attr(&resp.Attr); err != nil {
return err
}
if req.Valid&fuse.SetattrMode != 0 { if req.Valid&fuse.SetattrMode != 0 {
if err := os.Chmod(this.rebasedPath(), req.Mode); err != nil { if err := os.Chmod(this.rebasedPath(), req.Mode); err != nil {
return err return err
} }
resp.Attr.Mode = req.Mode
} }
if setGid, setUid := req.Valid&fuse.SetattrGid != 0, req.Valid&fuse.SetattrUid != 0; setGid || setUid { if setGid, setUid := req.Valid&fuse.SetattrGid != 0, req.Valid&fuse.SetattrUid != 0; setGid || setUid {
gid, uid := this.owner()
if setGid { if setGid {
gid = req.Gid resp.Attr.Gid = req.Gid
} }
if setUid { if setUid {
uid = req.Uid resp.Attr.Uid = req.Uid
} }
if err := os.Chown(this.rebasedPath(), int(uid), int(gid)); err != nil { if err := os.Chown(this.rebasedPath(), int(resp.Attr.Uid), int(resp.Attr.Gid)); err != nil {
return err return err
} }
} }
if setAtime, setMtime := req.Valid&fuse.SetattrAtime != 0, req.Valid&fuse.SetattrMtime != 0; setAtime || setMtime { if setAtime, setMtime := req.Valid&fuse.SetattrAtime != 0, req.Valid&fuse.SetattrMtime != 0; setAtime || setMtime {
atime, mtime, _ := this.times()
if setAtime { if setAtime {
atime = req.Atime resp.Attr.Atime = req.Atime
} }
if setMtime { if setMtime {
mtime = req.Mtime resp.Attr.Mtime = req.Mtime
} }
if err := os.Chtimes(this.rebasedPath(), atime, mtime); err != nil { if err := os.Chtimes(this.rebasedPath(), resp.Attr.Atime, resp.Attr.Mtime); err != nil {
return err return err
} }
} }
if err := this.sync(); err != nil {
return err
}
this.attr(&resp.Attr)
return nil
}
func (this *versionedNode) sync() error {
info, err := os.Stat(this.rebasedPath())
if err != nil {
return err
}
this.info = info
return nil return nil
} }
func (this *versionedNode) remove() error { func (this *versionedNode) remove() error {
ver := this.ver ver := this.ver
if this.versioned { if this.flags&NodeFlagVer == NodeFlagVer {
if err := os.Remove(this.rebasedPath()); err != nil { if err := os.Remove(this.rebasedPath()); err != nil {
return err return err
} }
@ -126,33 +110,36 @@ func (this *versionedNode) rebasedPath() string {
return this.ver.rebasePath(this.path) return this.ver.rebasePath(this.path)
} }
func (this *versionedNode) owner() (gid, uid uint32) { func (this *versionedNode) owner(stat syscall.Stat_t) (gid, uid uint32) {
stat := this.info.Sys().(*syscall.Stat_t)
gid = stat.Gid gid = stat.Gid
uid = stat.Uid uid = stat.Uid
return return
} }
func (this *versionedNode) times() (atime, mtime, ctime time.Time) { func (this *versionedNode) times(stat syscall.Stat_t) (atime, mtime, ctime time.Time) {
stat := this.info.Sys().(*syscall.Stat_t)
atime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec)) atime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
mtime = this.info.ModTime() mtime = time.Unix(int64(stat.Mtim.Sec), int64(stat.Mtim.Nsec))
ctime = time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec)) ctime = time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec))
return return
} }
func (this *versionedNode) attr(attr *fuse.Attr) { func (this *versionedNode) attr(attr *fuse.Attr) error {
stat := this.info.Sys().(*syscall.Stat_t) info, err := os.Stat(this.rebasedPath())
if err != nil {
return err
}
attr.Size = uint64(this.info.Size()) stat := info.Sys().(*syscall.Stat_t)
attr.Size = uint64(stat.Size)
attr.Blocks = uint64(stat.Blocks) attr.Blocks = uint64(stat.Blocks)
attr.Atime, attr.Mtime, attr.Ctime = this.times() attr.Atime, attr.Mtime, attr.Ctime = this.times(*stat)
attr.Mode = this.info.Mode() attr.Mode = info.Mode()
attr.Nlink = uint32(stat.Nlink) attr.Nlink = uint32(stat.Nlink)
attr.Gid, attr.Uid = this.owner() attr.Gid, attr.Uid = this.owner(*stat)
attr.Rdev = uint32(stat.Rdev) attr.Rdev = uint32(stat.Rdev)
return nil
} }
// //

View File

@ -79,9 +79,15 @@ func (this *version) scanDir(path string) (versionedNodeMap, error) {
} }
for _, info := range infos { for _, info := range infos {
childFlags := 0
if info.IsDir() {
childFlags |= NodeFlagDir
}
childName := info.Name() childName := info.Name()
childPath := filepath.Join(path, childName) childPath := filepath.Join(path, childName)
ownNodes[childName] = newVersionedNodeStat(childPath, this, nil, info)
ownNodes[childName] = newVersionedNode(childPath, this, nil, childFlags)
} }
} }
@ -100,16 +106,16 @@ func (this *version) scanDir(path string) (versionedNodeMap, error) {
return baseNodes, nil return baseNodes, nil
} }
func (this *version) buildVerDir(dir *versionedDir) error { func (this *version) buildDir(dir *versionedDir) error {
nodes, err := this.scanDir(dir.node.path) nodes, err := this.scanDir(dir.node.path)
if err != nil { if err != nil {
return err return err
} }
for name, node := range nodes { for name, node := range nodes {
if node.info.IsDir() { if node.flags&NodeFlagDir == NodeFlagDir {
subDir := newVersionedDir(node, dir) subDir := newVersionedDir(node, dir)
if err := this.buildVerDir(subDir); err != nil { if err := this.buildDir(subDir); err != nil {
return err return err
} }
@ -123,13 +129,10 @@ func (this *version) buildVerDir(dir *versionedDir) error {
} }
func (this *version) resolve() error { func (this *version) resolve() error {
node, err := newVersionedNode("/", this, nil) node := newVersionedNode("/", this, nil, NodeFlagDir)
if err != nil {
return err
}
root := newVersionedDir(node, nil) root := newVersionedDir(node, nil)
if err = this.buildVerDir(root); err != nil {
if err := this.buildDir(root); err != nil {
return err return err
} }
@ -178,11 +181,7 @@ func (this versionList) Less(i, j int) bool {
func buildNewVersion(base string) error { func buildNewVersion(base string) error {
name := buildVerName(time.Now()) name := buildVerName(time.Now())
if err := os.MkdirAll(path.Join(base, name, "root"), 0755); err != nil {
if err := os.Mkdir(path.Join(base, name), 0755); err != nil {
return err
}
if err := os.Mkdir(path.Join(base, name, "root"), 0755); err != nil {
return err return err
} }