tar.py
ofrak_components.tar
TarArchive (GenericBinary, FilesystemRoot)
dataclass
Filesystem stored in a tar archive.
TarPacker (Packer)
Pack files into a tar archive.
pack(self, resource, config)
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 |
~CC |
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. |
required |
Source code in ofrak_components/tar.py
async def pack(self, resource: Resource, config: CC) -> None:
# Flush the child files to the filesystem
tar_view = await resource.view_as(TarArchive)
flush_dir = await tar_view.flush_to_disk()
# Pack it back into a temporary archive
with tempfile.NamedTemporaryFile(suffix=".tar") as temp_archive:
command = ["tar", "--xattrs", "-C", flush_dir, "-cf", temp_archive.name, "."]
subprocess.run(command, check=True, capture_output=True)
# Replace the original archive data
resource.queue_patch(Range(0, await resource.get_data_length()), temp_archive.read())
TarUnpacker (Unpacker)
Unpack a tar archive.
unpack(self, resource, config)
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 |
~CC |
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. |
required |
Source code in ofrak_components/tar.py
async def unpack(self, resource: Resource, config: CC) -> None:
# Write the archive data to a file
with tempfile.NamedTemporaryFile(suffix=".tar") as temp_archive:
temp_archive.write(await resource.get_data())
temp_archive.flush()
# Check the archive member files to ensure none unpack to a parent directory
command = ["tar", "-P", "-tf", temp_archive.name]
output = subprocess.run(command, check=True, capture_output=True)
for filename in output.stdout.decode().splitlines():
# Handles relative parent paths and rooted paths, and normalizes paths like "./../"
rel_filename = os.path.relpath(filename)
if rel_filename.startswith("../"):
raise UnpackerError(
f"Tar archive contains a file {filename} that would extract to a parent "
f"directory {rel_filename}."
)
# Unpack into a temporary directory using the temporary file
with tempfile.TemporaryDirectory() as temp_dir:
command = ["tar", "--xattrs", "-C", temp_dir, "-xf", temp_archive.name]
subprocess.run(command, check=True, capture_output=True)
# Initialize a filesystem from the unpacked/untarred temporary folder
tar_view = await resource.view_as(TarArchive)
await tar_view.initialize_from_disk(temp_dir)