blob: 94ff468f8facfc5cc078ecbd11062b7d8e66f5c4 [file] [log] [blame]
// Trivial tar loader.
use core::mem::{size_of, transmute};
use core::ptr;
use matcha_hal::dprintf;
const EFLASH_START: u32 = 0x44000000;
const EFLASH_END: u32 = 0x45000000;
#[repr(C, packed)]
pub struct TarHeader {
/* byte offset */
name: [u8; 100], /* 0 */
mode: [u8; 8], /* 100 */
uid: [u8; 8], /* 108 */
gid: [u8; 8], /* 116 */
size: [u8; 12], /* 124 */
mtime: [u8; 12], /* 136 */
chksum: [u8; 8], /* 148 */
typeflag: u8, /* 156 */
linkname: [u8; 100], /* 157 */
magic: [u8; 6], /* 257 */
version: [u8; 2], /* 263 */
uname: [u8; 32], /* 265 */
gname: [u8; 32], /* 297 */
devmajor: [u8; 8], /* 329 */
devminor: [u8; 8], /* 337 */
prefix: [u8; 155], /* 345 */
reserved: [u8; 12], /* 512 */
}
impl Default for TarHeader {
fn default() -> Self {
return TarHeader {
name: [0; 100],
mode: [0; 8],
uid: [0; 8],
gid: [0; 8],
size: [0; 12],
mtime: [0; 12],
chksum: [0; 8],
typeflag: 0,
linkname: [0; 100],
magic: [0; 6],
version: [0; 2],
uname: [0; 32],
gname: [0; 32],
devmajor: [0; 8],
devminor: [0; 8],
prefix: [0; 155],
reserved: [0; 12],
};
}
}
impl TarHeader {
pub fn from_bytes(b: &[u8]) -> TarHeader {
unsafe { b.as_ptr().cast::<TarHeader>().read() }
}
pub fn has_magic(&self) -> bool {
self.magic[..5] == *b"ustar"
}
pub fn name(&self) -> &str {
if let Some(len) = self.name.iter().position(|&x| x == 0) {
core::str::from_utf8(&self.name[..len])
} else {
core::str::from_utf8(&self.name)
}
.unwrap_or("<invalid>")
}
pub fn size(&self) -> u32 {
parse_octal(&self.size)
}
}
fn parse_octal(text: &[u8]) -> u32 {
text.iter()
.take_while(|&&x| x != 0)
.fold(0u32, |acc, &x| (acc << 3) + (x as u32 - '0' as u32))
}
pub unsafe fn find_file(name: &str) -> (u32, u32) {
let mut cursor = EFLASH_START;
while (cursor + 512) < EFLASH_END {
let tar_header = &*(cursor as *const TarHeader);
if !tar_header.has_magic() {
// Our tar files have the "ustar" magic field; use it
// to avoid scanning all EFLASH.
break;
}
cursor += size_of::<TarHeader>() as u32;
let tar_name = tar_header.name();
let tar_size = tar_header.size();
if tar_name == name {
return (cursor, tar_size);
} else {
fn roundup(a: u32, b: u32) -> u32 {
((a + b - 1) / b) * b
}
cursor += roundup(
tar_size,
size_of::<TarHeader>() as u32,
);
}
}
dprintf!("Could not find tar entry for '{}'\n", name);
return (0, 0);
}
// TODO(sleffler): rethink api, e.g. supply a range for bounds check
pub unsafe fn copy_file(name: &str, offset: u32) -> bool {
let (cursor, size) = find_file(name);
if cursor != 0 {
ptr::copy_nonoverlapping::<u8>(
transmute(cursor),
transmute(offset),
size as usize,
);
true
} else {
false
}
}