mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-23 00:17:42 +00:00
Support compressing during cpio backup
This commit is contained in:
parent
d73c2daf6d
commit
8b7fae278b
@ -78,6 +78,21 @@ private:
|
|||||||
void resize(size_t new_sz, bool zero = false);
|
void resize(size_t new_sz, bool zero = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class rust_vec_channel : public channel {
|
||||||
|
public:
|
||||||
|
rust_vec_channel(rust::Vec<uint8_t> &data) : _data(data) {}
|
||||||
|
|
||||||
|
ssize_t read(void *buf, size_t len) override;
|
||||||
|
bool write(const void *buf, size_t len) override;
|
||||||
|
off_t seek(off_t off, int whence) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
rust::Vec<uint8_t> &_data;
|
||||||
|
size_t _pos = 0;
|
||||||
|
|
||||||
|
void ensure_size(size_t sz);
|
||||||
|
};
|
||||||
|
|
||||||
class file_channel : public channel {
|
class file_channel : public channel {
|
||||||
public:
|
public:
|
||||||
bool write(const void *buf, size_t len) final;
|
bool write(const void *buf, size_t len) final;
|
||||||
|
@ -44,6 +44,7 @@ pub mod ffi {
|
|||||||
fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool);
|
fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool);
|
||||||
fn exit_on_error(b: bool);
|
fn exit_on_error(b: bool);
|
||||||
fn cmdline_logging();
|
fn cmdline_logging();
|
||||||
|
fn resize_vec(vec: &mut Vec<u8>, size: usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[namespace = "rust"]
|
#[namespace = "rust"]
|
||||||
@ -63,3 +64,7 @@ fn set_log_level_state_cxx(level: ffi::LogLevelCxx, enabled: bool) {
|
|||||||
set_log_level_state(level, enabled)
|
set_log_level_state(level, enabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resize_vec(vec: &mut Vec<u8>, size: usize) {
|
||||||
|
vec.resize(size, 0);
|
||||||
|
}
|
||||||
|
@ -180,6 +180,47 @@ void byte_channel::resize(size_t new_sz, bool zero) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t rust_vec_channel::read(void *buf, size_t len) {
|
||||||
|
len = std::min<size_t>(len, _data.size() - _pos);
|
||||||
|
memcpy(buf, _data.data() + _pos, len);
|
||||||
|
_pos += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rust_vec_channel::write(const void *buf, size_t len) {
|
||||||
|
ensure_size(_pos + len);
|
||||||
|
memcpy(_data.data() + _pos, buf, len);
|
||||||
|
_pos += len;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t rust_vec_channel::seek(off_t off, int whence) {
|
||||||
|
off_t np;
|
||||||
|
switch (whence) {
|
||||||
|
case SEEK_CUR:
|
||||||
|
np = _pos + off;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
np = _data.size() + off;
|
||||||
|
break;
|
||||||
|
case SEEK_SET:
|
||||||
|
np = off;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ensure_size(np);
|
||||||
|
_pos = np;
|
||||||
|
return np;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rust_vec_channel::ensure_size(size_t sz) {
|
||||||
|
size_t old_sz = _data.size();
|
||||||
|
if (sz > old_sz) {
|
||||||
|
resize_vec(_data, sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t fd_channel::read(void *buf, size_t len) {
|
ssize_t fd_channel::read(void *buf, size_t len) {
|
||||||
return ::read(fd, buf, len);
|
return ::read(fd, buf, len);
|
||||||
}
|
}
|
||||||
|
@ -732,3 +732,24 @@ bool decompress(rust::Slice<const uint8_t> buf, int fd) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool xz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out) {
|
||||||
|
auto strm = get_encoder(XZ, make_unique<rust_vec_channel>(out));
|
||||||
|
if (!strm->write(buf.data(), buf.length())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unxz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out) {
|
||||||
|
format_t type = check_fmt(buf.data(), buf.length());
|
||||||
|
if (type != XZ) {
|
||||||
|
LOGE("Input file is not in xz format!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto strm = get_decoder(XZ, make_unique<rust_vec_channel>(out));
|
||||||
|
if (!strm->write(buf.data(), buf.length())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -10,3 +10,5 @@ out_strm_ptr get_decoder(format_t type, out_strm_ptr &&base);
|
|||||||
void compress(const char *method, const char *infile, const char *outfile);
|
void compress(const char *method, const char *infile, const char *outfile);
|
||||||
void decompress(char *infile, const char *outfile);
|
void decompress(char *infile, const char *outfile);
|
||||||
bool decompress(rust::Slice<const uint8_t> buf, int fd);
|
bool decompress(rust::Slice<const uint8_t> buf, int fd);
|
||||||
|
bool xz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out);
|
||||||
|
bool unxz(rust::Slice<const uint8_t> buf, rust::Vec<uint8_t> &out);
|
||||||
|
@ -15,6 +15,7 @@ use bytemuck::{from_bytes, Pod, Zeroable};
|
|||||||
use num_traits::cast::AsPrimitive;
|
use num_traits::cast::AsPrimitive;
|
||||||
use size::{Base, Size, Style};
|
use size::{Base, Size, Style};
|
||||||
|
|
||||||
|
use crate::ffi::{unxz, xz};
|
||||||
use base::libc::{
|
use base::libc::{
|
||||||
c_char, dev_t, gid_t, major, makedev, minor, mknod, mode_t, uid_t, S_IFBLK, S_IFCHR, S_IFDIR,
|
c_char, dev_t, gid_t, major, makedev, minor, mknod, mode_t, uid_t, S_IFBLK, S_IFCHR, S_IFDIR,
|
||||||
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,
|
||||||
@ -81,6 +82,8 @@ struct Exists {
|
|||||||
struct Backup {
|
struct Backup {
|
||||||
#[argh(positional, arg_name = "orig")]
|
#[argh(positional, arg_name = "orig")]
|
||||||
origin: String,
|
origin: String,
|
||||||
|
#[argh(switch, short = 'n')]
|
||||||
|
skip_compress: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs)]
|
#[derive(FromArgs)]
|
||||||
@ -177,8 +180,8 @@ Supported commands:
|
|||||||
patch
|
patch
|
||||||
Apply ramdisk patches
|
Apply ramdisk patches
|
||||||
Configure with env variables: KEEPVERITY KEEPFORCEENCRYPT
|
Configure with env variables: KEEPVERITY KEEPFORCEENCRYPT
|
||||||
backup ORIG
|
backup ORIG [-n]
|
||||||
Create ramdisk backups from ORIG
|
Create ramdisk backups from ORIG, specify [-n] to skip compression
|
||||||
restore
|
restore
|
||||||
Restore ramdisk from ramdisk backup stored within incpio
|
Restore ramdisk from ramdisk backup stored within incpio
|
||||||
"#
|
"#
|
||||||
@ -495,6 +498,26 @@ impl Cpio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CpioEntry {
|
||||||
|
pub(crate) fn compress(&mut self) -> LoggedResult<()> {
|
||||||
|
let mut compressed = Vec::new();
|
||||||
|
if !xz(&self.data, &mut compressed) {
|
||||||
|
return Err(log_err!("xz compression failed"));
|
||||||
|
}
|
||||||
|
self.data = compressed;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn decompress(&mut self) -> LoggedResult<()> {
|
||||||
|
let mut decompressed = Vec::new();
|
||||||
|
if !unxz(&self.data, &mut decompressed) {
|
||||||
|
return Err(log_err!("xz decompression failed"));
|
||||||
|
}
|
||||||
|
self.data = decompressed;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for CpioEntry {
|
impl Display for CpioEntry {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
@ -572,9 +595,10 @@ pub fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CpioSubCommand::Backup(Backup { origin }) => {
|
CpioSubCommand::Backup(Backup {
|
||||||
cpio.backup(Utf8CStr::from_string(origin))?
|
origin,
|
||||||
}
|
skip_compress,
|
||||||
|
}) => cpio.backup(Utf8CStr::from_string(origin), *skip_compress)?,
|
||||||
CpioSubCommand::Remove(Remove { path, recursive }) => cpio.rm(path, *recursive),
|
CpioSubCommand::Remove(Remove { path, recursive }) => cpio.rm(path, *recursive),
|
||||||
CpioSubCommand::Move(Move { from, to }) => cpio.mv(from, to)?,
|
CpioSubCommand::Move(Move { from, to }) => cpio.mv(from, to)?,
|
||||||
CpioSubCommand::MakeDir(MakeDir { mode, dir }) => cpio.mkdir(mode, dir),
|
CpioSubCommand::MakeDir(MakeDir { mode, dir }) => cpio.mkdir(mode, dir),
|
||||||
|
@ -25,6 +25,8 @@ pub mod ffi {
|
|||||||
unsafe extern "C++" {
|
unsafe extern "C++" {
|
||||||
include!("compress.hpp");
|
include!("compress.hpp");
|
||||||
fn decompress(buf: &[u8], fd: i32) -> bool;
|
fn decompress(buf: &[u8], fd: i32) -> bool;
|
||||||
|
fn xz(buf: &[u8], out: &mut Vec<u8>) -> bool;
|
||||||
|
fn unxz(buf: &[u8], out: &mut Vec<u8>) -> bool;
|
||||||
|
|
||||||
include!("bootimg.hpp");
|
include!("bootimg.hpp");
|
||||||
#[cxx_name = "boot_img"]
|
#[cxx_name = "boot_img"]
|
||||||
|
@ -13,7 +13,7 @@ pub trait MagiskCpio {
|
|||||||
fn patch(&mut self);
|
fn patch(&mut self);
|
||||||
fn test(&self) -> i32;
|
fn test(&self) -> i32;
|
||||||
fn restore(&mut self) -> LoggedResult<()>;
|
fn restore(&mut self) -> LoggedResult<()>;
|
||||||
fn backup(&mut self, origin: &Utf8CStr) -> LoggedResult<()>;
|
fn backup(&mut self, origin: &Utf8CStr, skip_compress: bool) -> LoggedResult<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAGISK_PATCHED: i32 = 1 << 0;
|
const MAGISK_PATCHED: i32 = 1 << 0;
|
||||||
@ -89,13 +89,17 @@ impl MagiskCpio for Cpio {
|
|||||||
let mut rm_list = String::new();
|
let mut rm_list = String::new();
|
||||||
self.entries
|
self.entries
|
||||||
.extract_if(|name, _| name.starts_with(".backup/"))
|
.extract_if(|name, _| name.starts_with(".backup/"))
|
||||||
.for_each(|(name, entry)| {
|
.for_each(|(name, mut entry)| {
|
||||||
if name == ".backup/.rmlist" {
|
if name == ".backup/.rmlist" {
|
||||||
if let Ok(data) = from_utf8(&entry.data) {
|
if let Ok(data) = from_utf8(&entry.data) {
|
||||||
rm_list.push_str(data);
|
rm_list.push_str(data);
|
||||||
}
|
}
|
||||||
} else if name != ".backup/.magisk" {
|
} else if name != ".backup/.magisk" {
|
||||||
let new_name = &name[8..];
|
let new_name = if name.ends_with(".xz") && entry.decompress().is_ok() {
|
||||||
|
&name[8..name.len() - 3]
|
||||||
|
} else {
|
||||||
|
&name[8..]
|
||||||
|
};
|
||||||
eprintln!("Restore [{}] -> [{}]", name, new_name);
|
eprintln!("Restore [{}] -> [{}]", name, new_name);
|
||||||
backups.insert(new_name.to_string(), entry);
|
backups.insert(new_name.to_string(), entry);
|
||||||
}
|
}
|
||||||
@ -115,7 +119,7 @@ impl MagiskCpio for Cpio {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn backup(&mut self, origin: &Utf8CStr) -> LoggedResult<()> {
|
fn backup(&mut self, origin: &Utf8CStr, skip_compress: bool) -> LoggedResult<()> {
|
||||||
let mut backups = HashMap::<String, Box<CpioEntry>>::new();
|
let mut backups = HashMap::<String, Box<CpioEntry>>::new();
|
||||||
let mut rm_list = String::new();
|
let mut rm_list = String::new();
|
||||||
backups.insert(
|
backups.insert(
|
||||||
@ -170,8 +174,12 @@ impl MagiskCpio for Cpio {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
match action {
|
match action {
|
||||||
Action::Backup(name, entry) => {
|
Action::Backup(name, mut entry) => {
|
||||||
let backup = format!(".backup/{}", name);
|
let backup = if !skip_compress && entry.compress().is_ok() {
|
||||||
|
format!(".backup/{}.xz", name)
|
||||||
|
} else {
|
||||||
|
format!(".backup/{}", name)
|
||||||
|
};
|
||||||
eprintln!("Backup [{}] -> [{}]", name, backup);
|
eprintln!("Backup [{}] -> [{}]", name, backup);
|
||||||
backups.insert(backup, entry);
|
backups.insert(backup, entry);
|
||||||
}
|
}
|
||||||
|
@ -217,8 +217,24 @@ bool check_two_stage() {
|
|||||||
return init.contains("selinux_setup");
|
return init.contains("selinux_setup");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unxz_init(const char *init_xz, const char *init) {
|
||||||
|
LOGD("unxz %s -> %s\n", init_xz, init);
|
||||||
|
int fd = xopen(init, O_WRONLY | O_CREAT, 0777);
|
||||||
|
fd_channel ch(fd);
|
||||||
|
unxz(ch, mmap_data{init_xz});
|
||||||
|
close(fd);
|
||||||
|
clone_attr(init_xz, init);
|
||||||
|
unlink(init_xz);
|
||||||
|
}
|
||||||
|
|
||||||
const char *backup_init() {
|
const char *backup_init() {
|
||||||
if (access("/.backup/init.real", F_OK) == 0)
|
if (access("/.backup/init.real", F_OK) == 0)
|
||||||
return "/.backup/init.real";
|
return "/.backup/init.real";
|
||||||
|
if (access("/.backup/init.real.xz", F_OK) == 0) {
|
||||||
|
unxz_init("/.backup/init.real.xz", "/.backup/init.real");
|
||||||
|
return "/.backup/init.real";
|
||||||
|
}
|
||||||
|
if (access("/.backup/init.xz", F_OK) == 0)
|
||||||
|
unxz_init("/.backup/init.xz", "/.backup/init");
|
||||||
return "/.backup/init";
|
return "/.backup/init";
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user