mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-08-22 14:32:21 +02:00
These will not be returned as part of the subclasses of their descendents when listed using the classes_subclasses function. They can be inherited from and their descendents will be listed unless they also specify the hidden property and mark it as True (ideally, using the class decorator hide_from_subclasses).
108 lines
4.2 KiB
Python
108 lines
4.2 KiB
Python
"""Volatility 3 framework"""
|
|
import inspect
|
|
import logging
|
|
import os
|
|
import sys
|
|
|
|
# ##
|
|
#
|
|
# Libtool version scheme
|
|
#
|
|
# Current - The number of the current interface exported by the library
|
|
# Revision - The implementation number of the most recent interface exported by this library
|
|
# Age - The number of previous additional interfaces supported by this library
|
|
#
|
|
# 1. If the source changes, increment the revision
|
|
# 2. If the interface has changed, increment current, set revision to 0
|
|
# 3. If only additions to the interface have been made, increment age
|
|
# 4. If changes or removals of the interface have been made, set age to 0
|
|
|
|
# We use the libtool library versioning
|
|
|
|
CURRENT = 0 # Number of releases of the library with any change
|
|
REVISION = 0 # Number of changes that don't affect the interface
|
|
AGE = 0 # Number of consecutive versions of the interface the current version supports
|
|
|
|
|
|
def interface_version():
|
|
"""Provides the so version number of the library"""
|
|
return CURRENT - AGE, AGE, REVISION
|
|
|
|
|
|
vollog = logging.getLogger(__name__)
|
|
|
|
|
|
def require_interface_version(*args):
|
|
"""Checks the required version of a plugin"""
|
|
if len(args):
|
|
if args[0] != interface_version()[0]:
|
|
raise RuntimeError(
|
|
"Framework interface version {} is incompatible with required version {}".format(interface_version()[0],
|
|
args[0]))
|
|
if len(args) > 1:
|
|
if args[1] > interface_version()[1]:
|
|
raise RuntimeError(
|
|
"Framework interface version {} is an older revision than the required version {}".format(
|
|
".".join([str(x) for x in interface_version()[0:1]]),
|
|
".".join([str(x) for x in args[0:2]])))
|
|
|
|
|
|
class noninheritable(object):
|
|
def __init__(self, f, cls):
|
|
self.f = f
|
|
self.cls = cls
|
|
|
|
def __get__(self, obj, type = None):
|
|
if type == self.cls:
|
|
if hasattr(self.f, '__get__'):
|
|
return self.f.__get__(obj, type)
|
|
return self.f
|
|
raise AttributeError
|
|
|
|
|
|
def hide_from_subclasses(cls):
|
|
cls.hidden = noninheritable(True, cls)
|
|
return cls
|
|
|
|
|
|
def class_subclasses(cls):
|
|
"""Returns all the (recursive) subclasses of a given class"""
|
|
if not inspect.isclass(cls):
|
|
raise TypeError("class_subclasses parameter not a valid class: {}".format(cls))
|
|
for clazz in cls.__subclasses__():
|
|
if not hasattr(clazz, 'hidden') or not clazz.hidden:
|
|
yield clazz
|
|
for return_value in class_subclasses(clazz):
|
|
yield return_value
|
|
|
|
|
|
def import_files(base_module):
|
|
"""Imports all plugins present under plugins path"""
|
|
if not isinstance(base_module.__path__, list):
|
|
raise TypeError("[base_module].__path__ must be a list of paths")
|
|
for path in base_module.__path__:
|
|
for root, _, files in os.walk(path, followlinks = True):
|
|
# TODO: Figure out how to import pycache files
|
|
if root.endswith("__pycache__"):
|
|
continue
|
|
for f in files:
|
|
if (f.endswith(".py") or f.endswith(".pyc") or f.endswith(".pyo")) and not f.startswith("__"):
|
|
modpath = os.path.join(root[len(path) + len(os.path.sep):], f[:f.rfind(".")])
|
|
module = modpath.replace(os.path.sep, ".")
|
|
if module not in sys.modules:
|
|
try:
|
|
vollog.debug("Importing module: {}.{}".format(base_module.__name__, module))
|
|
__import__(base_module.__name__ + "." + module)
|
|
except ImportError as e:
|
|
vollog.debug(str(e))
|
|
vollog.warning("Failed to import module {} based on file: {}".format(module, modpath))
|
|
raise
|
|
else:
|
|
vollog.info("Skipping existing module: {}".format(module))
|
|
|
|
|
|
# Check the python version to ensure it's suitable
|
|
required_python_version = (3, 4)
|
|
if sys.version_info.major != required_python_version[0] or sys.version_info.minor < required_python_version[1]:
|
|
raise RuntimeError("Volatility framework requires python version {}.{} or greater".format(*required_python_version))
|