Skip to content

Commit 2c3e227

Browse files
memfs: When using O_CREATE, the file is allowed to exist, unless O_EXCL
OpenFile currently gives an error if O_CREATE is passed and the file already exists. This is not how O_CREATE is meant to work. O_CREATE requests the file to be created if it does not exist. However, if O_EXCL is also set, then the file must not exist. Implement and test this behavior.
1 parent c14afca commit 2c3e227

File tree

2 files changed

+25
-12
lines changed

2 files changed

+25
-12
lines changed

memfs/memfs.go

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -229,13 +229,9 @@ func (fs *MemFS) OpenFile(name string, flag int, perm os.FileMode) (vfs.File, er
229229
return nil, &os.PathError{"open", name, err}
230230
}
231231

232-
if hasFlag(os.O_CREATE, flag) {
233-
if fiNode != nil {
234-
235-
// If O_TRUNC is set, existing file is overwritten
236-
if !hasFlag(os.O_TRUNC, flag) {
237-
return nil, &os.PathError{"open", name, os.ErrExist}
238-
}
232+
if fiNode == nil {
233+
if !hasFlag(os.O_CREATE, flag) {
234+
return nil, &os.PathError{"open", name, os.ErrNotExist}
239235
}
240236
fiNode = &fileInfo{
241237
name: base,
@@ -246,14 +242,15 @@ func (fs *MemFS) OpenFile(name string, flag int, perm os.FileMode) (vfs.File, er
246242
fs: fs,
247243
}
248244
fiParent.childs[base] = fiNode
249-
} else { // find existing
250-
if fiNode == nil {
251-
return nil, &os.PathError{"open", name, os.ErrNotExist}
245+
} else { // file exists
246+
if hasFlag(os.O_CREATE|os.O_EXCL, flag) {
247+
return nil, &os.PathError{"open", name, os.ErrExist}
252248
}
253249
if fiNode.dir {
254250
return nil, &os.PathError{"open", name, ErrIsDirectory}
255251
}
256252
}
253+
257254
if !hasFlag(os.O_RDONLY, flag) {
258255
fiNode.modTime = time.Now()
259256
}

memfs/memfs_test.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,29 @@ func TestCreate(t *testing.T) {
2626
}
2727
}
2828

29-
// Create same file twice, no error because os.O_TRUNC is used
29+
// Create same file again
30+
{
31+
_, err := fs.OpenFile("/testfile", os.O_RDWR|os.O_CREATE, 0666)
32+
if err != nil {
33+
t.Fatalf("Unexpected error creating file: %s", err)
34+
}
35+
36+
}
37+
38+
// Create same file again, but truncate it
3039
{
3140
_, err := fs.OpenFile("/testfile", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
3241
if err != nil {
33-
t.Fatalf("Expected error creating file: %s", err)
42+
t.Fatalf("Unexpected error creating file: %s", err)
3443
}
44+
}
3545

46+
// Create same file again with O_CREATE|O_EXCL, which is an error
47+
{
48+
_, err := fs.OpenFile("/testfile", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
49+
if err == nil {
50+
t.Fatalf("Expected error creating file: %s", err)
51+
}
3652
}
3753

3854
// Create file with unkown parent

0 commit comments

Comments
 (0)