fix: only enforce O_EXCL on MemMapFs OpenFile when O_CREATE is set
Per POSIX, O_EXCL is meaningful only together with O_CREATE. MemMapFs OpenFile returned ErrFileExists whenever O_EXCL was set on an existing file, so reopening a file with O_RDWR|O_EXCL failed even though no creation was requested. Guard the existence check with O_CREATE so that O_EXCL without O_CREATE opens the existing file, matching os.OpenFile. Fixes #415
This commit is contained in:
1 parent
2ae4e0266a
commit
afcb7e66f3
2 files changed
+32
-1
No files matched your search
@@ -263,7 +263,9 @@ func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, erro
|
|||||||
perm &= chmodBits
|
perm &= chmodBits
|
||||||
chmod := false
|
chmod := false
|
||||||
file, err := m.openWrite(name)
|
file, err := m.openWrite(name)
|
||||||
if err == nil && (flag&os.O_EXCL > 0) {
|
// O_EXCL is only meaningful together with O_CREATE (POSIX); without
|
||||||
|
// O_CREATE it must not prevent opening an existing file.
|
||||||
|
if err == nil && flag&os.O_EXCL > 0 && flag&os.O_CREATE > 0 {
|
||||||
return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileExists}
|
return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileExists}
|
||||||
}
|
}
|
||||||
if os.IsNotExist(err) && (flag&os.O_CREATE > 0) {
|
if os.IsNotExist(err) && (flag&os.O_CREATE > 0) {
|
||||||
|
|||||||
@@ -135,6 +135,35 @@ func TestOpenFileExcl(t *testing.T) {
|
|||||||
checkPathError(t, err, "Open")
|
checkPathError(t, err, "Open")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure os.O_EXCL only rejects an existing file when os.O_CREATE is also
|
||||||
|
// requested. Per POSIX, O_EXCL is meaningful only in combination with
|
||||||
|
// O_CREATE, so opening an existing file with O_RDWR|O_EXCL must succeed.
|
||||||
|
func TestOpenFileExclWithoutCreate(t *testing.T) {
|
||||||
|
const fileName = "/myExclNoCreate"
|
||||||
|
const fileMode = os.FileMode(0o644)
|
||||||
|
|
||||||
|
fs := NewMemMapFs()
|
||||||
|
|
||||||
|
// Create the file up front.
|
||||||
|
f, err := fs.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_EXCL, fileMode)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("initial create failed: %s", err)
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
|
||||||
|
// Reopening with O_EXCL but without O_CREATE must succeed.
|
||||||
|
f, err = fs.OpenFile(fileName, os.O_RDWR|os.O_EXCL, fileMode)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("OpenFile(O_RDWR|O_EXCL) on existing file should succeed, got: %s", err)
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
|
||||||
|
// O_CREATE|O_EXCL on an existing file must still fail.
|
||||||
|
if _, err := fs.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_EXCL, fileMode); err == nil {
|
||||||
|
t.Fatalf("OpenFile(O_CREATE|O_EXCL) on existing file should fail, but it didn't")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure Permissions are set on OpenFile/Mkdir/MkdirAll
|
// Ensure Permissions are set on OpenFile/Mkdir/MkdirAll
|
||||||
func TestPermSet(t *testing.T) {
|
func TestPermSet(t *testing.T) {
|
||||||
const fileName = "/myFileTest"
|
const fileName = "/myFileTest"
|
||||||
|
|||||||
Reference in new issue
Block a user