git-svn: better attempt to handle broken symlink updates

This is a followup to 7fc35e0e94782bbbefb920875813519038659930,
(workaround a for broken symlinks in SVN).

Since broken SVN clients can commit svn:special files without
the magic "link " prefix, this can affect delta application
when we update the broken svn:special file.  So now we fall
back and retry the delta application on symlinks if having
a "link " prefix fails.

Our behavior differs from svn(1) (v1.5.1) slightly:

  When a svn:special file is created w/o a "link " prefix, svn
  will create a regular file (mode 100644 to git) with the
  contents of the blob as-is.

  Our behavior is to continue creating the symlink (mode 120000
  to git) with the contents of the blob as-is.  While this
  differs from current svn(1) behavior, this is easier and more
  efficient to implement (and the correctness of the svn(1) is
  debatable, since it's a workaround for a bug in the first
  place).

More information on this SVN bug is described here:
  http://subversion.tigris.org/issues/show_bug.cgi?id=2692

Signed-off-by: Eric Wong <normalperson@yhbt.net>
diff --git a/git-svn.perl b/git-svn.perl
index 1b87a65..b0e3d7c 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -3380,19 +3380,35 @@
 	open my $dup, '<&', $fh or croak $!;
 	my $base = $::_repository->temp_acquire('git_blob');
 	if ($fb->{blob}) {
+		my ($base_is_link, $size);
+
 		if ($fb->{mode_a} eq '120000' &&
 		    ! $self->{empty_symlinks}->{$fb->{path}}) {
 			print $base 'link ' or die "print $!\n";
+			$base_is_link = 1;
 		}
-		my $size = $::_repository->cat_blob($fb->{blob}, $base);
+	retry:
+		$size = $::_repository->cat_blob($fb->{blob}, $base);
 		die "Failed to read object $fb->{blob}" if ($size < 0);
 
 		if (defined $exp) {
 			seek $base, 0, 0 or croak $!;
 			my $got = ::md5sum($base);
-			die "Checksum mismatch: $fb->{path} $fb->{blob}\n",
-			    "expected: $exp\n",
-			    "     got: $got\n" if ($got ne $exp);
+			if ($got ne $exp) {
+				my $err = "Checksum mismatch: ".
+				       "$fb->{path} $fb->{blob}\n" .
+				       "expected: $exp\n" .
+				       "     got: $got\n";
+				if ($base_is_link) {
+					warn $err,
+					     "Retrying... (possibly ",
+					     "a bad symlink from SVN)\n";
+					$::_repository->temp_reset($base);
+					$base_is_link = 0;
+					goto retry;
+				}
+				die $err;
+			}
 		}
 	}
 	seek $base, 0, 0 or croak $!;