Просмотр исходного кода

lib/model: Don't leak fd when truncate fails (fixes #4593)

Also attempt to handle this nicer by ignoring the truncate failure when
it doesn't matter, and recover by deleting the temp file when it does.

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4594
Jakob Borg 8 лет назад
Родитель
Сommit
c7522063b3
1 измененных файлов с 21 добавлено и 2 удалено
  1. 21 2
      lib/model/sharedpullerstate.go

+ 21 - 2
lib/model/sharedpullerstate.go

@@ -158,8 +158,27 @@ func (s *sharedPullerState) tempFile() (io.WriterAt, error) {
 		// Truncate sets the size of the file. This creates a sparse file or a
 		// space reservation, depending on the underlying filesystem.
 		if err := fd.Truncate(s.file.Size); err != nil {
-			s.failLocked("dst truncate", err)
-			return nil, err
+			// The truncate call failed. That can happen in some cases when
+			// space reservation isn't possible or over some network
+			// filesystems... This generally doesn't matter.
+
+			if s.reused > 0 {
+				// ... but if we are attempting to reuse a file we have a
+				// corner case when the old file is larger than the new one
+				// and we can't just overwrite blocks and let the old data
+				// linger at the end. In this case we attempt a delete of
+				// the file and hope for better luck next time, when we
+				// should come around with s.reused == 0.
+
+				fd.Close()
+
+				if remErr := s.fs.Remove(s.tempName); remErr != nil {
+					l.Debugln("failed to remove temporary file:", remErr)
+				}
+
+				s.failLocked("dst truncate", err)
+				return nil, err
+			}
 		}
 	}