port RO & Regexp from filter to filesystem
diff --git a/filter_readonly.go b/filter_readonly.go
deleted file mode 100644
index c24c09b..0000000
--- a/filter_readonly.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package afero
-
-import (
-	"os"
-	"syscall"
-	"time"
-)
-
-type ReadOnlyFilter struct {
-	source 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
-}
-
-func (r *ReadOnlyFilter) Chmod(n string, m os.FileMode) error {
-	return syscall.EPERM
-}
-
-func (r *ReadOnlyFilter) Name() string {
-	return "ReadOnlyFilter"
-}
-
-func (r *ReadOnlyFilter) Stat(name string) (os.FileInfo, error) {
-	return r.source.Stat(name)
-}
-
-func (r *ReadOnlyFilter) Rename(o, n string) error {
-	return syscall.EPERM
-}
-
-func (r *ReadOnlyFilter) RemoveAll(p string) error {
-	return syscall.EPERM
-}
-
-func (r *ReadOnlyFilter) Remove(n string) error {
-	return syscall.EPERM
-}
-
-func (r *ReadOnlyFilter) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
-	if flag&(os.O_WRONLY|syscall.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 {
-		return nil, syscall.EPERM
-	}
-	return r.source.OpenFile(name, flag, perm)
-}
-
-func (r *ReadOnlyFilter) Open(n string) (File, error) {
-	return r.source.Open(n)
-}
-
-func (r *ReadOnlyFilter) Mkdir(n string, p os.FileMode) error {
-	return syscall.EPERM
-}
-
-func (r *ReadOnlyFilter) MkdirAll(n string, p os.FileMode) error {
-	return syscall.EPERM
-}
-
-func (r *ReadOnlyFilter) Create(n string) (File, error) {
-	return nil, syscall.EPERM
-}
diff --git a/readonlyfs.go b/readonlyfs.go
new file mode 100644
index 0000000..fa23703
--- /dev/null
+++ b/readonlyfs.go
@@ -0,0 +1,66 @@
+package afero
+
+import (
+	"os"
+	"syscall"
+	"time"
+)
+
+type ReadOnlyFs struct {
+	source Fs
+}
+
+func (r *ReadOnlyFs) ReadDir(name string) ([]os.FileInfo, error) {
+	return ReadDir(r.source, name)
+}
+
+func (r *ReadOnlyFs) Chtimes(n string, a, m time.Time) error {
+	return syscall.EPERM
+}
+
+func (r *ReadOnlyFs) Chmod(n string, m os.FileMode) error {
+	return syscall.EPERM
+}
+
+func (r *ReadOnlyFs) Name() string {
+	return "ReadOnlyFilter"
+}
+
+func (r *ReadOnlyFs) Stat(name string) (os.FileInfo, error) {
+	return r.source.Stat(name)
+}
+
+func (r *ReadOnlyFs) Rename(o, n string) error {
+	return syscall.EPERM
+}
+
+func (r *ReadOnlyFs) RemoveAll(p string) error {
+	return syscall.EPERM
+}
+
+func (r *ReadOnlyFs) Remove(n string) error {
+	return syscall.EPERM
+}
+
+func (r *ReadOnlyFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
+	if flag&(os.O_WRONLY|syscall.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 {
+		return nil, syscall.EPERM
+	}
+	return r.source.OpenFile(name, flag, perm)
+}
+
+func (r *ReadOnlyFs) Open(n string) (File, error) {
+	return r.source.Open(n)
+}
+
+func (r *ReadOnlyFs) Mkdir(n string, p os.FileMode) error {
+	return syscall.EPERM
+}
+
+func (r *ReadOnlyFs) MkdirAll(n string, p os.FileMode) error {
+	return syscall.EPERM
+}
+
+func (r *ReadOnlyFs) Create(n string) (File, error) {
+	return nil, syscall.EPERM
+}
diff --git a/filter_regexp.go b/regexpfs.go
similarity index 71%
rename from filter_regexp.go
rename to regexpfs.go
index 36e97e6..071b1bd 100644
--- a/filter_regexp.go
+++ b/regexpfs.go
@@ -7,11 +7,11 @@
 	"time"
 )
 
-// The RegexpFilter filters files (not directories) by regular expression. Only
+// The RegexpFs 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 {
+type RegexpFs struct {
 	re     *regexp.Regexp
 	source Fs
 }
@@ -21,21 +21,7 @@
 	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 {
+func (r *RegexpFs) matchesName(name string) error {
 	if r.re == nil {
 		return nil
 	}
@@ -45,7 +31,7 @@
 	return syscall.ENOENT
 }
 
-func (r *RegexpFilter) dirOrMatches(name string) error {
+func (r *RegexpFs) dirOrMatches(name string) error {
 	dir, err := IsDir(r.source, name)
 	if err != nil {
 		return err
@@ -56,32 +42,32 @@
 	return r.matchesName(name)
 }
 
-func (r *RegexpFilter) Chtimes(name string, a, m time.Time) error {
+func (r *RegexpFs) 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 {
+func (r *RegexpFs) 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 *RegexpFs) Name() string {
+	return "RegexpFs"
 }
 
-func (r *RegexpFilter) Stat(name string) (os.FileInfo, error) {
+func (r *RegexpFs) 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 {
+func (r *RegexpFs) Rename(oldname, newname string) error {
 	dir, err := IsDir(r.source, oldname)
 	if err != nil {
 		return err
@@ -98,7 +84,7 @@
 	return r.source.Rename(oldname, newname)
 }
 
-func (r *RegexpFilter) RemoveAll(p string) error {
+func (r *RegexpFs) RemoveAll(p string) error {
 	dir, err := IsDir(r.source, p)
 	if err != nil {
 		return err
@@ -111,21 +97,21 @@
 	return r.source.RemoveAll(p)
 }
 
-func (r *RegexpFilter) Remove(name string) error {
+func (r *RegexpFs) 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) {
+func (r *RegexpFs) 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) {
+func (r *RegexpFs) Open(name string) (File, error) {
 	dir, err := IsDir(r.source, name)
 	if err != nil {
 		return nil, err
@@ -139,15 +125,15 @@
 	return &RegexpFile{f: f, re: r.re}, nil
 }
 
-func (r *RegexpFilter) Mkdir(n string, p os.FileMode) error {
+func (r *RegexpFs) Mkdir(n string, p os.FileMode) error {
 	return r.source.Mkdir(n, p)
 }
 
-func (r *RegexpFilter) MkdirAll(n string, p os.FileMode) error {
+func (r *RegexpFs) MkdirAll(n string, p os.FileMode) error {
 	return r.source.MkdirAll(n, p)
 }
 
-func (r *RegexpFilter) Create(name string) (File, error) {
+func (r *RegexpFs) Create(name string) (File, error) {
 	if err := r.matchesName(name); err != nil {
 		return nil, err
 	}
diff --git a/filter_test.go b/ro_regexp_test.go
similarity index 77%
rename from filter_test.go
rename to ro_regexp_test.go
index 679cf92..d408fab 100644
--- a/filter_test.go
+++ b/ro_regexp_test.go
@@ -6,9 +6,7 @@
 )
 
 func TestFilterReadOnly(t *testing.T) {
-	mfs := &MemMapFs{}
-	fs := NewFilter(mfs)
-	fs.AddFilter(NewReadonlyFilter())
+	fs := &ReadOnlyFs{source: &MemMapFs{}}
 	_, err := fs.Create("/file.txt")
 	if err == nil {
 		t.Errorf("Did not fail to create file")
@@ -22,8 +20,7 @@
 	fh.Write([]byte("content here"))
 	fh.Close()
 
-	fs := NewFilter(mfs)
-	fs.AddFilter(NewReadonlyFilter())
+	fs := &ReadOnlyFs{source: mfs}
 	err = fs.Remove("/file.txt")
 	if err == nil {
 		t.Errorf("Did not fail to remove file")
@@ -54,9 +51,7 @@
 }
 
 func TestFilterRegexp(t *testing.T) {
-	mfs := &MemMapFs{}
-	fs := NewFilter(mfs)
-	fs.AddFilter(NewRegexpFilter(regexp.MustCompile(`\.txt$`)))
+	fs := &RegexpFs{re: regexp.MustCompile(`\.txt$`), source: &MemMapFs{}}
 	_, err := fs.Create("/file.html")
 	if err == nil {
 
@@ -66,10 +61,8 @@
 }
 
 func TestFilterRORegexpChain(t *testing.T) {
-	mfs := &MemMapFs{}
-	fs := NewFilter(mfs)
-	fs.AddFilter(NewReadonlyFilter())
-	fs.AddFilter(NewRegexpFilter(regexp.MustCompile(`\.txt$`)))
+	rofs := &ReadOnlyFs{source: &MemMapFs{}}
+	fs := &RegexpFs{re: regexp.MustCompile(`\.txt$`), source: rofs}
 	_, err := fs.Create("/file.txt")
 	if err == nil {
 		t.Errorf("Did not fail to create file")
@@ -79,9 +72,8 @@
 
 func TestFilterRegexReadDir(t *testing.T) {
 	mfs := &MemMapFs{}
-	fs := NewFilter(mfs)
-	fs.AddFilter(NewRegexpFilter(regexp.MustCompile(`\.txt$`)))
-	fs.AddFilter(NewRegexpFilter(regexp.MustCompile(`^a`)))
+	fs1 := &RegexpFs{re: regexp.MustCompile(`\.txt$`), source: mfs}
+	fs := &RegexpFs{re: regexp.MustCompile(`^a`), source: fs1}
 
 	mfs.MkdirAll("/dir/sub", 0777)
 	for _, name := range []string{"afile.txt", "afile.html", "bfile.txt"} {
diff --git a/union_test.go b/union_test.go
index 14736ff..24f93cd 100644
--- a/union_test.go
+++ b/union_test.go
@@ -9,8 +9,7 @@
 
 func TestUnionCreateExisting(t *testing.T) {
 	base := &MemMapFs{}
-	roBase := NewFilter(base)
-	roBase.AddFilter(NewReadonlyFilter())
+	roBase := &ReadOnlyFs{source: base}
 
 	ufs := NewUnionFs(roBase, &MemMapFs{}, NewCoWUnionFs())
 
@@ -60,8 +59,7 @@
 
 func TestUnionMergeReaddir(t *testing.T) {
 	base := &MemMapFs{}
-	roBase := NewFilter(base)
-	roBase.AddFilter(NewReadonlyFilter())
+	roBase := &ReadOnlyFs{source: base}
 
 	ufs := NewUnionFs(roBase, &MemMapFs{}, NewCoWUnionFs())