Implement and test read only MemMapFs file handles
Fixes #53
diff --git a/filter_test.go b/filter_test.go
index dcbc6f4..679cf92 100644
--- a/filter_test.go
+++ b/filter_test.go
@@ -13,7 +13,7 @@
if err == nil {
t.Errorf("Did not fail to create file")
}
- t.Logf("ERR=%s", err)
+ // t.Logf("ERR=%s", err)
}
func TestFilterReadonlyRemoveAndRead(t *testing.T) {
@@ -59,9 +59,10 @@
fs.AddFilter(NewRegexpFilter(regexp.MustCompile(`\.txt$`)))
_, err := fs.Create("/file.html")
if err == nil {
+
t.Errorf("Did not fail to create file")
}
- t.Logf("ERR=%s", err)
+ // t.Logf("ERR=%s", err)
}
func TestFilterRORegexpChain(t *testing.T) {
@@ -73,7 +74,7 @@
if err == nil {
t.Errorf("Did not fail to create file")
}
- t.Logf("ERR=%s", err)
+ // t.Logf("ERR=%s", err)
}
func TestFilterRegexReadDir(t *testing.T) {
diff --git a/mem/file.go b/mem/file.go
index e92d943..7d43a52 100644
--- a/mem/file.go
+++ b/mem/file.go
@@ -33,6 +33,7 @@
at int64
readDirCount int64
closed bool
+ readOnly bool
fileData *FileData
}
@@ -40,6 +41,10 @@
return &File{fileData: data}
}
+func NewReadOnlyFileHandle(data *FileData) *File {
+ return &File{fileData: data, readOnly: true}
+}
+
func (f File) Data() *FileData {
return f.fileData
}
@@ -203,6 +208,9 @@
}
func (f *File) Write(b []byte) (n int, err error) {
+ if f.readOnly {
+ return 0, &os.PathError{"write", f.fileData.name, errors.New("file handle is read only")}
+ }
n = len(b)
cur := atomic.LoadInt64(&f.at)
f.fileData.Lock()
diff --git a/memmap.go b/memmap.go
index 2c1ba39..2f2c612 100644
--- a/memmap.go
+++ b/memmap.go
@@ -163,6 +163,22 @@
}
func (m *MemMapFs) Open(name string) (File, error) {
+ f, err := m.open(name)
+ if f != nil {
+ return mem.NewReadOnlyFileHandle(f), err
+ }
+ return nil, err
+}
+
+func (m *MemMapFs) openWrite(name string) (File, error) {
+ f, err := m.open(name)
+ if f != nil {
+ return mem.NewFileHandle(f), err
+ }
+ return nil, err
+}
+
+func (m *MemMapFs) open(name string) (*mem.FileData, error) {
name = normalizePath(name)
m.mu.RLock()
@@ -171,7 +187,7 @@
if !ok {
return nil, &os.PathError{"open", name, ErrFileNotFound}
}
- return mem.NewFileHandle(f), nil
+ return f, nil
}
func (m *MemMapFs) lockfreeOpen(name string) (*mem.FileData, error) {
@@ -185,13 +201,16 @@
}
func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
- file, err := m.Open(name)
+ file, err := m.openWrite(name)
if os.IsNotExist(err) && (flag&os.O_CREATE > 0) {
file, err = m.Create(name)
}
if err != nil {
return nil, err
}
+ if flag == os.O_RDONLY {
+ file = mem.NewReadOnlyFileHandle(file.(*mem.File).Data())
+ }
if flag&os.O_APPEND > 0 {
_, err = file.Seek(0, os.SEEK_END)
if err != nil {
diff --git a/memmap_test.go b/memmap_test.go
index d8de243..c0e6825 100644
--- a/memmap_test.go
+++ b/memmap_test.go
@@ -104,7 +104,7 @@
// Fails if multiple file objects use the same file.at counter in MemMapFs
func TestMultipleOpenFiles(t *testing.T) {
defer removeAllTestFiles(t)
- const fileName = "./afero-demo2.txt"
+ const fileName = "afero-demo2.txt"
var data = make([][]byte, len(Fss))
@@ -113,7 +113,7 @@
path := filepath.Join(dir, fileName)
fh1, err := fs.Create(path)
if err != nil {
- t.Error("os.Create failed: " + err.Error())
+ t.Error("fs.Create failed: " + err.Error())
}
_, err = fh1.Write([]byte("test"))
if err != nil {
@@ -167,3 +167,44 @@
}
}
}
+
+// Test if file.Write() fails when opened as read only
+func TestReadOnly(t *testing.T) {
+ defer removeAllTestFiles(t)
+ const fileName = "afero-demo.txt"
+
+ for _, fs := range Fss {
+ dir := testDir(fs)
+ path := filepath.Join(dir, fileName)
+
+ f, err := fs.Create(path)
+ if err != nil {
+ t.Error(fs.Name()+":", "fs.Create failed: "+err.Error())
+ }
+ _, err = f.Write([]byte("test"))
+ if err != nil {
+ t.Error(fs.Name()+":", "Write failed: "+err.Error())
+ }
+ f.Close()
+
+ f, err = fs.Open(path)
+ if err != nil {
+ t.Error("fs.Open failed: " + err.Error())
+ }
+ _, err = f.Write([]byte("data"))
+ if err == nil {
+ t.Error(fs.Name()+":", "No write error")
+ }
+ f.Close()
+
+ f, err = fs.OpenFile(path, os.O_RDONLY, 0644)
+ if err != nil {
+ t.Error("fs.Open failed: " + err.Error())
+ }
+ _, err = f.Write([]byte("data"))
+ if err == nil {
+ t.Error(fs.Name()+":", "No write error")
+ }
+ f.Close()
+ }
+}