From 260a7097b6dd6e534b1f300a905d40cd8112cfcd Mon Sep 17 00:00:00 2001 From: rayoo Date: Fri, 8 May 2026 21:50:37 +0800 Subject: [PATCH] internal/download: close dst on io.Copy error PR #34866 refactored DownloadFile to return early on io.Copy errors, but moved dst.Close() behind the error check. When io.Copy fails (e.g. on a mid-download network error), the underlying file descriptor is no longer closed before the function returns - only os.Remove is called against the still-open tmpfile, which is a no-op on Windows. Before #34866: _, err = io.Copy(dst, resp.Body) dst.Close() // unconditional if err != nil { os.Remove(tmpfile) return err } After #34866: if _, err = io.Copy(dst, resp.Body); err != nil { os.Remove(tmpfile) // dst never closed return err } if err = dst.Close(); err != nil { ... } Restore the pre-refactor invariant by closing dst on the io.Copy error path before os.Remove, matching the existing close-then-remove ordering on the dst.Close() error path a few lines below. --- internal/download/download.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/download/download.go b/internal/download/download.go index 27d37327314c..94517166f534 100644 --- a/internal/download/download.go +++ b/internal/download/download.go @@ -212,6 +212,7 @@ func (db *ChecksumDB) DownloadFile(url, dstPath string) error { dst = newDownloadWriter(fd, resp.ContentLength) } if _, err = io.Copy(dst, resp.Body); err != nil { + dst.Close() os.Remove(tmpfile) return err }