@matheusbsbs / matheus-bagliano / commits / 94b2ee1aee
Fork 0

perl: make SVN code hash independent

There are several places throughout git-svn that use various hard-coded constants. For matching object IDs, use the $oid variable. Compute the record size we use for our revision storage based on the object ID. When parsing the revision map format, use a wildcard in the pack format since we know that the data we're parsing is always exactly the record size. This lets us continue to use a constant for the pack format. Finally, update several comments to reflect the fact that an object ID may be of one of multiple sizes. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Acked-by: Eric Wong <e@80x24.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

brian m. carlson committed Jun 22, 2020 at 18:04 UTC 94b2ee1aeeb2dbec8383118db74d5c5c0a95476f
5 files changed +48 -45
git-svn.perl
+2 -2
@@ -2008,10 +2008,10 @@ sub cmt_sha2rev_batch {
2008 print $out $sha, "\n";
2009
2010 while (my $line = <$in>) {
2011 - if ($first && $line =~ /^[[:xdigit:]]{40}\smissing$/) {
2011 + if ($first && $line =~ /^$::oid\smissing$/) {
2012 last;
2013 } elsif ($first &&
2014 - $line =~ /^[[:xdigit:]]{40}\scommit\s(\d+)$/) {
2014 + $line =~ /^$::oid\scommit\s(\d+)$/) {
2015 $first = 0;
2016 $size = $1;
2017 next;
perl/Git/SVN.pm
+38 -35
@@ -2,7 +2,7 @@ package Git::SVN;
2 use strict;
3 use warnings;
4 use Fcntl qw/:DEFAULT :seek/;
5 -use constant rev_map_fmt => 'NH40';
5 +use constant rev_map_fmt => 'NH*';
6 use vars qw/$_no_metadata
7 $_repack $_repack_flags $_use_svm_props $_head
8 $_use_svnsync_props $no_reuse_existing
@@ -2087,10 +2087,10 @@ sub rebuild_from_rev_db {
2087 open my $fh, '<', $path or croak "open: $!";
2088 binmode $fh or croak "binmode: $!";
2089 while (<$fh>) {
2090 - length($_) == 41 or croak "inconsistent size in ($_) != 41";
2090 + length($_) == $::oid_length + 1 or croak "inconsistent size in ($_)";
2091 chomp($_);
2092 ++$r;
2093 - next if $_ eq ('0' x 40);
2093 + next if $_ eq ('0' x $::oid_length);
2094 $self->rev_map_set($r, $_);
2095 print "r$r = $_\n";
2096 }
@@ -2196,9 +2196,9 @@ sub rebuild {
2196 # (mainly tags)
2197 #
2198 # The format is this:
2199 -# - 24 bytes for every record,
2199 +# - 24 or 36 bytes for every record,
2200 # * 4 bytes for the integer representing an SVN revision number
2201 -# * 20 bytes representing the sha1 of a git commit
2201 +# * 20 or 32 bytes representing the oid of a git commit
2202 # - No empty padding records like the old format
2203 # (except the last record, which can be overwritten)
2204 # - new records are written append-only since SVN revision numbers
@@ -2207,7 +2207,7 @@ sub rebuild {
2207 # - Piping the file to xxd -c24 is a good way of dumping it for
2208 # viewing or editing (piped back through xxd -r), should the need
2209 # ever arise.
2210 -# - The last record can be padding revision with an all-zero sha1
2210 +# - The last record can be padding revision with an all-zero oid
2211 # This is used to optimize fetch performance when using multiple
2212 # "fetch" directives in .git/config
2213 #
@@ -2215,38 +2215,39 @@ sub rebuild {
2215
2216 sub _rev_map_set {
2217 my ($fh, $rev, $commit) = @_;
2218 + my $record_size = ($::oid_length / 2) + 4;
2219
2220 binmode $fh or croak "binmode: $!";
2221 my $size = (stat($fh))[7];
2221 - ($size % 24) == 0 or croak "inconsistent size: $size";
2222 + ($size % $record_size) == 0 or croak "inconsistent size: $size";
2223
2224 my $wr_offset = 0;
2225 if ($size > 0) {
2225 - sysseek($fh, -24, SEEK_END) or croak "seek: $!";
2226 - my $read = sysread($fh, my $buf, 24) or croak "read: $!";
2227 - $read == 24 or croak "read only $read bytes (!= 24)";
2226 + sysseek($fh, -$record_size, SEEK_END) or croak "seek: $!";
2227 + my $read = sysread($fh, my $buf, $record_size) or croak "read: $!";
2228 + $read == $record_size or croak "read only $read bytes (!= $record_size)";
2229 my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf);
2229 - if ($last_commit eq ('0' x40)) {
2230 - if ($size >= 48) {
2231 - sysseek($fh, -48, SEEK_END) or croak "seek: $!";
2232 - $read = sysread($fh, $buf, 24) or
2230 + if ($last_commit eq ('0' x $::oid_length)) {
2231 + if ($size >= ($record_size * 2)) {
2232 + sysseek($fh, -($record_size * 2), SEEK_END) or croak "seek: $!";
2233 + $read = sysread($fh, $buf, $record_size) or
2234 croak "read: $!";
2234 - $read == 24 or
2235 - croak "read only $read bytes (!= 24)";
2235 + $read == $record_size or
2236 + croak "read only $read bytes (!= $record_size)";
2237 ($last_rev, $last_commit) =
2238 unpack(rev_map_fmt, $buf);
2238 - if ($last_commit eq ('0' x40)) {
2239 + if ($last_commit eq ('0' x $::oid_length)) {
2240 croak "inconsistent .rev_map\n";
2241 }
2242 }
2243 if ($last_rev >= $rev) {
2244 croak "last_rev is higher!: $last_rev >= $rev";
2245 }
2245 - $wr_offset = -24;
2246 + $wr_offset = -$record_size;
2247 }
2248 }
2249 sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!";
2249 - syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or
2250 + syswrite($fh, pack(rev_map_fmt, $rev, $commit), $record_size) == $record_size or
2251 croak "write: $!";
2252 }
2253
@@ -2271,7 +2272,7 @@ sub mkfile {
2272 sub rev_map_set {
2273 my ($self, $rev, $commit, $update_ref, $uuid) = @_;
2274 defined $commit or die "missing arg3\n";
2274 - length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n";
2275 + $commit =~ /^$::oid$/ or die "arg3 must be a full hex object ID\n";
2276 my $db = $self->map_path($uuid);
2277 my $db_lock = "$db.lock";
2278 my $sigmask;
@@ -2344,29 +2345,30 @@ sub rev_map_max {
2345
2346 sub rev_map_max_norebuild {
2347 my ($self, $want_commit) = @_;
2348 + my $record_size = ($::oid_length / 2) + 4;
2349 my $map_path = $self->map_path;
2350 stat $map_path or return $want_commit ? (0, undef) : 0;
2351 sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
2352 binmode $fh or croak "binmode: $!";
2353 my $size = (stat($fh))[7];
2352 - ($size % 24) == 0 or croak "inconsistent size: $size";
2354 + ($size % $record_size) == 0 or croak "inconsistent size: $size";
2355
2356 if ($size == 0) {
2357 close $fh or croak "close: $!";
2358 return $want_commit ? (0, undef) : 0;
2359 }
2360
2359 - sysseek($fh, -24, SEEK_END) or croak "seek: $!";
2360 - sysread($fh, my $buf, 24) == 24 or croak "read: $!";
2361 + sysseek($fh, -$record_size, SEEK_END) or croak "seek: $!";
2362 + sysread($fh, my $buf, $record_size) == $record_size or croak "read: $!";
2363 my ($r, $c) = unpack(rev_map_fmt, $buf);
2362 - if ($want_commit && $c eq ('0' x40)) {
2363 - if ($size < 48) {
2364 + if ($want_commit && $c eq ('0' x $::oid_length)) {
2365 + if ($size < $record_size * 2) {
2366 return $want_commit ? (0, undef) : 0;
2367 }
2366 - sysseek($fh, -48, SEEK_END) or croak "seek: $!";
2367 - sysread($fh, $buf, 24) == 24 or croak "read: $!";
2368 + sysseek($fh, -($record_size * 2), SEEK_END) or croak "seek: $!";
2369 + sysread($fh, $buf, $record_size) == $record_size or croak "read: $!";
2370 ($r, $c) = unpack(rev_map_fmt, $buf);
2369 - if ($c eq ('0'x40)) {
2371 + if ($c eq ('0' x $::oid_length)) {
2372 croak "Penultimate record is all-zeroes in $map_path";
2373 }
2374 }
@@ -2387,30 +2389,31 @@ sub rev_map_get {
2389
2390 sub _rev_map_get {
2391 my ($fh, $rev) = @_;
2392 + my $record_size = ($::oid_length / 2) + 4;
2393
2394 binmode $fh or croak "binmode: $!";
2395 my $size = (stat($fh))[7];
2393 - ($size % 24) == 0 or croak "inconsistent size: $size";
2396 + ($size % $record_size) == 0 or croak "inconsistent size: $size";
2397
2398 if ($size == 0) {
2399 return undef;
2400 }
2401
2399 - my ($l, $u) = (0, $size - 24);
2402 + my ($l, $u) = (0, $size - $record_size);
2403 my ($r, $c, $buf);
2404
2405 while ($l <= $u) {
2403 - my $i = int(($l/24 + $u/24) / 2) * 24;
2406 + my $i = int(($l/$record_size + $u/$record_size) / 2) * $record_size;
2407 sysseek($fh, $i, SEEK_SET) or croak "seek: $!";
2405 - sysread($fh, my $buf, 24) == 24 or croak "read: $!";
2408 + sysread($fh, my $buf, $record_size) == $record_size or croak "read: $!";
2409 my ($r, $c) = unpack(rev_map_fmt, $buf);
2410
2411 if ($r < $rev) {
2409 - $l = $i + 24;
2412 + $l = $i + $record_size;
2413 } elsif ($r > $rev) {
2411 - $u = $i - 24;
2414 + $u = $i - $record_size;
2415 } else { # $r == $rev
2413 - return $c eq ('0' x 40) ? undef : $c;
2416 + return $c eq ('0' x $::oid_length) ? undef : $c;
2417 }
2418 }
2419 undef;
perl/Git/SVN/Editor.pm
+3 -3
@@ -400,12 +400,12 @@ sub T {
400 ($m->{mode_b} !~ /^120/ && $m->{mode_a} =~ /^120/)) {
401 $self->D({
402 mode_a => $m->{mode_a}, mode_b => '000000',
403 - sha1_a => $m->{sha1_a}, sha1_b => '0' x 40,
403 + sha1_a => $m->{sha1_a}, sha1_b => '0' x $::oid_length,
404 chg => 'D', file_b => $m->{file_b}
405 }, $deletions);
406 $self->A({
407 mode_a => '000000', mode_b => $m->{mode_b},
408 - sha1_a => '0' x 40, sha1_b => $m->{sha1_b},
408 + sha1_a => '0' x $::oid_length, sha1_b => $m->{sha1_b},
409 chg => 'A', file_b => $m->{file_b}
410 }, $deletions);
411 return;
@@ -434,7 +434,7 @@ sub _chg_file_get_blob ($$$$) {
434 $self->change_file_prop($fbat,'svn:special',undef);
435 }
436 my $blob = $m->{"sha1_$which"};
437 - return ($fh,) if ($blob =~ /^0{40}$/);
437 + return ($fh,) if ($blob =~ /^0+$/);
438 my $size = $::_repository->cat_blob($blob, $fh);
439 croak "Failed to read object $blob" if ($size < 0);
440 $fh->flush == 0 or croak $!;
perl/Git/SVN/Fetcher.pm
+3 -3
@@ -173,7 +173,7 @@ sub delete_entry {
173
174 # remove entire directories.
175 my ($tree) = (command('ls-tree', '-z', $self->{c}, "./$gpath")
176 - =~ /\A040000 tree ([a-f\d]{40})\t\Q$gpath\E\0/);
176 + =~ /\A040000 tree ($::oid)\t\Q$gpath\E\0/);
177 if ($tree) {
178 my ($ls, $ctx) = command_output_pipe(qw/ls-tree
179 -r --name-only -z/,
@@ -203,7 +203,7 @@ sub open_file {
203
204 my $gpath = $self->git_path($path);
205 ($mode, $blob) = (command('ls-tree', '-z', $self->{c}, "./$gpath")
206 - =~ /\A(\d{6}) blob ([a-f\d]{40})\t\Q$gpath\E\0/);
206 + =~ /\A(\d{6}) blob ($::oid)\t\Q$gpath\E\0/);
207 unless (defined $mode && defined $blob) {
208 die "$path was not found in commit $self->{c} (r$rev)\n";
209 }
@@ -413,7 +413,7 @@ sub close_file {
413
414 $hash = $::_repository->hash_and_insert_object(
415 Git::temp_path($fh));
416 - $hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n";
416 + $hash =~ /^$::oid$/ or die "not an object ID: $hash\n";
417
418 Git::temp_release($fb->{base}, 1);
419 Git::temp_release($fh, 1);
perl/Git/SVN/Ra.pm
+2 -2
@@ -486,11 +486,11 @@ sub gs_fetch_loop_common {
486 $reload_ra->() if $ra_invalid;
487 }
488 # pre-fill the .rev_db since it'll eventually get filled in
489 - # with '0' x40 if something new gets committed
489 + # with '0' x $oid_length if something new gets committed
490 foreach my $gs (@$gsv) {
491 next if $gs->rev_map_max >= $max;
492 next if defined $gs->rev_map_get($max);
493 - $gs->rev_map_set($max, 0 x40);
493 + $gs->rev_map_set($max, 0 x $::oid_length);
494 }
495 foreach my $g (@$globs) {
496 my $k = "svn-remote.$g->{remote}.$g->{t}-maxRev";