Skip to content

Commit 7f3cb2e

Browse files
committed
fix: modtimes should be part of the content, not of the file
Otherwise f.Duplicate() copies the modTime. Subsequent modtime mutations are then on this copy instead of the original file's modtime. Effectively any mutation to a modtime can never be seen by other callers of f.Stat()
1 parent 429cdfb commit 7f3cb2e

File tree

3 files changed

+16
-13
lines changed

3 files changed

+16
-13
lines changed

memfs/file.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ type file struct {
1717
position int64
1818
flag int
1919
mode os.FileMode
20-
modTime time.Time
2120

2221
isClosed bool
2322
}
@@ -81,7 +80,6 @@ func (f *file) WriteAt(p []byte, off int64) (int, error) {
8180
return 0, errors.New("write not supported")
8281
}
8382

84-
f.modTime = time.Now()
8583
n, err := f.content.WriteAt(p, off)
8684
f.position = off + int64(n)
8785

@@ -113,7 +111,6 @@ func (f *file) Duplicate(filename string, mode fs.FileMode, flag int) billy.File
113111
content: f.content,
114112
mode: mode,
115113
flag: flag,
116-
modTime: f.modTime,
117114
}
118115

119116
if isTruncate(flag) {
@@ -132,7 +129,7 @@ func (f *file) Stat() (os.FileInfo, error) {
132129
name: f.Name(),
133130
mode: f.mode,
134131
size: f.content.Len(),
135-
modTime: f.modTime,
132+
modTime: f.content.modTime,
136133
}, nil
137134
}
138135

@@ -178,8 +175,9 @@ func (*fileInfo) Sys() interface{} {
178175
}
179176

180177
type content struct {
181-
name string
182-
bytes []byte
178+
name string
179+
bytes []byte
180+
modTime time.Time
183181

184182
m sync.RWMutex
185183
}
@@ -205,6 +203,7 @@ func (c *content) WriteAt(p []byte, off int64) (int, error) {
205203
if len(c.bytes) < prev {
206204
c.bytes = c.bytes[:prev]
207205
}
206+
c.modTime = time.Now()
208207
c.m.Unlock()
209208

210209
return len(p), nil

memfs/memory_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,11 @@ func TestModTime(t *testing.T) {
6666
// new calls to ModTime() retain existing mod time.
6767
assert.Equal(t, modtime, fi1a.ModTime())
6868

69-
// Writing to to file should change the mod time
70-
util.WriteFile(fs, "/file1", []byte{0}, 0o666)
69+
// Writing to file should change the mod time
70+
err = util.WriteFile(fs, "/file1", []byte{0}, 0o666)
71+
require.NoError(t, err)
7172
fi1c, err := fs.Stat("/file1")
73+
require.NoError(t, err)
7274
assert.NotEqual(t, modtime, fi1c.ModTime())
7375
}
7476

memfs/storage.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,13 @@ func (s *storage) New(path string, mode fs.FileMode, flag int) (*file, error) {
4444

4545
name := filepath.Base(path)
4646
f := &file{
47-
name: name,
48-
content: &content{name: name},
49-
mode: mode,
50-
flag: flag,
51-
modTime: time.Now(),
47+
name: name,
48+
content: &content{
49+
name: name,
50+
modTime: time.Now(),
51+
},
52+
mode: mode,
53+
flag: flag,
5254
}
5355

5456
s.mf.Lock()

0 commit comments

Comments
 (0)