Skip to main content

hash_reader

Function hash_reader 

Source
pub fn hash_reader(
    reader: impl Read,
    max_bytes: u64,
) -> Result<ArtifactIdentity, ArtifactError>
Expand description

Hash one stream with constant working memory and no reliance on metadata.

Reads at most max_bytes + 1 bytes, using the extra byte to detect overflow. Retries interrupted reads only; no subprocess or network retry is performed. A blocking reader’s timeouts remain the caller’s responsibility.

§Errors

Returns ArtifactError::LimitExceeded or the underlying read error. An impossible reader byte count returns IO io::ErrorKind::InvalidData.

Examples found in repository?
examples/inspect_response.rs (line 39)
9fn main() -> Result<(), Box<dyn Error>> {
10    let mut args = std::env::args_os().skip(1);
11    let path = args.next().ok_or_else(|| {
12        invalid_argument(
13            "usage: inspect_response PATH json|hex|labeled MAX_INPUT_BYTES MAX_DECODED_BYTES",
14        )
15    })?;
16    let format = match args.next().as_deref().and_then(std::ffi::OsStr::to_str) {
17        Some("json") => ResponseFormat::Json,
18        Some("hex") => ResponseFormat::Hex,
19        Some("labeled") => ResponseFormat::LabeledHex,
20        _ => return Err(invalid_argument("format must be json, hex or labeled").into()),
21    };
22    let mut limit = || -> Result<usize, Box<dyn Error>> {
23        Ok(args
24            .next()
25            .ok_or_else(|| invalid_argument("missing response limit"))?
26            .to_str()
27            .ok_or_else(|| invalid_argument("limits must be UTF-8"))?
28            .parse()?)
29    };
30    let limits = ResponseLimits {
31        input_bytes: limit()?,
32        decoded_bytes: limit()?,
33    };
34    if args.next().is_some() {
35        return Err(invalid_argument("unexpected argument").into());
36    }
37    let input = read_file(Path::new(&path), limits.input_bytes)?;
38    let bytes = decode(&input, format, limits)?;
39    let identity = hash_reader(bytes.as_slice(), u64::try_from(limits.decoded_bytes)?)?;
40    println!(
41        "response_bytes={} sha256={}",
42        identity.bytes, identity.sha256
43    );
44    Ok(())
45}
More examples
Hide additional examples
examples/inspect_artifact.rs (line 45)
9fn main() -> Result<(), Box<dyn Error>> {
10    let mut args = std::env::args_os().skip(1);
11    let path = args.next().ok_or_else(|| invalid_argument("usage: inspect_artifact PATH MAX_BYTES MAX_SECTIONS MAX_EXPORTS MAX_CUSTOM_SECTIONS [SHA256]"))?;
12    let mut number = || -> Result<usize, Box<dyn Error>> {
13        Ok(args
14            .next()
15            .ok_or_else(|| invalid_argument("missing inspection limit"))?
16            .to_str()
17            .ok_or_else(|| invalid_argument("inspection limits must be UTF-8"))?
18            .parse()?)
19    };
20    let limits = InspectionLimits {
21        module_bytes: number()?,
22        sections: number()?,
23        exports: u32::try_from(number()?)?,
24        custom_sections: number()?,
25    };
26    let expected = args
27        .next()
28        .map(|value| {
29            value
30                .into_string()
31                .map_err(|_| invalid_argument("digest must be UTF-8"))
32        })
33        .transpose()?;
34    if args.next().is_some() {
35        return Err(invalid_argument("unexpected argument").into());
36    }
37    let bytes = read_file(Path::new(&path), limits.module_bytes)?;
38    let identity = if let Some(expected) = expected {
39        verify_reader(
40            bytes.as_slice(),
41            limits.module_bytes as u64,
42            expected.parse()?,
43        )?
44    } else {
45        ic_host_tools::artifact::hash_reader(bytes.as_slice(), limits.module_bytes as u64)?
46    };
47    let facts = inspect(&bytes, limits)?;
48    println!(
49        "raw_bytes={} sha256={} code_section_bytes={} data_section_bytes={} defined_functions={} data_segments={}",
50        identity.bytes,
51        identity.sha256,
52        facts.code_section_bytes,
53        facts.data_section_bytes,
54        facts.defined_functions,
55        facts.data_segments
56    );
57    for (name, export) in facts.exports {
58        println!(
59            "export={name:?} kind={:?} index={}",
60            export.kind, export.index
61        );
62    }
63    for section in facts.custom_sections {
64        println!(
65            "custom_section={:?} bytes={}",
66            section.name,
67            section.data.len()
68        );
69    }
70    Ok(())
71}