Handle cpio commands properly

This commit is contained in:
topjohnwu 2023-07-03 21:57:28 -07:00
parent 43b9a09c9b
commit 5ee6daf126
5 changed files with 51 additions and 27 deletions

1
native/src/Cargo.lock generated
View File

@ -69,6 +69,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
name = "base" name = "base"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"argh",
"cfg-if", "cfg-if",
"cxx", "cxx",
"cxx-gen", "cxx-gen",

View File

@ -14,3 +14,4 @@ cxx = { workspace = true }
libc = { workspace = true } libc = { workspace = true }
cfg-if = { workspace = true } cfg-if = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
argh = { workspace = true }

View File

@ -3,9 +3,11 @@ use std::ffi::{CStr, FromBytesWithNulError, OsStr};
use std::fmt::{Arguments, Debug, Display, Formatter}; use std::fmt::{Arguments, Debug, Display, Formatter};
use std::ops::Deref; use std::ops::Deref;
use std::path::Path; use std::path::Path;
use std::process::exit;
use std::str::Utf8Error; use std::str::Utf8Error;
use std::{fmt, io, mem, slice, str}; use std::{fmt, io, mem, slice, str};
use argh::EarlyExit;
use libc::c_char; use libc::c_char;
use thiserror::Error; use thiserror::Error;
@ -297,18 +299,18 @@ where
fn as_raw_bytes(&self) -> &[u8] { fn as_raw_bytes(&self) -> &[u8] {
unsafe { unsafe {
let self_ptr = self as *const Self as *const u8; let self_ptr = self as *const Self as *const u8;
slice::from_raw_parts(self_ptr, std::mem::size_of::<Self>()) slice::from_raw_parts(self_ptr, mem::size_of::<Self>())
} }
} }
fn as_raw_bytes_mut(&mut self) -> &mut [u8] { fn as_raw_bytes_mut(&mut self) -> &mut [u8] {
unsafe { unsafe {
let self_ptr = self as *mut Self as *mut u8; let self_ptr = self as *mut Self as *mut u8;
slice::from_raw_parts_mut(self_ptr, std::mem::size_of::<Self>()) slice::from_raw_parts_mut(self_ptr, mem::size_of::<Self>())
} }
} }
fn bytes_size(&self) -> usize { fn bytes_size(&self) -> usize {
std::mem::size_of::<Self>() mem::size_of::<Self>()
} }
} }
@ -369,3 +371,34 @@ impl<T: AsMut<[u8]>> MutBytesExt for T {
ffi::mut_u8_patch(self.as_mut(), from, to) ffi::mut_u8_patch(self.as_mut(), from, to)
} }
} }
// SAFETY: libc guarantees argc and argv is properly setup
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn map_args<'a>(argc: i32, argv: *const *const c_char) -> Result<Vec<&'a Utf8CStr>, StrErr> {
unsafe { slice::from_raw_parts(argv, argc as usize) }
.iter()
.map(|s| unsafe { Utf8CStr::from_ptr(*s) })
.collect()
}
pub trait EarlyExitExt<T> {
fn early_exit(self) -> T;
}
impl<T> EarlyExitExt<T> for Result<T, EarlyExit> {
fn early_exit(self) -> T {
match self {
Ok(t) => t,
Err(EarlyExit { output, status }) => match status {
Ok(_) => {
eprintln!("{}", output);
exit(0)
}
Err(_) => {
eprintln!("{}", output);
exit(1)
}
},
}
}
}

View File

@ -7,9 +7,8 @@ use std::mem::size_of;
use std::os::unix::fs::{symlink, DirBuilderExt, FileTypeExt, MetadataExt}; use std::os::unix::fs::{symlink, DirBuilderExt, FileTypeExt, MetadataExt};
use std::path::Path; use std::path::Path;
use std::process::exit; use std::process::exit;
use std::slice;
use argh::{EarlyExit, FromArgs}; use argh::FromArgs;
use size::{Base, Size, Style}; use size::{Base, Size, Style};
use base::libc::{ use base::libc::{
@ -17,7 +16,9 @@ use base::libc::{
S_IFLNK, S_IFMT, S_IFREG, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IFLNK, S_IFMT, S_IFREG, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP,
S_IXOTH, S_IXUSR, S_IXOTH, S_IXUSR,
}; };
use base::{log_err, LoggedResult, MappedFile, ResultExt, StrErr, Utf8CStr, WriteExt}; use base::{
log_err, map_args, EarlyExitExt, LoggedResult, MappedFile, ResultExt, Utf8CStr, WriteExt,
};
use crate::ramdisk::MagiskCpio; use crate::ramdisk::MagiskCpio;
@ -525,12 +526,7 @@ pub fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool {
return Err(log_err!("no arguments")); return Err(log_err!("no arguments"));
} }
let cmds: Result<Vec<&Utf8CStr>, StrErr> = let cmds = map_args(argc, argv)?;
unsafe { slice::from_raw_parts(argv, argc as usize) }
.iter()
.map(|s| unsafe { Utf8CStr::from_ptr(*s) })
.collect();
let cmds = cmds?;
let file = cmds[0]; let file = cmds[0];
let mut cpio = if Path::new(file).exists() { let mut cpio = if Path::new(file).exists() {
@ -538,26 +534,20 @@ pub fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool {
} else { } else {
Cpio::new() Cpio::new()
}; };
for cmd in &cmds[1..] { for cmd in &cmds[1..] {
if cmd.starts_with('#') { if cmd.starts_with('#') {
continue; continue;
} }
let mut cli = match CpioCli::from_args( let mut cli = CpioCli::from_args(
&["magiskboot", "cpio", file], &["magiskboot", "cpio", file],
cmd.split(' ') cmd.split(' ')
.filter(|x| !x.is_empty()) .filter(|x| !x.is_empty())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.as_slice(), .as_slice(),
) { )
Ok(cli) => cli, .early_exit();
Err(EarlyExit { output, status }) => match status {
Ok(_) => {
eprintln!("{}", output);
exit(0)
}
Err(_) => return Err(log_err!(output)),
},
};
match &mut cli.command { match &mut cli.command {
CpioCommands::Test(Test {}) => exit(cpio.test()), CpioCommands::Test(Test {}) => exit(cpio.test()),
CpioCommands::Restore(Restore {}) => cpio.restore()?, CpioCommands::Restore(Restore {}) => cpio.restore()?,
@ -590,7 +580,7 @@ pub fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool {
cpio.ls(path.as_str(), *recursive); cpio.ls(path.as_str(), *recursive);
exit(0); exit(0);
} }
} };
} }
cpio.dump(file)?; cpio.dump(file)?;
Ok(()) Ok(())

View File

@ -177,9 +177,8 @@ int main(int argc, char *argv[]) {
compress(action[8] == '=' ? &action[9] : "gzip", argv[2], argv[3]); compress(action[8] == '=' ? &action[9] : "gzip", argv[2], argv[3]);
} else if (argc > 4 && action == "hexpatch") { } else if (argc > 4 && action == "hexpatch") {
return hexpatch(byte_view(argv[2]), byte_view(argv[3]), byte_view(argv[4])) ? 0 : 1; return hexpatch(byte_view(argv[2]), byte_view(argv[3]), byte_view(argv[4])) ? 0 : 1;
} else if (argc > 2 && action == "cpio"sv) { } else if (argc > 2 && action == "cpio") {
if (!rust::cpio_commands(argc - 2, argv + 2)) return rust::cpio_commands(argc - 2, argv + 2) ? 0 : 1;
usage(argv[0]);
} else if (argc > 3 && action == "dtb") { } else if (argc > 3 && action == "dtb") {
if (dtb_commands(argc - 2, argv + 2)) if (dtb_commands(argc - 2, argv + 2))
usage(argv[0]); usage(argv[0]);