Bug#28614: Patch for dpkg-source three bug
retitle 28977 [PATCH] libgtkada_0.1a-6(frozen): source cannot be unpacked
retitle 28614 [PATCH] dpkg-dev: Interprets libgtkada_0.1a-6 diff file incorrectly
retitle 28979 [PATCH] abacus_0.9.13-1(frozen): Source cannot be unpacked
stop
Hi Ian, Wichert, or whoever feels responsible for dpkg-source...
I finally decided to fix the long-stand "three dashes" bug in
dpkg-source [1]. I did this by completely rewriting the code looking
through the patch and checking it. The new code doesn't follow a
check-if-everything-looks-ok principle, but really parses the diff.
Because I already was at dpkg-source, I also fixed two minor things:
- A (harmless) typo in an error message.
- Call patch with -g0, so that it in no case calls rcs or sccs to
check out things, which doesn't work (#28979)
If anyone of you agrees, I also can make a NMU of dpkg including this
patch. But I'd prefer if somebody else makes a new version, probably
including other fixes. Just don't forget this patch then :-)
Roman
[1]: see the bugs reports for a description. Briefly: If the diff
changes a line that starts with --, a line with "---" at the start
will be in the diff. dpkg-source misinterpreted this as the start of a
new file and probably complained that it's in a wrong dir.
------------------------------------------------------------------------------
--- dpkg-source~ Fri Aug 6 15:07:50 1999
+++ dpkg-source Fri Aug 6 16:40:46 1999
@@ -453,7 +453,7 @@
$sourcestyle =~ y/X/p/;
$sourcestyle =~ m/[pun]/ ||
- &usageerr("source handling style -s$sourcestyle not allowed with -b");
+ &usageerr("source handling style -s$sourcestyle not allowed with -x");
@ARGV==1 || &usageerr("-x needs exactly one argument, the .dsc");
$dsc= shift(@ARGV);
@@ -509,31 +509,48 @@
&forkgzipread("$dscdir/$difffile");
$/="\n";
- while (<GZIP>) {
- s/\n$// || &error("diff is missing trailing newline");
- if (/^--- /) {
- $fn= $';
- substr($fn,0,length($expectprefix)+1) eq "$expectprefix/" ||
- &error("diff patches file ($fn) not in expected subdirectory");
- $fn =~ m/\.dpkg-orig$/ &&
- &error("diff patches file with name ending .dpkg-orig");
- $dirname= $fn;
- if ($dirname =~ s,/[^/]+$,, && !defined($dirincluded{$dirname})) {
- $dirtocreate{$dirname} = 1;
+ $_ = <GZIP>;
+ do {
+ # read file header (---/+++ pair)
+ s/\n$// or &error("diff is missing trailing newline");
+ /^--- / or &error("expected ^--- in line $. of diff");
+ $fn= $';
+ substr($fn,0,length($expectprefix)+1) eq "$expectprefix/" ||
+ &error("diff patches file ($fn) not in expected subdirectory");
+ $fn =~ m/\.dpkg-orig$/ &&
+ &error("diff patches file with name ending .dpkg-orig");
+ $dirname= $fn;
+ if ($dirname =~ s,/[^/]+$,, && !defined($dirincluded{$dirname})) {
+ $dirtocreate{$dirname} = 1;
+ }
+ defined($notfileobject{$fn}) &&
+ &error("diff patches something which is not a plain file");
+ $_= <GZIP>; s/\n$// ||
+ &error("diff finishes in middle of ---/+++ (line $.)");
+ $_ eq '+++ '.$newdirectory.substr($fn,length($expectprefix)) ||
+ &error("line after --- for file $fn isn't as expected");
+ $filepatched{$fn}++ && &error("diff patches file $fn twice");
+ # read hunks
+ my $hunk = 0;
+ while (($_ = <GZIP>) && !/^--- /) {
+ # read hunk header (@@)
+ s/\n$// or &error("diff is missing trailing newline");
+ /^@@ -\d+(,(\d+))? \+\d+(,(\d+))? @\@$/ or
+ &error("Expected ^@@ in line $. of diff");
+ my ($olines, $nlines) = ($1 ? $2 : 1, $3 ? $4 : 1);
+ ++$hunk;
+ # read hunk
+ while ($olines || $nlines) {
+ $_ = <GZIP> or &error("unexpected end of diff");
+ s/\n$// or &error("diff is missing trailing newline");
+ if (/^ /) { --$olines; --$nlines; }
+ elsif (/^-/) { --$olines; }
+ elsif (/^\+/) { --$nlines; }
+ else { &error("expected [ +-] at start of line $. of diff"); }
}
- defined($notfileobject{$fn}) &&
- &error("diff patches something which is not a plain file");
- $_= <GZIP>; s/\n$// ||
- &error("diff finishes in middle of ---/+++ (line $.)");
- $_ eq '+++ '.$newdirectory.substr($fn,length($expectprefix)) ||
- &error("line after --- for file $fn isn't as expected");
- $filepatched{$fn}++ && &error("diff patches file $fn twice");
- } elsif (/^\\ No newline at end of file$/) {
- } elsif (/^[-+ \@]/) {
- } else {
- &error ("diff contains unknown line \`$_'");
- }
- }
+ }
+ $hunk or &error("expected ^\@\@ at line $. of diff");
+ } while ($_ || !eof(GZIP));
close(GZIP);
&reapgzip;
@@ -610,7 +627,7 @@
open(STDIN,"<&GZIP") || &syserr("reopen gzip for patch");
chdir($newdirectory) || &syserr("chdir to $newdirectory for patch");
exec('patch','-s','-t','-F','0','-N','-p1','-u',
- '-V','never','-b','-z','.dpkg-orig');
+ '-V','never','-g0','-b','-z','.dpkg-orig');
&syserr("exec patch");
}
close(GZIP);
Reply to: