#![no_std]
#![allow(dead_code)]
use core::fmt::Result;
extern crate alloc;
pub fn oct2bin(s: &[u8]) -> usize {
let mut n = 0;
for &c in s {
if (b'0'..=b'7').contains(&c) {
n = n * 8 + (c - b'0') as usize;
}
}
n
}
pub struct TarHeader<'a> {
pub name: &'a str, pub size: usize,
pub file_start: usize,
pub file_end: usize,
}
fn parse_header<'a>(archive: &'a [u8], offset: usize) -> Option<TarHeader<'a>> {
if offset + 512 > archive.len() {
return None;
}
let header = &archive[offset..offset + 512];
if &header[257..257 + 5] != b"ustar" {
return None;
}
let size = oct2bin(&header[0x7c..0x7c + 11]);
let raw_name = &header[..100];
let nul_pos = raw_name.iter().position(|&b| b == 0).unwrap_or(raw_name.len());
let name = core::str::from_utf8(&raw_name[..nul_pos]).ok()?;
Some(TarHeader {
name,
size,
file_start: offset + 512,
file_end: offset + 512 + size,
})
}
pub struct TarIter<'a> {
archive: &'a [u8],
offset: usize,
}
impl<'a> TarIter<'a> {
pub fn new(archive: &'a [u8]) -> Self {
Self { archive, offset: 0 }
}
}
impl<'a> Iterator for TarIter<'a> {
type Item = TarHeader<'a>;
fn next(&mut self) -> Option<Self::Item> {
let header = parse_header(self.archive, self.offset)?;
let size = header.size;
let blocks = (size + 511) / 512;
self.offset += 512 + blocks * 512;
Some(header)
}
}
pub fn tar_lookup<'a>(archive: &'a [u8], filename: &str) -> Option<&'a [u8]> {
for header in TarIter::new(archive) {
if header.name == filename {
if header.file_end <= archive.len() {
return Some(&archive[header.file_start..header.file_end]);
}
}
}
None
}
pub fn extract_file(archive: &[u8], filename: &str) -> Option<alloc::vec::Vec<u8>> {
tar_lookup(archive, filename).map(|data| data.to_vec())
}
pub trait TarReader {
fn read_block(&mut self, lba: u64, buf: &mut [u8]) -> Result<>;
}