use std::ffi::CString;
use std::mem;
use std::os::unix::prelude::OsStrExt;
use std::path::Path;
use super::rc::{RpmErrorKind, RpmReturnCode};
use super::ts::TransactionSet;
use super::{tag::Tag, td::TagData};
pub(crate) struct Header(librpm_sys::Header);
impl Header {
pub(crate) unsafe fn from_ptr(ffi_header: librpm_sys::Header) -> Self {
assert!(!ffi_header.is_null());
unsafe {
librpm_sys::headerLink(ffi_header);
}
Header(ffi_header)
}
pub(crate) fn as_ptr(&self) -> librpm_sys::Header {
self.0
}
pub(crate) fn from_file(path: &Path) -> Result<Self, RpmErrorKind> {
let txn = TransactionSet::create();
let filename = CString::new(path.as_os_str().as_bytes()).unwrap();
let fmode = CString::new("r.ufdio").unwrap();
let fd: librpm_sys::FD_t = unsafe { librpm_sys::Fopen(filename.as_ptr(), fmode.as_ptr()) };
#[allow(unused_mut)]
let mut vsflags = librpm_sys::rpmVSFlags_e_RPMVSF_NOHDRCHK
| librpm_sys::rpmVSFlags_e_RPMVSF_NOSHA1HEADER
| librpm_sys::rpmVSFlags_e_RPMVSF_NOSHA256HEADER
| librpm_sys::rpmVSFlags_e_RPMVSF_NOMD5
| librpm_sys::rpmVSFlags_e_RPMVSF_NODSAHEADER
| librpm_sys::rpmVSFlags_e_RPMVSF_NORSAHEADER
| librpm_sys::rpmVSFlags_e_RPMVSF_NODSA
| librpm_sys::rpmVSFlags_e_RPMVSF_NORSA;
#[cfg(has_rpmvsflag_nosha256payload)]
{
vsflags |= librpm_sys::rpmVSFlags_e_RPMVSF_NOSHA256PAYLOAD;
}
#[cfg(has_rpmvsflag_nosha512payload)]
{
vsflags |= librpm_sys::rpmVSFlags_e_RPMVSF_NOSHA512PAYLOAD;
}
#[cfg(has_rpmvsflag_nosha3_256payload)]
{
vsflags |= librpm_sys::rpmVSFlags_e_RPMVSF_NOSHA3_256PAYLOAD;
}
#[cfg(has_rpmvsflag_nosha3_256header)]
{
vsflags |= librpm_sys::rpmVSFlags_e_RPMVSF_NOSHA3_256HEADER;
}
#[cfg(has_rpmvsflag_noopenpgp)]
{
vsflags |= librpm_sys::rpmVSFlags_e_RPMVSF_NOOPENPGP;
}
unsafe {
let raw_ts = txn.as_ptr();
librpm_sys::rpmtsSetVSFlags(raw_ts, vsflags);
let mut hdr_ptr: librpm_sys::Header = std::ptr::null_mut();
let rc = librpm_sys::rpmReadPackageFile(raw_ts, fd, std::ptr::null(), &mut hdr_ptr);
librpm_sys::Fclose(fd);
match RpmReturnCode::from_raw(rc) {
Some(RpmReturnCode::Ok) => {
assert!(!hdr_ptr.is_null());
Ok(Header(hdr_ptr))
}
Some(RpmReturnCode::NotFound) => Err(RpmErrorKind::NotFound),
Some(RpmReturnCode::NotTrusted) => Err(RpmErrorKind::NotTrusted),
Some(RpmReturnCode::NoKey) => Err(RpmErrorKind::NoKey),
_ => Err(RpmErrorKind::Fail),
}
}
}
pub(crate) fn get(&self, tag: Tag) -> Option<TagData<'_>> {
let mut td: librpm_sys::rpmtd_s = unsafe { mem::zeroed() };
unsafe {
librpm_sys::rpmtdReset(&mut td);
}
let rc = unsafe {
librpm_sys::headerGet(
self.0,
tag.into(),
&mut td,
librpm_sys::headerGetFlags_e_HEADERGET_MINMEM,
)
};
if rc == 0 {
return None;
}
let data = match td.type_ {
librpm_sys::rpmTagType_e_RPM_NULL_TYPE => TagData::Null,
librpm_sys::rpmTagType_e_RPM_CHAR_TYPE => unsafe { TagData::char(&td) },
librpm_sys::rpmTagType_e_RPM_INT8_TYPE => unsafe { TagData::int8(&td) },
librpm_sys::rpmTagType_e_RPM_INT16_TYPE => unsafe { TagData::int16(&td) },
librpm_sys::rpmTagType_e_RPM_INT32_TYPE => unsafe { TagData::int32(&td) },
librpm_sys::rpmTagType_e_RPM_INT64_TYPE => unsafe { TagData::int64(&td) },
librpm_sys::rpmTagType_e_RPM_STRING_TYPE => unsafe { TagData::string(&td) },
librpm_sys::rpmTagType_e_RPM_STRING_ARRAY_TYPE => unsafe {
TagData::string_array(&mut td)
},
librpm_sys::rpmTagType_e_RPM_I18NSTRING_TYPE => unsafe {
TagData::i18n_string(&mut td)
},
librpm_sys::rpmTagType_e_RPM_BIN_TYPE => unsafe { TagData::bin(&td) },
other => panic!("unsupported rpmtd tag type: {other}"),
};
unsafe {
librpm_sys::rpmtdFreeData(&mut td);
}
Some(data)
}
}
impl Clone for Header {
fn clone(&self) -> Self {
unsafe {
librpm_sys::headerLink(self.0);
}
Header(self.0)
}
}
impl Drop for Header {
fn drop(&mut self) {
unsafe {
librpm_sys::headerFree(self.0);
}
}
}