storage/filesystem: atomically check for IfNoneMatch

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.
This commit is contained in:
Simon Ser 2022-06-03 06:33:48 +00:00 committed by Conrad Hoffmann
parent a3bfd56bf9
commit 228384530e

View File

@ -425,13 +425,16 @@ func (b *filesystemBackend) PutAddressObject(ctx context.Context, objPath string
return "", err return "", err
} }
// TODO handle IfMatch flags := os.O_RDWR | os.O_CREATE | os.O_TRUNC
if _, err := os.Stat(localPath); !os.IsNotExist(err) && opts.IfNoneMatch { if opts.IfNoneMatch {
return "", carddav.NewPreconditionError(carddav.PreconditionNoUIDConflict) flags |= os.O_EXCL
} }
f, err := os.Create(localPath) // TODO handle IfMatch
if err != nil { f, err := os.OpenFile(localPath, flags, 0666)
if os.IsExist(err) {
return "", carddav.NewPreconditionError(carddav.PreconditionNoUIDConflict)
} else if err != nil {
return "", err return "", err
} }
defer f.Close() defer f.Close()
@ -602,13 +605,16 @@ func (b *filesystemBackend) PutCalendarObject(ctx context.Context, objPath strin
return "", err return "", err
} }
// TODO handle IfMatch flags := os.O_RDWR | os.O_CREATE | os.O_TRUNC
if _, err := os.Stat(localPath); !os.IsNotExist(err) && opts.IfNoneMatch { if opts.IfNoneMatch {
return "", caldav.NewPreconditionError(caldav.PreconditionNoUIDConflict) flags |= os.O_EXCL
} }
f, err := os.Create(localPath) // TODO handle IfMatch
if err != nil { f, err := os.OpenFile(localPath, flags, 0666)
if os.IsExist(err) {
return "", caldav.NewPreconditionError(caldav.PreconditionNoUIDConflict)
} else if err != nil {
return "", err return "", err
} }
defer f.Close() defer f.Close()
@ -620,5 +626,4 @@ func (b *filesystemBackend) PutCalendarObject(ctx context.Context, objPath strin
} }
return objPath, nil return objPath, nil
return "", nil
} }