fix(artifacts): harden reconciliation scanner
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
use crate::{ArtifactError, ArtifactStore, TempScan};
|
||||
|
||||
pub(crate) fn valid_temp_name(name: &str) -> bool {
|
||||
let Some(rest) = name.strip_prefix(ArtifactStore::temp_prefix()) else {
|
||||
return false;
|
||||
};
|
||||
let mut fields = rest.split('-');
|
||||
let (Some(nonce), Some(pid), Some(sequence), None) =
|
||||
(fields.next(), fields.next(), fields.next(), fields.next())
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
nonce.len() == 32
|
||||
&& nonce
|
||||
.bytes()
|
||||
.all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
|
||||
&& !pid.is_empty()
|
||||
&& pid.bytes().all(|byte| byte.is_ascii_digit())
|
||||
&& !sequence.is_empty()
|
||||
&& sequence.bytes().all(|byte| byte.is_ascii_digit())
|
||||
}
|
||||
|
||||
pub(crate) fn list_names(
|
||||
parent: i32,
|
||||
remaining: &mut usize,
|
||||
report: &mut TempScan,
|
||||
) -> Result<Vec<String>, ArtifactError> {
|
||||
let dot = std::ffi::CString::new(".").map_err(|_| ArtifactError::Storage)?;
|
||||
let raw = unsafe {
|
||||
libc::openat(
|
||||
parent,
|
||||
dot.as_ptr(),
|
||||
libc::O_RDONLY | libc::O_DIRECTORY | libc::O_CLOEXEC,
|
||||
)
|
||||
};
|
||||
if raw < 0 {
|
||||
return Err(ArtifactError::Storage);
|
||||
}
|
||||
let directory = unsafe { libc::fdopendir(raw) };
|
||||
if directory.is_null() {
|
||||
unsafe {
|
||||
libc::close(raw);
|
||||
}
|
||||
return Err(ArtifactError::Storage);
|
||||
}
|
||||
let mut names = Vec::new();
|
||||
loop {
|
||||
if *remaining == 0 {
|
||||
break;
|
||||
}
|
||||
unsafe {
|
||||
*libc::__errno_location() = 0;
|
||||
}
|
||||
let entry = unsafe { libc::readdir(directory) };
|
||||
if entry.is_null() {
|
||||
if unsafe { *libc::__errno_location() } != 0 {
|
||||
unsafe {
|
||||
libc::closedir(directory);
|
||||
}
|
||||
return Err(ArtifactError::Storage);
|
||||
}
|
||||
break;
|
||||
}
|
||||
let name = unsafe { std::ffi::CStr::from_ptr((*entry).d_name.as_ptr()) }.to_bytes();
|
||||
if name == b"." || name == b".." {
|
||||
continue;
|
||||
}
|
||||
report.scanned += 1;
|
||||
*remaining -= 1;
|
||||
if let Ok(name) = std::str::from_utf8(name) {
|
||||
names.push(name.to_owned());
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
libc::closedir(directory);
|
||||
}
|
||||
Ok(names)
|
||||
}
|
||||
Reference in New Issue
Block a user