tar_loader: fixups
- from_bytes does not need a mutable reference
- add has_magic method to check the magic field
- fix name to return a string w/o embedded nul's
- rewrite parse_octal to use iterators
- rewrite find_file to use methods, to stop searching at the first
invalid (according to has_magic) header, and to correctly check
for end-of-flash
- change copy_file to check the offset instead of the file size
when deciding if a file was found--zero-length files can and do exist
Bug: 294433731
Change-Id: Ic769517bfbcc51e2e8c4f1cb485d3bb6338179b4
diff --git a/utils/src/tar_loader.rs b/utils/src/tar_loader.rs
index 10a3024..94ff468 100644
--- a/utils/src/tar_loader.rs
+++ b/utils/src/tar_loader.rs
@@ -1,6 +1,6 @@
// Trivial tar loader.
-use core::mem::transmute;
+use core::mem::{size_of, transmute};
use core::ptr;
use matcha_hal::dprintf;
@@ -54,12 +54,21 @@
}
impl TarHeader {
- pub fn from_bytes(b: &mut [u8]) -> TarHeader {
- unsafe { ptr::read(b.as_ptr() as *const 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 {
- core::str::from_utf8(&self.name).unwrap()
+ 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 {
@@ -68,28 +77,33 @@
}
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;
+ 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 < 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);
+ 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 {
- let tar_size = parse_octal(&(*tar_header).size);
- cursor += (tar_size + 511) & !511;
+ fn roundup(a: u32, b: u32) -> u32 {
+ ((a + b - 1) / b) * b
+ }
+ cursor += roundup(
+ tar_size,
+ size_of::<TarHeader>() as u32,
+ );
}
}
@@ -100,9 +114,14 @@
// 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;
+ if cursor != 0 {
+ ptr::copy_nonoverlapping::<u8>(
+ transmute(cursor),
+ transmute(offset),
+ size as usize,
+ );
+ true
+ } else {
+ false
}
- ptr::copy_nonoverlapping::<u8>(transmute(cursor), transmute(offset), size as usize);
- true
}