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.
This commit is contained in:
rayoo 2026-05-08 21:50:37 +08:00
parent 592209c0ee
commit 260a7097b6

View file

@ -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
}