Commit 68d48f61 authored by Aaron Jacobs's avatar Aaron Jacobs

Added an Nlink field and updated tests and samples to use it.

For #2.
parents c1c54788 cd4980bf
......@@ -265,6 +265,9 @@ func init() {
type InodeAttributes struct {
Size uint64
// The number of incoming hard links to this inode.
Nlink uint64
// The mode of the inode. This is exposed to the user in e.g. the result of
// fstat(2).
//
......
......@@ -164,6 +164,7 @@ func (fs *cachingFS) rootAttrs() fuse.InodeAttributes {
// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) fooAttrs() fuse.InodeAttributes {
return fuse.InodeAttributes{
Nlink: 1,
Size: FooSize,
Mode: 0777,
Mtime: fs.mtime,
......@@ -173,6 +174,7 @@ func (fs *cachingFS) fooAttrs() fuse.InodeAttributes {
// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) dirAttrs() fuse.InodeAttributes {
return fuse.InodeAttributes{
Nlink: 1,
Mode: os.ModeDir | 0777,
Mtime: fs.mtime,
}
......@@ -181,6 +183,7 @@ func (fs *cachingFS) dirAttrs() fuse.InodeAttributes {
// LOCKS_REQUIRED(fs.mu)
func (fs *cachingFS) barAttrs() fuse.InodeAttributes {
return fuse.InodeAttributes{
Nlink: 1,
Size: BarSize,
Mode: 0777,
Mtime: fs.mtime,
......
......@@ -201,6 +201,7 @@ func (t *BasicsTest) StatFoo() {
ExpectThat(fi.ModTime(), timeutil.TimeEq(t.initialMtime))
ExpectFalse(fi.IsDir())
ExpectEq(t.fs.FooID(), getInodeID(fi))
ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)
}
func (t *BasicsTest) StatDir() {
......@@ -212,6 +213,7 @@ func (t *BasicsTest) StatDir() {
ExpectThat(fi.ModTime(), timeutil.TimeEq(t.initialMtime))
ExpectTrue(fi.IsDir())
ExpectEq(t.fs.DirID(), getInodeID(fi))
ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)
}
func (t *BasicsTest) StatBar() {
......@@ -224,6 +226,7 @@ func (t *BasicsTest) StatBar() {
ExpectThat(fi.ModTime(), timeutil.TimeEq(t.initialMtime))
ExpectFalse(fi.IsDir())
ExpectEq(t.fs.BarID(), getInodeID(fi))
ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)
}
////////////////////////////////////////////////////////////////////////
......
......@@ -61,7 +61,8 @@ var gInodeInfo = map[fuse.InodeID]inodeInfo{
// root
rootInode: inodeInfo{
attributes: fuse.InodeAttributes{
Mode: 0555 | os.ModeDir,
Nlink: 1,
Mode: 0555 | os.ModeDir,
},
dir: true,
children: []fuseutil.Dirent{
......@@ -83,15 +84,17 @@ var gInodeInfo = map[fuse.InodeID]inodeInfo{
// hello
helloInode: inodeInfo{
attributes: fuse.InodeAttributes{
Mode: 0444,
Size: uint64(len("Hello, world!")),
Nlink: 1,
Mode: 0444,
Size: uint64(len("Hello, world!")),
},
},
// dir
dirInode: inodeInfo{
attributes: fuse.InodeAttributes{
Mode: 0555 | os.ModeDir,
Nlink: 1,
Mode: 0555 | os.ModeDir,
},
dir: true,
children: []fuseutil.Dirent{
......@@ -107,8 +110,9 @@ var gInodeInfo = map[fuse.InodeID]inodeInfo{
// world
worldInode: inodeInfo{
attributes: fuse.InodeAttributes{
Mode: 0444,
Size: uint64(len("Hello, world!")),
Nlink: 1,
Mode: 0444,
Size: uint64(len("Hello, world!")),
},
},
}
......
......@@ -21,6 +21,7 @@ import (
"os"
"path"
"strings"
"syscall"
"testing"
"time"
......@@ -158,6 +159,7 @@ func (t *HelloFSTest) Stat_Hello() {
ExpectEq(0444, fi.Mode())
ExpectEq(0, t.clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime())
ExpectFalse(fi.IsDir())
ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)
}
func (t *HelloFSTest) Stat_Dir() {
......@@ -169,6 +171,7 @@ func (t *HelloFSTest) Stat_Dir() {
ExpectEq(0555|os.ModeDir, fi.Mode())
ExpectEq(0, t.clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime())
ExpectTrue(fi.IsDir())
ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)
}
func (t *HelloFSTest) Stat_World() {
......@@ -180,6 +183,7 @@ func (t *HelloFSTest) Stat_World() {
ExpectEq(0444, fi.Mode())
ExpectEq(0, t.clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime())
ExpectFalse(fi.IsDir())
ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)
}
func (t *HelloFSTest) Stat_NonExistent() {
......
......@@ -305,9 +305,10 @@ func (fs *memFS) MkDir(
// Set up attributes from the child, using the credentials of the calling
// process as owner (matching inode_init_owner, cf. http://goo.gl/5qavg8).
childAttrs := fuse.InodeAttributes{
Mode: req.Mode,
Uid: req.Header.Uid,
Gid: req.Header.Gid,
Nlink: 1,
Mode: req.Mode,
Uid: req.Header.Uid,
Gid: req.Header.Gid,
}
// Allocate a child.
......@@ -345,6 +346,7 @@ func (fs *memFS) CreateFile(
// process as owner (matching inode_init_owner, cf. http://goo.gl/5qavg8).
now := fs.clock.Now()
childAttrs := fuse.InodeAttributes{
Nlink: 1,
Mode: req.Mode,
Atime: now,
Mtime: now,
......@@ -408,7 +410,7 @@ func (fs *memFS) RmDir(
parent.RemoveChild(req.Name)
// Mark the child as unlinked.
child.linkCount--
child.attributes.Nlink--
return
}
......@@ -440,7 +442,7 @@ func (fs *memFS) Unlink(
parent.RemoveChild(req.Name)
// Mark the child as unlinked.
child.linkCount--
child.attributes.Nlink--
return
}
......
......@@ -47,13 +47,6 @@ type inode struct {
mu syncutil.InvariantMutex
// The number of times this inode is linked into a parent directory. This may
// be zero if the inode has been unlinked but not yet forgotten, because some
// process still has an open file handle.
//
// INVARIANT: linkCount >= 0
linkCount int // GUARDED_BY(mu)
// The current attributes of this inode.
//
// INVARIANT: No non-permission mode bits are set besides os.ModeDir
......@@ -87,7 +80,6 @@ type inode struct {
// Create a new inode with the supplied attributes, which need not contain
// time-related information (the inode object will take care of that).
// Initially the link count is one.
func newInode(
clock timeutil.Clock,
attrs fuse.InodeAttributes) (in *inode) {
......@@ -99,7 +91,6 @@ func newInode(
// Create the object.
in = &inode{
clock: clock,
linkCount: 1,
dir: (attrs.Mode&os.ModeDir != 0),
attributes: attrs,
}
......@@ -109,11 +100,6 @@ func newInode(
}
func (inode *inode) checkInvariants() {
// Check the link count.
if inode.linkCount < 0 {
panic(fmt.Sprintf("Negative link count: %v", inode.linkCount))
}
// No non-permission mode bits should be set besides os.ModeDir.
if inode.attributes.Mode & ^(os.ModePerm|os.ModeDir) != 0 {
panic(fmt.Sprintf("Unexpected mode: %v", inode.attributes.Mode))
......
......@@ -602,9 +602,7 @@ func (t *MemFSTest) UnlinkFile_StillOpen() {
AssertEq(nil, err)
ExpectEq(4, fi.Size())
// TODO(jacobsa): Re-enable this assertion if the following issue is fixed:
// https://github.com/bazillion/fuse/issues/66
// ExpectEq(0, fi.Sys().(*syscall.Stat_t).Nlink)
ExpectEq(0, fi.Sys().(*syscall.Stat_t).Nlink)
// The contents should still be available.
buf := make([]byte, 1024)
......@@ -724,10 +722,7 @@ func (t *MemFSTest) Rmdir_OpenedForReading() {
ExpectEq("dir", fi.Name())
ExpectEq(0, fi.ModTime().Sub(createTime))
// TODO(jacobsa): Re-enable this assertion if the following issue is fixed:
// https://github.com/bazillion/fuse/issues/66
// ExpectEq(0, fi.Sys().(*syscall.Stat_t).Nlink)
ExpectEq(0, fi.Sys().(*syscall.Stat_t).Nlink)
// Attempt to read from the directory. This shouldn't see any junk from the
// new directory. It should either succeed with an empty result or should
......
......@@ -504,6 +504,7 @@ func convertAttributes(inode InodeID, attr InodeAttributes) bazilfuse.Attr {
Inode: uint64(inode),
Size: attr.Size,
Mode: attr.Mode,
Nlink: uint32(attr.Nlink),
Atime: attr.Atime,
Mtime: attr.Mtime,
Ctime: attr.Ctime,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment