diff --git a/memfs/example_test.go b/memfs/example_test.go index d76adcc..8c180d1 100644 --- a/memfs/example_test.go +++ b/memfs/example_test.go @@ -2,8 +2,8 @@ package memfs_test import ( "fmt" - "log" "io/fs" + "log" "github.com/jarxorg/io2" "github.com/jarxorg/io2/memfs" diff --git a/memfs/memfs.go b/memfs/memfs.go index 0873766..7ba2ffa 100644 --- a/memfs/memfs.go +++ b/memfs/memfs.go @@ -8,6 +8,7 @@ import ( "path/filepath" "strings" "sync" + "syscall" "github.com/jarxorg/io2" ) @@ -108,6 +109,7 @@ func (fsys *MemFS) Open(name string) (fs.File, error) { f := &MemFile{ fsys: fsys, name: name, + mode: v.mode, } if !v.isDir { f.buf = bytes.NewBuffer(v.data) @@ -147,9 +149,14 @@ func (fsys *MemFS) ReadDir(dir string) ([]fs.DirEntry, error) { fsys.mutex.Lock() defer fsys.mutex.Unlock() - if !fs.ValidPath(dir) { - return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: fs.ErrInvalid} + v, err := fsys.open(dir) + if err != nil { + return nil, err } + if !v.isDir { + return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: syscall.ENOTDIR} + } + prefix := fsys.key(dir) keys := fsys.store.prefixKeys(prefix) var dirEntries []fs.DirEntry @@ -289,6 +296,9 @@ var ( // Read reads bytes from this file. func (f *MemFile) Read(p []byte) (int, error) { + if f.buf == nil { + return 0, &fs.PathError{Op: "Read", Path: f.name, Err: syscall.EISDIR} + } return f.buf.Read(p) } diff --git a/memfs/memfs_test.go b/memfs/memfs_test.go index f55516a..ac33442 100644 --- a/memfs/memfs_test.go +++ b/memfs/memfs_test.go @@ -198,10 +198,14 @@ func TestReadDir(t *testing.T) { }, dir: "dir0", }, { - dir: "not-found", + dir: "not-found", + errStr: "Open not-found: file does not exist", + }, { + dir: "dir0/file01.txt", + errStr: "ReadDir dir0/file01.txt: not a directory", }, { dir: "../invalid", - errStr: "ReadDir ../invalid: invalid argument", + errStr: "Open ../invalid: invalid argument", }, } @@ -328,7 +332,7 @@ func TestWriteFile(t *testing.T) { { name: "new.txt", }, { - name: "dir0/file01.txt", + name: "dir0/file01.txt", }, { name: "dir0", errStr: "Create dir0: invalid argument", @@ -394,7 +398,7 @@ func TestRemoveAll(t *testing.T) { var want []string for _, k := range fsys.store.keys { - if !strings.HasPrefix(k, "/" + dir) { + if !strings.HasPrefix(k, "/"+dir) { want = append(want, k) } } @@ -422,6 +426,26 @@ func TestRemoveAll_Errors(t *testing.T) { } } +func TestMemFile_Read_Errors(t *testing.T) { + fsys := newMemFSTest(t) + name := "dir0" + + f, err := fsys.Open(name) + if err != nil { + t.Fatal(err) + } + + memf, ok := f.(*MemFile) + if !ok { + t.Fatalf(`Fatal not MemFile: %#v`, f) + } + + _, err = memf.Read([]byte{}) + if err == nil { + t.Fatalf(`Fatal Read(1) returns no error`) + } +} + func TestMemFile_ReadDir(t *testing.T) { fsys := newMemFSTest(t) dir := "dir0" @@ -438,7 +462,7 @@ func TestMemFile_ReadDir(t *testing.T) { testCases := []struct { name string - err error + err error }{ { name: "file01.txt", diff --git a/memfs/store.go b/memfs/store.go index 96f9c7c..5a5917f 100644 --- a/memfs/store.go +++ b/memfs/store.go @@ -1,12 +1,12 @@ package memfs import ( - "io/fs" + "io/fs" "path" - "path/filepath" + "path/filepath" "sort" "strings" - "time" + "time" ) // Value works as fs.DirEntry or fs.FileInfo. @@ -87,7 +87,7 @@ func (s *store) put(k string, v *value) *value { } func (s *store) remove(key string) *value { - i := s.keyIndex(key) + i := s.keyIndex(key) if i == -1 { return nil } @@ -98,40 +98,40 @@ func (s *store) remove(key string) *value { } func (s *store) removeAll(prefix string) { - from := s.keyIndex(prefix) - if from == -1 { - return - } - - max := len(s.keys) - to := -1 - for i := from; i < max; i++ { - key := s.keys[i] - if !strings.HasPrefix(key, prefix) { - break - } - delete(s.values, key) - to = i - } - s.keys = append(s.keys[0:from], s.keys[to+1:]...) + from := s.keyIndex(prefix) + if from == -1 { + return + } + + max := len(s.keys) + to := -1 + for i := from; i < max; i++ { + key := s.keys[i] + if !strings.HasPrefix(key, prefix) { + break + } + delete(s.values, key) + to = i + } + s.keys = append(s.keys[0:from], s.keys[to+1:]...) } func (s *store) keyIndex(key string) int { - i := sort.SearchStrings(s.keys, key) - if i < len(s.keys) && s.keys[i] == key { - return i - } - return -1 + i := sort.SearchStrings(s.keys, key) + if i < len(s.keys) && s.keys[i] == key { + return i + } + return -1 } func (s *store) prefixKeys(prefix string) []string { - i := s.keyIndex(prefix) + i := s.keyIndex(prefix) if i == -1 { return nil } - if !strings.HasSuffix(prefix, "/") { - prefix = prefix + "/" - } + if !strings.HasSuffix(prefix, "/") { + prefix = prefix + "/" + } var keys []string max := len(s.keys) @@ -149,13 +149,13 @@ func (s *store) prefixKeys(prefix string) []string { } func (s *store) prefixGlobKeys(prefix, pattern string) ([]string, error) { - i := s.keyIndex(prefix) + i := s.keyIndex(prefix) if i == -1 { return nil, nil } - if !strings.HasSuffix(prefix, "/") { - prefix = prefix + "/" - } + if !strings.HasSuffix(prefix, "/") { + prefix = prefix + "/" + } var keys []string max := len(s.keys) diff --git a/memfs/store_test.go b/memfs/store_test.go index 4103c4f..3738033 100644 --- a/memfs/store_test.go +++ b/memfs/store_test.go @@ -208,18 +208,18 @@ func TestStore_prefixGlobKeys(t *testing.T) { s := newStoreTest() for _, tc := range testCases { got, err := s.prefixGlobKeys(tc.prefix, tc.pattern) - errStr := "" + errStr := "" if err != nil { - errStr = err.Error() - } + errStr = err.Error() + } if errStr != tc.errStr { t.Errorf(`Error prefixGlobKeys("%s", "%s") error got "%s"; want "%s"`, - tc.prefix, tc.pattern, errStr, tc.errStr) + tc.prefix, tc.pattern, errStr, tc.errStr) continue } if !reflect.DeepEqual(got, tc.want) { t.Errorf(`Error prefixGlobKeys("%s", "%s") got %v; want %v`, - tc.prefix, tc.pattern, got, tc.want) + tc.prefix, tc.pattern, got, tc.want) } } }