MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / fingerprint

Function fingerprint

atomic-agent/src/record/scope.rs:49–80  ·  view source on GitHub ↗

Fingerprint a file without following its final symlink. `None` means deleted. Reject directories and paths outside the working tree.

(root: &Path, path: &str)

Source from the content-addressed store, hash-verified

47/// Fingerprint a file without following its final symlink. `None` means deleted.
48/// Reject directories and paths outside the working tree.
49pub fn fingerprint(root: &Path, path: &str) -> Result<Option<String>, String> {
50 let full = checked_path(root, path)?;
51 let meta = match std::fs::symlink_metadata(&full) {
52 Ok(m) => m,
53 Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None),
54 Err(e) => return Err(e.to_string()),
55 };
56 if meta.file_type().is_symlink() {
57 let target = std::fs::read_link(full).map_err(|e| e.to_string())?;
58 return Ok(Some(format!(
59 "link:{:x}",
60 Sha256::digest(target.as_os_str().as_encoded_bytes())
61 )));
62 }
63 if !meta.is_file() {
64 return Err(format!("not a regular scoped file: {path}"));
65 }
66 #[cfg(unix)]
67 let executable = {
68 use std::os::unix::fs::PermissionsExt;
69 meta.permissions().mode() & 0o111 != 0
70 };
71 #[cfg(not(unix))]
72 let executable = false;
73 let mut file = std::fs::File::open(full).map_err(|e| e.to_string())?;
74 let mut hash = Sha256::new();
75 std::io::copy(&mut file, &mut hash).map_err(|e| e.to_string())?;
76 Ok(Some(format!(
77 "file:{hash:x}:{executable}",
78 hash = hash.finalize()
79 )))
80}
81
82/// Return fingerprints for dirty files and explicitly requested prior candidates.
83/// The protocol version also lets plugins refuse an older, unscoped CLI.

Callers 3

snapshotFunction · 0.85
validateFunction · 0.85

Calls 4

checked_pathFunction · 0.85
kindMethod · 0.45
is_fileMethod · 0.45
permissionsMethod · 0.45