use std::fs::File;
use std::io::{self, Seek, SeekFrom, Write};
use std::path::{Path, PathBuf};
pub(crate) fn quarantine_dropped_tail(path: &Path, from: u64) -> io::Result<PathBuf> {
let ts = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
let qpath = PathBuf::from(format!("{}.corrupt-quarantine.{ts}", path.display()));
let mut src = File::open(path)?;
src.seek(SeekFrom::Start(from))?;
let mut dst = File::create(&qpath)?;
io::copy(&mut src, &mut dst)?;
dst.sync_data()?;
Ok(qpath)
}
pub fn write_aof_base(path: &Path) -> io::Result<()> {
let mut f = File::create(path)?;
f.write_all(crate::record::AOF2_MAGIC)?;
f.sync_all()
}
pub(crate) fn rewrite_tmp_path(path: &Path) -> PathBuf {
let mut p = path.to_path_buf();
let new_name = match path.file_name() {
Some(n) => {
let mut s = n.to_os_string();
s.push(".rewrite");
s
}
None => std::ffi::OsString::from("aof.rewrite"),
};
p.set_file_name(new_name);
p
}
pub(crate) fn repair_tail(
path: &Path,
file: &mut File,
size: &mut u64,
resync: bool,
) -> io::Result<Option<PathBuf>> {
let valid = crate::replay::valid_prefix_len_of_file(path, resync)?;
if valid >= *size {
return Ok(None);
}
let q = crate::aof_util::quarantine_dropped_tail(path, valid)?;
file.set_len(valid)?;
file.sync_data()?;
eprintln!(
"kevy WARN: AOF {} dropped a non-replayable tail: {} bytes \
quarantined to {} then truncated at byte {valid}.",
path.display(),
*size - valid,
q.display(),
);
*size = valid;
Ok(Some(q))
}