-
Notifications
You must be signed in to change notification settings - Fork 1
cpio miniroot support #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| // This Source Code Form is subject to the terms of the Mozilla Public | ||
| // License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| // file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
|
|
||
| //! cpio miniroot support. | ||
|
|
||
| use crate::io; | ||
| use crate::ramdisk; | ||
| use crate::result::{Error, Result}; | ||
| use crate::{print, println}; | ||
| use alloc::boxed::Box; | ||
| use core::slice; | ||
|
|
||
| pub(crate) struct FileSystem { | ||
| sd: io::Sd, | ||
| } | ||
|
|
||
| impl FileSystem { | ||
| pub(crate) fn try_new(bs: &[u8]) -> Result<FileSystem> { | ||
| if bs.starts_with(b"070707") { | ||
| let sd = io::Sd::from_slice(bs); | ||
| Ok(FileSystem { sd }) | ||
| } else { | ||
| Err(Error::FsInvMagic) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| pub(crate) struct File { | ||
| data: io::Sd, | ||
| } | ||
|
|
||
| impl File { | ||
| fn as_slice(&self) -> &[u8] { | ||
| let ptr = self.data.as_ptr(); | ||
| let len = self.data.len(); | ||
| unsafe { slice::from_raw_parts(ptr, len) } | ||
| } | ||
| } | ||
|
|
||
| impl ramdisk::File for File { | ||
| fn file_type(&self) -> ramdisk::FileType { | ||
| ramdisk::FileType::Regular | ||
| } | ||
| } | ||
|
|
||
| impl io::Read for File { | ||
| fn read(&self, offset: u64, dst: &mut [u8]) -> Result<usize> { | ||
| let s = self.as_slice(); | ||
| s.read(offset, dst) | ||
| } | ||
|
|
||
| fn size(&self) -> usize { | ||
| self.data.len() | ||
| } | ||
| } | ||
|
|
||
| impl ramdisk::FileSystem for FileSystem { | ||
| fn open(&self, path: &str) -> Result<Box<dyn ramdisk::File>> { | ||
| let ptr: *const u8 = self.sd.as_ptr(); | ||
| let len = self.sd.len(); | ||
| let cpio = unsafe { core::slice::from_raw_parts(ptr, len) }; | ||
| let key = path.strip_prefix("/").unwrap_or(path); | ||
| for file in cpio_reader::iter_files(cpio) { | ||
| if file.name() == key { | ||
| let data = io::Sd::from_slice(file.file()); | ||
| return Ok(Box::new(File { data })); | ||
| } | ||
| } | ||
| Err(Error::FsNoFile) | ||
| } | ||
|
|
||
| fn list(&self, path: &str) -> Result<()> { | ||
| let ptr: *const u8 = self.sd.as_ptr(); | ||
| let len = self.sd.len(); | ||
| let cpio = unsafe { core::slice::from_raw_parts(ptr, len) }; | ||
| let key = path.strip_prefix('/').unwrap_or(path); | ||
| for file in cpio_reader::iter_files(cpio) { | ||
| if file.name() == key { | ||
| lsfile(path, &file); | ||
| return Ok(()); | ||
| } | ||
| } | ||
| let mut found = false; | ||
| for file in cpio_reader::iter_files(cpio) { | ||
| if file.name().starts_with(key) { | ||
| lsfile(file.name(), &file); | ||
| found = true; | ||
| } | ||
| } | ||
| if found { Ok(()) } else { Err(Error::FsNoFile) } | ||
| } | ||
|
|
||
| fn as_str(&self) -> &str { | ||
| "cpio" | ||
| } | ||
|
|
||
| fn with_addr(&self, addr: usize) -> *const u8 { | ||
| self.sd.as_ptr().with_addr(addr) | ||
| } | ||
| } | ||
|
|
||
| fn lsfile(path: &str, file: &cpio_reader::Entry) { | ||
| print!("#{ino:<4} ", ino = file.ino()); | ||
| print_mode(file.mode()); | ||
| println!( | ||
| " {nlink:<2} {uid:<3} {gid:<3} {size:>8} {path}", | ||
| nlink = file.nlink(), | ||
| uid = file.uid(), | ||
| gid = file.gid(), | ||
| size = file.file().len(), | ||
| ); | ||
| } | ||
|
|
||
| fn first_char(mode: cpio_reader::Mode) -> char { | ||
| use cpio_reader::Mode; | ||
| match mode { | ||
| _ if mode.contains(Mode::DIRECTORY) => 'd', | ||
| _ if mode.contains(Mode::CHARACTER_SPECIAL_DEVICE) => 'c', | ||
| _ if mode.contains(Mode::BLOCK_SPECIAL_DEVICE) => 'b', | ||
| _ if mode.contains(Mode::SYMBOLIK_LINK) => 'l', | ||
| _ if mode.contains(Mode::SOCKET) => 's', | ||
| _ if mode.contains(Mode::NAMED_PIPE_FIFO) => 'f', | ||
| _ => '-', | ||
| } | ||
| } | ||
|
|
||
| fn print_mode(mode: cpio_reader::Mode) { | ||
| use cpio_reader::Mode; | ||
| print!("{}", first_char(mode)); | ||
| let alt = |bit, t, f| { | ||
| if mode.contains(bit) { t } else { f } | ||
| }; | ||
| // For some reason, the cpio reader library appears to have | ||
| // the meaning of these bits mirrored with respect to the owner | ||
| // bits. | ||
| print!("{}", alt(Mode::WORLD_READABLE, 'r', '-')); | ||
| print!("{}", alt(Mode::WORLD_WRITABLE, 'w', '-')); | ||
| if !mode.contains(Mode::SUID) { | ||
| print!("{}", alt(Mode::WORLD_EXECUTABLE, 'x', '-')); | ||
| } else { | ||
| print!("{}", alt(Mode::WORLD_EXECUTABLE, 's', 'S')); | ||
| } | ||
|
|
||
| print!("{}", alt(Mode::GROUP_READABLE, 'r', '-')); | ||
| print!("{}", alt(Mode::GROUP_WRITABLE, 'w', '-')); | ||
| if !mode.contains(Mode::SGID) { | ||
| print!("{}", alt(Mode::GROUP_EXECUTABLE, 'x', '-')); | ||
| } else { | ||
| print!("{}", alt(Mode::GROUP_EXECUTABLE, 's', 'S')); | ||
| } | ||
|
|
||
| print!("{}", alt(Mode::USER_READABLE, 'r', '-')); | ||
| print!("{}", alt(Mode::USER_WRITABLE, 'w', '-')); | ||
| if !mode.contains(Mode::STICKY) { | ||
| print!("{}", alt(Mode::USER_EXECUTABLE, 'x', '-')); | ||
| } else { | ||
| print!("{}", alt(Mode::USER_EXECUTABLE, 't', 'T')); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| // This Source Code Form is subject to the terms of the Mozilla Public | ||
| // License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| // file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
|
|
||
| use crate::result::Result; | ||
|
|
||
| #[derive(Debug)] | ||
| pub(crate) struct Sd { | ||
dancrossnyc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| pub(crate) ptr: *const u8, | ||
| pub(crate) len: usize, | ||
| } | ||
|
|
||
| impl Sd { | ||
| pub(crate) fn new(ptr: *const u8, len: usize) -> Sd { | ||
| Sd { ptr, len } | ||
| } | ||
|
|
||
| pub(crate) fn from_slice(bs: &[u8]) -> Sd { | ||
dancrossnyc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Sd::new(bs.as_ptr(), bs.len()) | ||
| } | ||
|
|
||
| pub(crate) fn as_ptr(&self) -> *const u8 { | ||
| self.ptr | ||
| } | ||
|
|
||
| pub(crate) fn len(&self) -> usize { | ||
| self.len | ||
| } | ||
|
|
||
| pub(crate) fn subset(&self, offset: usize, len: usize) -> Sd { | ||
| assert!(offset + len <= self.len); | ||
| let ptr = self.ptr.wrapping_add(offset); | ||
| Sd { ptr, len } | ||
| } | ||
| } | ||
|
|
||
| pub(crate) trait Read { | ||
| fn read(&self, off: u64, dst: &mut [u8]) -> Result<usize>; | ||
| fn size(&self) -> usize; | ||
| } | ||
|
|
||
| impl Read for &[u8] { | ||
| fn read(&self, off: u64, dst: &mut [u8]) -> Result<usize> { | ||
| let off = off as usize; | ||
| if off > self.len() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... i did not know that
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed! It occurs to me that, regardless of correctness, it's clearer all around to just use |
||
| return Ok(0); | ||
| } | ||
| let bytes = &self[off..]; | ||
| let len = usize::min(bytes.len(), dst.len()); | ||
| if len > 0 { | ||
| dst[..len].copy_from_slice(&bytes[..len]); | ||
| } | ||
| Ok(len) | ||
| } | ||
|
|
||
| fn size(&self) -> usize { | ||
| self.len() | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.