From 4b48e464dc2082d2aa3f01fa6bdf8df7c025da0c Mon Sep 17 00:00:00 2001 From: Antonio Jesus Navarro Perez Date: Tue, 18 Apr 2017 13:38:53 +0200 Subject: [PATCH] memfs: bug fixing In this PR we fix two different bugs in memfs implementation: - Using ReadAt, if the provided slice of bytes has a size bigger than the data to read, it must return the result and a io.EOF error. - ReadAt must not affect to the offset position: https://golang.org/src/io/io.go?s=7545:7620#L203 --- memfs/memory.go | 7 ++++--- memfs/storage.go | 11 ++++++++--- test/fs_suite.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/memfs/memory.go b/memfs/memory.go index 3f10d13..c9f40bb 100644 --- a/memfs/memory.go +++ b/memfs/memory.go @@ -170,8 +170,10 @@ type file struct { func (f *file) Read(b []byte) (int, error) { n, err := f.ReadAt(b, f.position) - if err != nil { - return 0, err + f.position += int64(n) + + if err == io.EOF && n != 0 { + err = nil } return n, err @@ -187,7 +189,6 @@ func (f *file) ReadAt(b []byte, off int64) (int, error) { } n, err := f.content.ReadAt(b, off) - f.position += int64(n) return n, err } diff --git a/memfs/storage.go b/memfs/storage.go index 03e39c3..0856f82 100644 --- a/memfs/storage.go +++ b/memfs/storage.go @@ -185,7 +185,7 @@ func (c *content) WriteAt(p []byte, off int64) (int, error) { return len(p), nil } -func (c *content) ReadAt(b []byte, off int64) (int, error) { +func (c *content) ReadAt(b []byte, off int64) (n int, err error) { size := int64(len(c.bytes)) if off >= size { return 0, io.EOF @@ -196,6 +196,11 @@ func (c *content) ReadAt(b []byte, off int64) (int, error) { l = size - off } - n := copy(b, c.bytes[off:off+l]) - return n, nil + btr := c.bytes[off : off+l] + if len(btr) < len(b) { + err = io.EOF + } + n = copy(b, btr) + + return } diff --git a/test/fs_suite.go b/test/fs_suite.go index ebe1f2b..e819d69 100644 --- a/test/fs_suite.go +++ b/test/fs_suite.go @@ -715,6 +715,54 @@ func (s *FilesystemSuite) TestReadAtOnReadOnly(c *C) { c.Assert(f.Close(), IsNil) } +func (s *FilesystemSuite) TestReadAtEOF(c *C) { + err := WriteFile(s.FS, "foo", []byte("TEST"), 0644) + c.Assert(err, IsNil) + + f, err := s.FS.Open("foo") + c.Assert(err, IsNil) + + rf, ok := f.(io.ReaderAt) + c.Assert(ok, Equals, true) + + b := make([]byte, 5) + n, err := rf.ReadAt(b, 0) + c.Assert(err, Equals, io.EOF) + c.Assert(n, Equals, 4) + c.Assert(string(b), Equals, "TEST\x00") + + err = f.Close() + c.Assert(err, IsNil) +} + +func (s *FilesystemSuite) TestReadAtOffset(c *C) { + err := WriteFile(s.FS, "foo", []byte("TEST"), 0644) + c.Assert(err, IsNil) + + f, err := s.FS.Open("foo") + c.Assert(err, IsNil) + + rf, ok := f.(io.ReaderAt) + c.Assert(ok, Equals, true) + + o, err := f.Seek(0, io.SeekCurrent) + c.Assert(err, IsNil) + c.Assert(o, Equals, int64(0)) + + b := make([]byte, 4) + n, err := rf.ReadAt(b, 0) + c.Assert(err, IsNil) + c.Assert(n, Equals, 4) + c.Assert(string(b), Equals, "TEST") + + o, err = f.Seek(0, io.SeekCurrent) + c.Assert(err, IsNil) + c.Assert(o, Equals, int64(0)) + + err = f.Close() + c.Assert(err, IsNil) +} + func (s *FilesystemSuite) TestReadWriteLargeFile(c *C) { f, err := s.FS.Create("foo") c.Assert(err, IsNil)