public function indexPack($filename, $fix_thin = true) { $this->f = fopen($filename, "r+b"); if (!$this->f) { throw new Exception("Cannot open file {$filename}"); } flock($this->f, LOCK_EX); $this->hash = hash_init("sha1"); // Read pack header $s = $this->getBytes(8); if ($s != "PACK") { throw new Exception("Invalid pack header"); } $count = Binary::uint32($this->GetBytes(4)); // Read objects for ($i = 0; $i < $count; $i++) { $obj = $this->readObject(); } // Check pack sha1 sum $fixpos = ftell($this->f); $pack_hash = hash_final($this->hash, true); $pack_hash_check = fread($this->f, 20); if ($pack_hash !== $pack_hash_check) { throw new Exception("Invalid pack checksum"); } // Resolve deltas foreach ($this->objects as $hash => $obj) { $this->resolveDeltas($hash, $obj); } if (count($this->unresolved_hash) !== 0 && $fix_thin) { unset($this->hash); foreach ($this->unresolved_hash as $hash => $objs) { try { list($type, $data) = $this->repo->getRawObject($hash); } catch (Exception $e) { continue; } // Create new PackObj $newobj = new PackObj(); $newobj->type = $type; $newobj->pos = $fixpos; // Write object to the file fseek($this->f, $fixpos); $this->writeObject($type, $data); $fixpos = ftell($this->f); // Add object to index $newhash = $this->addObject($newobj, $data); assert($newhash === $hash); //resolve child deltas $this->resolveObjs($objs, $newobj, $data); unset($data); unset($this->unresolved_hash[$hash]); } // fix count of objects in the pack fseek($this->f, 8); $this->writeInt32(count($this->objects)); // recalculate hash of entire pack ftruncate($this->f, $fixpos); fseek($this->f, 0); $newhash = hash_init("sha1"); while (!feof($this->f)) { hash_update($newhash, fread($this->f, 0x10000)); } $pack_hash = hash_final($newhash, true); fwrite($this->f, $pack_hash); } if (count($this->unresolved_hash) !== 0 || count($this->unresolved_offs) !== 0) { throw new Exception("Cannot resolve deltas"); } fclose($this->f); // Build fanout table and pack name ksort($this->objects); $h = hash_init("sha1"); $fanout = array(); for ($i = 0; $i < 256; $i++) { $fanout[$i] = 0; } foreach ($this->objects as $hash => $obj) { $fanout[ord($hash[0])]++; hash_update($h, $hash); } for ($i = 1; $i < 256; $i++) { $fanout[$i] += $fanout[$i - 1]; } $packname = hash_final($h); // Rename the temporary pack file and write index (at this time only index v1 supported) rename($filename, sprintf('%s/objects/pack/pack-%s.pack', $this->repo->dir, $packname)); $this->f = fopen(sprintf('%s/objects/pack/pack-%s.idx', $this->repo->dir, $packname), "wb"); if (!$this->f) { throw new Exception("Cannot open index file"); } $this->hash = hash_init("sha1"); // Write fanout table for ($i = 0; $i < 256; $i++) { $this->writeInt32($fanout[$i]); } // Write objects table foreach ($this->objects as $hash => $obj) { $this->writeInt32($obj->pos); $this->writeBytes($hash); } // Write original pack hashsum $this->writeBytes($pack_hash); // Write index hashsum $idx_hash = hash_final($this->hash, true); fwrite($this->f, $idx_hash); fclose($this->f); }
public static function fuint32($f) { return Binary::uint32(fread($f, 4)); }
protected function uint32_at($pos) { return Binary::uint32($this->cache, $pos); }