diff --git a/lib/model/sharedpullerstate.go b/lib/model/sharedpullerstate.go index 5fdd72066..61628cb03 100644 --- a/lib/model/sharedpullerstate.go +++ b/lib/model/sharedpullerstate.go @@ -86,8 +86,24 @@ func (s *sharedPullerState) tempFile() (io.WriterAt, error) { // here. dir := filepath.Dir(s.tempName) if info, err := os.Stat(dir); err != nil { - s.failLocked("dst stat dir", err) - return nil, err + if os.IsNotExist(err) { + // XXX: This works around a bug elsewhere, a race condition when + // things are deleted while being synced. However that happens, we + // end up with a directory for "foo" with the delete bit, but a + // file "foo/bar" that we want to sync. We never create the + // directory, and hence fail to create the file and end up looping + // forever on it. This breaks that by creating the directory; on + // next scan it'll be found and the delete bit on it is removed. + // The user can then clean up as they like... + l.Infoln("Resurrecting directory", dir) + if err := os.MkdirAll(dir, 0755); err != nil { + s.failLocked("resurrect dir", err) + return nil, err + } + } else { + s.failLocked("dst stat dir", err) + return nil, err + } } else if info.Mode()&0200 == 0 { err := os.Chmod(dir, 0755) if !s.ignorePerms && err == nil {