mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 22:26:42 +00:00
internal/download: download to temporary file
This commit is contained in:
parent
b9bd298fba
commit
e127b9f71e
1 changed files with 59 additions and 25 deletions
|
|
@ -128,8 +128,46 @@ func (db *ChecksumDB) Files() iter.Seq[string] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// findHash returns the known hash of a file.
|
||||||
|
func (db *ChecksumDB) findHash(basename string) string {
|
||||||
|
for _, e := range db.hashes {
|
||||||
|
if e.file == basename {
|
||||||
|
return e.hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// Verify checks whether the given file is valid according to the checksum database.
|
// Verify checks whether the given file is valid according to the checksum database.
|
||||||
func (db *ChecksumDB) Verify(path string) error {
|
func (db *ChecksumDB) Verify(path string) error {
|
||||||
|
basename := filepath.Base(path)
|
||||||
|
hash := db.findHash(basename)
|
||||||
|
if hash == "" {
|
||||||
|
return fmt.Errorf("no known hash for file %q", basename)
|
||||||
|
}
|
||||||
|
return verifyHash(path, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyAll downloads all files and checks that they match the checksum given in
|
||||||
|
// the database. This task can be used to sanity-check new checksums.
|
||||||
|
func (db *ChecksumDB) VerifyAll() {
|
||||||
|
var (
|
||||||
|
tmp = os.TempDir()
|
||||||
|
)
|
||||||
|
for _, e := range db.hashes {
|
||||||
|
if e.url == nil {
|
||||||
|
log.Printf("Skipping verification of %s: no URL defined in checksum database", e.file)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
url := e.url.JoinPath(e.file).String()
|
||||||
|
dst := filepath.Join(tmp, e.file)
|
||||||
|
if err := db.DownloadFile(url, dst); err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyHash(path, expectedHash string) error {
|
||||||
fd, err := os.Open(path)
|
fd, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -141,10 +179,11 @@ func (db *ChecksumDB) Verify(path string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fileHash := hex.EncodeToString(h.Sum(nil))
|
fileHash := hex.EncodeToString(h.Sum(nil))
|
||||||
if !db.containsHash(filepath.Base(path), fileHash) {
|
if fileHash != expectedHash {
|
||||||
return fmt.Errorf("invalid file hash: %s %s", fileHash, filepath.Base(path))
|
return fmt.Errorf("invalid file hash: %s %s", fileHash, filepath.Base(path))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadFileFromKnownURL downloads a file from the URL defined in the checksum database.
|
// DownloadFileFromKnownURL downloads a file from the URL defined in the checksum database.
|
||||||
|
|
@ -159,26 +198,34 @@ func (db *ChecksumDB) DownloadFileFromKnownURL(dstPath string) error {
|
||||||
|
|
||||||
// DownloadFile downloads a file and verifies its checksum.
|
// DownloadFile downloads a file and verifies its checksum.
|
||||||
func (db *ChecksumDB) DownloadFile(url, dstPath string) error {
|
func (db *ChecksumDB) DownloadFile(url, dstPath string) error {
|
||||||
if err := db.Verify(dstPath); err == nil {
|
basename := filepath.Base(dstPath)
|
||||||
|
hash := db.findHash(basename)
|
||||||
|
if hash == "" {
|
||||||
|
return fmt.Errorf("no known hash for file %q", basename)
|
||||||
|
}
|
||||||
|
// Shortcut if already downloaded.
|
||||||
|
if verifyHash(dstPath, hash) == nil {
|
||||||
fmt.Printf("%s is up-to-date\n", dstPath)
|
fmt.Printf("%s is up-to-date\n", dstPath)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%s is stale\n", dstPath)
|
fmt.Printf("%s is stale\n", dstPath)
|
||||||
fmt.Printf("downloading from %s\n", url)
|
fmt.Printf("downloading from %s\n", url)
|
||||||
|
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("download error: %v", err)
|
return fmt.Errorf("download error: %v", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return fmt.Errorf("download error: status %d", resp.StatusCode)
|
return fmt.Errorf("download error: status %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(filepath.Dir(dstPath), 0755); err != nil {
|
if err := os.MkdirAll(filepath.Dir(dstPath), 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fd, err := os.OpenFile(dstPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
|
||||||
|
// Download to a temporary file.
|
||||||
|
tmpfile := dstPath + ".tmp"
|
||||||
|
fd, err := os.OpenFile(tmpfile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -186,9 +233,15 @@ func (db *ChecksumDB) DownloadFile(url, dstPath string) error {
|
||||||
_, err = io.Copy(dst, resp.Body)
|
_, err = io.Copy(dst, resp.Body)
|
||||||
dst.Close()
|
dst.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
os.Remove(tmpfile)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return db.Verify(dstPath)
|
if err := verifyHash(tmpfile, hash); err != nil {
|
||||||
|
os.Remove(tmpfile)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// It's valid, rename to dstPath to complete the download.
|
||||||
|
return os.Rename(tmpfile, dstPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindVersion returns the current known version of a tool, if it is defined in the file.
|
// FindVersion returns the current known version of a tool, if it is defined in the file.
|
||||||
|
|
@ -214,25 +267,6 @@ func (db *ChecksumDB) FindURL(basename string) (string, error) {
|
||||||
return "", fmt.Errorf("file %q does not exist in checksum database", basename)
|
return "", fmt.Errorf("file %q does not exist in checksum database", basename)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyAll downloads all files and checks that they match the checksum given in
|
|
||||||
// the database. This task can be used to sanity-check new checksums.
|
|
||||||
func (db *ChecksumDB) VerifyAll() {
|
|
||||||
var (
|
|
||||||
tmp = os.TempDir()
|
|
||||||
)
|
|
||||||
for _, e := range db.hashes {
|
|
||||||
if e.url == nil {
|
|
||||||
log.Printf("Skipping verification of %s: no URL defined in checksum database", e.file)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
url := e.url.JoinPath(e.file).String()
|
|
||||||
dst := filepath.Join(tmp, e.file)
|
|
||||||
if err := db.DownloadFile(url, dst); err != nil {
|
|
||||||
log.Print(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *ChecksumDB) containsHash(basename, hash string) bool {
|
func (db *ChecksumDB) containsHash(basename, hash string) bool {
|
||||||
return slices.ContainsFunc(db.hashes, func(e hashEntry) bool {
|
return slices.ContainsFunc(db.hashes, func(e hashEntry) bool {
|
||||||
return e.file == basename && e.hash == hash
|
return e.file == basename && e.hash == hash
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue