squashfs.py
ofrak.core.squashfs
SquashfsFilesystem (GenericBinary, FilesystemRoot)
dataclass
Filesystem stored in a squashfs format.
SquashfsPacker (Packer)
Compresses and packages files into a SquashFS compressed read-only filesystem. Use after modifying extracted SquashFS contents to recreate firmware images or compressed root filesystems. The packer preserves Unix permissions, ownership, symbolic links, device nodes, and applies compression to blocks for optimal size.
pack(self, resource, config=None)
async
Pack the given resource.
Users should not call this method directly; rather, they should run Resource.run or Resource.pack.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource |
Resource |
required | |
config |
Optional config for packing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run. |
None |
Source code in ofrak/core/squashfs.py
async def pack(self, resource: Resource, config=None):
squashfs_view: SquashfsFilesystem = await resource.view_as(SquashfsFilesystem)
temp_flush_dir = await squashfs_view.flush_to_disk()
with tempfile.NamedTemporaryFile(suffix=".sqsh", mode="rb", delete_on_close=False) as temp:
temp.close()
cmd = [
"mksquashfs",
temp_flush_dir,
temp.name,
"-noappend",
]
proc = await asyncio.create_subprocess_exec(
*cmd,
)
returncode = await proc.wait()
if proc.returncode:
raise CalledProcessError(returncode=returncode, cmd=cmd)
with open(temp.name, "rb") as new_fh:
new_data = new_fh.read()
# Passing in the original range effectively replaces the original data with the new data
resource.queue_patch(Range(0, await resource.get_data_length()), new_data)
SquashfsUnpacker (Unpacker)
Extracts files and directories from SquashFS compressed read-only filesystems, which are heavily used in embedded Linux systems and Live CD distributions. SquashFS is the standard format for read-only root filesystems in router firmware, embedded devices, and Linux distribution installers. Use when analyzing firmware or examining compressed Linux filesystems. The unpacker preserves file permissions, ownership, symbolic links, and special files.
unpack(self, resource, config=None)
async
Unpack the given resource.
Users should not call this method directly; rather, they should run Resource.run or Resource.unpack.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource |
Resource |
The resource that is being unpacked |
required |
config |
Optional config for unpacking. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run. |
None |
Source code in ofrak/core/squashfs.py
async def unpack(self, resource: Resource, config=None):
async with resource.temp_to_disk() as temp_path:
with tempfile.TemporaryDirectory() as temp_flush_dir:
cmd = [
"unsquashfs",
"-no-exit-code",
"-force",
"-dest",
temp_flush_dir,
temp_path,
]
proc = await asyncio.create_subprocess_exec(
*cmd,
)
returncode = await proc.wait()
if proc.returncode:
raise CalledProcessError(returncode=returncode, cmd=cmd)
squashfs_view = await resource.view_as(SquashfsFilesystem)
await squashfs_view.initialize_from_disk(temp_flush_dir)
_UnsquashfsV45Tool (ComponentExternalTool)
private
__init__(self)
special
Initialize self. See help(type(self)) for accurate signature.
Source code in ofrak/core/squashfs.py
def __init__(self):
super().__init__("unsquashfs", "https://github.com/plougher/squashfs-tools", "")
is_tool_installed(self)
async
Check if a tool is installed by running it with the install_check_arg.
This method runs <tool> <install_check_arg>.
Returns:
| Type | Description |
|---|---|
bool |
True if the |
Source code in ofrak/core/squashfs.py
async def is_tool_installed(self) -> bool:
try:
cmd = ["unsquashfs", "-help"]
proc = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.DEVNULL,
)
stdout, stderr = await proc.communicate()
except FileNotFoundError:
return False
if 0 != proc.returncode:
return False
if b"-no-exit" not in stdout:
# Version 4.5+ has the required -no-exit option
return False
return True