[PATCH] scripts: avoid simultanious downloads from interfering

Dustin Lundquist dustin at null-ptr.net
Thu Feb 9 16:57:59 PST 2023


When you have multiple build roots sharing the download cache,
simultaneous downloads of the same file can result download.pl failing
with:

    Could not generate file hash

Use File::Temp for the download and hash output files, and then move the
download into place after the file hash is verified.

Signed-off-by: Dustin Lundquist <dustin at null-ptr.net>
---
 scripts/download.pl | 40 +++++++++++++++-------------------------
 1 file changed, 15 insertions(+), 25 deletions(-)

diff --git a/scripts/download.pl b/scripts/download.pl
index 676c6e9e6b..f735ecc6d5 100755
--- a/scripts/download.pl
+++ b/scripts/download.pl
@@ -1,5 +1,5 @@
 #!/usr/bin/env perl
-# 
+#
 # Copyright (C) 2006 OpenWrt.org
 # Copyright (C) 2016 LEDE project
 #
@@ -11,6 +11,7 @@ use strict;
 use warnings;
 use File::Basename;
 use File::Copy;
+use File::Temp;
 use Text::ParseWords;
 
 @ARGV > 2 or die "Syntax: $0 <target dir> <filename> <hash> <url filename> [<mirror> ...]\n";
@@ -149,10 +150,12 @@ sub download
 
 	$mirror =~ s!/$!!;
 
+	my $hash_tmp = File::Temp->new();
+	my $dl_tmp = File::Temp->new();
+
 	if ($mirror =~ s!^file://!!) {
 		if (! -d "$mirror") {
 			print STDERR "Wrong local cache directory -$mirror-.\n";
-			cleanup();
 			return;
 		}
 
@@ -183,10 +186,10 @@ sub download
 		}
 
 		print("Copying $filename from $link\n");
-		copy($link, "$target/$filename.dl");
+		copy($link, $dl_tmp);
 
 		$hash_cmd and do {
-			if (system("cat '$target/$filename.dl' | $hash_cmd > '$target/$filename.hash'")) {
+			if (system("cat '$dl_tmp' | $hash_cmd > '$hash_tmp'")) {
 				print("Failed to generate hash for $filename\n");
 				return;
 			}
@@ -196,46 +199,34 @@ sub download
 		print STDERR "+ ".join(" ", at cmd)."\n";
 		open(FETCH_FD, '-|', @cmd) or die "Cannot launch aria2c, curl or wget.\n";
 		$hash_cmd and do {
-			open MD5SUM, "| $hash_cmd > '$target/$filename.hash'" or die "Cannot launch $hash_cmd.\n";
+			open MD5SUM, "| $hash_cmd > '$hash_tmp'" or die "Cannot launch $hash_cmd.\n";
 		};
-		open OUTPUT, "> $target/$filename.dl" or die "Cannot create file $target/$filename.dl: $!\n";
 		my $buffer;
 		while (read FETCH_FD, $buffer, 1048576) {
 			$hash_cmd and print MD5SUM $buffer;
-			print OUTPUT $buffer;
+			print $dl_tmp $buffer;
 		}
 		$hash_cmd and close MD5SUM;
 		close FETCH_FD;
-		close OUTPUT;
 
 		if ($? >> 8) {
 			print STDERR "Download failed.\n";
-			cleanup();
 			return;
 		}
 	}
 
 	$hash_cmd and do {
-		my $sum = `cat "$target/$filename.hash"`;
+		my $sum = `cat "$hash_tmp"`;
 		$sum =~ /^(\w+)\s*/ or die "Could not generate file hash\n";
 		$sum = $1;
 
 		if ($sum ne $file_hash) {
 			print STDERR "Hash of the downloaded file does not match (file: $sum, requested: $file_hash) - deleting download.\n";
-			cleanup();
 			return;
 		}
 	};
 
-	unlink "$target/$filename";
-	system("mv", "$target/$filename.dl", "$target/$filename");
-	cleanup();
-}
-
-sub cleanup
-{
-	unlink "$target/$filename.dl";
-	unlink "$target/$filename.hash";
+	system("mv", "-f", "$dl_tmp", "$target/$filename");
 }
 
 @mirrors = localmirrors();
@@ -332,19 +323,19 @@ push @mirrors, 'https://mirror2.openwrt.org/sources';
 
 if (-f "$target/$filename") {
 	$hash_cmd and do {
-		if (system("cat '$target/$filename' | $hash_cmd > '$target/$filename.hash'")) {
+		my $hash_tmp = File::Temp->new();
+
+		if (system("cat '$target/$filename' | $hash_cmd > '$hash_tmp'")) {
 			die "Failed to generate hash for $filename\n";
 		}
 
-		my $sum = `cat "$target/$filename.hash"`;
+		my $sum = `cat "$hash_tmp"`;
 		$sum =~ /^(\w+)\s*/ or die "Could not generate file hash\n";
 		$sum = $1;
 
-		cleanup();
 		exit 0 if $sum eq $file_hash;
 
 		die "Hash of the local file $filename does not match (file: $sum, requested: $file_hash) - deleting download.\n";
-		unlink "$target/$filename";
 	};
 }
 
@@ -360,4 +351,3 @@ while (!-f "$target/$filename") {
 	}
 }
 
-$SIG{INT} = \&cleanup;
-- 
2.30.2




More information about the openwrt-devel mailing list