mirror of
https://github.com/platomav/BIOSUtilities.git
synced 2025-05-09 13:52:00 -04:00
Updated Dell PFS/PKG Update Extractor v6.0_a12
Added support for Dell ThinOS PKG with multiple PFS
This commit is contained in:
parent
0e170334c6
commit
0c6c35b354
1 changed files with 50 additions and 16 deletions
|
@ -7,7 +7,7 @@ Dell PFS/PKG Update Extractor
|
|||
Copyright (C) 2018-2022 Plato Mavropoulos
|
||||
"""
|
||||
|
||||
TITLE = 'Dell PFS/PKG Update Extractor v6.0_a11'
|
||||
TITLE = 'Dell PFS/PKG Update Extractor v6.0_a12'
|
||||
|
||||
import os
|
||||
import io
|
||||
|
@ -21,7 +21,8 @@ import contextlib
|
|||
sys.dont_write_bytecode = True
|
||||
|
||||
from common.checksums import get_chk_8_xor
|
||||
from common.path_ops import make_dirs, path_stem, safe_name
|
||||
from common.comp_szip import is_szip_supported, szip_decompress
|
||||
from common.path_ops import del_dirs, get_path_files, make_dirs, path_name, path_parent, path_stem, safe_name
|
||||
from common.patterns import PAT_DELL_FTR, PAT_DELL_HDR, PAT_DELL_PKG
|
||||
from common.struct_ops import char, get_struct, uint8_t, uint16_t, uint32_t, uint64_t
|
||||
from common.system import argparse_init, printer, script_init
|
||||
|
@ -225,9 +226,12 @@ def is_dell_pfs(in_file):
|
|||
return bool(is_pkg or is_hdr and is_ftr)
|
||||
|
||||
# Extract Dell ThinOS PKG 7zXZ
|
||||
def thinos_pkg_extract(in_file):
|
||||
def thinos_pkg_extract(in_file, output_path):
|
||||
in_buffer = file_to_bytes(in_file)
|
||||
|
||||
# Initialize PFS results (Name: Buffer)
|
||||
pfs_results = {}
|
||||
|
||||
# Search input image for ThinOS PKG 7zXZ header
|
||||
thinos_pkg_match = PAT_DELL_PKG.search(in_buffer)
|
||||
|
||||
|
@ -238,9 +242,33 @@ def thinos_pkg_extract(in_file):
|
|||
|
||||
# Check if the compressed 7zXZ stream is complete
|
||||
if len(lzma_bin_dat) != lzma_len_int:
|
||||
return in_buffer
|
||||
return pfs_results
|
||||
|
||||
return lzma.decompress(lzma_bin_dat)
|
||||
working_path = os.path.join(output_path, 'THINOS_PKG_TEMP')
|
||||
|
||||
make_dirs(working_path, delete=True)
|
||||
|
||||
pkg_tar_path = os.path.join(working_path, 'THINOS_PKG.TAR')
|
||||
|
||||
with open(pkg_tar_path, 'wb') as pkg_payload:
|
||||
pkg_payload.write(lzma.decompress(lzma_bin_dat))
|
||||
|
||||
if is_szip_supported(pkg_tar_path, 0, args=['-tTAR'], check=True, silent=True):
|
||||
if szip_decompress(pkg_tar_path, working_path, 'TAR', 0, args=['-tTAR'], check=True, silent=True) == 0:
|
||||
os.remove(pkg_tar_path)
|
||||
else:
|
||||
return pfs_results
|
||||
else:
|
||||
return pfs_results
|
||||
|
||||
for pkg_file in get_path_files(working_path):
|
||||
if is_pfs_hdr(pkg_file):
|
||||
pfs_name = path_name(path_parent(pkg_file))
|
||||
pfs_results.update({pfs_name: file_to_bytes(pkg_file)})
|
||||
|
||||
del_dirs(working_path)
|
||||
|
||||
return pfs_results
|
||||
|
||||
# Get PFS ZLIB Section Offsets
|
||||
def get_section_offsets(buffer):
|
||||
|
@ -275,7 +303,7 @@ def pfs_section_parse(zlib_data, zlib_start, output_path, pfs_name, pfs_index, p
|
|||
section_name = {0xAA:'Firmware', 0xBB:'Utilities'}.get(section_type, f'Unknown ({section_type:02X})')
|
||||
|
||||
# Show extraction complete message for each main PFS ZLIB Section
|
||||
printer(f'Extracting Dell PFS {pfs_index} >{pfs_name} > {section_name}', padding)
|
||||
printer(f'Extracting Dell PFS {pfs_index} > {pfs_name} > {section_name}', padding)
|
||||
|
||||
# Set PFS ZLIB Section extraction sub-directory path
|
||||
section_path = os.path.join(output_path, safe_name(section_name))
|
||||
|
@ -565,10 +593,10 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, s
|
|||
# its PFS Information should contain their names (CombineBiosNameX). Since the main/first
|
||||
# full PFS structure has count/index 1, the rest start at 2+ and thus, their PFS Information
|
||||
# names can be retrieved in order by subtracting 2 from the main/first PFS Information values
|
||||
sub_pfs_name = f' {info_all[pfs_count - 2][1]} v{info_all[pfs_count - 2][2]}' if info_all else ' UNKNOWN'
|
||||
sub_pfs_name = f'{info_all[pfs_count - 2][1]} v{info_all[pfs_count - 2][2]}' if info_all else ' UNKNOWN'
|
||||
|
||||
# Set the sub-PFS output path (create sub-folders for each sub-PFS and its ZLIB sections)
|
||||
sub_pfs_path = os.path.join(output_path, str(pfs_count) + safe_name(sub_pfs_name))
|
||||
sub_pfs_path = os.path.join(output_path, f'{pfs_count} {safe_name(sub_pfs_name)}')
|
||||
|
||||
# Recursively call the PFS ZLIB Section Parser function for the sub-PFS Volume (pfs_index = pfs_count)
|
||||
pfs_section_parse(entry_data, offset, sub_pfs_path, sub_pfs_name, pfs_count, pfs_count, True, pfs_padd + 4, structure, advanced)
|
||||
|
@ -639,7 +667,7 @@ def pfs_extract(buffer, pfs_index, pfs_name, pfs_count, output_path, pfs_padd, s
|
|||
|
||||
# Write/Extract PFS Entry files
|
||||
for file in write_files:
|
||||
full_name = f'{pfs_index}{pfs_name} -- {file_index} {file_name} v{file_version}' # Full PFS Entry Name
|
||||
full_name = f'{pfs_index} {pfs_name} -- {file_index} {file_name} v{file_version}' # Full PFS Entry Name
|
||||
pfs_file_write(file[0], file[1], file_type, full_name, output_path, pfs_padd, structure, advanced)
|
||||
|
||||
# Get PFS Footer Data after PFS Header Payload
|
||||
|
@ -994,15 +1022,21 @@ if __name__ == '__main__':
|
|||
|
||||
extract_path = os.path.join(output_path, f'{input_name}_extracted')
|
||||
|
||||
extract_name = ' ' + path_stem(input_file)
|
||||
is_dell_pkg = is_pfs_pkg(input_buffer)
|
||||
|
||||
if is_pfs_pkg(input_buffer):
|
||||
input_buffer = thinos_pkg_extract(input_buffer)
|
||||
if is_dell_pkg:
|
||||
pfs_results = thinos_pkg_extract(input_buffer, extract_path)
|
||||
else:
|
||||
pfs_results = {path_stem(input_file): input_buffer}
|
||||
|
||||
# Parse each PFS ZLIB Section
|
||||
for zlib_offset in get_section_offsets(input_buffer):
|
||||
# Call the PFS ZLIB Section Parser function
|
||||
pfs_section_parse(input_buffer, zlib_offset, extract_path, extract_name, 1, 1, False, padding, structure, advanced)
|
||||
# Parse each Dell PFS image contained in the input file
|
||||
for pfs_index,(pfs_name,pfs_buffer) in enumerate(pfs_results.items(), start=1):
|
||||
# At ThinOS PKG packages, multiple PFS images may be included in separate model-named folders
|
||||
pfs_path = os.path.join(extract_path, f'{pfs_index} {pfs_name}') if is_dell_pkg else extract_path
|
||||
# Parse each PFS ZLIB section
|
||||
for zlib_offset in get_section_offsets(pfs_buffer):
|
||||
# Call the PFS ZLIB section parser function
|
||||
pfs_section_parse(pfs_buffer, zlib_offset, pfs_path, pfs_name, pfs_index, 1, False, padding, structure, advanced)
|
||||
|
||||
exit_code -= 1
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue