use std::{io::{self, Seek, SeekFrom, BufReader, Read}, fs::{File, OpenOptions}, path::Path, fs};
use std::os::windows::fs::FileExt;
use std::path::PathBuf;
pub struct Type {
pub suffix: String,
pub bytes: Vec<u8>
}
pub const FLAG: &[u8; 64] = b"67ea716879a2881181afb79f9737553ae96ed1d65119551ab416957a01ff0f58";
pub fn fake(path: &Path, flag: &[u8], f_type: Type) -> Result<(), io::Error> {
let mut suffix = path.extension().unwrap().to_str().unwrap().as_bytes().to_vec();
while suffix.len() < 16 {
suffix.push(u8::try_from('#').unwrap());
}
while suffix.len() > 16 {
suffix.pop();
}
let mut head = [0u8; 48];
let mut f_reader = BufReader::new(File::open(path)?);
let f_writer = OpenOptions::new().write(true).open(path)?;
f_reader.read_exact(&mut head)?;
f_writer.seek_write(f_type.bytes.as_slice(), 0)?;
let offset = f_reader.seek(SeekFrom::End(0))?;
let data = [flag, suffix.as_slice(), &head].concat();
f_writer.seek_write(data.as_slice(), offset)?;
let mut new_path = PathBuf::from(path);
new_path.set_extension(f_type.suffix);
fs::rename(path.as_os_str(), new_path.as_os_str())?;
Ok(())
}
pub fn restore(path: &Path) -> Result<(), io::Error> {
let mut f_reader = File::open(path)?;
let offset = f_reader.seek(SeekFrom::End(-64))?;
let mut data = [0u8; 64];
f_reader.seek_read(data.as_mut_slice(), offset)?;
let (suffix, head) = data.split_at(16);
let suffix = std::str::from_utf8(suffix).unwrap().replace('#', "");
let f_writer = OpenOptions::new().write(true).open(path)?;
f_writer.seek_write(head, 0)?;
f_writer.set_len(offset - 64)?;
let mut new_path = PathBuf::from(path);
new_path.set_extension(suffix);
fs::rename(path.as_os_str(), new_path.as_os_str())?;
Ok(())
}
pub fn check(path: &Path, flag: &[u8]) -> Result<bool, io::Error> {
let mut f_reader = File::open(path)?;
if f_reader.seek(SeekFrom::End(0))? < 128 {
return Ok(false);
}
let offset = f_reader.seek(SeekFrom::End(-128))?;
let mut data = [0u8; 64];
f_reader.seek_read(&mut data, offset)?;
Ok(data.eq(flag))
}