From 3bf336df41aec0e19f4f309e592d55d85ce4b8f1 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Sun, 10 Jan 2016 16:29:47 +0000 Subject: [PATCH] Rework the dependency section and contemplate how to thread it all together a little more. --- volatility/cli/__init__.py | 3 +- .../framework/configuration/depresolver.py | 56 ++++++++++++++----- .../framework/interfaces/configuration.py | 8 +-- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/volatility/cli/__init__.py b/volatility/cli/__init__.py index 865b73d00..f56525be5 100644 --- a/volatility/cli/__init__.py +++ b/volatility/cli/__init__.py @@ -39,10 +39,11 @@ class CommandLine(object): # Determine the selected plugin # Resolve the dependencies on that plugin dldr = depresolver.DataLayerDependencyResolver() - dependencies = dldr.resolve_dependencies(plugin) + dependencies = dldr.build_tree(plugin) # TODO: write functions that determine all possible options/requirements for this plugin # (flatten the tree, treating disjunctions as conjunctions) + print(list(dependencies)) # TODO: Write functions that walk the tree and produce instances of each of the requirements diff --git a/volatility/framework/configuration/depresolver.py b/volatility/framework/configuration/depresolver.py index 8df842278..8ebc93d6e 100644 --- a/volatility/framework/configuration/depresolver.py +++ b/volatility/framework/configuration/depresolver.py @@ -34,7 +34,10 @@ class DataLayerDependencyResolver(validity.ValidityRoutines): satisfied = satisfied and (layer_class.metadata[k] == v) return satisfied - def resolve_dependencies(self, configurable): + def resolve_dependencies(self, deptree, context): + pass + + def build_tree(self, configurable, path = None): """Takes a configurable class and produces a priority ordered tree of possible solutions to satisfy the various requirements The return should include each of the potential nodes (and requirements, including optional ones) allowing the UI @@ -42,32 +45,57 @@ class DataLayerDependencyResolver(validity.ValidityRoutines): """ self._check_class(configurable, configuration.Configurable) - fulfillment = {} + if path is None: + path = [] + deptree = [] + deptree_names = set() for requirement in configurable.get_schema(): + + # Choose a name for the node/leaf + node_name = requirement.name + if node_name in deptree_names: + node_name += str(len([x for x in deptree_names if x.startswith(requirement.name)])) + node_path = path + [node_name] + # If the requirement is a layer/configurable if isinstance(requirement, framework.configuration.TranslationLayerRequirement): # Find all the different ways to fulfill it (recursively) # TODO: Ensure no cycles or loops - possibilities = Possibility() + branches = {} for potential_layer in self.layer_cache: if self.satisfies(potential_layer, requirement): - possibility = self.resolve_dependencies(potential_layer) + branch = self.build_tree(potential_layer, path = node_path) # Only add a possibility if there are suitable lower layers for it - if possibility: - possibilities[potential_layer] = possibility - fulfillment[requirement.name] = possibilities + if branch: + branches[potential_layer] = branch + deptree.append(Node(node_path, requirement = requirement, branches = branches)) else: # Add all base-type requirements # Add all optional base-type requirements in order - fulfillment[requirement.name] = requirement - return fulfillment - - def all_possible_requirements(self, deptree): + deptree.append(Leaf(node_path, requirement)) + return deptree +class Leaf(object): + def __init__(self, path, requirement = None): + self.requirement = requirement + self._path = path + + @property + def path(self): + return configuration.schema_name_join(self._path) + + def __repr__(self): + return "" -class Possibility(dict): - """Class to differentiate between different available options for completion of a requirement""" - pass +class Node(Leaf): + def __init__(self, path, requirement = None, branches = None): + Leaf.__init__(self, path, requirement) + self.branches = branches + if branches is None: + self.branches = {} + + def __repr__(self): + return "" diff --git a/volatility/framework/interfaces/configuration.py b/volatility/framework/interfaces/configuration.py index 0a82edd27..17c57ee55 100644 --- a/volatility/framework/interfaces/configuration.py +++ b/volatility/framework/interfaces/configuration.py @@ -76,16 +76,10 @@ class ConfigurationSchemaNode(validity.ValidityRoutines): """ -class Configurable(object, metaclass = ABCMeta): +class Configurable(object): """Class to allow objects to have requirements and populate the context config tree""" @classmethod - @abstractmethod def get_schema(cls): """Returns a list of configuration schema nodes for this object""" return [] - - def create_configuration(self, location, context): - """Pins the configuration schemas to a location within the context's config storage""" - for requirement in self.get_schema(): - pass