add and leverage write_inode_content_to_stream

This commit is contained in:
Abyss Watcher
2025-01-19 15:13:26 +01:00
parent 8594106005
commit e8b44efc17
@@ -6,7 +6,7 @@ import math
import logging
import datetime
from dataclasses import dataclass, astuple
from typing import List, Set, Type, Iterable
from typing import List, Set, Type, Iterable, IO
from volatility3.framework.constants import architectures
from volatility3.framework import renderers, interfaces
@@ -452,31 +452,47 @@ class InodePages(plugins.PluginInterface):
vollog.error("The inode is not a regular file")
return None
# By using truncate/seek, provided the filesystem supports it, a sparse file will be
try:
with open_method(filename) as f:
InodePages.write_inode_content_to_stream(inode, f, vmlinux_layer)
except OSError as e:
vollog.error("Unable to write to file (%s): %s", filename, e)
@staticmethod
def write_inode_content_to_stream(
inode: interfaces.objects.ObjectInterface,
stream: IO,
vmlinux_layer: interfaces.layers.TranslationLayerInterface,
) -> None:
"""Extracts the inode's contents from the page cache and saves them to a stream
Args:
inode: The inode to dump
stream: A IO steam to write to, typically FileHandlerInterface or BytesIO
vmlinux_layer: The kernel layer to obtain the page size
"""
# By using truncate/seek, provided the filesystem supports it, and the
# stream is a File interface, a sparse file will be
# created, saving both disk space and I/O time.
# Additionally, using the page index will guarantee that each page is written at the
# appropriate file position.
try:
with open_method(filename) as f:
inode_size = inode.i_size
f.truncate(inode_size)
inode_size = inode.i_size
stream.truncate(inode_size)
for page_idx, page_content in inode.get_contents():
current_fp = page_idx * vmlinux_layer.page_size
max_length = inode_size - current_fp
page_bytes = page_content[:max_length]
if current_fp + len(page_bytes) > inode_size:
vollog.error(
"Page out of file bounds: inode 0x%x, inode size %d, page index %d",
inode.vol.offset,
inode_size,
page_idx,
)
f.seek(current_fp)
f.write(page_bytes)
except OSError as e:
vollog.error("Unable to write to file (%s): %s", filename, e)
for page_idx, page_content in inode.get_contents():
current_fp = page_idx * vmlinux_layer.page_size
max_length = inode_size - current_fp
page_bytes = page_content[:max_length]
if current_fp + len(page_bytes) > inode_size:
vollog.error(
"Page out of file bounds: inode 0x%x, inode size %d, page index %d",
inode.vol.offset,
inode_size,
page_idx,
)
stream.seek(current_fp)
stream.write(page_bytes)
def _generator(self):
vmlinux_module_name = self.config["kernel"]