Add RegexpFilter

- rework FilterFs to be truely chaining, i.e. every call not intercepted
  must be passed to the source Fs
- AddFilter accepts just a FilterFs, not a Fs
- FilterFs' AddFilter(FilterFs) should be implemented by any
  FilterFs like

  func (f *myFilter) AddFilter(fs FilterFs) {
       fs.SetSource(f.source)
       f.source = fs
  }
diff --git a/filter.go b/filter.go
index ae85b36..5cdcf2d 100644
--- a/filter.go
+++ b/filter.go
@@ -15,14 +15,18 @@
 // of filtering (e.g. admins get write access, normal users just readonly)
 type FilterFs interface {
 	Fs
-	AddFilter(Fs)
+	AddFilter(FilterFs)
+	SetSource(Fs)
 }
 
 type Filter struct {
-	chain  []Fs
 	source Fs
 }
 
+func (f *Filter) SetSource(fs Fs) {
+	f.source = fs
+}
+
 // create a new FilterFs that implements Fs, argument must be an Fs, not
 // a FilterFs
 func NewFilter(fs Fs) FilterFs {
@@ -30,101 +34,44 @@
 }
 
 // prepend a filter in the filter chain
-func (f *Filter) AddFilter(fs Fs) {
-	c := []Fs{fs}
-	for _, ch := range f.chain {
-		c = append(c, ch)
-	}
-	f.chain = c
+func (f *Filter) AddFilter(fs FilterFs) {
+	fs.SetSource(f.source)
+	f.source = fs
 }
 
 func (f *Filter) Create(name string) (file File, err error) {
-	for _, c := range f.chain {
-		file, err = c.Create(name)
-		if err != nil {
-			return
-		}
-	}
 	return f.source.Create(name)
 }
 
-func (f *Filter) Mkdir(name string, perm os.FileMode) (err error) {
-	for _, c := range f.chain {
-		err = c.Mkdir(name, perm)
-		if err != nil {
-			return
-		}
-	}
+func (f *Filter) Mkdir(name string, perm os.FileMode) (error) {
 	return f.source.Mkdir(name, perm)
 }
 
-func (f *Filter) MkdirAll(path string, perm os.FileMode) (err error) {
-	for _, c := range f.chain {
-		err = c.MkdirAll(path, perm)
-		if err != nil {
-			return
-		}
-	}
+func (f *Filter) MkdirAll(path string, perm os.FileMode) (error) {
 	return f.source.MkdirAll(path, perm)
 }
 
-func (f *Filter) Open(name string) (file File, err error) {
-	for _, c := range f.chain {
-		file, err = c.Open(name)
-		if err != nil {
-			return
-		}
-	}
+func (f *Filter) Open(name string) (File, error) {
 	return f.source.Open(name)
 }
 
-func (f *Filter) OpenFile(name string, flag int, perm os.FileMode) (file File, err error) {
-	for _, c := range f.chain {
-		file, err = c.OpenFile(name, flag, perm)
-		if err != nil {
-			return
-		}
-	}
+func (f *Filter) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
 	return f.source.OpenFile(name, flag, perm)
 }
 
-func (f *Filter) Remove(name string) (err error) {
-	for _, c := range f.chain {
-		err = c.Remove(name)
-		if err != nil {
-			return
-		}
-	}
+func (f *Filter) Remove(name string) (error) {
 	return f.source.Remove(name)
 }
 
-func (f *Filter) RemoveAll(path string) (err error) {
-	for _, c := range f.chain {
-		err = c.RemoveAll(path)
-		if err != nil {
-			return
-		}
-	}
+func (f *Filter) RemoveAll(path string) (error) {
 	return f.source.RemoveAll(path)
 }
 
-func (f *Filter) Rename(oldname, newname string) (err error) {
-	for _, c := range f.chain {
-		err = c.Rename(oldname, newname)
-		if err != nil {
-			return
-		}
-	}
+func (f *Filter) Rename(oldname, newname string) (error) {
 	return f.source.Rename(oldname, newname)
 }
 
-func (f *Filter) Stat(name string) (fi os.FileInfo, err error) {
-	for _, c := range f.chain {
-		fi, err = c.Stat(name)
-		if err != nil {
-			return
-		}
-	}
+func (f *Filter) Stat(name string) (os.FileInfo, error) {
 	return f.source.Stat(name)
 }
 
@@ -132,22 +79,10 @@
 	return f.source.Name()
 }
 
-func (f *Filter) Chmod(name string, mode os.FileMode) (err error) {
-	for _, c := range f.chain {
-		err = c.Chmod(name, mode)
-		if err != nil {
-			return
-		}
-	}
+func (f *Filter) Chmod(name string, mode os.FileMode) (error) {
 	return f.source.Chmod(name, mode)
 }
 
-func (f *Filter) Chtimes(name string, atime, mtime time.Time) (err error) {
-	for _, c := range f.chain {
-		err = c.Chtimes(name, atime, mtime)
-		if err != nil {
-			return
-		}
-	}
+func (f *Filter) Chtimes(name string, atime, mtime time.Time) (error) {
 	return f.source.Chtimes(name, atime, mtime)
 }
diff --git a/filter_readonly.go b/filter_readonly.go
index 0ff67a7..c24c09b 100644
--- a/filter_readonly.go
+++ b/filter_readonly.go
@@ -7,12 +7,27 @@
 )
 
 type ReadOnlyFilter struct {
+	source Fs
 }
 
-func NewReadonlyFilter() Fs {
+func NewReadonlyFilter() FilterFs {
 	return &ReadOnlyFilter{}
 }
 
+func (r *ReadOnlyFilter) SetSource(fs Fs) {
+	r.source = fs
+}
+
+// prepend a filter in the filter chain
+func (r *ReadOnlyFilter) AddFilter(fs FilterFs) {
+	fs.SetSource(r.source)
+	r.source = fs
+}
+
+func (r *ReadOnlyFilter) ReadDir(name string) ([]os.FileInfo, error) {
+	return ReadDir(r.source, name)
+}
+
 func (r *ReadOnlyFilter) Chtimes(n string, a, m time.Time) error {
 	return syscall.EPERM
 }
@@ -22,11 +37,11 @@
 }
 
 func (r *ReadOnlyFilter) Name() string {
-	return "readOnlyFilter"
+	return "ReadOnlyFilter"
 }
 
 func (r *ReadOnlyFilter) Stat(name string) (os.FileInfo, error) {
-	return nil, nil
+	return r.source.Stat(name)
 }
 
 func (r *ReadOnlyFilter) Rename(o, n string) error {
@@ -45,11 +60,11 @@
 	if flag&(os.O_WRONLY|syscall.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 {
 		return nil, syscall.EPERM
 	}
-	return nil, nil
+	return r.source.OpenFile(name, flag, perm)
 }
 
 func (r *ReadOnlyFilter) Open(n string) (File, error) {
-	return nil, nil
+	return r.source.Open(n)
 }
 
 func (r *ReadOnlyFilter) Mkdir(n string, p os.FileMode) error {
diff --git a/filter_regexp.go b/filter_regexp.go
new file mode 100644
index 0000000..36e97e6
--- /dev/null
+++ b/filter_regexp.go
@@ -0,0 +1,224 @@
+package afero
+
+import (
+	"os"
+	"regexp"
+	"syscall"
+	"time"
+)
+
+// The RegexpFilter filters files (not directories) by regular expression. Only
+// files matching the given regexp will be allowed, all others get a ENOENT error (
+// "No such file or directory").
+//
+type RegexpFilter struct {
+	re     *regexp.Regexp
+	source Fs
+}
+
+type RegexpFile struct {
+	f  File
+	re *regexp.Regexp
+}
+
+func NewRegexpFilter(re *regexp.Regexp) FilterFs {
+	return &RegexpFilter{re: re}
+}
+
+// prepend a filter in the filter chain
+func (r *RegexpFilter) AddFilter(fs FilterFs) {
+	fs.SetSource(r.source)
+	r.source = fs
+}
+
+func (r *RegexpFilter) SetSource(fs Fs) {
+	r.source = fs
+}
+
+func (r *RegexpFilter) matchesName(name string) error {
+	if r.re == nil {
+		return nil
+	}
+	if r.re.MatchString(name) {
+		return nil
+	}
+	return syscall.ENOENT
+}
+
+func (r *RegexpFilter) dirOrMatches(name string) error {
+	dir, err := IsDir(r.source, name)
+	if err != nil {
+		return err
+	}
+	if dir {
+		return nil
+	}
+	return r.matchesName(name)
+}
+
+func (r *RegexpFilter) Chtimes(name string, a, m time.Time) error {
+	if err := r.dirOrMatches(name); err != nil {
+		return err
+	}
+	return r.source.Chtimes(name, a, m)
+}
+
+func (r *RegexpFilter) Chmod(name string, mode os.FileMode) error {
+	if err := r.dirOrMatches(name); err != nil {
+		return err
+	}
+	return r.source.Chmod(name, mode)
+}
+
+func (r *RegexpFilter) Name() string {
+	return "RegexpFilter"
+}
+
+func (r *RegexpFilter) Stat(name string) (os.FileInfo, error) {
+	if err := r.dirOrMatches(name); err != nil {
+		return nil, err
+	}
+	return r.source.Stat(name)
+}
+
+func (r *RegexpFilter) Rename(oldname, newname string) error {
+	dir, err := IsDir(r.source, oldname)
+	if err != nil {
+		return err
+	}
+	if dir {
+		return nil
+	}
+	if err := r.matchesName(oldname); err != nil {
+		return err
+	}
+	if err := r.matchesName(newname); err != nil {
+		return err
+	}
+	return r.source.Rename(oldname, newname)
+}
+
+func (r *RegexpFilter) RemoveAll(p string) error {
+	dir, err := IsDir(r.source, p)
+	if err != nil {
+		return err
+	}
+	if !dir {
+		if err := r.matchesName(p); err != nil {
+			return err
+		}
+	}
+	return r.source.RemoveAll(p)
+}
+
+func (r *RegexpFilter) Remove(name string) error {
+	if err := r.dirOrMatches(name); err != nil {
+		return err
+	}
+	return r.source.Remove(name)
+}
+
+func (r *RegexpFilter) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
+	if err := r.dirOrMatches(name); err != nil {
+		return nil, err
+	}
+	return r.source.OpenFile(name, flag, perm)
+}
+
+func (r *RegexpFilter) Open(name string) (File, error) {
+	dir, err := IsDir(r.source, name)
+	if err != nil {
+		return nil, err
+	}
+	if !dir {
+		if err := r.matchesName(name); err != nil {
+			return nil, err
+		}
+	}
+	f, err := r.source.Open(name)
+	return &RegexpFile{f: f, re: r.re}, nil
+}
+
+func (r *RegexpFilter) Mkdir(n string, p os.FileMode) error {
+	return r.source.Mkdir(n, p)
+}
+
+func (r *RegexpFilter) MkdirAll(n string, p os.FileMode) error {
+	return r.source.MkdirAll(n, p)
+}
+
+func (r *RegexpFilter) Create(name string) (File, error) {
+	if err := r.matchesName(name); err != nil {
+		return nil, err
+	}
+	return r.source.Create(name)
+}
+
+func (f *RegexpFile) Close() error {
+	return f.f.Close()
+}
+
+func (f *RegexpFile) Read(s []byte) (int, error) {
+	return f.f.Read(s)
+}
+
+func (f *RegexpFile) ReadAt(s []byte, o int64) (int, error) {
+	return f.f.ReadAt(s, o)
+}
+
+func (f *RegexpFile) Seek(o int64, w int) (int64, error) {
+	return f.f.Seek(o, w)
+}
+
+func (f *RegexpFile) Write(s []byte) (int, error) {
+	return f.f.Write(s)
+}
+
+func (f *RegexpFile) WriteAt(s []byte, o int64) (int, error) {
+	return f.f.WriteAt(s, o)
+}
+
+func (f *RegexpFile) Name() string {
+	return f.f.Name()
+}
+
+func (f *RegexpFile) Readdir(c int) (fi []os.FileInfo, err error) {
+	var rfi []os.FileInfo
+	rfi, err = f.f.Readdir(c)
+	if err != nil {
+		return nil, err
+	}
+	for _, i := range rfi {
+		if i.IsDir() || f.re.MatchString(i.Name()) {
+			fi = append(fi, i)
+		}
+	}
+	return fi, nil
+}
+
+func (f *RegexpFile) Readdirnames(c int) (n []string, err error) {
+	fi, err := f.Readdir(c)
+	if err != nil {
+		return nil, err
+	}
+	for _, s := range fi {
+		n = append(n, s.Name())
+	}
+	return n, nil
+}
+
+func (f *RegexpFile) Stat() (os.FileInfo, error) {
+	return f.f.Stat()
+}
+
+func (f *RegexpFile) Sync() error {
+	return f.f.Sync()
+}
+
+func (f *RegexpFile) Truncate(s int64) error {
+	return f.f.Truncate(s)
+}
+
+func (f *RegexpFile) WriteString(s string) (int, error) {
+	return f.f.WriteString(s)
+}
diff --git a/filter_test.go b/filter_test.go
index 803fdb0..dcbc6f4 100644
--- a/filter_test.go
+++ b/filter_test.go
@@ -1,11 +1,11 @@
 package afero
 
 import (
-//	"regexp"
+	"regexp"
 	"testing"
 )
 
-func TestReadOnly(t *testing.T) {
+func TestFilterReadOnly(t *testing.T) {
 	mfs := &MemMapFs{}
 	fs := NewFilter(mfs)
 	fs.AddFilter(NewReadonlyFilter())
@@ -16,7 +16,7 @@
 	t.Logf("ERR=%s", err)
 }
 
-func TestReadonlyRemoveAndRead(t *testing.T) {
+func TestFilterReadonlyRemoveAndRead(t *testing.T) {
 	mfs := &MemMapFs{}
 	fh, err := mfs.Create("/file.txt")
 	fh.Write([]byte("content here"))
@@ -52,11 +52,11 @@
 		t.Errorf("File still present")
 	}
 }
-/*
-func TestRegexp(t *testing.T) {
+
+func TestFilterRegexp(t *testing.T) {
 	mfs := &MemMapFs{}
 	fs := NewFilter(mfs)
-	fs.AddFilter(NewRegexpFilter(regexp.MustCompile(`\.txt$`), nil))
+	fs.AddFilter(NewRegexpFilter(regexp.MustCompile(`\.txt$`)))
 	_, err := fs.Create("/file.html")
 	if err == nil {
 		t.Errorf("Did not fail to create file")
@@ -64,15 +64,40 @@
 	t.Logf("ERR=%s", err)
 }
 
-func TestRORegexpChain(t *testing.T) {
+func TestFilterRORegexpChain(t *testing.T) {
 	mfs := &MemMapFs{}
 	fs := NewFilter(mfs)
 	fs.AddFilter(NewReadonlyFilter())
-	fs.AddFilter(NewRegexpFilter(regexp.MustCompile(`\.txt$`), nil))
+	fs.AddFilter(NewRegexpFilter(regexp.MustCompile(`\.txt$`)))
 	_, err := fs.Create("/file.txt")
 	if err == nil {
 		t.Errorf("Did not fail to create file")
 	}
 	t.Logf("ERR=%s", err)
 }
-*/
+
+func TestFilterRegexReadDir(t *testing.T) {
+	mfs := &MemMapFs{}
+	fs := NewFilter(mfs)
+	fs.AddFilter(NewRegexpFilter(regexp.MustCompile(`\.txt$`)))
+	fs.AddFilter(NewRegexpFilter(regexp.MustCompile(`^a`)))
+
+	mfs.MkdirAll("/dir/sub", 0777)
+	for _, name := range []string{"afile.txt", "afile.html", "bfile.txt"} {
+		for _, dir := range []string{"/dir/", "/dir/sub/"} {
+			fh, _ := mfs.Create(dir + name)
+			fh.Close()
+		}
+	}
+
+	files, _ := ReadDir(fs, "/dir")
+	if len(files) != 2 { // afile.txt, sub
+		t.Errorf("Got wrong number of files: %#v", files)
+	}
+
+	f, _ := fs.Open("/dir/sub")
+	names, _ := f.Readdirnames(-1)
+	if len(names) != 1 {
+		t.Errorf("Got wrong number of names: %v", names)
+	}
+}