blob: 10a30242af3ac6de4b5102e103801b2644005f49 [file] [log] [blame]
// Trivial tar loader.
use core::mem::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: &mut [u8]) -> TarHeader {
unsafe { ptr::read(b.as_ptr() as *const TarHeader) }
}
pub fn name(&self) -> &str {
core::str::from_utf8(&self.name).unwrap()
}
pub fn size(&self) -> u32 {
parse_octal(&self.size)
}
}
fn parse_octal(text: &[u8]) -> u32 {
let mut n: u32 = 0;
for x in text.iter() {
if *x == (0 as u8) {
break;
}
n = (n << 3) | ((*x as u32) - ('0' as u32));
}
return n;
}
pub unsafe fn find_file(name: &str) -> (u32, u32) {
let mut cursor = EFLASH_START;
while cursor < EFLASH_END {
let tar_header: *const TarHeader = transmute(cursor);
cursor += 512;
let tar_name = core::str::from_utf8(&(*tar_header).name).unwrap();
if tar_name.contains(name) {
let tar_size = parse_octal(&(*tar_header).size);
return (cursor, tar_size);
} else {
let tar_size = parse_octal(&(*tar_header).size);
cursor += (tar_size + 511) & !511;
}
}
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 size == 0 {
return false;
}
ptr::copy_nonoverlapping::<u8>(transmute(cursor), transmute(offset), size as usize);
true
}