From 0377d675ddbbee9c88ce02481f1c8dbf67710f43 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 6 Mar 2015 04:59:47 +1100 Subject: [PATCH 01/11] MemFSTest.CreateNewFile_InSubDir --- samples/memfs/memfs_test.go | 47 +++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/samples/memfs/memfs_test.go b/samples/memfs/memfs_test.go index 8b2afd9..24b3a6d 100644 --- a/samples/memfs/memfs_test.go +++ b/samples/memfs/memfs_test.go @@ -313,10 +313,10 @@ func (t *MemFSTest) CreateNewFile_InRoot() { var fi os.FileInfo var stat *syscall.Stat_t + // Write a file. fileName := path.Join(t.mfs.Dir(), "foo") const contents = "Hello\x00world" - // Write a file. createTime := t.clock.Now() err = ioutil.WriteFile(fileName, []byte(contents), 0400) AssertEq(nil, err) @@ -351,7 +351,50 @@ func (t *MemFSTest) CreateNewFile_InRoot() { } func (t *MemFSTest) CreateNewFile_InSubDir() { - AssertTrue(false, "TODO") + var err error + var fi os.FileInfo + var stat *syscall.Stat_t + + // Create a sub-dir. + dirName := path.Join(t.mfs.Dir(), "dir") + err = os.Mkdir(dirName, 0700) + AssertEq(nil, err) + + // Write a file. + fileName := path.Join(dirName, "foo") + const contents = "Hello\x00world" + + createTime := t.clock.Now() + err = ioutil.WriteFile(fileName, []byte(contents), 0400) + AssertEq(nil, err) + + // Simulate time advancing. + t.clock.AdvanceTime(time.Second) + + // Stat it. + fi, err = os.Stat(fileName) + stat = fi.Sys().(*syscall.Stat_t) + + AssertEq(nil, err) + ExpectEq("foo", fi.Name()) + ExpectEq(len(contents), fi.Size()) + ExpectEq(0400, fi.Mode()) + ExpectEq(0, fi.ModTime().Sub(createTime)) + ExpectFalse(fi.IsDir()) + + ExpectNe(0, stat.Ino) + ExpectEq(1, stat.Nlink) + ExpectEq(currentUid(), stat.Uid) + ExpectEq(currentGid(), stat.Gid) + ExpectEq(len(contents), stat.Size) + ExpectEq(0, timespecToTime(stat.Atimespec).Sub(createTime)) + ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) + ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) + + // Read it back. + slice, err := ioutil.ReadFile(fileName) + AssertEq(nil, err) + ExpectEq(contents, string(slice)) } func (t *MemFSTest) ModifyExistingFile_InRoot() { From b8ea62986f2d0261d16ca52801dd3840bc5b8a95 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 6 Mar 2015 05:02:20 +1100 Subject: [PATCH 02/11] Dumped in posix tests. --- samples/memfs/memfs_test.go | 178 +++++++++++++++++++++++++++++++++++- 1 file changed, 176 insertions(+), 2 deletions(-) diff --git a/samples/memfs/memfs_test.go b/samples/memfs/memfs_test.go index 24b3a6d..2529005 100644 --- a/samples/memfs/memfs_test.go +++ b/samples/memfs/memfs_test.go @@ -15,6 +15,7 @@ package memfs_test import ( + "io" "io/ioutil" "log" "os" @@ -79,6 +80,9 @@ func timespecToTime(ts syscall.Timespec) time.Time { type MemFSTest struct { clock timeutil.SimulatedClock mfs *fuse.MountedFileSystem + + // Files to close when tearing down. Nil entries are skipped. + toClose []io.Closer } var _ SetUpInterface = &MemFSTest{} @@ -110,6 +114,18 @@ func (t *MemFSTest) SetUp(ti *TestInfo) { } func (t *MemFSTest) TearDown() { + // Close any files we opened. + for _, c := range t.toClose { + if c == nil { + continue + } + + err := c.Close() + if err != nil { + panic(err) + } + } + // Unmount the file system. Try again on "resource busy" errors. delay := 10 * time.Millisecond for { @@ -558,6 +574,164 @@ func (t *MemFSTest) FileReadsAndWrites() { AssertTrue(false, "TODO") } -func (t *MemFSTest) FileReadsAndWrites_BeyondEOF() { - AssertTrue(false, "TODO") +func (t *MemFSTest) WriteOverlapsEndOfFile() { + var err error + var n int + + // Create a file. + f, err := os.Create(path.Join(t.mfs.Dir(), "foo")) + t.toClose = append(t.toClose, f) + AssertEq(nil, err) + + // Make it 4 bytes long. + err = f.Truncate(4) + AssertEq(nil, err) + + // Write the range [2, 6). + n, err = f.WriteAt([]byte("taco"), 2) + AssertEq(nil, err) + AssertEq(4, n) + + // Read the full contents of the file. + contents, err := ioutil.ReadAll(f) + AssertEq(nil, err) + ExpectEq("\x00\x00taco", string(contents)) +} + +func (t *MemFSTest) WriteStartsAtEndOfFile() { + var err error + var n int + + // Create a file. + f, err := os.Create(path.Join(t.mfs.Dir(), "foo")) + t.toClose = append(t.toClose, f) + AssertEq(nil, err) + + // Make it 2 bytes long. + err = f.Truncate(2) + AssertEq(nil, err) + + // Write the range [2, 6). + n, err = f.WriteAt([]byte("taco"), 2) + AssertEq(nil, err) + AssertEq(4, n) + + // Read the full contents of the file. + contents, err := ioutil.ReadAll(f) + AssertEq(nil, err) + ExpectEq("\x00\x00taco", string(contents)) +} + +func (t *MemFSTest) WriteStartsPastEndOfFile() { + var err error + var n int + + // Create a file. + f, err := os.Create(path.Join(t.mfs.Dir(), "foo")) + t.toClose = append(t.toClose, f) + AssertEq(nil, err) + + // Write the range [2, 6). + n, err = f.WriteAt([]byte("taco"), 2) + AssertEq(nil, err) + AssertEq(4, n) + + // Read the full contents of the file. + contents, err := ioutil.ReadAll(f) + AssertEq(nil, err) + ExpectEq("\x00\x00taco", string(contents)) +} + +func (t *MemFSTest) WriteAtDoesntChangeOffset_NotAppendMode() { + var err error + var n int + + // Create a file. + f, err := os.Create(path.Join(t.mfs.Dir(), "foo")) + t.toClose = append(t.toClose, f) + AssertEq(nil, err) + + // Make it 16 bytes long. + err = f.Truncate(16) + AssertEq(nil, err) + + // Seek to offset 4. + _, err = f.Seek(4, 0) + AssertEq(nil, err) + + // Write the range [10, 14). + n, err = f.WriteAt([]byte("taco"), 2) + AssertEq(nil, err) + AssertEq(4, n) + + // We should still be at offset 4. + offset, err := getFileOffset(f) + AssertEq(nil, err) + ExpectEq(4, offset) +} + +func (t *MemFSTest) WriteAtDoesntChangeOffset_AppendMode() { + var err error + var n int + + // Create a file in append mode. + f, err := os.OpenFile( + path.Join(t.mfs.Dir(), "foo"), + os.O_RDWR|os.O_APPEND|os.O_CREATE, + 0600) + + t.toClose = append(t.toClose, f) + AssertEq(nil, err) + + // Make it 16 bytes long. + err = f.Truncate(16) + AssertEq(nil, err) + + // Seek to offset 4. + _, err = f.Seek(4, 0) + AssertEq(nil, err) + + // Write the range [10, 14). + n, err = f.WriteAt([]byte("taco"), 2) + AssertEq(nil, err) + AssertEq(4, n) + + // We should still be at offset 4. + offset, err := getFileOffset(f) + AssertEq(nil, err) + ExpectEq(4, offset) +} + +func (t *MemFSTest) ReadsPastEndOfFile() { + var err error + var n int + buf := make([]byte, 1024) + + // Create a file. + f, err := os.Create(path.Join(t.mfs.Dir(), "foo")) + t.toClose = append(t.toClose, f) + AssertEq(nil, err) + + // Give it some contents. + n, err = f.Write([]byte("taco")) + AssertEq(nil, err) + AssertEq(4, n) + + // Read a range overlapping EOF. + n, err = f.ReadAt(buf[:4], 2) + AssertEq(io.EOF, err) + ExpectEq(2, n) + ExpectEq("co", string(buf[:n])) + + // Read a range starting at EOF. + n, err = f.ReadAt(buf[:4], 4) + AssertEq(io.EOF, err) + ExpectEq(0, n) + ExpectEq("", string(buf[:n])) + + // Read a range starting past EOF. + n, err = f.ReadAt(buf[:4], 100) + AssertEq(io.EOF, err) + ExpectEq(0, n) + ExpectEq("", string(buf[:n])) } From b814416bb2f2e7b7701644d39d65de8d7e6fac2d Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 6 Mar 2015 05:10:40 +1100 Subject: [PATCH 03/11] PosixTest.AppendMode --- samples/memfs/posix_test.go | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/samples/memfs/posix_test.go b/samples/memfs/posix_test.go index f48be48..4edb824 100644 --- a/samples/memfs/posix_test.go +++ b/samples/memfs/posix_test.go @@ -218,6 +218,52 @@ func (t *PosixTest) WriteAtDoesntChangeOffset_AppendMode() { ExpectEq(4, offset) } +func (t *PosixTest) AppendMode() { + var err error + var n int + var off int64 + buf := make([]byte, 1024) + + // Create a file with some contents. + fileName := path.Join(t.dir, "foo") + err = ioutil.WriteFile(fileName, []byte("Jello, "), 0600) + AssertEq(nil, err) + + // Open the file in append mode. + f, err := os.OpenFile(fileName, os.O_RDWR|os.O_APPEND, 0600) + t.toClose = append(t.toClose, f) + AssertEq(nil, err) + + // Seek to somewhere silly and then write. + off, err = f.Seek(2, 0) + AssertEq(nil, err) + AssertEq(2, off) + + n, err = f.Write([]byte("world!")) + AssertEq(nil, err) + AssertEq(6, n) + + // The offset should have been updated to point at the end of the file. + off, err = getFileOffset(f) + AssertEq(nil, err) + ExpectEq(13, off) + + // A random write should still work, without updating the offset. + n, err = f.WriteAt([]byte("H"), 0) + AssertEq(nil, err) + AssertEq(1, n) + + off, err = getFileOffset(f) + AssertEq(nil, err) + ExpectEq(13, off) + + // Read back the contents of the file, which should be correct even though we + // seeked to a silly place before writing the world part. + n, err = f.ReadAt(buf, 0) + AssertEq(io.EOF, err) + ExpectEq("Hello, world!", string(buf[:n])) +} + func (t *PosixTest) ReadsPastEndOfFile() { var err error var n int From 3a2b0a6de4e12a406836e32f72e614425aafcdc0 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 6 Mar 2015 05:14:07 +1100 Subject: [PATCH 04/11] MemFSTest.AppendMode --- samples/memfs/memfs_test.go | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/samples/memfs/memfs_test.go b/samples/memfs/memfs_test.go index 2529005..e471d96 100644 --- a/samples/memfs/memfs_test.go +++ b/samples/memfs/memfs_test.go @@ -702,6 +702,52 @@ func (t *MemFSTest) WriteAtDoesntChangeOffset_AppendMode() { ExpectEq(4, offset) } +func (t *MemFSTest) AppendMode() { + var err error + var n int + var off int64 + buf := make([]byte, 1024) + + // Create a file with some contents. + fileName := path.Join(t.mfs.Dir(), "foo") + err = ioutil.WriteFile(fileName, []byte("Jello, "), 0600) + AssertEq(nil, err) + + // Open the file in append mode. + f, err := os.OpenFile(fileName, os.O_RDWR|os.O_APPEND, 0600) + t.toClose = append(t.toClose, f) + AssertEq(nil, err) + + // Seek to somewhere silly and then write. + off, err = f.Seek(2, 0) + AssertEq(nil, err) + AssertEq(2, off) + + n, err = f.Write([]byte("world!")) + AssertEq(nil, err) + AssertEq(6, n) + + // The offset should have been updated to point at the end of the file. + off, err = getFileOffset(f) + AssertEq(nil, err) + ExpectEq(13, off) + + // A random write should still work, without updating the offset. + n, err = f.WriteAt([]byte("H"), 0) + AssertEq(nil, err) + AssertEq(1, n) + + off, err = getFileOffset(f) + AssertEq(nil, err) + ExpectEq(13, off) + + // Read back the contents of the file, which should be correct even though we + // seeked to a silly place before writing the world part. + n, err = f.ReadAt(buf, 0) + AssertEq(io.EOF, err) + ExpectEq("Hello, world!", string(buf[:n])) +} + func (t *MemFSTest) ReadsPastEndOfFile() { var err error var n int From 62bda89ca91961e245a4d3d2c0ca636bde62e178 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 6 Mar 2015 05:19:07 +1100 Subject: [PATCH 05/11] MemFSTest.ModifyExistingFile_InRoot --- samples/memfs/memfs_test.go | 53 ++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/samples/memfs/memfs_test.go b/samples/memfs/memfs_test.go index e471d96..2a53faa 100644 --- a/samples/memfs/memfs_test.go +++ b/samples/memfs/memfs_test.go @@ -414,7 +414,58 @@ func (t *MemFSTest) CreateNewFile_InSubDir() { } func (t *MemFSTest) ModifyExistingFile_InRoot() { - AssertTrue(false, "TODO") + var err error + var n int + var fi os.FileInfo + var stat *syscall.Stat_t + + // Write a file. + fileName := path.Join(t.mfs.Dir(), "foo") + + createTime := t.clock.Now() + err = ioutil.WriteFile(fileName, []byte("Jello, world!"), 0600) + AssertEq(nil, err) + + // Simulate time advancing. + t.clock.AdvanceTime(time.Second) + + // Open the file and modify it. + f, err := os.OpenFile(fileName, os.O_WRONLY, 0400) + t.toClose = append(t.toClose, f) + AssertEq(nil, err) + + modifyTime := t.clock.Now() + n, err = f.WriteAt([]byte("H"), 0) + AssertEq(nil, err) + AssertEq(1, n) + + // Simulate time advancing. + t.clock.AdvanceTime(time.Second) + + // Stat the file. + fi, err = os.Stat(fileName) + stat = fi.Sys().(*syscall.Stat_t) + + AssertEq(nil, err) + ExpectEq("foo", fi.Name()) + ExpectEq(len("Hello, world!"), fi.Size()) + ExpectEq(0600, fi.Mode()) + ExpectEq(0, fi.ModTime().Sub(modifyTime)) + ExpectFalse(fi.IsDir()) + + ExpectNe(0, stat.Ino) + ExpectEq(1, stat.Nlink) + ExpectEq(currentUid(), stat.Uid) + ExpectEq(currentGid(), stat.Gid) + ExpectEq(len("Hello, world!"), stat.Size) + ExpectEq(0, timespecToTime(stat.Atimespec).Sub(modifyTime)) + ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(modifyTime)) + ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) + + // Read the file back. + slice, err := ioutil.ReadFile(fileName) + AssertEq(nil, err) + ExpectEq("Hello, world!", string(slice)) } func (t *MemFSTest) ModifyExistingFile_InSubDir() { From ab18be237833e81fce17bda9232713626e0761c4 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 6 Mar 2015 05:23:44 +1100 Subject: [PATCH 06/11] Refactored inode time tracking. --- samples/memfs/fs.go | 15 +++++---------- samples/memfs/inode.go | 22 +++++++++++++++++++++- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/samples/memfs/fs.go b/samples/memfs/fs.go index 312963e..b65bc26 100644 --- a/samples/memfs/fs.go +++ b/samples/memfs/fs.go @@ -74,7 +74,7 @@ func NewMemFS( Mode: 0700 | os.ModeDir, } - fs.inodes[fuse.RootInodeID] = newInode(rootAttrs) + fs.inodes[fuse.RootInodeID] = newInode(clock, rootAttrs) // Set up invariant checking. fs.mu = syncutil.NewInvariantMutex(fs.checkInvariants) @@ -163,7 +163,7 @@ func (fs *memFS) getInodeForReadingOrDie(id fuse.InodeID) (inode *inode) { func (fs *memFS) allocateInode( attrs fuse.InodeAttributes) (id fuse.InodeID, inode *inode) { // Create and lock the inode. - inode = newInode(attrs) + inode = newInode(fs.clock, attrs) inode.mu.Lock() // Re-use a free ID if possible. Otherwise mint a new one. @@ -281,15 +281,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). - now := fs.clock.Now() childAttrs := fuse.InodeAttributes{ - Mode: req.Mode, - Atime: now, - Mtime: now, - Ctime: now, - Crtime: now, - Uid: req.Header.Uid, - Gid: req.Header.Gid, + Mode: req.Mode, + Uid: req.Header.Uid, + Gid: req.Header.Gid, } // Allocate a child. diff --git a/samples/memfs/inode.go b/samples/memfs/inode.go index 3ef46b6..477182c 100644 --- a/samples/memfs/inode.go +++ b/samples/memfs/inode.go @@ -22,6 +22,7 @@ import ( "github.com/jacobsa/fuse" "github.com/jacobsa/fuse/fuseutil" "github.com/jacobsa/gcloud/syncutil" + "github.com/jacobsa/gcsfuse/timeutil" ) // Common attributes for files and directories. @@ -30,6 +31,12 @@ import ( // been unlinked, including creating a new file. Make sure we don't screw up // and reuse an inode ID while it is still in use. type inode struct { + ///////////////////////// + // Dependencies + ///////////////////////// + + clock timeutil.Clock + ///////////////////////// // Constant data ///////////////////////// @@ -84,9 +91,22 @@ type inode struct { // Helpers //////////////////////////////////////////////////////////////////////// +// 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(attrs fuse.InodeAttributes) (in *inode) { +func newInode( + clock timeutil.Clock, + attrs fuse.InodeAttributes) (in *inode) { + // Update time info. + now := clock.Now() + attrs.Atime = now + attrs.Mtime = now + attrs.Ctime = now + attrs.Crtime = now + + // Create the object. in = &inode{ + clock: clock, linkCount: 1, dir: (attrs.Mode&os.ModeDir != 0), attributes: attrs, From 77fee50b808063e4816b2f57839606592b4c0c92 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 6 Mar 2015 05:25:25 +1100 Subject: [PATCH 07/11] Tightened up time tests. --- samples/memfs/memfs_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/samples/memfs/memfs_test.go b/samples/memfs/memfs_test.go index 2a53faa..a127d6e 100644 --- a/samples/memfs/memfs_test.go +++ b/samples/memfs/memfs_test.go @@ -195,6 +195,7 @@ func (t *MemFSTest) Mkdir_OneLevel() { ExpectEq(0, timespecToTime(stat.Atimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) + ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Read the directory. entries, err = ioutil.ReadDir(dirName) @@ -250,6 +251,7 @@ func (t *MemFSTest) Mkdir_TwoLevels() { ExpectEq(0, timespecToTime(stat.Atimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) + ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Read the directory. entries, err = ioutil.ReadDir(path.Join(t.mfs.Dir(), "parent/dir")) @@ -359,6 +361,7 @@ func (t *MemFSTest) CreateNewFile_InRoot() { ExpectEq(0, timespecToTime(stat.Atimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) + ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Read it back. slice, err := ioutil.ReadFile(fileName) @@ -406,6 +409,7 @@ func (t *MemFSTest) CreateNewFile_InSubDir() { ExpectEq(0, timespecToTime(stat.Atimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) + ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Read it back. slice, err := ioutil.ReadFile(fileName) @@ -461,6 +465,7 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() { ExpectEq(0, timespecToTime(stat.Atimespec).Sub(modifyTime)) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(modifyTime)) ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) + ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Read the file back. slice, err := ioutil.ReadFile(fileName) From 087f48cc728a532103a50c22e014faf912d05d02 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 6 Mar 2015 05:27:04 +1100 Subject: [PATCH 08/11] Update mtime on write. --- samples/memfs/inode.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/samples/memfs/inode.go b/samples/memfs/inode.go index 477182c..3561a36 100644 --- a/samples/memfs/inode.go +++ b/samples/memfs/inode.go @@ -344,6 +344,9 @@ func (inode *inode) WriteAt(p []byte, off int64) (n int, err error) { panic("WriteAt called on directory.") } + // Update the modification time. + inode.attributes.Mtime = inode.clock.Now() + // Ensure that the contents slice is long enough. newLen := int(off) + len(p) if len(inode.contents) < newLen { From ea53ba848843972dfece5e2c95e3e6d853782c6b Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 6 Mar 2015 05:27:35 +1100 Subject: [PATCH 09/11] Don't attempt to track atime. --- samples/memfs/inode.go | 1 - samples/memfs/memfs_test.go | 5 ----- 2 files changed, 6 deletions(-) diff --git a/samples/memfs/inode.go b/samples/memfs/inode.go index 3561a36..edbe983 100644 --- a/samples/memfs/inode.go +++ b/samples/memfs/inode.go @@ -99,7 +99,6 @@ func newInode( attrs fuse.InodeAttributes) (in *inode) { // Update time info. now := clock.Now() - attrs.Atime = now attrs.Mtime = now attrs.Ctime = now attrs.Crtime = now diff --git a/samples/memfs/memfs_test.go b/samples/memfs/memfs_test.go index a127d6e..7bad96e 100644 --- a/samples/memfs/memfs_test.go +++ b/samples/memfs/memfs_test.go @@ -192,7 +192,6 @@ func (t *MemFSTest) Mkdir_OneLevel() { ExpectEq(currentUid(), stat.Uid) ExpectEq(currentGid(), stat.Gid) ExpectEq(0, stat.Size) - ExpectEq(0, timespecToTime(stat.Atimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) @@ -248,7 +247,6 @@ func (t *MemFSTest) Mkdir_TwoLevels() { ExpectEq(currentUid(), stat.Uid) ExpectEq(currentGid(), stat.Gid) ExpectEq(0, stat.Size) - ExpectEq(0, timespecToTime(stat.Atimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) @@ -358,7 +356,6 @@ func (t *MemFSTest) CreateNewFile_InRoot() { ExpectEq(currentUid(), stat.Uid) ExpectEq(currentGid(), stat.Gid) ExpectEq(len(contents), stat.Size) - ExpectEq(0, timespecToTime(stat.Atimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) @@ -406,7 +403,6 @@ func (t *MemFSTest) CreateNewFile_InSubDir() { ExpectEq(currentUid(), stat.Uid) ExpectEq(currentGid(), stat.Gid) ExpectEq(len(contents), stat.Size) - ExpectEq(0, timespecToTime(stat.Atimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) @@ -462,7 +458,6 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() { ExpectEq(currentUid(), stat.Uid) ExpectEq(currentGid(), stat.Gid) ExpectEq(len("Hello, world!"), stat.Size) - ExpectEq(0, timespecToTime(stat.Atimespec).Sub(modifyTime)) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(modifyTime)) ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) From 650467fedb2d6d8a3357049392c6dadc74dbdb22 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 6 Mar 2015 05:33:17 +1100 Subject: [PATCH 10/11] Update mtime for mkdir and rmdir. --- samples/memfs/inode.go | 6 ++++++ samples/memfs/memfs_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/samples/memfs/inode.go b/samples/memfs/inode.go index edbe983..9090db1 100644 --- a/samples/memfs/inode.go +++ b/samples/memfs/inode.go @@ -236,6 +236,9 @@ func (inode *inode) AddChild( dt fuseutil.DirentType) { var index int + // Update the modification time. + inode.attributes.Mtime = inode.clock.Now() + // No matter where we place the entry, make sure it has the correct Offset // field. defer func() { @@ -268,6 +271,9 @@ func (inode *inode) AddChild( // REQUIRES: An entry for the given name exists. // EXCLUSIVE_LOCKS_REQUIRED(inode.mu) func (inode *inode) RemoveChild(name string) { + // Update the modification time. + inode.attributes.Mtime = inode.clock.Now() + // Find the entry. i, ok := inode.findChild(name) if !ok { diff --git a/samples/memfs/memfs_test.go b/samples/memfs/memfs_test.go index 7bad96e..c27a4ef 100644 --- a/samples/memfs/memfs_test.go +++ b/samples/memfs/memfs_test.go @@ -168,6 +168,9 @@ func (t *MemFSTest) Mkdir_OneLevel() { dirName := path.Join(t.mfs.Dir(), "dir") + // Simulate time advancing. + t.clock.AdvanceTime(time.Second) + // Create a directory within the root. createTime := t.clock.Now() err = os.Mkdir(dirName, 0754) @@ -196,6 +199,12 @@ func (t *MemFSTest) Mkdir_OneLevel() { ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) + // Check the root's mtime. + fi, err = os.Stat(t.mfs.Dir()) + + AssertEq(nil, err) + ExpectEq(0, fi.ModTime().Sub(createTime)) + // Read the directory. entries, err = ioutil.ReadDir(dirName) @@ -223,6 +232,9 @@ func (t *MemFSTest) Mkdir_TwoLevels() { err = os.Mkdir(path.Join(t.mfs.Dir(), "parent"), 0700) AssertEq(nil, err) + // Simulate time advancing. + t.clock.AdvanceTime(time.Second) + // Create a child of that directory. createTime := t.clock.Now() err = os.Mkdir(path.Join(t.mfs.Dir(), "parent/dir"), 0754) @@ -251,6 +263,11 @@ func (t *MemFSTest) Mkdir_TwoLevels() { ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) + // Check the parent's mtime. + fi, err = os.Stat(path.Join(t.mfs.Dir(), "parent")) + AssertEq(nil, err) + ExpectEq(0, fi.ModTime().Sub(createTime)) + // Read the directory. entries, err = ioutil.ReadDir(path.Join(t.mfs.Dir(), "parent/dir")) @@ -510,16 +527,28 @@ func (t *MemFSTest) Rmdir_Empty() { err = os.MkdirAll(path.Join(t.mfs.Dir(), "foo/bar"), 0754) AssertEq(nil, err) + // Simulate time advancing. + t.clock.AdvanceTime(time.Second) + // Remove the leaf. + rmTime := t.clock.Now() err = os.Remove(path.Join(t.mfs.Dir(), "foo/bar")) AssertEq(nil, err) + // Simulate time advancing. + t.clock.AdvanceTime(time.Second) + // There should be nothing left in the parent. entries, err = ioutil.ReadDir(path.Join(t.mfs.Dir(), "foo")) AssertEq(nil, err) ExpectThat(entries, ElementsAre()) + // Check the parent's mtime. + fi, err := os.Stat(path.Join(t.mfs.Dir(), "foo")) + AssertEq(nil, err) + ExpectEq(0, fi.ModTime().Sub(rmTime)) + // Remove the parent. err = os.Remove(path.Join(t.mfs.Dir(), "foo")) AssertEq(nil, err) From 1828931cce0c7f496feb14fa5af16de87819502b Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Fri, 6 Mar 2015 05:33:36 +1100 Subject: [PATCH 11/11] Don't attempt to track ctime. --- samples/memfs/inode.go | 1 - samples/memfs/memfs_test.go | 5 ----- 2 files changed, 6 deletions(-) diff --git a/samples/memfs/inode.go b/samples/memfs/inode.go index 9090db1..3505c13 100644 --- a/samples/memfs/inode.go +++ b/samples/memfs/inode.go @@ -100,7 +100,6 @@ func newInode( // Update time info. now := clock.Now() attrs.Mtime = now - attrs.Ctime = now attrs.Crtime = now // Create the object. diff --git a/samples/memfs/memfs_test.go b/samples/memfs/memfs_test.go index c27a4ef..0fa821a 100644 --- a/samples/memfs/memfs_test.go +++ b/samples/memfs/memfs_test.go @@ -196,7 +196,6 @@ func (t *MemFSTest) Mkdir_OneLevel() { ExpectEq(currentGid(), stat.Gid) ExpectEq(0, stat.Size) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) - ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Check the root's mtime. @@ -260,7 +259,6 @@ func (t *MemFSTest) Mkdir_TwoLevels() { ExpectEq(currentGid(), stat.Gid) ExpectEq(0, stat.Size) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) - ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Check the parent's mtime. @@ -374,7 +372,6 @@ func (t *MemFSTest) CreateNewFile_InRoot() { ExpectEq(currentGid(), stat.Gid) ExpectEq(len(contents), stat.Size) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) - ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Read it back. @@ -421,7 +418,6 @@ func (t *MemFSTest) CreateNewFile_InSubDir() { ExpectEq(currentGid(), stat.Gid) ExpectEq(len(contents), stat.Size) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) - ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Read it back. @@ -476,7 +472,6 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() { ExpectEq(currentGid(), stat.Gid) ExpectEq(len("Hello, world!"), stat.Size) ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(modifyTime)) - ExpectEq(0, timespecToTime(stat.Ctimespec).Sub(createTime)) ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Read the file back.