Lindenii Project Forge
Warning: Due to various recent migrations, viewing non-HEAD refs may be broken.
/git/loose.ha (raw)
use bytes;
use compress::zlib;
use errors;
use fmt;
use fs;
use io;
use strconv;
use strings;
// Find the path to a loose object with the given ID,
// relative to the repository root.
fn loose_relpath(id: oid) (str | nomem) = {
const hex = oid_string(id)?;
defer free(hex);
const dir = strings::bytesub(hex, 0z, 2z)!;
const file = strings::bytesub(hex, 2z, strings::end)!;
return fmt::asprintf("objects/{}/{}", dir, file);
};
// Reads a loose object from the repository by its ID.
export fn read_loose(
r: repo,
id: oid,
) (object | fs::error | io::error | errors::invalid | strconv::invalid | strconv::overflow | nomem) = {
const rel = loose_relpath(id)?;
defer free(rel);
const fh = fs::open(r.root, rel)?;
defer io::close(fh)!;
let zr = zlib::decompress(fh)?;
defer io::close(&zr.vtable)!;
let buf = io::drain(&zr.vtable)?;
defer free(buf);
let mnul = bytes::index(buf, 0u8);
if (mnul is void) {
return errors::invalid;
};
let nul = mnul: size;
const header = buf[..nul];
const body = buf[nul + 1z ..];
let msp = bytes::index(header, ' ');
if (msp is void) {
return errors::invalid;
};
let sp = msp: size;
const ty = strings::fromutf8_unsafe(header[..sp]);
const szs = strings::fromutf8_unsafe(header[sp + 1z ..]);
const expect = strconv::stoz(szs)?;
if (expect != len(body)) {
return errors::invalid;
};
if (!verify_oid(buf, id)) {
return errors::invalid;
};
if (ty == "blob") {
const b = parse_blob(id, body)?;
return (b: object);
} else if (ty == "tree") {
const t = parse_tree(id, body)?;
return (t: object);
} else if (ty == "commit") {
const c = parse_commit(id, body)?;
return (c: object);
} else {
return errors::invalid;
};
};
// Reads a loose object from the repository by its ID,
// returning its type and raw data.
export fn read_loose_typed(
r: repo,
id: oid,
) ((u8, []u8) | fs::error | io::error | errors::invalid | errors::noentry | strconv::invalid | strconv::overflow | nomem) = {
const rel = loose_relpath(id)?;
defer free(rel);
let fh = fs::open(r.root, rel)?;
defer io::close(fh)!;
let zr = zlib::decompress(fh)?;
defer io::close(&zr.vtable)!;
let buf = io::drain(&zr.vtable)?;
defer free(buf);
let mnul = bytes::index(buf, 0u8);
if (mnul is void) {
return errors::invalid;
};
let nul = mnul: size;
const header = buf[..nul];
const body = buf[nul + 1z ..];
let msp = bytes::index(header, ' ');
if (msp is void) {
return errors::invalid;
};
let sp = msp: size;
const ty = strings::fromutf8_unsafe(header[..sp]);
const szs = strings::fromutf8_unsafe(header[sp + 1z ..]);
const expect = strconv::stoz(szs)?;
if (expect != len(body)) {
return errors::invalid;
};
let code: u8 = 0u8;
if (ty == "blob") {
code = OBJ_BLOB;
} else if (ty == "tree") {
code = OBJ_TREE;
} else if (ty == "commit") {
code = OBJ_COMMIT;
} else {
return errors::invalid;
};
let out = alloc(body...)?;
return (code, out);
};