Lindenii Project Forge
Warning: Due to various recent migrations, viewing non-HEAD refs may be broken.
/git/object.ha (raw)
use bytes;
use crypto::sha256;
use errors;
use fmt;
use fs;
use hash;
use io;
use strconv;
use strings;
// Object/pack type tags.
//
// These are not typically used as we could represent objects with tagged
// unions. However, they may be useful in scenarios where a full object is
// undesirable or unavailable.
export type objtype = enum u8 {
OBJ_INVALID = 0u8,
OBJ_COMMIT = 1u8,
OBJ_TREE = 2u8,
OBJ_BLOB = 3u8,
OBJ_TAG = 4u8,
OBJ_FUTURE = 5u8,
OBJ_OFS_DELTA = 6u8,
OBJ_REF_DELTA = 7u8,
};
// Any Git object.
export type object = (blob | tree | commit | tag);
// Frees resources associated with any Git object.
export fn object_finish(o: object) void = {
match (o) {
case let b: blob =>
blob_finish(b);
case let t: tree =>
tree_finish(t);
case let c: commit =>
commit_finish(c);
case let g: tag =>
tag_finish(g);
case =>
abort("Unknown object type being freed...");
};
};
// Serializes an object into its on-disk representation.
export fn object_serialize(o: object)
([]u8 | errors::invalid | nomem) = {
match (o) {
case let b: blob =>
return blob_serialize(b);
case let t: tree =>
return tree_serialize(t);
case let c: commit =>
return commit_serialize(c);
case let g: tag =>
return tag_serialize(g);
case =>
abort("Unknown object type being serialized...");
};
};
// Verifies that the given buffer (which must be the exact on-disk format
// structured as "type size\0body") matches the given object ID.
export fn object_verify_oid(buf: []u8, want: oid) bool = {
let st = sha256::sha256();
hash::write(&st, buf);
let got: oid = [0...];
hash::sum(&st, got);
hash::close(&st);
return bytes::equal(got[..], want[..]);
};
// Verifies that the given typed body matches the given object ID.
export fn object_verify_typed(ty: objtype, body: []u8, want: oid) bool = {
let st = sha256::sha256();
defer hash::close(&st);
switch (ty) {
case objtype::OBJ_BLOB =>
hash::write(&st, strings::toutf8("blob"));
case objtype::OBJ_TREE =>
hash::write(&st, strings::toutf8("tree"));
case objtype::OBJ_COMMIT =>
hash::write(&st, strings::toutf8("commit"));
case objtype::OBJ_TAG =>
hash::write(&st, strings::toutf8("tag"));
case =>
return false;
};
hash::write(&st, strings::toutf8(" "));
let szs = strconv::ztos(len(body));
hash::write(&st, strings::toutf8(szs));
hash::write(&st, strings::toutf8("\x00"));
hash::write(&st, body);
let got: oid = [0...];
hash::sum(&st, got);
return bytes::equal(got[..], want[..]);
};
// Reads a Git object from the repository by its ID.
export fn object_read(
r: repo,
id: oid,
) (object | fs::error | io::error | errors::invalid | strconv::invalid | strconv::overflow | nomem) = {
match (loose_read(r, id)) {
case let o: object =>
return o;
case let fe: fs::error =>
if (fe is errors::noentry) {
void;
} else {
return fe;
};
case let e: (io::error | errors::invalid | strconv::invalid | strconv::overflow | nomem) =>
return e;
};
match (pack_read(r, id)) {
case let o: object =>
return o;
case let fe: fs::error =>
if (fe is errors::noentry) {
return errors::invalid;
} else {
return fe;
};
case let e: (io::error | errors::invalid | strconv::invalid | strconv::overflow | nomem) =>
return e;
};
};