[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: