From 90de5659ea8ad3241315a171c6bd2b05c40019ff Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Sat, 29 Nov 2014 23:51:53 +0100 Subject: [PATCH] Data race: sharedPullerState WriteAt+Close --- internal/model/sharedpullerstate.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/internal/model/sharedpullerstate.go b/internal/model/sharedpullerstate.go index 5d10d2d9..29fe68b6 100644 --- a/internal/model/sharedpullerstate.go +++ b/internal/model/sharedpullerstate.go @@ -16,6 +16,7 @@ package model import ( + "io" "os" "path/filepath" "sync" @@ -57,9 +58,22 @@ type pullerProgress struct { BytesTotal int64 } +// A lockedWriterAt synchronizes WriteAt calls with an external mutex. +// WriteAt() is goroutine safe by itself, but not against for example Close(). +type lockedWriterAt struct { + mut *sync.Mutex + wr io.WriterAt +} + +func (w lockedWriterAt) WriteAt(p []byte, off int64) (n int, err error) { + w.mut.Lock() + defer w.mut.Unlock() + return w.wr.WriteAt(p, off) +} + // tempFile returns the fd for the temporary file, reusing an open fd // or creating the file as necessary. -func (s *sharedPullerState) tempFile() (*os.File, error) { +func (s *sharedPullerState) tempFile() (io.WriterAt, error) { s.mut.Lock() defer s.mut.Unlock() @@ -70,7 +84,7 @@ func (s *sharedPullerState) tempFile() (*os.File, error) { // If the temp file is already open, return the file descriptor if s.fd != nil { - return s.fd, nil + return lockedWriterAt{&s.mut, s.fd}, nil } // Ensure that the parent directory is writable. This is @@ -106,7 +120,7 @@ func (s *sharedPullerState) tempFile() (*os.File, error) { // Same fd will be used by all writers s.fd = fd - return fd, nil + return lockedWriterAt{&s.mut, s.fd}, nil } // sourceFile opens the existing source file for reading