weavatrix-git 0.3.1

Fast, bounded, evidence-carrying Git reader with an optional read-only MCP server
Documentation
use std::{fs, path::Path};

use crate::{Object, ObjectId, Result, error::invalid, inflate};

pub(crate) fn read(
    objects: &Path,
    id: ObjectId,
    max_object_bytes: usize,
) -> Result<Option<Object>> {
    let hex = id.to_hex();
    let path = objects.join(&hex[..2]).join(&hex[2..]);
    let compressed = match fs::read(path) {
        Ok(value) => value,
        Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(None),
        Err(error) => return Err(error.into()),
    };
    let header_budget = 64;
    let inflate_limit = max_object_bytes
        .checked_add(header_budget)
        .ok_or_else(|| invalid("object size limit overflow"))?;
    let (raw, used) = inflate::zlib(&compressed, inflate_limit)?;
    if used != compressed.len() {
        return Err(invalid("loose object has trailing compressed data"));
    }
    let nul = raw
        .iter()
        .position(|byte| *byte == 0)
        .ok_or_else(|| invalid("loose object has no header terminator"))?;
    let space = raw[..nul]
        .iter()
        .position(|byte| *byte == b' ')
        .ok_or_else(|| invalid("loose object header has no size"))?;
    let kind = &raw[..space];
    let size = &raw[space + 1..nul];
    let size = std::str::from_utf8(size)
        .map_err(|_| invalid("loose object size is not ASCII"))?
        .parse::<usize>()
        .map_err(|_| invalid("invalid loose object size"))?;
    let data = raw[nul + 1..].to_vec();
    if data.len() != size {
        return Err(invalid("loose object size mismatch"));
    }
    if size > max_object_bytes {
        return Err(crate::GitError::LimitExceeded {
            resource: "object bytes",
            limit: max_object_bytes,
        });
    }
    Ok(Some(Object {
        id,
        kind: crate::ObjectKind::parse(kind)?,
        data,
    }))
}