Using a separate os.Stat() call may result in a race where another
request handler running concurrently creates the file in-between
the os.Stat() call and the os.Create() call.
Use O_EXCL to avoid this situation.
---
storage/filesystem.go | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/storage/filesystem.go b/storage/filesystem.go
index ce9f00bf468a..79ce1f218e23 100644
--- a/storage/filesystem.go
+++ b/storage/filesystem.go
@@ -425,13 +425,16 @@ func (b *filesystemBackend) PutAddressObject(ctx context.Context, objPath string
return "", err
}
- // TODO handle IfMatch
- if _, err := os.Stat(localPath); !os.IsNotExist(err) && opts.IfNoneMatch {
- return "", carddav.NewPreconditionError(carddav.PreconditionNoUIDConflict)
+ flags := os.O_RDWR | os.O_CREATE | os.O_TRUNC
+ if opts.IfNoneMatch {
+ flags |= os.O_EXCL
}
- f, err := os.Create(localPath)
- if err != nil {
+ // TODO handle IfMatch
+ f, err := os.OpenFile(localPath, flags, 0666)
+ if os.IsExist(err) {
+ return "", carddav.NewPreconditionError(carddav.PreconditionNoUIDConflict)
+ } else if err != nil {
return "", err
}
defer f.Close()
@@ -604,13 +607,16 @@ func (b *filesystemBackend) PutCalendarObject(ctx context.Context, objPath strin
return "", err
}
- // TODO handle IfMatch
- if _, err := os.Stat(localPath); !os.IsNotExist(err) && opts.IfNoneMatch {
- return "", caldav.NewPreconditionError(caldav.PreconditionNoUIDConflict)
+ flags := os.O_RDWR | os.O_CREATE | os.O_TRUNC
+ if opts.IfNoneMatch {
+ flags |= os.O_EXCL
}
- f, err := os.Create(localPath)
- if err != nil {
+ // TODO handle IfMatch
+ f, err := os.OpenFile(localPath, flags, 0666)
+ if os.IsExist(err) {
+ return "", caldav.NewPreconditionError(caldav.PreconditionNoUIDConflict)
+ } else if err != nil {
return "", err
}
defer f.Close()
@@ -622,5 +628,4 @@ func (b *filesystemBackend) PutCalendarObject(ctx context.Context, objPath strin
}
return objPath, nil
- return "", nil
}
base-commit: 04a422523a008a655e3b4eac3ae7b524b3afc38b
--
2.36.1