1
mirror of https://github.com/rclone/rclone synced 2024-10-04 11:17:51 +02:00

webdav: fix race when creating directories - fixes #3035

Before this change a race condition existed in mkdir
- the directory was attempted to be created
- the parent didn't exist so it failed
- the parent was created
- the directory was created again

The last step failed as the directory was created in a different thread.

This was fixed by checking the error messages of MKCOL for both
directory creations, rather than only the first.
This commit is contained in:
Nick Craig-Wood 2019-03-08 12:54:39 +00:00
parent 415eeca6cf
commit 4827496234

View File

@ -644,10 +644,18 @@ func (f *Fs) _mkdir(dirPath string) error {
Path: dirPath, Path: dirPath,
NoResponse: true, NoResponse: true,
} }
return f.pacer.Call(func() (bool, error) { err := f.pacer.Call(func() (bool, error) {
resp, err := f.srv.Call(&opts) resp, err := f.srv.Call(&opts)
return shouldRetry(resp, err) return shouldRetry(resp, err)
}) })
if apiErr, ok := err.(*api.Error); ok {
// already exists
// owncloud returns 423/StatusLocked if the create is already in progress
if apiErr.StatusCode == http.StatusMethodNotAllowed || apiErr.StatusCode == http.StatusNotAcceptable || apiErr.StatusCode == http.StatusLocked {
return nil
}
}
return err
} }
// mkdir makes the directory and parents using native paths // mkdir makes the directory and parents using native paths
@ -655,12 +663,7 @@ func (f *Fs) mkdir(dirPath string) error {
// defer log.Trace(dirPath, "")("") // defer log.Trace(dirPath, "")("")
err := f._mkdir(dirPath) err := f._mkdir(dirPath)
if apiErr, ok := err.(*api.Error); ok { if apiErr, ok := err.(*api.Error); ok {
// already exists // parent does not exist so create it first then try again
// owncloud returns 423/StatusLocked if the create is already in progress
if apiErr.StatusCode == http.StatusMethodNotAllowed || apiErr.StatusCode == http.StatusNotAcceptable || apiErr.StatusCode == http.StatusLocked {
return nil
}
// parent does not exist
if apiErr.StatusCode == http.StatusConflict { if apiErr.StatusCode == http.StatusConflict {
err = f.mkParentDir(dirPath) err = f.mkParentDir(dirPath)
if err == nil { if err == nil {