Skip to content

jffs2.py

ofrak.core.jffs2

Jffs2Filesystem (GenericBinary, FilesystemRoot) dataclass

Filesystem stored in a JFFS2 format.

Jffs2Packer (Packer)

Compresses and packages files into a JFFS2 (Journalling Flash File System 2) filesystem image with compression, inode structures, and directory entries. Use after modifying extracted JFFS2 contents to recreate firmware for embedded devices using NOR or NAND flash. The packer creates a valid JFFS2 image that can be directly flashed to devices.

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/jffs2.py
async def pack(self, resource: Resource, config=None):
    jffs2_view: Jffs2Filesystem = await resource.view_as(Jffs2Filesystem)
    temp_flush_dir = await jffs2_view.flush_to_disk()
    with tempfile.NamedTemporaryFile(suffix=".sqsh", mode="rb", delete_on_close=False) as temp:
        temp.close()
        cmd = [
            "mkfs.jffs2",
            "-r",
            temp_flush_dir,
            "-o",
            temp.name,
        ]
        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)

Jffs2Unpacker (Unpacker)

Extracts files and directories from JFFS2 (Journalling Flash File System 2) filesystems. Use when analyzing firmware from embedded devices using NOR or NAND flash memory.

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/jffs2.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 = [
                "jefferson",
                "--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)

            jffs2_view = await resource.view_as(Jffs2Filesystem)
            await jffs2_view.initialize_from_disk(temp_flush_dir)