| // 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 |
| } |