diff --git a/conversions.go b/conversions.go index ee5f041..adecf7b 100644 --- a/conversions.go +++ b/conversions.go @@ -633,6 +633,8 @@ func convertAttributes( out.Nlink = in.Nlink out.Uid = in.Uid out.Gid = in.Gid + // round up to the nearest 512 boundary + out.Blocks = (in.Size + 512 - 1) / 512 // Set the mode. out.Mode = uint32(in.Mode) & 0777 diff --git a/samples/statfs/statfs.go b/samples/statfs/statfs.go index e8656ec..166c2d2 100644 --- a/samples/statfs/statfs.go +++ b/samples/statfs/statfs.go @@ -40,6 +40,9 @@ type FS interface { // Set the canned response to be used for future statfs ops. SetStatFSResponse(r fuseops.StatFSOp) + // Set the canned response to be used for future stat ops. + SetStatResponse(r fuseops.InodeAttributes) + // Return the size of the most recent write delivered by the kernel, or -1 if // none. MostRecentWriteSize() int @@ -47,6 +50,9 @@ type FS interface { func New() (fs FS) { fs = &statFS{ + cannedStatResponse: fuseops.InodeAttributes{ + Mode: 0666, + }, mostRecentWriteSize: -1, } @@ -59,8 +65,9 @@ type statFS struct { fuseutil.NotImplementedFileSystem mu sync.Mutex - cannedResponse fuseops.StatFSOp // GUARDED_BY(mu) - mostRecentWriteSize int // GUARDED_BY(mu) + cannedResponse fuseops.StatFSOp // GUARDED_BY(mu) + cannedStatResponse fuseops.InodeAttributes // GUARDED_BY(mu) + mostRecentWriteSize int // GUARDED_BY(mu) } //////////////////////////////////////////////////////////////////////// @@ -73,10 +80,8 @@ func dirAttrs() fuseops.InodeAttributes { } } -func fileAttrs() fuseops.InodeAttributes { - return fuseops.InodeAttributes{ - Mode: 0666, - } +func (fs *statFS) fileAttrs() fuseops.InodeAttributes { + return fs.cannedStatResponse } //////////////////////////////////////////////////////////////////////// @@ -91,6 +96,14 @@ func (fs *statFS) SetStatFSResponse(r fuseops.StatFSOp) { fs.cannedResponse = r } +// LOCKS_EXCLUDED(fs.mu) +func (fs *statFS) SetStatResponse(r fuseops.InodeAttributes) { + fs.mu.Lock() + defer fs.mu.Unlock() + + fs.cannedStatResponse = r +} + // LOCKS_EXCLUDED(fs.mu) func (fs *statFS) MostRecentWriteSize() int { fs.mu.Lock() @@ -124,7 +137,7 @@ func (fs *statFS) LookUpInode( } op.Entry.Child = childInodeID - op.Entry.Attributes = fileAttrs() + op.Entry.Attributes = fs.fileAttrs() return } @@ -137,7 +150,7 @@ func (fs *statFS) GetInodeAttributes( op.Attributes = dirAttrs() case childInodeID: - op.Attributes = fileAttrs() + op.Attributes = fs.fileAttrs() default: err = fuse.ENOENT diff --git a/samples/statfs/statfs_test.go b/samples/statfs/statfs_test.go index 8f7a4cd..3f178ee 100644 --- a/samples/statfs/statfs_test.go +++ b/samples/statfs/statfs_test.go @@ -23,6 +23,7 @@ import ( "path/filepath" "runtime" "strconv" + "syscall" "testing" "github.com/jacobsa/fuse/fuseops" @@ -204,3 +205,24 @@ func (t *StatFSTest) WriteSize() { AddFailure("Unhandled OS: %s", runtime.GOOS) } } + +func (t *StatFSTest) StatBlocks() { + var err error + var stat syscall.Stat_t + const fileName = "foo" + const size = 1 << 22 + + err = ioutil.WriteFile( + path.Join(t.Dir, fileName), + bytes.Repeat([]byte{'x'}, size), + 0400) + AssertEq(nil, err) + + t.fs.SetStatResponse(fuseops.InodeAttributes{ + Size: size, + }) + + err = syscall.Stat(path.Join(t.Dir, fileName), &stat) + AssertEq(nil, err) + ExpectEq(size/512, stat.Blocks) +}