use std::path::Path;
use std::process::Command;
use crate::scanner::entry::FileEntry;
use crate::security;
pub fn is_git_repo(root: &Path) -> bool {
root.join(".git").exists()
}
pub fn scan_git(root: &Path) -> Option<Vec<FileEntry>> {
if !is_git_repo(root) {
return None;
}
let output = Command::new("git")
.args([
"ls-files",
"-z",
"--cached",
"--others",
"--exclude-standard",
])
.current_dir(root)
.output()
.ok()?;
if !output.status.success() {
return None;
}
let stdout = String::from_utf8_lossy(&output.stdout);
let mut entries = Vec::new();
for file in stdout.split('\0').filter(|s| !s.is_empty()) {
let path = root.join(file);
if !path.exists() {
continue;
}
let metadata = match path.symlink_metadata() {
Ok(m) => m,
Err(_) => continue,
};
if metadata.file_type().is_symlink() {
continue;
}
if security::validate_archive_entry_metadata(&path, &metadata).is_err() {
continue;
}
let is_dir = metadata.is_dir();
let size = if is_dir { 0 } else { metadata.len() };
entries.push(FileEntry::new(&path, root, is_dir, size));
}
if entries.is_empty() {
return None;
}
entries.sort_by(|a, b| a.relative_path.cmp(&b.relative_path));
Some(entries)
}