diff --git a/src/formats/mstar.rs b/src/formats/mstar.rs index 16a7372..2357ca1 100644 --- a/src/formats/mstar.rs +++ b/src/formats/mstar.rs @@ -5,12 +5,12 @@ use lz4::block::decompress; use lzma_rs::lzma_decompress; use crate::common; -use crate::utils::lzop::{decompress_lzop}; +use crate::utils::lzop::{unlzop_to_file}; use crate::utils::sparse::{unsparse_to_file}; //change whether the "userdata" partition is skipped -// this is because the userdata partition is sometimes enourmous sizes like 27gb, and it will fail to allocate memory on most computers -// if you want to attempt to extract "userdata" you can enable the option +// this is because the userdata partition is sometimes enourmous sizes like 27gb, and it is empty anyways +// if you want to extract "userdata" you can disable the option static CONFIG_SKIP_USERDATA: bool = true; pub fn is_mstar_file(file: &File) -> bool { @@ -76,125 +76,116 @@ pub fn extract_mstar(file: &File, output_folder: &str) -> Result<(), Box = script_string.lines().map(|l| l.trim()).collect(); let mut i = 0; - while i < lines.len() { - let line = lines[i]; - + for line in &lines { if line.starts_with("filepartload") { let parts: Vec<&str> = line.split_whitespace().collect(); + let offset = parse_number(parts[3]).unwrap_or(0); + let size = parse_number(parts[4]).unwrap_or(0); - if parts.len() >= 5 { - let offset = parse_number(parts[3]).unwrap_or(0); - let size = parse_number(parts[4]).unwrap_or(0); - - //try to get partname from comment - //let mut partname = if let Some(idx) = line.find('#') { - // line[idx + 1..].trim() - //} else { - // "unknown" - //}; - let mut partname = "unknown"; - - let mut compression = "none"; - let mut lz4_expect_size = 0; - let mut j = i + 1; + //try to get partname from comment + //let mut partname = if let Some(idx) = line.find('#') { + // line[idx + 1..].trim() + //} else { + // "unknown" + //}; + let mut partname = "unknown"; + let mut compression = "none"; + let mut lz4_expect_size = 0; + let mut j = i + 1; - // get lines after this filepartload, before the next one - while j < lines.len() && !lines[j].starts_with("filepartload") { - //get compression method - if lines[j].starts_with("mscompress7"){ - if compression == "none" { - compression = "lzma"; - } else if compression == "lzma" { - //thank the turks - compression = "double_lzma"; - } + // get lines after this filepartload, before the next one + while j < lines.len() && !lines[j].starts_with("filepartload") { + //get compression method + if lines[j].starts_with("mscompress7"){ + if compression == "none" { + compression = "lzma"; + } else if compression == "lzma" { + //thank the turks + compression = "double_lzma"; } - if lines[j].starts_with("lz4"){ - compression = "lz4"; - let parts: Vec<&str> = lines[j].split_whitespace().collect(); - lz4_expect_size = parse_number(parts[5]).unwrap_or(0); + } + if lines[j].starts_with("lz4"){ + compression = "lz4"; + let parts: Vec<&str> = lines[j].split_whitespace().collect(); + lz4_expect_size = parse_number(parts[5]).unwrap_or(0); + } + if lines[j].starts_with("mmc unlzo"){ + compression = "lzo"; + let parts: Vec<&str> = lines[j].split_whitespace().collect(); + // get part name from mmc unlzo + if partname == "unknown" { + partname = parts[4] } - if lines[j].starts_with("mmc unlzo"){ - compression = "lzo"; - let parts: Vec<&str> = lines[j].split_whitespace().collect(); - // get part name from mmc unlzo - if partname == "unknown" { - partname = parts[4] - } + } + if lines[j].starts_with("sparse_write"){ + compression = "sparse"; //its not really compression but anyway + let parts: Vec<&str> = lines[j].split_whitespace().collect(); + // get part name from sparse_write + if partname == "unknown" { + partname = parts[3] } - if lines[j].starts_with("sparse_write"){ - compression = "sparse"; //its not really compression but anyway - let parts: Vec<&str> = lines[j].split_whitespace().collect(); - // get part name from sparse_write - if partname == "unknown" { - partname = parts[3] - } - } - - // check if its boot partition - if lines[j].starts_with("mmc write.boot") { - if partname == "unknown" { - partname = "_mmc_boot" - } - } - - // try to get partname from nand/mmc/ubi writes - if lines[j].starts_with("mmc write") | lines[j].starts_with("nand write") | lines[j].starts_with("ubi write"){ - let parts: Vec<&str> = lines[j].split_whitespace().collect(); - if partname == "unknown" { - partname = parts[3] - } - } - - j += 1; } - println!("\nPart - Offset: {}, Size: {} --> {}", offset, size, partname); - - if partname == "unknown" { - println!("- Unknown destination, skipping!"); - } else if partname == "userdata" && CONFIG_SKIP_USERDATA { - println!("- Skipping userdata according to config!") - } else { - let data = common::read_file(&file, offset, size.try_into().unwrap())?; - let out_data; - let output_path = Path::new(&output_folder).join(format!("{}.bin", partname)); - - if compression == "lzma" { - println!("- Decompressing LZMA..."); - out_data = decompress_lzma(&data)?; - } else if compression == "double_lzma" { - println!("- Decompressing LZMA (Pass 1)..."); - let pass_1 = decompress_lzma(&data)?; - println!("- Decompressing LZMA (Pass 2)..."); - out_data = decompress_lzma(&pass_1)?; - } else if compression == "lz4" { - println!("- Decompressing lz4, expected size: {}", lz4_expect_size); - out_data = decompress_lz4(&data, lz4_expect_size.try_into().unwrap())?; - } else if compression == "lzo" { - println!("- Decompessing LZO.."); - out_data = decompress_lzop(&data)?; - } else if compression == "sparse" { - println!("- Unsparsing..."); - unsparse_to_file(&data, output_path)?; - println!("-- Saved file!"); - i += 1; - continue - //out_data = unsparse(&data)?; - } else { - out_data = data; + // check if its boot partition + if lines[j].starts_with("mmc write.boot") { + if partname == "unknown" { + partname = "_mmc_boot" } + } - fs::create_dir_all(&output_folder)?; - let mut out_file = OpenOptions::new() - .append(true) - .create(true) - .open(output_path)?; + // try to get partname from nand/mmc/ubi writes + if lines[j].starts_with("mmc write") | lines[j].starts_with("nand write") | lines[j].starts_with("ubi write"){ + let parts: Vec<&str> = lines[j].split_whitespace().collect(); + if partname == "unknown" { + partname = parts[3] + } + } + + j += 1; + } - out_file.write_all(&out_data)?; + println!("\nPart - Offset: {}, Size: {} --> {}", offset, size, partname); + if partname == "unknown" { + println!("- Unknown destination, skipping!"); + } else if partname == "userdata" && CONFIG_SKIP_USERDATA { + println!("- Skipping userdata according to config!") + } else { + let data = common::read_file(&file, offset, size.try_into().unwrap())?; + let out_data; + let output_path = Path::new(&output_folder).join(format!("{}.bin", partname)); + + if compression == "lzma" { + println!("- Decompressing LZMA..."); + out_data = decompress_lzma(&data)?; + } else if compression == "double_lzma" { + println!("- Decompressing LZMA (Pass 1)..."); + let pass_1 = decompress_lzma(&data)?; + println!("- Decompressing LZMA (Pass 2)..."); + out_data = decompress_lzma(&pass_1)?; + } else if compression == "lz4" { + println!("- Decompressing lz4, expected size: {}", lz4_expect_size); + out_data = decompress_lz4(&data, lz4_expect_size.try_into().unwrap())?; + } else if compression == "lzo" { + println!("- Decompessing LZO.."); + unlzop_to_file(&data, output_path)?; println!("-- Saved file!"); - } + i += 1; + continue + } else if compression == "sparse" { + println!("- Unsparsing..."); + unsparse_to_file(&data, output_path)?; + println!("-- Saved file!"); + i += 1; + continue + } else { + out_data = data; + } + + fs::create_dir_all(&output_folder)?; + let mut out_file = OpenOptions::new().append(true).create(true).open(output_path)?; + out_file.write_all(&out_data)?; + println!("-- Saved file!"); } } diff --git a/src/utils/lzop.rs b/src/utils/lzop.rs index 738237b..7ab9c20 100644 --- a/src/utils/lzop.rs +++ b/src/utils/lzop.rs @@ -1,5 +1,7 @@ use binrw::{BinRead, BinReaderExt}; -use std::io::{Cursor}; +use std::fs::OpenOptions; +use std::path::{PathBuf}; +use std::io::{Cursor, Write}; use simd_adler32::adler32; use crate::common; @@ -28,7 +30,7 @@ struct SegmentHeader { checksum: u32, } -pub fn decompress_lzop(data: &[u8]) -> Result, Box> { +pub fn unlzop_to_file(data: &[u8], file_path: PathBuf) -> Result<(), Box> { let mut data_reader = Cursor::new(data); let header: LzopHeader = data_reader.read_be()?; if header.magic_bytes != b"\x89LZO\x00\x0D\x0A\x1A\x0A" { @@ -39,7 +41,7 @@ pub fn decompress_lzop(data: &[u8]) -> Result, Box Result, Box