* download-using-manifests: don't check the cryptographic hash of

downloaded files; rather, check the hash of the unpacked store
  path.

  When the server produces bzipped NAR archives on demand (like Hydra
  does), the hash of the file is not known in advance; it's streamed
  from the server.  Thus the manifest doesn't contain a hash for the
  bzipped NAR archive.  However, the server does know the hash of the
  *uncompressed* NAR archive (the "NarHash" field), since it's stored
  in the Nix database (nix-store -q --hash /nix/store/bla).  So we use
  that instead for checking the integrity of the download.
This commit is contained in:
Eelco Dolstra 2009-02-19 23:46:37 +00:00
parent 621093cb1c
commit 041717eda3

View file

@ -185,13 +185,11 @@ while ($queueFront < scalar @queue) {
$format = "" if $baseHashAlgo eq "md5"; $format = "" if $baseHashAlgo eq "md5";
my $hash = `$binDir/nix-hash --type '$baseHashAlgo' $format "$patch->{basePath}"`; my $hash = `$binDir/nix-hash --type '$baseHashAlgo' $format "$patch->{basePath}"`;
chomp $hash; chomp $hash;
# print " MY HASH is $hash\n";
if ($hash ne $baseHash) { if ($hash ne $baseHash) {
print LOGFILE "$$ rejecting $patch->{basePath}\n"; print LOGFILE "$$ rejecting $patch->{basePath}\n";
next; next;
} }
} }
# print " PATCH from $patch->{basePath}\n";
addToQueue $patch->{basePath}; addToQueue $patch->{basePath};
addEdge $patch->{basePath}, $u, $patch->{size}, "patch", $patch; addEdge $patch->{basePath}, $u, $patch->{size}, "patch", $patch;
} }
@ -199,10 +197,12 @@ while ($queueFront < scalar @queue) {
# Add NAR file edges to the start node. # Add NAR file edges to the start node.
my $narFileList = $narFiles{$u}; my $narFileList = $narFiles{$u};
foreach my $narFile (@{$narFileList}) { foreach my $narFile (@{$narFileList}) {
# print " NAR from $narFile->{url}\n"; # !!! how to handle files whose size is not known in advance?
addEdge "start", $u, $narFile->{size}, "narfile", $narFile; # For now, assume some arbitrary size (1 MB).
addEdge "start", $u, ($narFile->{size} || 1000000), "narfile", $narFile;
if ($u eq $targetPath) { if ($u eq $targetPath) {
print LOGFILE "$$ full-download-would-be $narFile->{size}\n"; my $size = $narFile->{size} || -1;
print LOGFILE "$$ full-download-would-be $size\n";
} }
} }
@ -228,8 +228,6 @@ while (scalar @todo > 0) {
my $u_ = $graph{$u}; my $u_ = $graph{$u};
# print "IN $u $u_->{d}\n";
foreach my $edge (@{$u_->{edges}}) { foreach my $edge (@{$u_->{edges}}) {
my $v_ = $graph{$edge->{end}}; my $v_ = $graph{$edge->{end}};
if ($v_->{d} > $u_->{d} + $edge->{weight}) { if ($v_->{d} > $u_->{d} + $edge->{weight}) {
@ -237,7 +235,6 @@ while (scalar @todo > 0) {
# Store the edge; to edge->start is actually the # Store the edge; to edge->start is actually the
# predecessor. # predecessor.
$v_->{pred} = $edge; $v_->{pred} = $edge;
# print " RELAX $edge->{end} $v_->{d}\n";
} }
} }
} }
@ -261,18 +258,16 @@ my $maxStep = scalar @path;
sub downloadFile { sub downloadFile {
my $url = shift; my $url = shift;
my ($hashAlgo, $hash) = parseHash(shift);
$ENV{"PRINT_PATH"} = 1; $ENV{"PRINT_PATH"} = 1;
$ENV{"QUIET"} = 1; $ENV{"QUIET"} = 1;
$ENV{"NIX_HASH_ALGO"} = $hashAlgo; my ($hash, $path) = `$binDir/nix-prefetch-url '$url'`;
my ($hash2, $path) = `$binDir/nix-prefetch-url '$url' '$hash'`;
die "download of `$url' failed" unless $? == 0; die "download of `$url' failed" unless $? == 0;
chomp $hash2;
chomp $path; chomp $path;
die "hash mismatch, expected $hash, got $hash2" if $hash ne $hash2;
return $path; return $path;
} }
my $finalNarHash;
while (scalar @path > 0) { while (scalar @path > 0) {
my $edge = pop @path; my $edge = pop @path;
my $u = $edge->{start}; my $u = $edge->{start};
@ -302,7 +297,7 @@ while (scalar @path > 0) {
# Download the patch. # Download the patch.
print " downloading patch...\n"; print " downloading patch...\n";
my $patchPath = downloadFile "$patch->{url}", "$patch->{hash}"; my $patchPath = downloadFile "$patch->{url}";
# Apply the patch to the NAR archive produced in step 1 (for # Apply the patch to the NAR archive produced in step 1 (for
# the already present path) or a later step (for patch sequences). # the already present path) or a later step (for patch sequences).
@ -320,17 +315,20 @@ while (scalar @path > 0) {
system("$binDir/nix-store --restore $v < $tmpNar2") == 0 system("$binDir/nix-store --restore $v < $tmpNar2") == 0
or die "cannot unpack $tmpNar2 into `$v'"; or die "cannot unpack $tmpNar2 into `$v'";
} }
$finalNarHash = $patch->{narHash};
} }
elsif ($edge->{type} eq "narfile") { elsif ($edge->{type} eq "narfile") {
my $narFile = $edge->{info}; my $narFile = $edge->{info};
print "downloading `$narFile->{url}' into `$v'\n"; print "downloading `$narFile->{url}' into `$v'\n";
print LOGFILE "$$ narfile $narFile->{url} $narFile->{size} $v\n"; my $size = $narFile->{size} || -1;
print LOGFILE "$$ narfile $narFile->{url} $size $v\n";
# Download the archive. # Download the archive.
print " downloading archive...\n"; print " downloading archive...\n";
my $narFilePath = downloadFile "$narFile->{url}", "$narFile->{hash}"; my $narFilePath = downloadFile "$narFile->{url}";
if ($curStep < $maxStep) { if ($curStep < $maxStep) {
# The archive will be used a base to a patch. # The archive will be used a base to a patch.
@ -342,11 +340,25 @@ while (scalar @path > 0) {
system("@bunzip2@ < '$narFilePath' | $binDir/nix-store --restore '$v'") == 0 system("@bunzip2@ < '$narFilePath' | $binDir/nix-store --restore '$v'") == 0
or die "cannot unpack `$narFilePath' into `$v'"; or die "cannot unpack `$narFilePath' into `$v'";
} }
$finalNarHash = $narFile->{narHash};
} }
$curStep++; $curStep++;
} }
if (defined $finalNarHash) {
my ($hashAlgo, $hash) = parseHash $finalNarHash;
my $hash2 = `@bindir@/nix-hash --type $hashAlgo --base32 $targetPath`
or die "cannot compute hash of path `$targetPath'";
chomp $hash2;
die "hash mismatch in downloaded path $targetPath; expected $hash, got $hash2"
if $hash ne $hash2;
} else {
die "cannot check integrity of the downloaded path since its hash is not known";
}
print LOGFILE "$$ success\n"; print LOGFILE "$$ success\n";
close LOGFILE; close LOGFILE;