use crate::ref_files::RefFilesLayout;
use crate::transaction_journal::RefFormat;
use std::path::{Path, PathBuf};
const PACKED_REFS_LIMIT: u64 = 64 * 1024 * 1024;
fn lookup_paths(layout: &RefFilesLayout<'_>, name: &str) -> Vec<PathBuf> {
return vec![
layout.git_dir.join(name),
layout.common_dir.join(format!("refs/{name}")),
layout.common_dir.join(format!("refs/tags/{name}")),
layout.common_dir.join(format!("refs/heads/{name}")),
layout.common_dir.join(format!("refs/remotes/{name}")),
layout.common_dir.join(format!("refs/remotes/{name}/HEAD")),
];
}
fn something_is_at(path: &Path) -> bool {
return match std::fs::symlink_metadata(path) {
Ok(_) => true,
Err(error) => error.kind() != std::io::ErrorKind::NotFound,
};
}
fn packed_refs_bytes(common_dir: &Path) -> Option<Vec<u8>> {
let path: PathBuf = common_dir.join("packed-refs");
let metadata: std::fs::Metadata = match std::fs::metadata(&path) {
Ok(found) => found,
Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Some(Vec::new()),
Err(_) => return None,
};
if !metadata.is_file() || metadata.len() > PACKED_REFS_LIMIT {
return None;
}
return match std::fs::read(&path) {
Ok(bytes) => Some(bytes),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => Some(Vec::new()),
Err(_) => None,
};
}
fn contains_bytes(haystack: &[u8], needle: &[u8]) -> bool {
if needle.is_empty() {
return true;
}
return haystack.windows(needle.len()).any(|window| { return window == needle; });
}
pub fn markers_maybe_present(layout: &RefFilesLayout<'_>, names: &[&str]) -> Vec<bool> {
if layout.ref_format != RefFormat::Files {
return vec![true; names.len()];
}
let packed: Option<Vec<u8>> = packed_refs_bytes(layout.common_dir);
let mut answers: Vec<bool> = Vec::with_capacity(names.len());
for name in names {
let loose: bool = lookup_paths(layout, name).iter().any(|path| { return something_is_at(path.as_path()); });
let packed_hit: bool = match &packed {
Some(bytes) => contains_bytes(bytes.as_slice(), name.as_bytes()),
None => true,
};
answers.push(loose || packed_hit);
}
return answers;
}
#[cfg(test)]
#[path = "sequencer_marker_tests.rs"]
mod tests;