Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git
new/Git.php
while (!feof($f)) {
$chunk = fread($f, 128); // Read small chunks for the header
- $data .= inflate_add($ctx, $chunk, ZLIB_NO_FLUSH);
+ $inflated = @inflate_add($ctx, $chunk, ZLIB_NO_FLUSH);
+ if ($inflated === false) break;
+ $data .= $inflated;
if (strpos($data, "\0") !== false) break; // Stop once we have the header
}
fseek($pf, $info['offset']);
-
+
// Read Pack Object Header
$byte = ord(fread($pf, 1));
$buffer = '';
$found = false;
-
+
// We only need the first two VLQ integers from the stream
while (!$found && !feof($pf)) {
$chunk = fread($pf, 512);
- $buffer .= inflate_add($ctx, $chunk, ZLIB_NO_FLUSH);
-
+ $inflated = @inflate_add($ctx, $chunk, ZLIB_NO_FLUSH);
+ if ($inflated === false) { fclose($pf); return 0; }
+
+ $buffer .= $inflated;
+
// Check if we have enough bytes to decode two VLQs
- // (Just a heuristic check, the decoding loop below handles the actual logic)
- if (strlen($buffer) > 20) $found = true;
+ if (strlen($buffer) > 32) $found = true;
}
-
+
// Decode Delta Header: [Source Size VLQ] [Target Size VLQ]
$pos = 0;
-
+
// Skip Source Size
+ if (!isset($buffer[$pos])) { fclose($pf); return 0; }
$byte = ord($buffer[$pos++]);
- while ($byte & 128) { $byte = ord($buffer[$pos++]); }
-
+ while ($byte & 128) {
+ if (!isset($buffer[$pos])) break;
+ $byte = ord($buffer[$pos++]);
+ }
+
// Read Target Size (The full file size)
+ if (!isset($buffer[$pos])) { fclose($pf); return 0; }
$byte = ord($buffer[$pos++]);
$size = $byte & 127;
$shift = 7;
while ($byte & 128) {
+ if (!isset($buffer[$pos])) break;
$byte = ord($buffer[$pos++]);
$size |= (($byte & 127) << $shift);
$packs = glob("{$this->objPath}/pack/*.idx");
if (!$packs) return null;
+
+ $binSha = hex2bin($sha);
+ $firstByte = ord($binSha[0]);
+
foreach ($packs as $idxFile) {
$f = @fopen($idxFile, 'rb');
if (!$f) continue;
- fseek($f, 8 + (hexdec(substr($sha, 0, 2)) * 4));
- $count = unpack('N', fread($f, 4))[1];
- fseek($f, 8 + (255 * 4));
- $total = unpack('N', fread($f, 4))[1];
- fseek($f, 8 + (256 * 4));
- $idx = -1;
- for ($i = 0; $i < $total; $i++) {
- if (bin2hex(fread($f, 20)) === $sha) { $idx = $i; break; }
+
+ // Verify V2 Header
+ $sig = fread($f, 4);
+ $ver = unpack('N', fread($f, 4))[1];
+ if ($sig !== "\377tOc" || $ver !== 2) {
+ fclose($f); continue; // Only supports V2 for now
}
- if ($idx === -1) { fclose($f); continue; }
- fseek($f, 8 + (256 * 4) + ($total * 20) + ($total * 4) + ($idx * 4));
- $offset = unpack('N', fread($f, 4))[1];
+
+ // 1. Read Fanout Table to find range
+ // Range start: Value at index [firstByte - 1] (or 0 if firstByte is 0)
+ // Range end: Value at index [firstByte]
+ $fanoutOffset = 8; // After header
+ if ($firstByte > 0) {
+ fseek($f, $fanoutOffset + (($firstByte - 1) * 4));
+ $start = unpack('N', fread($f, 4))[1];
+ } else {
+ $start = 0;
+ }
+
+ fseek($f, $fanoutOffset + ($firstByte * 4));
+ $end = unpack('N', fread($f, 4))[1];
+
+ // Get Total Objects (last entry in fanout)
+ if ($end <= $start) { fclose($f); continue; }
+
+ fseek($f, $fanoutOffset + (255 * 4));
+ $totalObjects = unpack('N', fread($f, 4))[1];
+
+ // 2. Binary Search or Linear Scan in the specific range
+ // The SHA table starts after the fanout (1024 bytes)
+ $shaTableOffset = 8 + 1024;
+
+ // We scan only [$start, $end)
+ fseek($f, $shaTableOffset + ($start * 20));
+
+ $foundIdx = -1;
+ for ($i = $start; $i < $end; $i++) {
+ if (fread($f, 20) === $binSha) {
+ $foundIdx = $i;
+ break;
+ }
+ }
+
+ if ($foundIdx === -1) { fclose($f); continue; }
+
+ // 3. Read Offset
+ // Offsets table starts after: Header + Fanout + SHAs + CRCs
+ // CRCs are $totalObjects * 4 bytes
+ $crcOffset = $shaTableOffset + ($totalObjects * 20);
+ $offsetTableOffset = $crcOffset + ($totalObjects * 4);
+
+ fseek($f, $offsetTableOffset + ($foundIdx * 4));
+ $offset32 = unpack('N', fread($f, 4))[1];
+
+ // 4. Handle Large Offsets (MSB set)
+ if ($offset32 & 0x80000000) {
+ // It's an index into the 64-bit offset table
+ $largeOffsetIdx = $offset32 & 0x7FFFFFFF;
+ $largeOffsetTablePos = $offsetTableOffset + ($totalObjects * 4);
+
+ fseek($f, $largeOffsetTablePos + ($largeOffsetIdx * 8));
+ $data = unpack('J', fread($f, 8)); // 'J' is 64-bit big endian integer
+ $offset = $data[1];
+ } else {
+ $offset = $offset32;
+ }
+
fclose($f);
return ['file' => str_replace('.idx', '.pack', $idxFile), 'offset' => $offset];

Fixes V1/V2 repo reads

Author Dave Jarvis <email>
Date 2026-02-08 21:53:13 GMT-0800
Commit 18941c94c2c61caf95963e08c8c8286a659f9b2c
Parent a62bfc8
Delta 91 lines added, 22 lines removed, 69-line increase