From f2a748b7ebf0b57364f16064dd4b943d13085d6c Mon Sep 17 00:00:00 2001 From: gutosie Date: Tue, 9 Feb 2021 12:22:29 +0200 Subject: [PATCH] Add files via upload --- NeoBoot/ubi_reader_arm/argparse_neo.py | 1506 +++++++++++++++++ NeoBoot/ubi_reader_arm/ubi/__init__.py | 139 ++ NeoBoot/ubi_reader_arm/ubi/__init__.pyo | Bin 0 -> 6002 bytes NeoBoot/ubi_reader_arm/ubi/block/__init__.py | 59 + NeoBoot/ubi_reader_arm/ubi/block/__init__.pyo | Bin 0 -> 3042 bytes NeoBoot/ubi_reader_arm/ubi/block/layout.py | 23 + NeoBoot/ubi_reader_arm/ubi/block/sort.py | 84 + NeoBoot/ubi_reader_arm/ubi/defines.py | 63 + NeoBoot/ubi_reader_arm/ubi/display.py | 108 ++ .../ubi_reader_arm/ubi/headers/__init__.py | 89 + .../ubi_reader_arm/ubi/headers/__init__.pyo | Bin 0 -> 4676 bytes NeoBoot/ubi_reader_arm/ubi/headers/errors.py | 28 + NeoBoot/ubi_reader_arm/ubi/image.py | 38 + NeoBoot/ubi_reader_arm/ubi/volume/__init__.py | 67 + .../ubi_reader_arm/ubi/volume/__init__.pyo | Bin 0 -> 3590 bytes NeoBoot/ubi_reader_arm/ubi_extract_files.py | 65 + NeoBoot/ubi_reader_arm/ubi_io/__init__.py | 116 ++ NeoBoot/ubi_reader_arm/ubi_io/__init__.pyo | Bin 0 -> 5903 bytes NeoBoot/ubi_reader_arm/ubifs/__init__.py | 76 + NeoBoot/ubi_reader_arm/ubifs/__init__.pyo | Bin 0 -> 3374 bytes NeoBoot/ubi_reader_arm/ubifs/defines.py | 221 +++ NeoBoot/ubi_reader_arm/ubifs/log.py | 33 + NeoBoot/ubi_reader_arm/ubifs/lzo.so | Bin 0 -> 11560 bytes NeoBoot/ubi_reader_arm/ubifs/misc.py | 46 + .../ubi_reader_arm/ubifs/nodes/__init__.py | 151 ++ .../ubi_reader_arm/ubifs/nodes/__init__.pyo | Bin 0 -> 8985 bytes NeoBoot/ubi_reader_arm/ubifs/nodes/extract.py | 48 + NeoBoot/ubi_reader_arm/ubifs/output.py | 114 ++ NeoBoot/ubi_reader_arm/ubifs/walk.py | 33 + NeoBoot/ubi_reader_arm/ui/__init__.pyo | Bin 0 -> 163 bytes NeoBoot/ubi_reader_arm/ui/common.py | 88 + NeoBoot/ubi_reader_mips/ubi/__init__.py | 139 ++ NeoBoot/ubi_reader_mips/ubi/__init__.pyo | Bin 0 -> 6092 bytes NeoBoot/ubi_reader_mips/ubi/block/__init__.py | 59 + .../ubi_reader_mips/ubi/block/__init__.pyo | Bin 0 -> 3082 bytes NeoBoot/ubi_reader_mips/ubi/block/layout.py | 23 + NeoBoot/ubi_reader_mips/ubi/block/sort.py | 84 + NeoBoot/ubi_reader_mips/ubi/defines.py | 63 + NeoBoot/ubi_reader_mips/ubi/display.py | 108 ++ .../ubi_reader_mips/ubi/headers/__init__.py | 89 + .../ubi_reader_mips/ubi/headers/__init__.pyo | Bin 0 -> 4756 bytes NeoBoot/ubi_reader_mips/ubi/headers/errors.py | 28 + NeoBoot/ubi_reader_mips/ubi/image.py | 38 + .../ubi_reader_mips/ubi/volume/__init__.py | 67 + .../ubi_reader_mips/ubi/volume/__init__.pyo | Bin 0 -> 3655 bytes NeoBoot/ubi_reader_mips/ubi_extract_files.py | 64 + NeoBoot/ubi_reader_mips/ubi_io/__init__.py | 116 ++ NeoBoot/ubi_reader_mips/ubi_io/__init__.pyo | Bin 0 -> 5903 bytes NeoBoot/ubi_reader_mips/ubifs/__init__.py | 76 + NeoBoot/ubi_reader_mips/ubifs/__init__.pyo | Bin 0 -> 3424 bytes NeoBoot/ubi_reader_mips/ubifs/defines.py | 221 +++ NeoBoot/ubi_reader_mips/ubifs/log.py | 33 + NeoBoot/ubi_reader_mips/ubifs/lzo.so | Bin 0 -> 11560 bytes NeoBoot/ubi_reader_mips/ubifs/misc.py | 46 + .../ubi_reader_mips/ubifs/nodes/__init__.py | 151 ++ .../ubi_reader_mips/ubifs/nodes/__init__.pyo | Bin 0 -> 9150 bytes .../ubi_reader_mips/ubifs/nodes/extract.py | 48 + NeoBoot/ubi_reader_mips/ubifs/output.py | 114 ++ NeoBoot/ubi_reader_mips/ubifs/walk.py | 33 + NeoBoot/ubi_reader_mips/ui/__init__.py | 1 + NeoBoot/ubi_reader_mips/ui/__init__.pyo | Bin 0 -> 163 bytes NeoBoot/ubi_reader_mips/ui/common.py | 88 + 62 files changed, 4884 insertions(+) create mode 100644 NeoBoot/ubi_reader_arm/argparse_neo.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/__init__.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/__init__.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubi/block/__init__.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/block/__init__.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubi/block/layout.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/block/sort.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/defines.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/display.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/headers/__init__.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/headers/__init__.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubi/headers/errors.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/image.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/volume/__init__.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/volume/__init__.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubi_extract_files.py create mode 100644 NeoBoot/ubi_reader_arm/ubi_io/__init__.py create mode 100644 NeoBoot/ubi_reader_arm/ubi_io/__init__.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubifs/__init__.py create mode 100644 NeoBoot/ubi_reader_arm/ubifs/__init__.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubifs/defines.py create mode 100644 NeoBoot/ubi_reader_arm/ubifs/log.py create mode 100644 NeoBoot/ubi_reader_arm/ubifs/lzo.so create mode 100644 NeoBoot/ubi_reader_arm/ubifs/misc.py create mode 100644 NeoBoot/ubi_reader_arm/ubifs/nodes/__init__.py create mode 100644 NeoBoot/ubi_reader_arm/ubifs/nodes/__init__.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubifs/nodes/extract.py create mode 100644 NeoBoot/ubi_reader_arm/ubifs/output.py create mode 100644 NeoBoot/ubi_reader_arm/ubifs/walk.py create mode 100644 NeoBoot/ubi_reader_arm/ui/__init__.pyo create mode 100644 NeoBoot/ubi_reader_arm/ui/common.py create mode 100644 NeoBoot/ubi_reader_mips/ubi/__init__.py create mode 100644 NeoBoot/ubi_reader_mips/ubi/__init__.pyo create mode 100644 NeoBoot/ubi_reader_mips/ubi/block/__init__.py create mode 100644 NeoBoot/ubi_reader_mips/ubi/block/__init__.pyo create mode 100644 NeoBoot/ubi_reader_mips/ubi/block/layout.py create mode 100644 NeoBoot/ubi_reader_mips/ubi/block/sort.py create mode 100644 NeoBoot/ubi_reader_mips/ubi/defines.py create mode 100644 NeoBoot/ubi_reader_mips/ubi/display.py create mode 100644 NeoBoot/ubi_reader_mips/ubi/headers/__init__.py create mode 100644 NeoBoot/ubi_reader_mips/ubi/headers/__init__.pyo create mode 100644 NeoBoot/ubi_reader_mips/ubi/headers/errors.py create mode 100644 NeoBoot/ubi_reader_mips/ubi/image.py create mode 100644 NeoBoot/ubi_reader_mips/ubi/volume/__init__.py create mode 100644 NeoBoot/ubi_reader_mips/ubi/volume/__init__.pyo create mode 100644 NeoBoot/ubi_reader_mips/ubi_extract_files.py create mode 100644 NeoBoot/ubi_reader_mips/ubi_io/__init__.py create mode 100644 NeoBoot/ubi_reader_mips/ubi_io/__init__.pyo create mode 100644 NeoBoot/ubi_reader_mips/ubifs/__init__.py create mode 100644 NeoBoot/ubi_reader_mips/ubifs/__init__.pyo create mode 100644 NeoBoot/ubi_reader_mips/ubifs/defines.py create mode 100644 NeoBoot/ubi_reader_mips/ubifs/log.py create mode 100644 NeoBoot/ubi_reader_mips/ubifs/lzo.so create mode 100644 NeoBoot/ubi_reader_mips/ubifs/misc.py create mode 100644 NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.py create mode 100644 NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.pyo create mode 100644 NeoBoot/ubi_reader_mips/ubifs/nodes/extract.py create mode 100644 NeoBoot/ubi_reader_mips/ubifs/output.py create mode 100644 NeoBoot/ubi_reader_mips/ubifs/walk.py create mode 100644 NeoBoot/ubi_reader_mips/ui/__init__.py create mode 100644 NeoBoot/ubi_reader_mips/ui/__init__.pyo create mode 100644 NeoBoot/ubi_reader_mips/ui/common.py diff --git a/NeoBoot/ubi_reader_arm/argparse_neo.py b/NeoBoot/ubi_reader_arm/argparse_neo.py new file mode 100644 index 0000000..43ee10a --- /dev/null +++ b/NeoBoot/ubi_reader_arm/argparse_neo.py @@ -0,0 +1,1506 @@ + +__version__ = '1.1' +__all__ = ['ArgumentParser', + 'ArgumentError', + 'ArgumentTypeError', + 'FileType', + 'HelpFormatter', + 'ArgumentDefaultsHelpFormatter', + 'RawDescriptionHelpFormatter', + 'RawTextHelpFormatter', + 'Namespace', + 'Action', + 'ONE_OR_MORE', + 'OPTIONAL', + 'PARSER', + 'REMAINDER', + 'SUPPRESS', + 'ZERO_OR_MORE'] +import collections as _collections +import copy as _copy +import os as _os +import re as _re +import sys as _sys +import textwrap as _textwrap +from gettext import gettext as _ + +def _callable(obj): + return hasattr(obj, '__call__') or hasattr(obj, '__bases__') + + +SUPPRESS = '==SUPPRESS==' +OPTIONAL = '?' +ZERO_OR_MORE = '*' +ONE_OR_MORE = '+' +PARSER = 'A...' +REMAINDER = '...' +_UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args' + +class _AttributeHolder(object): + + def __repr__(self): + type_name = type(self).__name__ + arg_strings = [] + for arg in self._get_args(): + arg_strings.append(repr(arg)) + + for name, value in self._get_kwargs(): + arg_strings.append('%s=%r' % (name, value)) + + return '%s(%s)' % (type_name, ', '.join(arg_strings)) + + def _get_kwargs(self): + return sorted(self.__dict__.items()) + + def _get_args(self): + return [] + + +def _ensure_value(namespace, name, value): + if getattr(namespace, name, None) is None: + setattr(namespace, name, value) + return getattr(namespace, name) + + +class HelpFormatter(object): + + def __init__(self, prog, indent_increment = 2, max_help_position = 24, width = None): + if width is None: + try: + width = int(_os.environ['COLUMNS']) + except (KeyError, ValueError): + width = 80 + + width -= 2 + self._prog = prog + self._indent_increment = indent_increment + self._max_help_position = max_help_position + self._width = width + self._current_indent = 0 + self._level = 0 + self._action_max_length = 0 + self._root_section = self._Section(self, None) + self._current_section = self._root_section + self._whitespace_matcher = _re.compile('\\s+') + self._long_break_matcher = _re.compile('\\n\\n\\n+') + return + + def _indent(self): + self._current_indent += self._indent_increment + self._level += 1 + + def _dedent(self): + self._current_indent -= self._indent_increment + self._level -= 1 + + class _Section(object): + + def __init__(self, formatter, parent, heading = None): + self.formatter = formatter + self.parent = parent + self.heading = heading + self.items = [] + + def format_help(self): + if self.parent is not None: + self.formatter._indent() + join = self.formatter._join_parts + for func, args in self.items: + func(*args) + + item_help = join([ func(*args) for func, args in self.items ]) + if self.parent is not None: + self.formatter._dedent() + if not item_help: + return '' + else: + if self.heading is not SUPPRESS and self.heading is not None: + current_indent = self.formatter._current_indent + heading = '%*s%s:\n' % (current_indent, '', self.heading) + else: + heading = '' + return join(['\n', + heading, + item_help, + '\n']) + return + + def _add_item(self, func, args): + self._current_section.items.append((func, args)) + + def start_section(self, heading): + self._indent() + section = self._Section(self, self._current_section, heading) + self._add_item(section.format_help, []) + self._current_section = section + + def end_section(self): + self._current_section = self._current_section.parent + self._dedent() + + def add_text(self, text): + if text is not SUPPRESS and text is not None: + self._add_item(self._format_text, [text]) + return + + def add_usage(self, usage, actions, groups, prefix = None): + if usage is not SUPPRESS: + args = (usage, + actions, + groups, + prefix) + self._add_item(self._format_usage, args) + + def add_argument(self, action): + if action.help is not SUPPRESS: + get_invocation = self._format_action_invocation + invocations = [get_invocation(action)] + for subaction in self._iter_indented_subactions(action): + invocations.append(get_invocation(subaction)) + + invocation_length = max([ len(s) for s in invocations ]) + action_length = invocation_length + self._current_indent + self._action_max_length = max(self._action_max_length, action_length) + self._add_item(self._format_action, [action]) + + def add_arguments(self, actions): + for action in actions: + self.add_argument(action) + + def format_help(self): + help = self._root_section.format_help() + if help: + help = self._long_break_matcher.sub('\n\n', help) + help = help.strip('\n') + '\n' + return help + + def _join_parts(self, part_strings): + return ''.join([ part for part in part_strings if part and part is not SUPPRESS ]) + + def _format_usage(self, usage, actions, groups, prefix): + if prefix is None: + prefix = _('usage: ') + if usage is not None: + usage = usage % dict(prog=self._prog) + elif usage is None and not actions: + usage = '%(prog)s' % dict(prog=self._prog) + elif usage is None: + prog = '%(prog)s' % dict(prog=self._prog) + optionals = [] + positionals = [] + for action in actions: + if action.option_strings: + optionals.append(action) + else: + positionals.append(action) + + format = self._format_actions_usage + action_usage = format(optionals + positionals, groups) + usage = ' '.join([ s for s in [prog, action_usage] if s ]) + text_width = self._width - self._current_indent + if len(prefix) + len(usage) > text_width: + part_regexp = '\\(.*?\\)+|\\[.*?\\]+|\\S+' + opt_usage = format(optionals, groups) + pos_usage = format(positionals, groups) + opt_parts = _re.findall(part_regexp, opt_usage) + pos_parts = _re.findall(part_regexp, pos_usage) + + def get_lines(parts, indent, prefix = None): + lines = [] + line = [] + if prefix is not None: + line_len = len(prefix) - 1 + else: + line_len = len(indent) - 1 + for part in parts: + if line_len + 1 + len(part) > text_width: + lines.append(indent + ' '.join(line)) + line = [] + line_len = len(indent) - 1 + line.append(part) + line_len += len(part) + 1 + + if line: + lines.append(indent + ' '.join(line)) + if prefix is not None: + lines[0] = lines[0][len(indent):] + return lines + + if len(prefix) + len(prog) <= 0.75 * text_width: + indent = ' ' * (len(prefix) + len(prog) + 1) + if opt_parts: + lines = get_lines([prog] + opt_parts, indent, prefix) + lines.extend(get_lines(pos_parts, indent)) + elif pos_parts: + lines = get_lines([prog] + pos_parts, indent, prefix) + else: + lines = [prog] + else: + indent = ' ' * len(prefix) + parts = opt_parts + pos_parts + lines = get_lines(parts, indent) + if len(lines) > 1: + lines = [] + lines.extend(get_lines(opt_parts, indent)) + lines.extend(get_lines(pos_parts, indent)) + lines = [prog] + lines + usage = '\n'.join(lines) + return '%s%s\n\n' % (prefix, usage) + + def _format_actions_usage(self, actions, groups): + group_actions = set() + inserts = {} + for group in groups: + try: + start = actions.index(group._group_actions[0]) + except ValueError: + continue + else: + end = start + len(group._group_actions) + if actions[start:end] == group._group_actions: + for action in group._group_actions: + group_actions.add(action) + + if not group.required: + if start in inserts: + inserts[start] += ' [' + else: + inserts[start] = '[' + inserts[end] = ']' + else: + if start in inserts: + inserts[start] += ' (' + else: + inserts[start] = '(' + inserts[end] = ')' + for i in range(start + 1, end): + inserts[i] = '|' + + parts = [] + for i, action in enumerate(actions): + if action.help is SUPPRESS: + parts.append(None) + if inserts.get(i) == '|': + inserts.pop(i) + elif inserts.get(i + 1) == '|': + inserts.pop(i + 1) + elif not action.option_strings: + part = self._format_args(action, action.dest) + if action in group_actions: + if part[0] == '[' and part[-1] == ']': + part = part[1:-1] + parts.append(part) + else: + option_string = action.option_strings[0] + if action.nargs == 0: + part = '%s' % option_string + else: + default = action.dest.upper() + args_string = self._format_args(action, default) + part = '%s %s' % (option_string, args_string) + if not action.required and action not in group_actions: + part = '[%s]' % part + parts.append(part) + + for i in sorted(inserts, reverse=True): + parts[i:i] = [inserts[i]] + + text = ' '.join([ item for item in parts if item is not None ]) + open = '[\\[(]' + close = '[\\])]' + text = _re.sub('(%s) ' % open, '\\1', text) + text = _re.sub(' (%s)' % close, '\\1', text) + text = _re.sub('%s *%s' % (open, close), '', text) + text = _re.sub('\\(([^|]*)\\)', '\\1', text) + text = text.strip() + return text + + def _format_text(self, text): + if '%(prog)' in text: + text = text % dict(prog=self._prog) + text_width = self._width - self._current_indent + indent = ' ' * self._current_indent + return self._fill_text(text, text_width, indent) + '\n\n' + + def _format_action(self, action): + help_position = min(self._action_max_length + 2, self._max_help_position) + help_width = self._width - help_position + action_width = help_position - self._current_indent - 2 + action_header = self._format_action_invocation(action) + if not action.help: + tup = (self._current_indent, '', action_header) + action_header = '%*s%s\n' % tup + elif len(action_header) <= action_width: + tup = (self._current_indent, + '', + action_width, + action_header) + action_header = '%*s%-*s ' % tup + indent_first = 0 + else: + tup = (self._current_indent, '', action_header) + action_header = '%*s%s\n' % tup + indent_first = help_position + parts = [action_header] + if action.help: + help_text = self._expand_help(action) + help_lines = self._split_lines(help_text, help_width) + parts.append('%*s%s\n' % (indent_first, '', help_lines[0])) + for line in help_lines[1:]: + parts.append('%*s%s\n' % (help_position, '', line)) + + elif not action_header.endswith('\n'): + parts.append('\n') + for subaction in self._iter_indented_subactions(action): + parts.append(self._format_action(subaction)) + + return self._join_parts(parts) + + def _format_action_invocation(self, action): + if not action.option_strings: + metavar, = self._metavar_formatter(action, action.dest)(1) + return metavar + else: + parts = [] + if action.nargs == 0: + parts.extend(action.option_strings) + else: + default = action.dest.upper() + args_string = self._format_args(action, default) + for option_string in action.option_strings: + parts.append('%s %s' % (option_string, args_string)) + + return ', '.join(parts) + + def _metavar_formatter(self, action, default_metavar): + if action.metavar is not None: + result = action.metavar + elif action.choices is not None: + choice_strs = [ str(choice) for choice in action.choices ] + result = '{%s}' % ','.join(choice_strs) + else: + result = default_metavar + + def format(tuple_size): + if isinstance(result, tuple): + return result + else: + return (result,) * tuple_size + + return format + + def _format_args(self, action, default_metavar): + get_metavar = self._metavar_formatter(action, default_metavar) + if action.nargs is None: + result = '%s' % get_metavar(1) + elif action.nargs == OPTIONAL: + result = '[%s]' % get_metavar(1) + elif action.nargs == ZERO_OR_MORE: + result = '[%s [%s ...]]' % get_metavar(2) + elif action.nargs == ONE_OR_MORE: + result = '%s [%s ...]' % get_metavar(2) + elif action.nargs == REMAINDER: + result = '...' + elif action.nargs == PARSER: + result = '%s ...' % get_metavar(1) + else: + formats = [ '%s' for _ in range(action.nargs) ] + result = ' '.join(formats) % get_metavar(action.nargs) + return result + + def _expand_help(self, action): + params = dict(vars(action), prog=self._prog) + for name in list(params): + if params[name] is SUPPRESS: + del params[name] + + for name in list(params): + if hasattr(params[name], '__name__'): + params[name] = params[name].__name__ + + if params.get('choices') is not None: + choices_str = ', '.join([ str(c) for c in params['choices'] ]) + params['choices'] = choices_str + return self._get_help_string(action) % params + + def _iter_indented_subactions(self, action): + try: + get_subactions = action._get_subactions + except AttributeError: + pass + else: + self._indent() + for subaction in get_subactions(): + yield subaction + + self._dedent() + + def _split_lines(self, text, width): + text = self._whitespace_matcher.sub(' ', text).strip() + return _textwrap.wrap(text, width) + + def _fill_text(self, text, width, indent): + text = self._whitespace_matcher.sub(' ', text).strip() + return _textwrap.fill(text, width, initial_indent=indent, subsequent_indent=indent) + + def _get_help_string(self, action): + return action.help + + +class RawDescriptionHelpFormatter(HelpFormatter): + + def _fill_text(self, text, width, indent): + return ''.join([ indent + line for line in text.splitlines(True) ]) + + +class RawTextHelpFormatter(RawDescriptionHelpFormatter): + + def _split_lines(self, text, width): + return text.splitlines() + + +class ArgumentDefaultsHelpFormatter(HelpFormatter): + + def _get_help_string(self, action): + help = action.help + if '%(default)' not in action.help: + if action.default is not SUPPRESS: + defaulting_nargs = [OPTIONAL, ZERO_OR_MORE] + if action.option_strings or action.nargs in defaulting_nargs: + help += ' (default: %(default)s)' + return help + + +def _get_action_name(argument): + if argument is None: + return + elif argument.option_strings: + return '/'.join(argument.option_strings) + elif argument.metavar not in (None, SUPPRESS): + return argument.metavar + elif argument.dest not in (None, SUPPRESS): + return argument.dest + else: + return + return + + +class ArgumentError(Exception): + + def __init__(self, argument, message): + self.argument_name = _get_action_name(argument) + self.message = message + + def __str__(self): + if self.argument_name is None: + format = '%(message)s' + else: + format = 'argument %(argument_name)s: %(message)s' + return format % dict(message=self.message, argument_name=self.argument_name) + + +class ArgumentTypeError(Exception): + pass + + +class Action(_AttributeHolder): + + def __init__(self, option_strings, dest, nargs = None, const = None, default = None, type = None, choices = None, required = False, help = None, metavar = None): + self.option_strings = option_strings + self.dest = dest + self.nargs = nargs + self.const = const + self.default = default + self.type = type + self.choices = choices + self.required = required + self.help = help + self.metavar = metavar + + def _get_kwargs(self): + names = ['option_strings', + 'dest', + 'nargs', + 'const', + 'default', + 'type', + 'choices', + 'help', + 'metavar'] + return [ (name, getattr(self, name)) for name in names ] + + def __call__(self, parser, namespace, values, option_string = None): + raise NotImplementedError(_('.__call__() not defined')) + + +class _StoreAction(Action): + + def __init__(self, option_strings, dest, nargs = None, const = None, default = None, type = None, choices = None, required = False, help = None, metavar = None): + if nargs == 0: + raise ValueError('nargs for store actions must be > 0; if you have nothing to store, actions such as store true or store const may be more appropriate') + if const is not None and nargs != OPTIONAL: + raise ValueError('nargs must be %r to supply const' % OPTIONAL) + super(_StoreAction, self).__init__(option_strings=option_strings, dest=dest, nargs=nargs, const=const, default=default, type=type, choices=choices, required=required, help=help, metavar=metavar) + return + + def __call__(self, parser, namespace, values, option_string = None): + setattr(namespace, self.dest, values) + + +class _StoreConstAction(Action): + + def __init__(self, option_strings, dest, const, default = None, required = False, help = None, metavar = None): + super(_StoreConstAction, self).__init__(option_strings=option_strings, dest=dest, nargs=0, const=const, default=default, required=required, help=help) + + def __call__(self, parser, namespace, values, option_string = None): + setattr(namespace, self.dest, self.const) + + +class _StoreTrueAction(_StoreConstAction): + + def __init__(self, option_strings, dest, default = False, required = False, help = None): + super(_StoreTrueAction, self).__init__(option_strings=option_strings, dest=dest, const=True, default=default, required=required, help=help) + + +class _StoreFalseAction(_StoreConstAction): + + def __init__(self, option_strings, dest, default = True, required = False, help = None): + super(_StoreFalseAction, self).__init__(option_strings=option_strings, dest=dest, const=False, default=default, required=required, help=help) + + +class _AppendAction(Action): + + def __init__(self, option_strings, dest, nargs = None, const = None, default = None, type = None, choices = None, required = False, help = None, metavar = None): + if nargs == 0: + raise ValueError('nargs for append actions must be > 0; if arg strings are not supplying the value to append, the append const action may be more appropriate') + if const is not None and nargs != OPTIONAL: + raise ValueError('nargs must be %r to supply const' % OPTIONAL) + super(_AppendAction, self).__init__(option_strings=option_strings, dest=dest, nargs=nargs, const=const, default=default, type=type, choices=choices, required=required, help=help, metavar=metavar) + return + + def __call__(self, parser, namespace, values, option_string = None): + items = _copy.copy(_ensure_value(namespace, self.dest, [])) + items.append(values) + setattr(namespace, self.dest, items) + + +class _AppendConstAction(Action): + + def __init__(self, option_strings, dest, const, default = None, required = False, help = None, metavar = None): + super(_AppendConstAction, self).__init__(option_strings=option_strings, dest=dest, nargs=0, const=const, default=default, required=required, help=help, metavar=metavar) + + def __call__(self, parser, namespace, values, option_string = None): + items = _copy.copy(_ensure_value(namespace, self.dest, [])) + items.append(self.const) + setattr(namespace, self.dest, items) + + +class _CountAction(Action): + + def __init__(self, option_strings, dest, default = None, required = False, help = None): + super(_CountAction, self).__init__(option_strings=option_strings, dest=dest, nargs=0, default=default, required=required, help=help) + + def __call__(self, parser, namespace, values, option_string = None): + new_count = _ensure_value(namespace, self.dest, 0) + 1 + setattr(namespace, self.dest, new_count) + + +class _HelpAction(Action): + + def __init__(self, option_strings, dest = SUPPRESS, default = SUPPRESS, help = None): + super(_HelpAction, self).__init__(option_strings=option_strings, dest=dest, default=default, nargs=0, help=help) + + def __call__(self, parser, namespace, values, option_string = None): + parser.print_help() + parser.exit() + + +class _VersionAction(Action): + + def __init__(self, option_strings, version = None, dest = SUPPRESS, default = SUPPRESS, help = "show program's version number and exit"): + super(_VersionAction, self).__init__(option_strings=option_strings, dest=dest, default=default, nargs=0, help=help) + self.version = version + + def __call__(self, parser, namespace, values, option_string = None): + version = self.version + if version is None: + version = parser.version + formatter = parser._get_formatter() + formatter.add_text(version) + parser.exit(message=formatter.format_help()) + return + + +class _SubParsersAction(Action): + + class _ChoicesPseudoAction(Action): + + def __init__(self, name, help): + sup = super(_SubParsersAction._ChoicesPseudoAction, self) + sup.__init__(option_strings=[], dest=name, help=help) + + def __init__(self, option_strings, prog, parser_class, dest = SUPPRESS, help = None, metavar = None): + self._prog_prefix = prog + self._parser_class = parser_class + self._name_parser_map = _collections.OrderedDict() + self._choices_actions = [] + super(_SubParsersAction, self).__init__(option_strings=option_strings, dest=dest, nargs=PARSER, choices=self._name_parser_map, help=help, metavar=metavar) + + def add_parser(self, name, **kwargs): + if kwargs.get('prog') is None: + kwargs['prog'] = '%s %s' % (self._prog_prefix, name) + if 'help' in kwargs: + help = kwargs.pop('help') + choice_action = self._ChoicesPseudoAction(name, help) + self._choices_actions.append(choice_action) + parser = self._parser_class(**kwargs) + self._name_parser_map[name] = parser + return parser + + def _get_subactions(self): + return self._choices_actions + + def __call__(self, parser, namespace, values, option_string = None): + parser_name = values[0] + arg_strings = values[1:] + if self.dest is not SUPPRESS: + setattr(namespace, self.dest, parser_name) + try: + parser = self._name_parser_map[parser_name] + except KeyError: + tup = (parser_name, ', '.join(self._name_parser_map)) + msg = _('unknown parser %r (choices: %s)') % tup + raise ArgumentError(self, msg) + + namespace, arg_strings = parser.parse_known_args(arg_strings, namespace) + if arg_strings: + vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, []) + getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings) + + +class FileType(object): + + def __init__(self, mode = 'r', bufsize = -1): + self._mode = mode + self._bufsize = bufsize + + def __call__(self, string): + if string == '-': + if 'r' in self._mode: + return _sys.stdin + if 'w' in self._mode: + return _sys.stdout + msg = _('argument "-" with mode %r') % self._mode + raise ValueError(msg) + try: + return open(string, self._mode, self._bufsize) + except IOError as e: + message = _("can't open '%s': %s") + raise ArgumentTypeError(message % (string, e)) + + def __repr__(self): + args = (self._mode, self._bufsize) + args_str = ', '.join((repr(arg) for arg in args if arg != -1)) + return '%s(%s)' % (type(self).__name__, args_str) + + +class Namespace(_AttributeHolder): + + def __init__(self, **kwargs): + for name in kwargs: + setattr(self, name, kwargs[name]) + + __hash__ = None + + def __eq__(self, other): + return vars(self) == vars(other) + + def __ne__(self, other): + return not self == other + + def __contains__(self, key): + return key in self.__dict__ + + +class _ActionsContainer(object): + + def __init__(self, description, prefix_chars, argument_default, conflict_handler): + super(_ActionsContainer, self).__init__() + self.description = description + self.argument_default = argument_default + self.prefix_chars = prefix_chars + self.conflict_handler = conflict_handler + self._registries = {} + self.register('action', None, _StoreAction) + self.register('action', 'store', _StoreAction) + self.register('action', 'store_const', _StoreConstAction) + self.register('action', 'store_true', _StoreTrueAction) + self.register('action', 'store_false', _StoreFalseAction) + self.register('action', 'append', _AppendAction) + self.register('action', 'append_const', _AppendConstAction) + self.register('action', 'count', _CountAction) + self.register('action', 'help', _HelpAction) + self.register('action', 'version', _VersionAction) + self.register('action', 'parsers', _SubParsersAction) + self._get_handler() + self._actions = [] + self._option_string_actions = {} + self._action_groups = [] + self._mutually_exclusive_groups = [] + self._defaults = {} + self._negative_number_matcher = _re.compile('^-\\d+$|^-\\d*\\.\\d+$') + self._has_negative_number_optionals = [] + return + + def register(self, registry_name, value, object): + registry = self._registries.setdefault(registry_name, {}) + registry[value] = object + + def _registry_get(self, registry_name, value, default = None): + return self._registries[registry_name].get(value, default) + + def set_defaults(self, **kwargs): + self._defaults.update(kwargs) + for action in self._actions: + if action.dest in kwargs: + action.default = kwargs[action.dest] + + def get_default(self, dest): + for action in self._actions: + if action.dest == dest and action.default is not None: + return action.default + + return self._defaults.get(dest, None) + + def add_argument(self, *args, **kwargs): + chars = self.prefix_chars + if not args or len(args) == 1 and args[0][0] not in chars: + if args and 'dest' in kwargs: + raise ValueError('dest supplied twice for positional argument') + kwargs = self._get_positional_kwargs(*args, **kwargs) + else: + kwargs = self._get_optional_kwargs(*args, **kwargs) + if 'default' not in kwargs: + dest = kwargs['dest'] + if dest in self._defaults: + kwargs['default'] = self._defaults[dest] + elif self.argument_default is not None: + kwargs['default'] = self.argument_default + action_class = self._pop_action_class(kwargs) + if not _callable(action_class): + raise ValueError('unknown action "%s"' % (action_class,)) + action = action_class(**kwargs) + type_func = self._registry_get('type', action.type, action.type) + if not _callable(type_func): + raise ValueError('%r is not callable' % (type_func,)) + if hasattr(self, '_get_formatter'): + try: + self._get_formatter()._format_args(action, None) + except TypeError: + raise ValueError('length of metavar tuple does not match nargs') + + return self._add_action(action) + + def add_argument_group(self, *args, **kwargs): + group = _ArgumentGroup(self, *args, **kwargs) + self._action_groups.append(group) + return group + + def add_mutually_exclusive_group(self, **kwargs): + group = _MutuallyExclusiveGroup(self, **kwargs) + self._mutually_exclusive_groups.append(group) + return group + + def _add_action(self, action): + self._check_conflict(action) + self._actions.append(action) + action.container = self + for option_string in action.option_strings: + self._option_string_actions[option_string] = action + + for option_string in action.option_strings: + if self._negative_number_matcher.match(option_string): + if not self._has_negative_number_optionals: + self._has_negative_number_optionals.append(True) + + return action + + def _remove_action(self, action): + self._actions.remove(action) + + def _add_container_actions(self, container): + title_group_map = {} + for group in self._action_groups: + if group.title in title_group_map: + msg = _('cannot merge actions - two groups are named %r') + raise ValueError(msg % group.title) + title_group_map[group.title] = group + + group_map = {} + for group in container._action_groups: + if group.title not in title_group_map: + title_group_map[group.title] = self.add_argument_group(title=group.title, description=group.description, conflict_handler=group.conflict_handler) + for action in group._group_actions: + group_map[action] = title_group_map[group.title] + + for group in container._mutually_exclusive_groups: + mutex_group = self.add_mutually_exclusive_group(required=group.required) + for action in group._group_actions: + group_map[action] = mutex_group + + for action in container._actions: + group_map.get(action, self)._add_action(action) + + def _get_positional_kwargs(self, dest, **kwargs): + if 'required' in kwargs: + msg = _("'required' is an invalid argument for positionals") + raise TypeError(msg) + if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]: + kwargs['required'] = True + if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs: + kwargs['required'] = True + return dict(kwargs, dest=dest, option_strings=[]) + + def _get_optional_kwargs(self, *args, **kwargs): + option_strings = [] + long_option_strings = [] + for option_string in args: + if option_string[0] not in self.prefix_chars: + msg = _('invalid option string %r: must start with a character %r') + tup = (option_string, self.prefix_chars) + raise ValueError(msg % tup) + option_strings.append(option_string) + if option_string[0] in self.prefix_chars: + if len(option_string) > 1: + if option_string[1] in self.prefix_chars: + long_option_strings.append(option_string) + + dest = kwargs.pop('dest', None) + if dest is None: + if long_option_strings: + dest_option_string = long_option_strings[0] + else: + dest_option_string = option_strings[0] + dest = dest_option_string.lstrip(self.prefix_chars) + if not dest: + msg = _('dest= is required for options like %r') + raise ValueError(msg % option_string) + dest = dest.replace('-', '_') + return dict(kwargs, dest=dest, option_strings=option_strings) + + def _pop_action_class(self, kwargs, default = None): + action = kwargs.pop('action', default) + return self._registry_get('action', action, action) + + def _get_handler(self): + handler_func_name = '_handle_conflict_%s' % self.conflict_handler + try: + return getattr(self, handler_func_name) + except AttributeError: + msg = _('invalid conflict_resolution value: %r') + raise ValueError(msg % self.conflict_handler) + + def _check_conflict(self, action): + confl_optionals = [] + for option_string in action.option_strings: + if option_string in self._option_string_actions: + confl_optional = self._option_string_actions[option_string] + confl_optionals.append((option_string, confl_optional)) + + if confl_optionals: + conflict_handler = self._get_handler() + conflict_handler(action, confl_optionals) + + def _handle_conflict_error(self, action, conflicting_actions): + message = _('conflicting option string(s): %s') + conflict_string = ', '.join([ option_string for option_string, action in conflicting_actions ]) + raise ArgumentError(action, message % conflict_string) + + def _handle_conflict_resolve(self, action, conflicting_actions): + for option_string, action in conflicting_actions: + action.option_strings.remove(option_string) + self._option_string_actions.pop(option_string, None) + if not action.option_strings: + action.container._remove_action(action) + + return + + +class _ArgumentGroup(_ActionsContainer): + + def __init__(self, container, title = None, description = None, **kwargs): + update = kwargs.setdefault + update('conflict_handler', container.conflict_handler) + update('prefix_chars', container.prefix_chars) + update('argument_default', container.argument_default) + super_init = super(_ArgumentGroup, self).__init__ + super_init(description=description, **kwargs) + self.title = title + self._group_actions = [] + self._registries = container._registries + self._actions = container._actions + self._option_string_actions = container._option_string_actions + self._defaults = container._defaults + self._has_negative_number_optionals = container._has_negative_number_optionals + self._mutually_exclusive_groups = container._mutually_exclusive_groups + + def _add_action(self, action): + action = super(_ArgumentGroup, self)._add_action(action) + self._group_actions.append(action) + return action + + def _remove_action(self, action): + super(_ArgumentGroup, self)._remove_action(action) + self._group_actions.remove(action) + + +class _MutuallyExclusiveGroup(_ArgumentGroup): + + def __init__(self, container, required = False): + super(_MutuallyExclusiveGroup, self).__init__(container) + self.required = required + self._container = container + + def _add_action(self, action): + if action.required: + msg = _('mutually exclusive arguments must be optional') + raise ValueError(msg) + action = self._container._add_action(action) + self._group_actions.append(action) + return action + + def _remove_action(self, action): + self._container._remove_action(action) + self._group_actions.remove(action) + + +class ArgumentParser(_AttributeHolder, _ActionsContainer): + + def __init__(self, prog = None, usage = None, description = None, epilog = None, version = None, parents = [], formatter_class = HelpFormatter, prefix_chars = '-', fromfile_prefix_chars = None, argument_default = None, conflict_handler = 'error', add_help = True): + if version is not None: + import warnings + warnings.warn('The "version" argument to ArgumentParser is deprecated. Please use "add_argument(..., action=\'version\', version="N", ...)" instead', DeprecationWarning) + superinit = super(ArgumentParser, self).__init__ + superinit(description=description, prefix_chars=prefix_chars, argument_default=argument_default, conflict_handler=conflict_handler) + if prog is None: + prog = _os.path.basename(_sys.argv[0]) + self.prog = prog + self.usage = usage + self.epilog = epilog + self.version = version + self.formatter_class = formatter_class + self.fromfile_prefix_chars = fromfile_prefix_chars + self.add_help = add_help + add_group = self.add_argument_group + self._positionals = add_group(_('positional arguments')) + self._optionals = add_group(_('optional arguments')) + self._subparsers = None + + def identity(string): + return string + + self.register('type', None, identity) + default_prefix = '-' if '-' in prefix_chars else prefix_chars[0] + if self.add_help: + self.add_argument(default_prefix + 'h', default_prefix * 2 + 'help', action='help', default=SUPPRESS, help=_('show this help message and exit')) + if self.version: + self.add_argument(default_prefix + 'v', default_prefix * 2 + 'version', action='version', default=SUPPRESS, version=self.version, help=_("show program's version number and exit")) + for parent in parents: + self._add_container_actions(parent) + try: + defaults = parent._defaults + except AttributeError: + pass + else: + self._defaults.update(defaults) + + return + + def _get_kwargs(self): + names = ['prog', + 'usage', + 'description', + 'version', + 'formatter_class', + 'conflict_handler', + 'add_help'] + return [ (name, getattr(self, name)) for name in names ] + + def add_subparsers(self, **kwargs): + if self._subparsers is not None: + self.error(_('cannot have multiple subparser arguments')) + kwargs.setdefault('parser_class', type(self)) + if 'title' in kwargs or 'description' in kwargs: + title = _(kwargs.pop('title', 'subcommands')) + description = _(kwargs.pop('description', None)) + self._subparsers = self.add_argument_group(title, description) + else: + self._subparsers = self._positionals + if kwargs.get('prog') is None: + formatter = self._get_formatter() + positionals = self._get_positional_actions() + groups = self._mutually_exclusive_groups + formatter.add_usage(self.usage, positionals, groups, '') + kwargs['prog'] = formatter.format_help().strip() + parsers_class = self._pop_action_class(kwargs, 'parsers') + action = parsers_class(option_strings=[], **kwargs) + self._subparsers._add_action(action) + return action + + def _add_action(self, action): + if action.option_strings: + self._optionals._add_action(action) + else: + self._positionals._add_action(action) + return action + + def _get_optional_actions(self): + return [ action for action in self._actions if action.option_strings ] + + def _get_positional_actions(self): + return [ action for action in self._actions if not action.option_strings ] + + def parse_args(self, args = None, namespace = None): + args, argv = self.parse_known_args(args, namespace) + if argv: + msg = _('unrecognized arguments: %s') + self.error(msg % ' '.join(argv)) + return args + + def parse_known_args(self, args = None, namespace = None): + if args is None: + args = _sys.argv[1:] + if namespace is None: + namespace = Namespace() + for action in self._actions: + if action.dest is not SUPPRESS: + if not hasattr(namespace, action.dest): + if action.default is not SUPPRESS: + default = action.default + if isinstance(action.default, basestring): + default = self._get_value(action, default) + setattr(namespace, action.dest, default) + + for dest in self._defaults: + if not hasattr(namespace, dest): + setattr(namespace, dest, self._defaults[dest]) + + try: + namespace, args = self._parse_known_args(args, namespace) + if hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR): + args.extend(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR)) + delattr(namespace, _UNRECOGNIZED_ARGS_ATTR) + return (namespace, args) + except ArgumentError: + err = _sys.exc_info()[1] + self.error(str(err)) + + return + + def _parse_known_args(self, arg_strings, namespace): + if self.fromfile_prefix_chars is not None: + arg_strings = self._read_args_from_files(arg_strings) + action_conflicts = {} + for mutex_group in self._mutually_exclusive_groups: + group_actions = mutex_group._group_actions + for i, mutex_action in enumerate(mutex_group._group_actions): + conflicts = action_conflicts.setdefault(mutex_action, []) + conflicts.extend(group_actions[:i]) + conflicts.extend(group_actions[i + 1:]) + + option_string_indices = {} + arg_string_pattern_parts = [] + arg_strings_iter = iter(arg_strings) + for i, arg_string in enumerate(arg_strings_iter): + if arg_string == '--': + arg_string_pattern_parts.append('-') + for arg_string in arg_strings_iter: + arg_string_pattern_parts.append('A') + + else: + option_tuple = self._parse_optional(arg_string) + if option_tuple is None: + pattern = 'A' + else: + option_string_indices[i] = option_tuple + pattern = 'O' + arg_string_pattern_parts.append(pattern) + + arg_strings_pattern = ''.join(arg_string_pattern_parts) + seen_actions = set() + seen_non_default_actions = set() + + def take_action(action, argument_strings, option_string = None): + seen_actions.add(action) + argument_values = self._get_values(action, argument_strings) + if argument_values is not action.default: + seen_non_default_actions.add(action) + for conflict_action in action_conflicts.get(action, []): + if conflict_action in seen_non_default_actions: + msg = _('not allowed with argument %s') + action_name = _get_action_name(conflict_action) + raise ArgumentError(action, msg % action_name) + + if argument_values is not SUPPRESS: + action(self, namespace, argument_values, option_string) + + def consume_optional(start_index): + option_tuple = option_string_indices[start_index] + action, option_string, explicit_arg = option_tuple + match_argument = self._match_argument + action_tuples = [] + while True: + if action is None: + extras.append(arg_strings[start_index]) + return start_index + 1 + if explicit_arg is not None: + arg_count = match_argument(action, 'A') + chars = self.prefix_chars + if arg_count == 0 and option_string[1] not in chars: + action_tuples.append((action, [], option_string)) + char = option_string[0] + option_string = char + explicit_arg[0] + new_explicit_arg = explicit_arg[1:] or None + optionals_map = self._option_string_actions + if option_string in optionals_map: + action = optionals_map[option_string] + explicit_arg = new_explicit_arg + else: + msg = _('ignored explicit argument %r') + raise ArgumentError(action, msg % explicit_arg) + elif arg_count == 1: + stop = start_index + 1 + args = [explicit_arg] + action_tuples.append((action, args, option_string)) + break + else: + msg = _('ignored explicit argument %r') + raise ArgumentError(action, msg % explicit_arg) + else: + start = start_index + 1 + selected_patterns = arg_strings_pattern[start:] + arg_count = match_argument(action, selected_patterns) + stop = start + arg_count + args = arg_strings[start:stop] + action_tuples.append((action, args, option_string)) + break + + for action, args, option_string in action_tuples: + take_action(action, args, option_string) + + return stop + + positionals = self._get_positional_actions() + + def consume_positionals(start_index): + match_partial = self._match_arguments_partial + selected_pattern = arg_strings_pattern[start_index:] + arg_counts = match_partial(positionals, selected_pattern) + for action, arg_count in zip(positionals, arg_counts): + args = arg_strings[start_index:start_index + arg_count] + start_index += arg_count + take_action(action, args) + + positionals[:] = positionals[len(arg_counts):] + return start_index + + extras = [] + start_index = 0 + if option_string_indices: + max_option_string_index = max(option_string_indices) + else: + max_option_string_index = -1 + while start_index <= max_option_string_index: + next_option_string_index = min([ index for index in option_string_indices if index >= start_index ]) + if start_index != next_option_string_index: + positionals_end_index = consume_positionals(start_index) + if positionals_end_index > start_index: + start_index = positionals_end_index + continue + else: + start_index = positionals_end_index + if start_index not in option_string_indices: + strings = arg_strings[start_index:next_option_string_index] + extras.extend(strings) + start_index = next_option_string_index + start_index = consume_optional(start_index) + + stop_index = consume_positionals(start_index) + extras.extend(arg_strings[stop_index:]) + if positionals: + self.error(_('too few arguments')) + for action in self._actions: + if action.required: + if action not in seen_actions: + name = _get_action_name(action) + self.error(_('argument %s is required') % name) + + for group in self._mutually_exclusive_groups: + if group.required: + for action in group._group_actions: + if action in seen_non_default_actions: + break + else: + names = [ _get_action_name(action) for action in group._group_actions if action.help is not SUPPRESS ] + msg = _('one of the arguments %s is required') + self.error(msg % ' '.join(names)) + + return (namespace, extras) + + def _read_args_from_files(self, arg_strings): + new_arg_strings = [] + for arg_string in arg_strings: + if arg_string[0] not in self.fromfile_prefix_chars: + new_arg_strings.append(arg_string) + else: + try: + args_file = open(arg_string[1:]) + try: + arg_strings = [] + for arg_line in args_file.read().splitlines(): + for arg in self.convert_arg_line_to_args(arg_line): + arg_strings.append(arg) + + arg_strings = self._read_args_from_files(arg_strings) + new_arg_strings.extend(arg_strings) + finally: + args_file.close() + + except IOError: + err = _sys.exc_info()[1] + self.error(str(err)) + + return new_arg_strings + + def convert_arg_line_to_args(self, arg_line): + return [arg_line] + + def _match_argument(self, action, arg_strings_pattern): + nargs_pattern = self._get_nargs_pattern(action) + match = _re.match(nargs_pattern, arg_strings_pattern) + if match is None: + nargs_errors = {None: _('expected one argument'), + OPTIONAL: _('expected at most one argument'), + ONE_OR_MORE: _('expected at least one argument')} + default = _('expected %s argument(s)') % action.nargs + msg = nargs_errors.get(action.nargs, default) + raise ArgumentError(action, msg) + return len(match.group(1)) + + def _match_arguments_partial(self, actions, arg_strings_pattern): + result = [] + for i in range(len(actions), 0, -1): + actions_slice = actions[:i] + pattern = ''.join([ self._get_nargs_pattern(action) for action in actions_slice ]) + match = _re.match(pattern, arg_strings_pattern) + if match is not None: + result.extend([ len(string) for string in match.groups() ]) + break + + return result + + def _parse_optional(self, arg_string): + if not arg_string: + return None + elif arg_string[0] not in self.prefix_chars: + return None + elif arg_string in self._option_string_actions: + action = self._option_string_actions[arg_string] + return (action, arg_string, None) + elif len(arg_string) == 1: + return None + else: + if '=' in arg_string: + option_string, explicit_arg = arg_string.split('=', 1) + if option_string in self._option_string_actions: + action = self._option_string_actions[option_string] + return (action, option_string, explicit_arg) + option_tuples = self._get_option_tuples(arg_string) + if len(option_tuples) > 1: + options = ', '.join([ option_string for action, option_string, explicit_arg in option_tuples ]) + tup = (arg_string, options) + self.error(_('ambiguous option: %s could match %s') % tup) + elif len(option_tuples) == 1: + option_tuple, = option_tuples + return option_tuple + if self._negative_number_matcher.match(arg_string): + if not self._has_negative_number_optionals: + return None + if ' ' in arg_string: + return None + return (None, arg_string, None) + return None + + def _get_option_tuples(self, option_string): + result = [] + chars = self.prefix_chars + if option_string[0] in chars and option_string[1] in chars: + if '=' in option_string: + option_prefix, explicit_arg = option_string.split('=', 1) + else: + option_prefix = option_string + explicit_arg = None + for option_string in self._option_string_actions: + if option_string.startswith(option_prefix): + action = self._option_string_actions[option_string] + tup = (action, option_string, explicit_arg) + result.append(tup) + + elif option_string[0] in chars and option_string[1] not in chars: + option_prefix = option_string + explicit_arg = None + short_option_prefix = option_string[:2] + short_explicit_arg = option_string[2:] + for option_string in self._option_string_actions: + if option_string == short_option_prefix: + action = self._option_string_actions[option_string] + tup = (action, option_string, short_explicit_arg) + result.append(tup) + elif option_string.startswith(option_prefix): + action = self._option_string_actions[option_string] + tup = (action, option_string, explicit_arg) + result.append(tup) + + else: + self.error(_('unexpected option string: %s') % option_string) + return result + + def _get_nargs_pattern(self, action): + nargs = action.nargs + if nargs is None: + nargs_pattern = '(-*A-*)' + elif nargs == OPTIONAL: + nargs_pattern = '(-*A?-*)' + elif nargs == ZERO_OR_MORE: + nargs_pattern = '(-*[A-]*)' + elif nargs == ONE_OR_MORE: + nargs_pattern = '(-*A[A-]*)' + elif nargs == REMAINDER: + nargs_pattern = '([-AO]*)' + elif nargs == PARSER: + nargs_pattern = '(-*A[-AO]*)' + else: + nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs) + if action.option_strings: + nargs_pattern = nargs_pattern.replace('-*', '') + nargs_pattern = nargs_pattern.replace('-', '') + return nargs_pattern + + def _get_values(self, action, arg_strings): + if action.nargs not in [PARSER, REMAINDER]: + arg_strings = [ s for s in arg_strings if s != '--' ] + if not arg_strings and action.nargs == OPTIONAL: + if action.option_strings: + value = action.const + else: + value = action.default + if isinstance(value, basestring): + value = self._get_value(action, value) + self._check_value(action, value) + elif not arg_strings and action.nargs == ZERO_OR_MORE and not action.option_strings: + if action.default is not None: + value = action.default + else: + value = arg_strings + self._check_value(action, value) + elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]: + arg_string, = arg_strings + value = self._get_value(action, arg_string) + self._check_value(action, value) + elif action.nargs == REMAINDER: + value = [ self._get_value(action, v) for v in arg_strings ] + elif action.nargs == PARSER: + value = [ self._get_value(action, v) for v in arg_strings ] + self._check_value(action, value[0]) + else: + value = [ self._get_value(action, v) for v in arg_strings ] + for v in value: + self._check_value(action, v) + + return value + + def _get_value(self, action, arg_string): + type_func = self._registry_get('type', action.type, action.type) + if not _callable(type_func): + msg = _('%r is not callable') + raise ArgumentError(action, msg % type_func) + try: + result = type_func(arg_string) + except ArgumentTypeError: + name = getattr(action.type, '__name__', repr(action.type)) + msg = str(_sys.exc_info()[1]) + raise ArgumentError(action, msg) + except (TypeError, ValueError): + name = getattr(action.type, '__name__', repr(action.type)) + msg = _('invalid %s value: %r') + raise ArgumentError(action, msg % (name, arg_string)) + + return result + + def _check_value(self, action, value): + if action.choices is not None and value not in action.choices: + tup = (value, ', '.join(map(repr, action.choices))) + msg = _('invalid choice: %r (choose from %s)') % tup + raise ArgumentError(action, msg) + return + + def format_usage(self): + formatter = self._get_formatter() + formatter.add_usage(self.usage, self._actions, self._mutually_exclusive_groups) + return formatter.format_help() + + def format_help(self): + formatter = self._get_formatter() + formatter.add_usage(self.usage, self._actions, self._mutually_exclusive_groups) + formatter.add_text(self.description) + for action_group in self._action_groups: + formatter.start_section(action_group.title) + formatter.add_text(action_group.description) + formatter.add_arguments(action_group._group_actions) + formatter.end_section() + + formatter.add_text(self.epilog) + return formatter.format_help() + + def format_version(self): + import warnings + warnings.warn('The format_version method is deprecated -- the "version" argument to ArgumentParser is no longer supported.', DeprecationWarning) + formatter = self._get_formatter() + formatter.add_text(self.version) + return formatter.format_help() + + def _get_formatter(self): + return self.formatter_class(prog=self.prog) + + def print_usage(self, file = None): + if file is None: + file = _sys.stdout + self._print_message(self.format_usage(), file) + return + + def print_help(self, file = None): + if file is None: + file = _sys.stdout + self._print_message(self.format_help(), file) + return + + def print_version(self, file = None): + import warnings + warnings.warn('The print_version method is deprecated -- the "version" argument to ArgumentParser is no longer supported.', DeprecationWarning) + self._print_message(self.format_version(), file) + + def _print_message(self, message, file = None): + if message: + if file is None: + file = _sys.stderr + file.write(message) + return + + def exit(self, status = 0, message = None): + if message: + self._print_message(message, _sys.stderr) + _sys.exit(status) + + def error(self, message): + self.print_usage(_sys.stderr) + self.exit(2, _('%s: error: %s\n') % (self.prog, message)) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubi/__init__.py b/NeoBoot/ubi_reader_arm/ubi/__init__.py new file mode 100644 index 0000000..8da31e4 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubi/__init__.py @@ -0,0 +1,139 @@ +#!/usr/bin/python +import re +from ubi.volume import get_volumes +from ubi.block import sort, get_blocks_in_list, extract_blocks +from ubi.defines import * +from ubi import display +from ubi.image import description as image +from ubi.block import layout + +class ubi: + + def __init__(self, ubi_file): + self._file = ubi_file + self._first_peb_num = 0 + self._blocks = extract_blocks(self) + self._block_count = len(self.blocks) + if self._block_count <= 0: + raise Exception('No blocks found.') + layout_list, data_list, int_vol_list, unknown_list = sort.by_type(self.blocks) + self._layout_blocks_list = layout_list + self._data_blocks_list = data_list + self._int_vol_blocks_list = int_vol_list + self._unknown_blocks_list = unknown_list + arbitrary_block = self.blocks.itervalues().next() + self._min_io_size = arbitrary_block.ec_hdr.vid_hdr_offset + self._leb_size = self.file.block_size - arbitrary_block.ec_hdr.data_offset + layout_pairs = layout.group_pairs(self.blocks, self.layout_blocks_list) + layout_infos = layout.associate_blocks(self.blocks, layout_pairs, self.first_peb_num) + self._images = [] + for i in range(0, len(layout_infos)): + self._images.append(image(self.blocks, layout_infos[i])) + + def _get_file(self): + return self._file + + file = property(_get_file) + + def _get_images(self): + return self._images + + images = property(_get_images) + + def _get_data_blocks_list(self): + return self._data_blocks_list + + data_blocks_list = property(_get_data_blocks_list) + + def _get_layout_blocks_list(self): + return self._layout_blocks_list + + layout_blocks_list = property(_get_layout_blocks_list) + + def _get_int_vol_blocks_list(self): + return self._int_vol_blocks_list + + int_vol_blocks_list = property(_get_int_vol_blocks_list) + + def _get_unknown_blocks_list(self): + return self._unknown_blocks_list + + unknown_blocks_list = property(_get_unknown_blocks_list) + + def _get_block_count(self): + return self._block_count + + block_count = property(_get_block_count) + + def _set_first_peb_num(self, i): + self._first_peb_num = i + + def _get_first_peb_num(self): + return self._first_peb_num + + first_peb_num = property(_get_first_peb_num, _set_first_peb_num) + + def _get_leb_size(self): + return self._leb_size + + leb_size = property(_get_leb_size) + + def _get_peb_size(self): + return self.file.block_size + + peb_size = property(_get_peb_size) + + def _get_min_io_size(self): + return self._min_io_size + + min_io_size = property(_get_min_io_size) + + def _get_blocks(self): + return self._blocks + + blocks = property(_get_blocks) + + def display(self, tab = ''): + display.ubi(self, tab) + + +def get_peb_size(path): + file_offset = 0 + offsets = [] + f = open(path, 'rb') + f.seek(0, 2) + file_size = f.tell() + 1 + f.seek(0) + for i in range(0, file_size, FILE_CHUNK_SZ): + buf = f.read(FILE_CHUNK_SZ) + for m in re.finditer(UBI_EC_HDR_MAGIC, buf): + start = m.start() + if not file_offset: + file_offset = start + idx = start + else: + idx = start + file_offset + offsets.append(idx) + + file_offset += FILE_CHUNK_SZ + + f.close() + occurances = {} + for i in range(0, len(offsets)): + try: + diff = offsets[i] - offsets[i - 1] + except: + diff = offsets[i] + + if diff not in occurances: + occurances[diff] = 0 + occurances[diff] += 1 + + most_frequent = 0 + block_size = 0 + for offset in occurances: + if occurances[offset] > most_frequent: + most_frequent = occurances[offset] + block_size = offset + + return block_size \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubi/__init__.pyo b/NeoBoot/ubi_reader_arm/ubi/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..65f47247349ed26e19a1f483c6b6e2ff683ec470 GIT binary patch literal 6002 zcmcgw+j1Mn5$y#?kN^SRB$}i|$+8o>kfch8or`jjokXN;t75b4l^iCpRT}`ipcY*0 zg1Z9+Oo1u`9l-s3Jc9eit?~tg;?Q# z@v~cZkTnZP_55x$m*2e%pl2<)R@&tZ97Uj2bmYfUKD1=ECLQjCT(?$XRGXB z9P#@$JBO?vW`n48bUKkAWSuk|m@tVgSVAkbNQTC6;$b`N;Gh1md=Fpt7Df%AfJ1Xq zlL9qirYOOT1Vwq~&~|=7!IFX{1?OmDwwzaRUcs{XGYVD|tSAVZ%_>+`u&Q89{E~u; z3N9+RB>tR&%L*-!Ecn%Y8P*hE(_XJ}t=MZ_!F2^U#IGv2 zso6K5rd^sb>1vxItF*36<*1^4s zjEg${f{b;1uPS5IV#eB}Zx2Sryh}`vF=0@!N82721;CO);lxIZ042 zQJ8De%Ce*rwoEWl!PEerTLWwUu;1E;GF+^*6@v@80Ik6wh8-Je3~9vVbx}nF|DE;W&(t9H^~eaKdd7W zO|nmrYYelr5ryqW5QqEy*1L_tk$IBDjZdTDei&zs`y&&?8Q3>#>;}obBry$8u9pTa zKS-HvcyNf&c;0RFq>_1=(`RoZ5vPpbC1(}il5;+DgkV2ftKx)SGzJ(e>WIY#FIi{(o8Dq=c0H@@1tU>@h&2h`ZJ= zt|9AQM>1`>c}L})>od&#s?M=FJ$X;|toOyKv<6uly^#|b z9Vms6nNbDTfRBJn5Qy;U;GCcE>gw{gc1kB2O_)~uG8x6?ynnv>`uV$rdG)qe9`{EqbA_M3RJcC|=)TT`N1X;e zFF6L?pXQY>IcVHFtmI;xp>p?UD7!yr@&*&0MygJ}jon}7NWMYbyF@t785eZlL)j$> zsD)0KKy%;zMO~Mkmd>bhsZd@k7psM@|H{Rs7i#sw&On4~s*d*$5D|jpV~3G5f_pe2 zJdkey8t5akhfksbURdapETaxBW@H_&04Mbfn@4{WI3yb582~{P0`i^5Mjr~$YgQr5 zRFaWP7w935N7Ric9LDAEGp--c@wow`Bap`?$o|F19ilNUON@sG#n&0a7o>+WS~FgM zCVOa)Iq#tL;TI@j#s!Y#gcz+NBQp^VAs4!$lg|2>(jDO`0WTS|vT6T8wT;b<;|1A^ zSHy9gNhN^Tk>8K;%2APnIY~cos49e5kh^#*vAIq`HZj1R;@!jl$Q~_QRr}Ut^bVWs zJpP^>FKXjOOjwnJ8ASf`z_qfE5O~c&^x6*jFXRbQr~7HV ziai!j0@vU`GbV^4_dBd-qYoZ@eBayt==0s*dJmgg&v4KV7^wSq!`Nrkue7av_d7>MI(O3R5z@X5^`Zk{J z>H~+i(2$>ZB4x7nu&V)Y-+h!rp+8c3NjjY&;`YwuJ;D#WUDd0P7}@Kl!Ql}4>nW=2 zVy8RZli&V!)YzR@mYgI&*OJ{sB2EdvOU^QWYlxN^F;^8U7b?z5VG(Hw(R0zchHtS@ zMXRd?_Nk#q#iH1uy>&To4ygbbPN07M5ZF^}uS+6!-(tcwa@$BwZFWgKrp|WP9v1IYWPMtzLiH^uPopgtt~CD#5AiRD literal 0 HcmV?d00001 diff --git a/NeoBoot/ubi_reader_arm/ubi/block/__init__.py b/NeoBoot/ubi_reader_arm/ubi/block/__init__.py new file mode 100644 index 0000000..7d8c1de --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubi/block/__init__.py @@ -0,0 +1,59 @@ +#!/usr/bin/python +import re +from ubi import display +from ubi.defines import * +from ubi.headers import * + +class description(object): + + def __init__(self, block_buf): + self.file_offset = -1 + self.peb_num = -1 + self.leb_num = -1 + self.size = -1 + self.vid_hdr = None + self.is_internal_vol = False + self.vtbl_recs = [] + self.ec_hdr = extract_ec_hdr(block_buf[0:UBI_EC_HDR_SZ]) + if not self.ec_hdr.errors: + self.vid_hdr = extract_vid_hdr(block_buf[self.ec_hdr.vid_hdr_offset:self.ec_hdr.vid_hdr_offset + UBI_VID_HDR_SZ]) + self.is_internal_vol = self.vid_hdr.vol_id >= UBI_INTERNAL_VOL_START + if self.vid_hdr.vol_id >= UBI_INTERNAL_VOL_START: + self.vtbl_recs = extract_vtbl_rec(block_buf[self.ec_hdr.data_offset:]) + self.leb_num = self.vid_hdr.lnum + self.is_vtbl = bool(self.vtbl_recs) or False + self.is_valid = not self.ec_hdr.errors and not self.vid_hdr.errors + return + + def __repr__(self): + return 'Block: PEB# %s: LEB# %s' % (self.peb_num, self.leb_num) + + def display(self, tab = ''): + display.block(self, tab) + + +def get_blocks_in_list(blocks, idx_list): + return {i:blocks[i] for i in idx_list} + + +def extract_blocks(ubi): + blocks = {} + start_peb = 0 + ubi.file.seek(ubi.file.start_offset) + peb_count = 0 + cur_offset = 0 + for i in range(ubi.file.start_offset, ubi.file.end_offset, ubi.file.block_size): + buf = ubi.file.read(ubi.file.block_size) + if buf.startswith(UBI_EC_HDR_MAGIC): + blk = description(buf) + blk.file_offset = i + blk.peb_num = ubi.first_peb_num + peb_count + blk.size = ubi.file.block_size + blocks[blk.peb_num] = blk + peb_count += 1 + else: + cur_offset += ubi.file.block_size + ubi.first_peb_num = cur_offset / ubi.file.block_size + ubi.file.start_offset = cur_offset + + return blocks \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubi/block/__init__.pyo b/NeoBoot/ubi_reader_arm/ubi/block/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..cd7d5adb687395489bde5e282c5f9ad3afb4eb99 GIT binary patch literal 3042 zcmcgu&2Ah;5U!s6x7Ue@V>^h17(&7dq%49%L=;8DKY*pMM6)IcD^Y89r`MkKcxE%* z8yu9J91-rk0|y?31L6UA1};1Rd{r}JZ@3$;ySKXjx~jTQ8=a0u);M{$i5ci*dMI#Qz#MEF{a_pey)-dGeHw*&Kg=9Q|MMV* zg7bhPtE0r3ED2)$G>s8XqNi>U>&y(TJBO1wa#=8R+6+Z}0jO`*xAoSB{&LgT{aw5X zm~x_kS(av2l$WCA)vT_7OCK1;>K<-y&gz3HIttxNLEY}{Z27%=_w~cC@9X}~J%7h7 z@~wqwrNMd11}-SIa{yuv4+Db~{&B9uXO?hM2Y`b(3Ok&b!e&i8k}wS7ba2xt(R zjKQvG?rKCna$4VnJeyLU`3da1*hsZr`>d$8x}lcU1$7zglDeXXT&cV`U!}$! zoM)t>kw+_i@vmoBL0)ISZm&JqTEDh--QHfip98|-bD(@q5$Oc}TMS|SFYae%l4*Sz zw^@D-QjYhNw(**eAdRJ}QQOCPQ|yb$z1$C$lvI~k=Qwu8u@)B$&fY1XO}L6xIMd;% z77v{Shem6(EPnOFG@PQSwSNUi|83r|X2O1^spoU3xhgCdZ{2GxwJIkeXBr30a$3D2 z88C`|L}n@4L{lr$O45*dIeV6vpIt%cLPvYNL@yNmBqDD@>}QXj)FB9l!bKKzyxsiB zaV|&s5Mp!W@$8xUZ}}1KgwfCq)5FQ#_i&O2Yt2~a-vBmm7vYhPBkOYW*;=8USzow- z8}^LTc_7d*fl3r*z^MNBB- zm+J7WkrvNGwCMHbz_o$4F34OtHMmf-AVJ(YH%t= slist_len: + add_elements = blocks[block].leb_num - slist_len + 1 + slist += ['x'] * add_elements + slist_len = len(slist) + slist[blocks[block].leb_num] = block + + return slist + return sorted(blocks.iterkeys(), key=lambda x: blocks[x].leb_num) + + +def by_vol_id(blocks, slist = None): + vol_blocks = {} + for i in blocks: + if slist and i not in slist: + continue + elif not blocks[i].is_valid: + continue + if blocks[i].vid_hdr.vol_id not in vol_blocks: + vol_blocks[blocks[i].vid_hdr.vol_id] = [] + vol_blocks[blocks[i].vid_hdr.vol_id].append(blocks[i].peb_num) + + return vol_blocks + + +def clean_bad(blocks, slist = None): + clean_blocks = [] + for i in range(0, len(blocks)): + if slist and i not in slist: + continue + if blocks[i].is_valid: + clean_blocks.append(i) + + return clean_blocks + + +def by_type(blocks, slist = None): + layout = [] + data = [] + int_vol = [] + unknown = [] + for i in blocks: + if slist and i not in slist: + continue + if blocks[i].is_vtbl and blocks[i].is_valid: + layout.append(i) + elif blocks[i].is_internal_vol and blocks[i].is_valid: + int_vol.append(i) + elif blocks[i].is_valid: + data.append(i) + else: + unknown.append(i) + + return (layout, + data, + int_vol, + unknown) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubi/defines.py b/NeoBoot/ubi_reader_arm/ubi/defines.py new file mode 100644 index 0000000..668b197 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubi/defines.py @@ -0,0 +1,63 @@ +#!/usr/bin/python +import struct +UBI_CRC32_INIT = 4294967295L +UBI_MAX_VOLUMES = 128 +UBI_INTERNAL_VOL_START = 2147479551 +UBI_EC_HDR_MAGIC = 'UBI#' +EC_HDR_FORMAT = '>4sB3sQIII32sI' +EC_HDR_FIELDS = ['magic', + 'version', + 'padding', + 'ec', + 'vid_hdr_offset', + 'data_offset', + 'image_seq', + 'padding2', + 'hdr_crc'] +UBI_EC_HDR_SZ = struct.calcsize(EC_HDR_FORMAT) +UBI_VID_HDR_MAGIC = 'UBI!' +VID_HDR_FORMAT = '>4sBBBBII4sIIII4sQ12sI' +VID_HDR_FIELDS = ['magic', + 'version', + 'vol_type', + 'copy_flag', + 'compat', + 'vol_id', + 'lnum', + 'padding', + 'data_size', + 'used_ebs', + 'data_pad', + 'data_crc', + 'padding2', + 'sqnum', + 'padding3', + 'hdr_crc'] +UBI_VID_HDR_SZ = struct.calcsize(VID_HDR_FORMAT) +VTBL_REC_FORMAT = '>IIIBBH128sB23sI' +VTBL_REC_FIELDS = ['reserved_pebs', + 'alignment', + 'data_pad', + 'vol_type', + 'upd_marker', + 'name_len', + 'name', + 'flags', + 'padding', + 'crc'] +UBI_VTBL_REC_SZ = struct.calcsize(VTBL_REC_FORMAT) +UBI_VID_DYNAMIC = 1 +UBI_VID_STATIC = 2 +PRINT_VOL_TYPE_LIST = [0, 'dynamic', 'static'] +UBI_VTBL_AUTORESIZE_FLG = 1 +UBI_COMPAT_DELETE = 1 +UBI_COMPAT_RO = 2 +UBI_COMPAT_PRESERVE = 4 +UBI_COMPAT_REJECT = 5 +PRINT_COMPAT_LIST = [0, + 'Delete', + 'Read Only', + 0, + 'Preserve', + 'Reject'] +FILE_CHUNK_SZ = 5242880 \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubi/display.py b/NeoBoot/ubi_reader_arm/ubi/display.py new file mode 100644 index 0000000..8081041 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubi/display.py @@ -0,0 +1,108 @@ +#!/usr/bin/python +from ubi.defines import PRINT_COMPAT_LIST, PRINT_VOL_TYPE_LIST, UBI_VTBL_AUTORESIZE_FLG + +def ubi(ubi, tab = ''): + print '%sUBI File' % tab + print '%s---------------------' % tab + print '\t%sMin I/O: %s' % (tab, ubi.min_io_size) + print '\t%sLEB Size: %s' % (tab, ubi.leb_size) + print '\t%sPEB Size: %s' % (tab, ubi.peb_size) + print '\t%sTotal Block Count: %s' % (tab, ubi.block_count) + print '\t%sData Block Count: %s' % (tab, len(ubi.data_blocks_list)) + print '\t%sLayout Block Count: %s' % (tab, len(ubi.layout_blocks_list)) + print '\t%sInternal Volume Block Count: %s' % (tab, len(ubi.int_vol_blocks_list)) + print '\t%sUnknown Block Count: %s' % (tab, len(ubi.unknown_blocks_list)) + print '\t%sFirst UBI PEB Number: %s' % (tab, ubi.first_peb_num) + + +def image(image, tab = ''): + print '%s%s' % (tab, image) + print '%s---------------------' % tab + print '\t%sImage Sequence Num: %s' % (tab, image.image_seq) + for volume in image.volumes: + print '\t%sVolume Name:%s' % (tab, volume) + + print '\t%sPEB Range: %s - %s' % (tab, image.peb_range[0], image.peb_range[1]) + + +def volume(volume, tab = ''): + print '%s%s' % (tab, volume) + print '%s---------------------' % tab + print '\t%sVol ID: %s' % (tab, volume.vol_id) + print '\t%sName: %s' % (tab, volume.name) + print '\t%sBlock Count: %s' % (tab, volume.block_count) + print '\n' + print '\t%sVolume Record' % tab + print '\t%s---------------------' % tab + vol_rec(volume.vol_rec, '\t\t%s' % tab) + print '\n' + + +def block(block, tab = '\t'): + print '%s%s' % (tab, block) + print '%s---------------------' % tab + print '\t%sFile Offset: %s' % (tab, block.file_offset) + print '\t%sPEB #: %s' % (tab, block.peb_num) + print '\t%sLEB #: %s' % (tab, block.leb_num) + print '\t%sBlock Size: %s' % (tab, block.size) + print '\t%sInternal Volume: %s' % (tab, block.is_internal_vol) + print '\t%sIs Volume Table: %s' % (tab, block.is_vtbl) + print '\t%sIs Valid: %s' % (tab, block.is_valid) + if not block.ec_hdr.errors: + print '\n' + print '\t%sErase Count Header' % tab + print '\t%s---------------------' % tab + ec_hdr(block.ec_hdr, '\t\t%s' % tab) + if block.vid_hdr and not block.vid_hdr.errors: + print '\n' + print '\t%sVID Header Header' % tab + print '\t%s---------------------' % tab + vid_hdr(block.vid_hdr, '\t\t%s' % tab) + if block.vtbl_recs: + print '\n' + print '\t%sVolume Records' % tab + print '\t%s---------------------' % tab + for vol in block.vtbl_recs: + vol_rec(vol, '\t\t%s' % tab) + + print '\n' + + +def ec_hdr(ec_hdr, tab = ''): + for key, value in ec_hdr: + if key == 'errors': + value = ','.join(value) + print '%s%s: %r' % (tab, key, value) + + +def vid_hdr(vid_hdr, tab = ''): + for key, value in vid_hdr: + if key == 'errors': + value = ','.join(value) + elif key == 'compat': + if value in PRINT_COMPAT_LIST: + value = PRINT_COMPAT_LIST[value] + else: + value = -1 + elif key == 'vol_type': + if value < len(PRINT_VOL_TYPE_LIST): + value = PRINT_VOL_TYPE_LIST[value] + else: + value = -1 + print '%s%s: %s' % (tab, key, value) + + +def vol_rec(vol_rec, tab = ''): + for key, value in vol_rec: + if key == 'errors': + value = ','.join(value) + elif key == 'vol_type': + if value < len(PRINT_VOL_TYPE_LIST): + value = PRINT_VOL_TYPE_LIST[value] + else: + value = -1 + elif key == 'flags' and value == UBI_VTBL_AUTORESIZE_FLG: + value = 'autoresize' + elif key == 'name': + value = value.strip('\x00') + print '%s%s: %s' % (tab, key, value) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubi/headers/__init__.py b/NeoBoot/ubi_reader_arm/ubi/headers/__init__.py new file mode 100644 index 0000000..474a369 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubi/headers/__init__.py @@ -0,0 +1,89 @@ +#!/usr/bin/python +import struct +from ubi.defines import * +from ubi.headers import errors + +class ec_hdr(object): + + def __init__(self, buf): + fields = dict(zip(EC_HDR_FIELDS, struct.unpack(EC_HDR_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + + def __repr__(self): + return 'Error Count Header' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class vid_hdr(object): + + def __init__(self, buf): + fields = dict(zip(VID_HDR_FIELDS, struct.unpack(VID_HDR_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + def __repr__(self): + return 'VID Header' + + +class vtbl_rec(object): + + def __init__(self, buf): + fields = dict(zip(VTBL_REC_FIELDS, struct.unpack(VTBL_REC_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + setattr(self, 'rec_index', -1) + + def __repr__(self): + return 'Volume Table Record: %s' % getattr(self, 'name') + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +def extract_ec_hdr(buf): + ec_hdr_buf = buf + ec_hdr_ret = ec_hdr(ec_hdr_buf) + errors.ec_hdr(ec_hdr_ret, ec_hdr_buf) + return ec_hdr_ret + + +def extract_vid_hdr(buf): + vid_hdr_buf = buf + vid_hdr_ret = vid_hdr(vid_hdr_buf) + errors.vid_hdr(vid_hdr_ret, vid_hdr_buf) + return vid_hdr_ret + + +def extract_vtbl_rec(buf): + data_buf = buf + vtbl_recs = [] + vtbl_rec_ret = '' + for i in range(0, UBI_MAX_VOLUMES): + offset = i * UBI_VTBL_REC_SZ + vtbl_rec_buf = data_buf[offset:offset + UBI_VTBL_REC_SZ] + if len(vtbl_rec_buf) == UBI_VTBL_REC_SZ: + vtbl_rec_ret = vtbl_rec(vtbl_rec_buf) + errors.vtbl_rec(vtbl_rec_ret, vtbl_rec_buf) + if len(vtbl_rec_ret.errors) == 0: + vtbl_rec_ret.rec_index = i + vtbl_recs.append(vtbl_rec_ret) + + return vtbl_recs \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubi/headers/__init__.pyo b/NeoBoot/ubi_reader_arm/ubi/headers/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..b1f1290f530b8a1919e077ca90e226924ff77d12 GIT binary patch literal 4676 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 self._end_offset: + raise Exception('Start offset larger than file size!') + self._fhandle.seek(self._start_offset) + + def _set_start(self, i): + self._start_offset = i + + def _get_start(self): + return self._start_offset + + start_offset = property(_get_start, _set_start) + + def _get_end(self): + return self._end_offset + + end_offset = property(_get_end) + + def _get_block_size(self): + return self._block_size + + block_size = property(_get_block_size) + + def seek(self, offset): + self._fhandle.seek(offset) + + def read(self, size): + return self._fhandle.read(size) + + def tell(self): + return self._fhandle.tell() + + def reset(self): + self._fhandle.seek(self.start_offset) + + def reader(self): + self.reset() + while True: + cur_loc = self._fhandle.tell() + if self.end_offset and cur_loc > self.end_offset: + break + elif self.end_offset and self.end_offset - cur_loc < self.block_size: + chunk_size = self.end_offset - cur_loc + else: + chunk_size = self.block_size + buf = self.read(chunk_size) + if not buf: + break + yield buf + + def read_block(self, block): + self.seek(block.file_offset) + return self._fhandle.read(block.size) + + def read_block_data(self, block): + self.seek(block.file_offset + block.ec_hdr.data_offset) + buf = self._fhandle.read(block.size - block.ec_hdr.data_offset - block.vid_hdr.data_pad) + return buf + + +class leb_virtual_file: + + def __init__(self, ubi, volume): + self._ubi = ubi + self._volume = volume + self._blocks = sort.by_leb(self._volume.get_blocks(self._ubi.blocks)) + self._seek = 0 + self.leb_data_size = len(self._blocks) * self._ubi.leb_size + self._last_leb = -1 + self._last_buf = '' + + def read(self, i): + buf = '' + leb = int(self.tell() / self._ubi.leb_size) + offset = self.tell() % self._ubi.leb_size + if leb == self._last_leb: + self.seek(self.tell() + i) + return self._last_buf[offset:offset + i] + else: + buf = self._ubi.file.read_block_data(self._ubi.blocks[self._blocks[leb]]) + self._last_buf = buf + self._last_leb = leb + self.seek(self.tell() + i) + return buf[offset:offset + i] + + def reset(self): + self.seek(0) + + def seek(self, offset): + self._seek = offset + + def tell(self): + return self._seek + + def reader(self): + last_leb = 0 + for block in self._blocks: + while 0 != self._ubi.blocks[block].leb_num - last_leb: + last_leb += 1 + yield '\xff' * self._ubi.leb_size + + last_leb += 1 + yield self._ubi.file.read_block_data(self._ubi.blocks[block]) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubi_io/__init__.pyo b/NeoBoot/ubi_reader_arm/ubi_io/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..7d403d9e25031bca37ff88acf9f9e024f35eb12c GIT binary patch literal 5903 zcmcgwTW=dh6h5=QBzBV~P1{_cP?th6Dy>BkYK2Nw^#T$?QM4&kM4*-JT_>A3>vVS= zr6_qJm3TmiM_zd0g&)LU;RlrOJF~lXXF?S4lRtm@t}EGJ z3E%h8lF!ij_!#Mn>>AlHVthveM|wv5lDrT(7WsCgBz{@^De)`C6vkCqZ%$)}@Fo75 z22@(+u7fyDIX~=#UN7tiublgUEB-(i2#@3Gvt;0fBRt080UOv{58tRrP?Z3ES&p#) z9F%pzw9ZeSl$%Cr(^#jhzbCw^UtdGXIEaZdahB^Jb8 zZ=MC0A)0h6=-4Q@hiJ(!=u(kGT)>dCLlMu&VMz%L%M#yU&-s!>?~vFwvW<&5yc=FI zoT^a1cG02TrJC)sU6P%O#QT!!rE$?8jYPWGZp7Ce-qk>c>rJw^nmXv?jxrsRPOhR` zPup?Y81#BckT&}5cr%C_=~g>xP&thx{2{oadQ|NV_JT;Y=k>6}?+58Dw(t_};n_XX zGn@$`KOdKQQV{Iu25Hdm+ZCPupu6L7|Fnh`j}N-RUK$P}<<&wZ==YS^Yo}Xj9gD`^ znc=SE$MX5;)FwuvU9twMHB91GKkT%EDBRp_-)ikWPqzk9Ypp-r45Os=_#h3U1g9sh z)nM>oFi2a(XB@QsAXYLQv^+12!qoF_;$rlw zvbZT>g1T+^R70>{GgtVe0$*;1; z_+OH5%(Gc}>W@G`yK`62DTJTI!@$awkZ@`3E+dkwAX9;BgEj805l!|Jjro6Bb2VTi4Qem%%u#bT=)2$e>GOo(Gu45yGX znj(l%-|8kbHDThDB`;P|6phRC$84XksE3@i7#N)?2J4USW0X)!V&?6&sSUP=Xvr7o z#;?tr>Xnyr0h9?ZP6I#r!(~!avOO)!SVnv~g=iRjR5b2oP^y%m>uve5ipp=N?UO}? z#8hNI^mQqrrc3wWKgq1-32uYbTj(Y&L!x{nLyxRH!c;WSKyW*X_7@2XLK36~GG9+5dx=2dRORZ3WL}92sx^I)Z z!tNTnkr0%cNZ#t^PAuWsRcCItR;rceoLXrnYaHW$u2xQY&wkMH_QNmeS;ftpNFA$k3FlIkI}Njst&F6>D+BZHKuG0>>#yNqz|Ep%G_TJLy{bM%fGNIEV{ok?qyF6wKvgog>D z>m{>@D7$19oNKDzrBPW}q;q7I(pCLJr1nP#6^xpa&D?nTQ_JDh!*+3Ep1zTryeS-M zWrcrHP12`j7463$N74RNBv0}5&~k>!P2QAYF0fM0s}nwUl~tt(ze(d`8fQ?a<6IK) zv~m^qF$h|@k%Rq=-ACW=(CQC9%{((*wV*2$1xO)y4$ zDm9rna2=<8iI(tZxvEpE)y~>PV$~kcIG{iCAw1pGAUKMggU)u)O*J!dxzA}Ztcl)T Qo7&x@SJ0e#-dX(oAMDr6OaK4? literal 0 HcmV?d00001 diff --git a/NeoBoot/ubi_reader_arm/ubifs/__init__.py b/NeoBoot/ubi_reader_arm/ubifs/__init__.py new file mode 100644 index 0000000..05774c3 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubifs/__init__.py @@ -0,0 +1,76 @@ +#!/usr/bin/python +import re +import struct +from ubifs.defines import * +from ubifs import nodes +from ubifs.nodes import extract +from ubifs.log import log + +class ubifs: + + def __init__(self, ubifs_file): + self.log = log() + self._file = ubifs_file + self._sb_node = extract.sb_node(self, UBIFS_COMMON_HDR_SZ) + self._min_io_size = self._sb_node.min_io_size + self._leb_size = self._sb_node.leb_size + self._mst_node = extract.mst_node(self, 1, UBIFS_COMMON_HDR_SZ) + self._mst_node = extract.mst_node(self, 2, UBIFS_COMMON_HDR_SZ) + + def _get_file(self): + return self._file + + file = property(_get_file) + + def _get_superblock(self): + return self._sb_node + + superblock_node = property(_get_superblock) + + def _get_master_node(self): + return self._mst_node + + master_node = property(_get_master_node) + + def _get_master_node2(self): + return self._mst_node + + master_node2 = property(_get_master_node2) + + def _get_leb_size(self): + return self._leb_size + + leb_size = property(_get_leb_size) + + def _get_min_io_size(self): + return self._min_io_size + + min_io_size = property(_get_min_io_size) + + +def get_leb_size(path): + f = open(path, 'rb') + f.seek(0, 2) + file_size = f.tell() + 1 + f.seek(0) + block_size = 0 + for i in range(0, file_size, FILE_CHUNK_SZ): + buf = f.read(FILE_CHUNK_SZ) + for m in re.finditer(UBIFS_NODE_MAGIC, buf): + start = m.start() + chdr = nodes.common_hdr(buf[start:start + UBIFS_COMMON_HDR_SZ]) + if chdr and chdr.node_type == UBIFS_SB_NODE: + sb_start = start + UBIFS_COMMON_HDR_SZ + sb_end = sb_start + UBIFS_SB_NODE_SZ + if chdr.len != len(buf[sb_start:sb_end]): + f.seek(sb_start) + buf = f.read(UBIFS_SB_NODE_SZ) + else: + buf = buf[sb_start:sb_end] + sbn = nodes.sb_node(buf) + block_size = sbn.leb_size + f.close() + return block_size + + f.close() + return block_size \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubifs/__init__.pyo b/NeoBoot/ubi_reader_arm/ubifs/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..78a262602e5d1a839f6e1eae2f576132e8e9fa60 GIT binary patch literal 3374 zcmd5;-EJFI5T4z&9ow;!w560*2nit}Q;AqAmmma5T3SIJwCRtqsE%y!ak|cWH{Cs! zQWRemiA&ys7vUjz3@&&8_`cb0oeC}}QX-P<$;@~DzBy;k%mjaQ+Yf&E>HCSi{0Z>? z3w%Y6Cc>X5iOBGk?8(qm+?T|c2OJSd63DzJ!9kvX51CX4|nd}IWW8X_wVly%-y}v91L9(xTyxMLz%~^i8E8gKUl|= z%~^n>6FV+@TkL(Mv1?wqayRX&w4RdT`4u*qI{J}1fimqu6K#rpNc}~T_mgSxfBVGQw1_i^1Dow+nd@UMliN{bbBfcVZ%mxV&X{e?C96uO zb;Sl6@j711yXtM?_Z@G-ldL|yVV)cBjfc&S(&0mTuj=6@C4A>dTu<=OIz6PfuvNiR zlz-2bmR}fK9*7~^VsUKqagt4rt^;~g&b*upx5Bppgd7@PW5bZKib^V- zM@$WA1NSO!plSH6Rx9ZEfB!VDk~71p#??m%rpTOSxzGOS=irbJQU)6HRvL&ZT-kYF^?2RE? z;suI z+h+If!@<`q4>*mQ+QNj9Hn zsd*aZA$`Hod03Pf_x!lrw5&`Hb_^Ffv+hfTOae?wY#KK3U!7ienj~3awE|MA$0PSt z3)87?!k1RoDhwW)mP(b>VqJ2)nCgUi_z^H&WCEgUD9R$W1a1Ux9~+xSI;R+?t9N!D zPfVXW(`gkiKOuo_G=h?43%^~j;a!J(9i_|-lrnAnz6UDh7~jR2ipJxQ->7D zFk#&9_ujqKp z?Li6lh#}i0B9F+!6fNwAkfs(CkQx-NTSEcT&!IwUv^k$`|8}d$?N*;nL)%44plzz& zk30?|npVM+AX00i3-y}9C@1OmhySINcH7^LIuh%>zM-ftDI0Ir6@r<6&1dV=P5^ZL z^l!^o{^H;JfB1Vp`QG(E{_>8`pZcfUPa8)kXy1npFuz~r`;gxUK8%=t3VHV)$Cnt& z8Izx)J>hN9D0TQ$e~xbANl`OtNBY1s3NESD)J60e8hAL^0eRX(PJA-2B-}b0&SGoM<(`5 zC+)^#C}6*tKJ8?i{%0&WHjJBtGm*VY`a$H6fEY8K_NfPsi#t8wX7J4MV%*%xo&l|dwaHGU|rW3J3eCUL!`u~=QWu^d-_8SO7 zZzoYi%>J_aS>(hxQ!^s?YYdX1>vzcr_%WA!pGUt7;+$_xyI?PZdag%IL5whKI478P zqW+XeKY^+)fMFHo&5-99Xn&jG?~^Fk_UZ2=LEf zn=bwzA+zG*pQ1gL4CD_$e%V$33-Ajrz90O&i~kaI$}axL;0rGP55bSQ_z~#GT|Duq z(|$a>i~5+W{@dWYUHmF|!^O{l54!ljrZE@)r(joABaF{qLH?GD{|}Vibn$P4UvcpV zA;0Y6KZkmq=CRqio*AOXB#@nf|_^#F@dtkz=EY(Z2qnV+lzlCa3ecM6r~# zN(r!;T&5(6$wDHXDHbF#0Uk1`3rRjEvzf1&l6dM|V%VI_6icRcG@C3I&7#CF_F0pO zc+x7Gqcer9iGq=mmB~#e2Ce+G^VpY5k5E5;@sv58IF-z1^Qm>YzM>-~*{|jgUP$B% zrOfoY^q^%@@t9>LPUoSXw=ODn#4IUAr+P4NO(#prO4>~2rwf)@EGCM{36rIXl$Cno z5R^~mO15)D`P`%uKYaLbLMuq3)`elSNKYKc4z5ekS~8tAE!bn+z#~>HC6_qIRuU)i zcq*Ts$(lW2ou|Zcvow%Nl~fl_o9B;RNSWwyK8GUKB+#vsB~wKXg?B{L?#nsTDpHAU zs%H!(<6c*kPL|+)W*lONqQ!jl5Sc=0$}*E_^4;W9e0mZ?UNSEL0uxY55($zpoyWvD z!$_c@7SE{2rRDh0$^N5>L$JxjbBpumeg-r@a>DXsCtBm#ptc8QGT3hXa#jl{xfs?u zuJZ#bA5wW-<)bQpR^?+VPpdqu@`B1sD!-)ivdU*wKBw{?tkG=OFME$! zi&y5GaaJ1cc)Vp8JIGkjC;j1ai(f)5DU8;|Iog2S8*cv^DyBp5FCfM)#<59^z*_5Un0n-OY;S(Y z>HjkNAD3%OA!9+p<*!wqg>DPtFoYPKKnw;DgBW6PM3xbg*E$XPVJH1A@3|hHLwk^g zZ`a}1V&qGRQ$(&+L@v*-%F(Vb%GmDzl>V+~D2KTDWPaW+&(F*AKyS}BoQDJMi~f?p)3>`^M|@){xJF!kwuL6@)G+Nl!YbAb)#&) zrW^Bvuk^qN)`jHHRVpTz`>~V@?oMn?)OTAG>49&%3wvVf-PsyRSOi;Y zu>n2@fX^7Pc?8((-2j`J8aCg=SoD9U*T&`|uz3{NOn3E28Q4s99m2e1jC~RZHV5V# zP;cWCKdb`M4{SEnVH4*<7dD4G9BdAYp|FXu7CRmhj5)?Eat8)uI0n6gd3~)ihZqub z#9O1xhC`7U@o4K4llxp)djwdcpXj%ZH}oAiyHP>kZLFOD);7a{t%Dzc#K1;+Zmj)l zRf6>U<(b;xxdiozk$zPE}zYs&&!o@VD9oOKnZ*c zT`l-ShJ&#dF*`Unk1JWUQ#mb92lYC*T^f$qeZ$)Ggv6S;4tA@4?~-DNAwQ^athwJ% zZa~I^-1mN2#r^|XtWDU1u3?=Nf1`ACMAX_JgzuE^MceN65q#yh6lNo^{W$iy&tXmR zcLc@17t|a?Tj52&v@Hf;o3U?{w}K7Qz4)@@n>}WYay^VVas90zRu#mmf;hrI2kU1M z_iot7TaP)equbFYo?mC*8szevUQ0QK^wW)R+TF}1#~pje5w6v5VZ5okidZlX?}9%I zAF0pr-^>Pm5V-=s^m=+l`E><;IqNCors8+UdiwXS^>nMYh`pw7)z1x%rF$-dP6_%Uza!J7Ua*7O_jcX=s{ zx-p|6?3YHY$lL6_ra`uI?*vxg!5a7;aCigr(!oZ|UI)L1xISMA<6LwJZT%{MnDmOo zI|)teV~m2$Z+hr29O8daTc1blu#}YV_oi6YkFDLV~y7P;H!{nc=&oa z-Z}odV?+G3LH&ZVdmn7rb}`quM^guL*nb3iwhrv^Oh6gpc?x~wxxj7X#3nZ4o7i|- z*?2+uz_~#CdVQ<))#KB%o7nqxWpC7DPxo;%dsCa(!T^Ws|d;6t=T_PUFzTx1({ae`m8#ZRwJHK^Tb{y{f z!rJD)VT)}z#i|!MX4>HE2;*EPpH1?OiP4^6<0tSg!?X<3vhtR3z{upz;cZpg(64ip znn7lC^bxEFzY5x8pv@U6E> z0iE-Cbjma)W^yTRH$`kMMrkTjG^Xvh`UbyaoL}EJupuRL*rRG+9=Ju#6uF<2UGvLPtgKv2Lw1>f_bM8nyk~t#Y?vXWX3Tx@w(Bn-j^IY{@g0T{iYCvovGnIKTi= zCRZ{i5o9&i^@!_oifd!I8Sw7(fLOM{SHqD}u=3|JX*0c*6FWqQ(Hj68LQYRzQ$}}H zYjHx^crC_zsWDFfZU@jSu4;-|v&F;P1nw z9h-0S$u;m zea20W@|xOH$;Cmu-^05<>?3ae)YYFriLPf%km~AtUGF< zIh{#KbShb#vf1LrX(umPVhigp_iiSEI?K#bU81}~AW{2UeDu`G_(-%^ni(%j)V`4s zwet2i`KURSn6Q%5rbJVvyoKttlYKb_TaL(N9(Ib(Gr!tL3u)y;vV@&|9BV!br_<*6 z%w#kegbTyW2vW{{9}%pb^gXUlaIj~~x$iZyjEQnh zpl(nji1uRmNBU<#o@GpwBRvVCkCfxRLDB*k-3Da{G5k!I0ElwDXGr4xLY?$%8bkr0 zoM#p90g^`XtlMQdX#~W(gM8-wL6U)Iwo6-VmuVb?DqDy57D@PQRkKGq_V+mu^{CG~ zTBNIZ)=As@3JSCw?}CwTx-RcI(@EsKOOA7uv_M6bw7o0fwLRWdBgM54axM4!N{+}W zLxwcqu}AisN{(^)Db_TSwt=GB^LLdT$Hck+>coLEOj>6V&$LUq_p#=^k41&?(n-tx z7zJ8x4RULc({+^9&u_To#DIo@xG?A{>G=Hwys{VM9lM1Nk(ad)a>~)>pMbO+*TWtF zT(^a)+VcvY={NfkgIq7<3_Rl>0Z$AlGvL3z0%TC;$Ke literal 0 HcmV?d00001 diff --git a/NeoBoot/ubi_reader_arm/ubifs/misc.py b/NeoBoot/ubi_reader_arm/ubifs/misc.py new file mode 100644 index 0000000..658068b --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubifs/misc.py @@ -0,0 +1,46 @@ +#!/usr/bin/python +#import lzo +import struct +import zlib +from ubifs.defines import * +ino_types = ['file', + 'dir', + 'lnk', + 'blk', + 'chr', + 'fifo', + 'sock'] +node_types = ['ino', + 'data', + 'dent', + 'xent', + 'trun', + 'pad', + 'sb', + 'mst', + 'ref', + 'idx', + 'cs', + 'orph'] +key_types = ['ino', + 'data', + 'dent', + 'xent'] + +def parse_key(key): + hkey, lkey = struct.unpack('> UBIFS_S_KEY_BLOCK_BITS + khash = lkey + return {'type': key_type, + 'ino_num': ino_num, + 'khash': khash} + + +def decompress(ctype, unc_len, data): + #if ctype == UBIFS_COMPR_LZO: + #return lzo.decompress(''.join(('\xf0', struct.pack('>I', unc_len), data))) + if ctype == UBIFS_COMPR_ZLIB: + return zlib.decompress(data, -11) + else: + return data \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubifs/nodes/__init__.py b/NeoBoot/ubi_reader_arm/ubifs/nodes/__init__.py new file mode 100644 index 0000000..d2b3346 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubifs/nodes/__init__.py @@ -0,0 +1,151 @@ +#!/usr/bin/python +import struct +from ubifs.defines import * +from ubifs.misc import parse_key + +class common_hdr(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_COMMON_HDR_FIELDS, struct.unpack(UBIFS_COMMON_HDR_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + + def __repr__(self): + return 'UBIFS Common Header' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class sb_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_SB_NODE_FIELDS, struct.unpack(UBIFS_SB_NODE_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + def __repr__(self): + return 'UBIFS Super Block Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class mst_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_MST_NODE_FIELDS, struct.unpack(UBIFS_MST_NODE_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + def __repr__(self): + return 'UBIFS Master Block Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class dent_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_DENT_NODE_FIELDS, struct.unpack(UBIFS_DENT_NODE_FORMAT, buf))) + for key in fields: + if key == 'key': + setattr(self, key, parse_key(fields[key])) + else: + setattr(self, key, fields[key]) + + setattr(self, 'name', '') + + def __repr__(self): + return 'UBIFS Directory Entry Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class data_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_DATA_NODE_FIELDS, struct.unpack(UBIFS_DATA_NODE_FORMAT, buf))) + for key in fields: + if key == 'key': + setattr(self, key, parse_key(fields[key])) + else: + setattr(self, key, fields[key]) + + setattr(self, 'offset', 0) + setattr(self, 'compr_len', 0) + + def __repr__(self): + return 'UBIFS Data Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class idx_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_IDX_NODE_FIELDS, struct.unpack(UBIFS_IDX_NODE_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'branches', []) + + def __repr__(self): + return 'UBIFS Index Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class ino_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_INO_NODE_FIELDS, struct.unpack(UBIFS_INO_NODE_FORMAT, buf))) + for key in fields: + if key == 'key': + setattr(self, key, parse_key(fields[key])) + else: + setattr(self, key, fields[key]) + + setattr(self, 'data', '') + + def __repr__(self): + return 'UBIFS Ino Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class branch(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_BRANCH_FIELDS, struct.unpack(UBIFS_BRANCH_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + def __repr__(self): + return 'UBIFS Branch' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubifs/nodes/__init__.pyo b/NeoBoot/ubi_reader_arm/ubifs/nodes/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..f674057fac37f321ce83e3a8a03a040f2c0abb41 GIT binary patch literal 8985 zcmd^EZEqVz5S}~d{iRKlHk2a3v|p^Ms!>0o3L)Y+r2*ogbxI+kIyt^|a*chL-mcXY zr5{i#AtAmX_znCh{sun)=9%-IO`9}9O=4GZyqmf8+A}*Z&(7@T{+^y#`}5}?>ePAV z`2XkJ%wOF3{C22Gw4Tr|H62>RXpWjLwQ{tcBgY>iJwy$M{9$@Qv`_T?`Y`z;>F8)S zIzs+fIy#<>j*>r-j!tHyW8_bzqtn^wIQbXS(TmyW1o<=R=%s9QlKk0pbS@j6!jh_m z%e=hcAAVH|4wDw$&4e6ha;Fv>?QQF4c7mVkQL7b&-j*L{dcyn?H*K zU;rXVzAMBKscHd=t-IU}aU0>b$jz`~$qIYxlFiZMA+p1?=g__@Z-<_{w0oWQTq-}h zM$dC(M`({|FNY!S-`!^mJSot_WSm)VvI$@n;#GoQg+E~t<2Z^;@vMR@80s#*X62w+1R+v)A2j)aHm$^KI9v#YGq-~f``$z zW^G&mE8%B!vmyL8+70=kMxdL%ks(%df#;EQ<^fa1wuy_)V56wRV6#=bQ`~uGx1zB4 zO|!ijgr>N(YjtRXh{=kMN>OBs?Tx^TbT>92|GEMw` z*yBaejVEp_M)QMMV#C;4Y|YcaZi(SHJBEiCq7Zd~sWa3{U^Q!HmYEv(D>-w{MW+Cb zbnGA2TH5nOcF$`?e!Iz!3Tjj{=&o?rl~<_KGo^x_Ag2gB;*O7w=aK;0@Zi9(qP(E} z61O+Rn=kn%P6ltpGayw(Kt&;1l&BfdnxILwN6 zQ$_`KiCG9JD1@8>NGe!YK=W(?KqB`#^L{z-73`z1$@MMFuQGGAG|Y!N%n=DKW8d01 z2T&$)zEWK~B+w6+nQl9lNRIsryVEy{CVb)DVlPA-Hbf5l6nj!e6Qt1^`DsV6i?)MdQj~ zf>Q>;k(#ZYWX_P`$nVUo&p49cjX(4sTtQLM!4+63YBczCAz+F`AAC5&b#POMufdsx zwS_|xlpdVvP8v9zS>?qVlt8^WGjnudf~vNIH0(8fg%_N3olAImgoO_tyxd^1R#MRz zUM4#gN#O6EB)VYXlBK}@N2ALdo^&G9*obRkeM={2ojqwsw-i|}e|HEP95km32K~=B zGz^ACCOB}6Tmwg12?8vKzTWLC1n@<|`GkN73m-fPK$TKYMeCeB!nuMlI!Oq~5{v;Y zRD9kVRi4-VasttV29?#L5hI(^MT`L{Q=Y=e|GP{ 1: + if 'hlink' not in inode: + inode['hlink'] = dent_path + buf = process_reg_file(ubifs, inode, dent_path) + write_reg_file(dent_path, buf) + else: + os.link(inode['hlink'], dent_path) + else: + buf = process_reg_file(ubifs, inode, dent_path) + write_reg_file(dent_path, buf) + if perms: + set_file_perms(dent_path, inode) + except Exception as e: + ubifs.log.write('FILE Fail: %s' % e) + + elif dent_node.type == UBIFS_ITYPE_LNK: + try: + os.symlink('%s' % inode['ino'].data, dent_path) + except Exception as e: + ubifs.log.write('SYMLINK Fail: %s : %s' % (inode['ino'].data, dent_path)) + + elif dent_node.type in [UBIFS_ITYPE_BLK, UBIFS_ITYPE_CHR]: + try: + dev = struct.unpack(' len(buf): + buf += '\x00' * (inode['ino'].size - len(buf)) + return buf \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubifs/walk.py b/NeoBoot/ubi_reader_arm/ubifs/walk.py new file mode 100644 index 0000000..d8b8020 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubifs/walk.py @@ -0,0 +1,33 @@ +#!/usr/bin/python +from ubifs import extract +from ubifs.defines import * + +def index(ubifs, lnum, offset, inodes = {}): + chdr = extract.common_hdr(ubifs, lnum, offset) + if chdr.node_type == UBIFS_IDX_NODE: + idxn = extract.idx_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ) + for branch in idxn.branches: + index(ubifs, branch.lnum, branch.offs, inodes) + + elif chdr.node_type == UBIFS_INO_NODE: + inon = extract.ino_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ) + ino_num = inon.key['ino_num'] + if ino_num not in inodes: + inodes[ino_num] = {} + inodes[ino_num]['ino'] = inon + elif chdr.node_type == UBIFS_DATA_NODE: + datn = extract.data_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ, chdr.len) + ino_num = datn.key['ino_num'] + if ino_num not in inodes: + inodes[ino_num] = {} + if 'data' not in inodes[ino_num]: + inodes[ino_num]['data'] = [] + inodes[ino_num]['data'].append(datn) + elif chdr.node_type == UBIFS_DENT_NODE: + dn = extract.dent_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ) + ino_num = dn.key['ino_num'] + if ino_num not in inodes: + inodes[ino_num] = {} + if 'dent' not in inodes[ino_num]: + inodes[ino_num]['dent'] = [] + inodes[ino_num]['dent'].append(dn) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ui/__init__.pyo b/NeoBoot/ubi_reader_arm/ui/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..0c87ff186b1c32a2a48535d4704c0855215fdba2 GIT binary patch literal 163 zcmZSn%*z$BtUV@~0SXv_v;zA8tU`URCG8Tono0Xe1VnR&(ft`#MzdBvIeK&D@6zEggFiGFEPW_(d most_frequent: + most_frequent = occurances[offset] + block_size = offset + + return block_size \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/__init__.pyo b/NeoBoot/ubi_reader_mips/ubi/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..ca8b1f64fbb2a2831f0a4ae85dbdfed922a93639 GIT binary patch literal 6092 zcmc&&OLH5?5$**@kN^R`B$}i|$+8o>;G{~3orm&}okXN;t75b4l^r^;RT}`ipcY*0 zg1ZBSOo5lkha6Km+kH7up ztDfXPW&HmYzU;3keEc~QiL`CKB#|S-lC(?Wu&*ppS%y>6o|56Tw5MfQk#@!QO-VE( zpOI=>qFEVMrCqf>6^UvxoRfClwr6yfhO`@K&x$`MepS8}c`EX|Hrh2d+Vf=PVY3dl z!vElByXl~6=1}Yg#(R=P<6)3B$-kLGktL}y%Xx1%N_u;l7sg%`X2#3|4h~G(=^4*< z*~vKL_iS|rRX@x|QRnbvAwS4^X*e=r5?inWDo`Y2W4Q3R8}{%|f7rf z;JkwK3NDC0qu`=~iwZ6Y6wig0bKSSEXfMiTd5R6cT5Q9L;ww7p748*Bttz;x;F|b# z1=kf^SMZwn4F#_&cwNB_@v*53@-@W2A@0NGBGlC@p{U`bYB%v^pFn>TM8E0#%MyG4qZQ~1Y|Y9pw1BZ2a`3L08x)K(t4Uz&)}uG&$O^O}gPUSrEoPaO zNmbTC0@cVMpo#h=SN~<8p|H)pmP5%xg>)!2N?>phw8n1I#J9hn_hc1?CFr?Rm;) zwdZw-xZg3IGw4;KVXSBW`HpeC7bky+&vekPLKCDSJxl*@b|rS&4{i=$i$YTZ?uj7Q$6Lv_+Y zy+B~@NhiyaUf3}~E`n(QJhKN@{o$~)3t_lfX(xs+cjfg zS=r4c+c^*F9m%$ep)GZ|xss28Lb(bofWDJ=K1q7bKw-vwtG--2^fTSQjST6fl*>!@!yJ+fGQ zn;gq6Cp&Z!;%@DrhIdTUniRs;F1`og?VJy+A6j5 zvMlqUTqesa1y^ftw(evvoR$rJ4v@5q~{Npf{IZi`KP z7wh)vE<9Y`XCEzFKwsAJDEpV_E0uHW+)q8XJ~#*GH>l)GY+QKKg%5Q?K?e z9WbsVpWD_tYiH0 zgk^)OjREN~7-Oh|p$A77ECnV5PlIrV35YXh!w0a-=iZ64(U`<^x)<(mTrU25e7VIm zZ=#;RJ>$+W@H|6%_q<`^k0Uf)-ox(O1=T1`MnP&0UA6sp2=f(hpG)o!+2&q9`xbG3 z1kinz1@A?TpI&fhx<4s8UvMG0ci71tIpyu$pQ7#ljKym#cx$OR#nEm1Q_#c#G6k?s5Flei>tq{!pqP?XWEGD48HOMHSzwwVMp^+u83O#R zM@AD57&WaBR;tK>OFI}KFMuc>DIv!B?=ep>nPK_@vm-HplXn7$9rt{v9=Bf9T+EXVQQ(;9l9J2C_qlhPxsE zg}hptv_Xx3anRyC5DxaVVuC1gzr%hKz5n2&``+eHV}O?0-&1sY@^VF=%OIx*oG{9|}5_Y+U>XDfGI88jcv<;iZqSIoh zA7E>PO#O%YtK(tnh+Vp5_YD@@D7TB^L~$4C(bVkj+PmXD@~ug`I^^Gg2B^8k(v|jq E0dMS8)&Kwi literal 0 HcmV?d00001 diff --git a/NeoBoot/ubi_reader_mips/ubi/block/__init__.py b/NeoBoot/ubi_reader_mips/ubi/block/__init__.py new file mode 100644 index 0000000..7d8c1de --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/block/__init__.py @@ -0,0 +1,59 @@ +#!/usr/bin/python +import re +from ubi import display +from ubi.defines import * +from ubi.headers import * + +class description(object): + + def __init__(self, block_buf): + self.file_offset = -1 + self.peb_num = -1 + self.leb_num = -1 + self.size = -1 + self.vid_hdr = None + self.is_internal_vol = False + self.vtbl_recs = [] + self.ec_hdr = extract_ec_hdr(block_buf[0:UBI_EC_HDR_SZ]) + if not self.ec_hdr.errors: + self.vid_hdr = extract_vid_hdr(block_buf[self.ec_hdr.vid_hdr_offset:self.ec_hdr.vid_hdr_offset + UBI_VID_HDR_SZ]) + self.is_internal_vol = self.vid_hdr.vol_id >= UBI_INTERNAL_VOL_START + if self.vid_hdr.vol_id >= UBI_INTERNAL_VOL_START: + self.vtbl_recs = extract_vtbl_rec(block_buf[self.ec_hdr.data_offset:]) + self.leb_num = self.vid_hdr.lnum + self.is_vtbl = bool(self.vtbl_recs) or False + self.is_valid = not self.ec_hdr.errors and not self.vid_hdr.errors + return + + def __repr__(self): + return 'Block: PEB# %s: LEB# %s' % (self.peb_num, self.leb_num) + + def display(self, tab = ''): + display.block(self, tab) + + +def get_blocks_in_list(blocks, idx_list): + return {i:blocks[i] for i in idx_list} + + +def extract_blocks(ubi): + blocks = {} + start_peb = 0 + ubi.file.seek(ubi.file.start_offset) + peb_count = 0 + cur_offset = 0 + for i in range(ubi.file.start_offset, ubi.file.end_offset, ubi.file.block_size): + buf = ubi.file.read(ubi.file.block_size) + if buf.startswith(UBI_EC_HDR_MAGIC): + blk = description(buf) + blk.file_offset = i + blk.peb_num = ubi.first_peb_num + peb_count + blk.size = ubi.file.block_size + blocks[blk.peb_num] = blk + peb_count += 1 + else: + cur_offset += ubi.file.block_size + ubi.first_peb_num = cur_offset / ubi.file.block_size + ubi.file.start_offset = cur_offset + + return blocks \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/block/__init__.pyo b/NeoBoot/ubi_reader_mips/ubi/block/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..4865745f9ed746f4526cf547dc675b7063484c25 GIT binary patch literal 3082 zcmcgu&2Ah;5U!s6x7Ue@V>^h17(&7dq%49%L=;8DKY*oViDpdzD^Y89X4and?967m zH#jIcIRcJINSrzIC>#(Ez%y{+0pP2e8GFOs@w$7ftE;N3s;leU%0CNpzy9*mL!XMj z3cf$VFb^>W_*WDY?dG&Yv7)g7UCAZ(HLeytP9yN>&46}@bpz(}I9}_T^bHo^L!5E25jci?r z2JPjXCfOD}gNj3Tj@~-THRoAqG*6>8nZL*`utdQ*b3)j&v|4J^gk7W2BH7pIK$g1k ze`fYO*>f|-mgsVEVv`baXap1ISxr04vCCqjNf4X-U3$MFOmVNB&MWo|YHez>-YN&% z?{G2n*eOqsB=+8G@ z-QUHXKq%i7GRxA;i1AXjJetiFbQuG)*xZBd%~^YJMMr^MDR#GeJ6mq=&RzZBi@UnN zbI0AWi+pO~TIq0JvYz!y>zsg?)5F9dMSNWAh?zC4yaUi)90eUNOc66-Jd`vH;?zIT zgXyq?Et1K64XQgeSvQUb-7tyv#@>hB$y2+ZCf)n-bT3Lwck9rGiNT98-Cmfkr>X5u z2N4qL1!1Pg(Zuk&E9Scz>5r_|*I|VHDc5`t=50)*S}%Q8R9jtB%j%rEh;cz(Qa(Rd z9$Yl?uFiwVU(qNpOGQJ6R{9cT&#Yp5orAl%c7JRA%Gy>>x($j@V$_-JRdiZmjcDsNZvPI`BB~;`{H*m4~8|R=q2Gfk0Y{d#d?ER z6q(C@T*fFO>TrIGD^I*}s5Lqm-~Tubrg-Dpy@aLvCQleM7jXKO=yKBer5JwDb*Ht| zsvIYu_c(QitLz67&{6a~3Qf@_8eLIkQk5*r#k9oo91pq~y4<5Bdame4QF$F|KRfie z4n+tQak8T2>G}tjOFPPeiQSQFG^d{g!`E>uhL zWAhl;W!XF3hH(zZ?1fh6DM2R@7p|0^Qr;SxSo0-pFuw-Za0y618pLx)ps0L6Xci-f zu}bkCU>9?h4*%q*!YC!%1yL@RR=DS0g#}RtqUGQ5!O4p|-9nxH9g!F7yYR;Fn<7=mXGP}sfoErdZ!NWm z?*+BsEUG27=yW(tX$M*8egs-NqM$u8aXko!Q4*Tt^}Zmjksl`MU=;c`&o4*oevIiP fY@tp!_9hOzl{fX<+|dkIR2vb_sX1rmVypTe= slist_len: + add_elements = blocks[block].leb_num - slist_len + 1 + slist += ['x'] * add_elements + slist_len = len(slist) + slist[blocks[block].leb_num] = block + + return slist + return sorted(blocks.iterkeys(), key=lambda x: blocks[x].leb_num) + + +def by_vol_id(blocks, slist = None): + vol_blocks = {} + for i in blocks: + if slist and i not in slist: + continue + elif not blocks[i].is_valid: + continue + if blocks[i].vid_hdr.vol_id not in vol_blocks: + vol_blocks[blocks[i].vid_hdr.vol_id] = [] + vol_blocks[blocks[i].vid_hdr.vol_id].append(blocks[i].peb_num) + + return vol_blocks + + +def clean_bad(blocks, slist = None): + clean_blocks = [] + for i in range(0, len(blocks)): + if slist and i not in slist: + continue + if blocks[i].is_valid: + clean_blocks.append(i) + + return clean_blocks + + +def by_type(blocks, slist = None): + layout = [] + data = [] + int_vol = [] + unknown = [] + for i in blocks: + if slist and i not in slist: + continue + if blocks[i].is_vtbl and blocks[i].is_valid: + layout.append(i) + elif blocks[i].is_internal_vol and blocks[i].is_valid: + int_vol.append(i) + elif blocks[i].is_valid: + data.append(i) + else: + unknown.append(i) + + return (layout, + data, + int_vol, + unknown) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/defines.py b/NeoBoot/ubi_reader_mips/ubi/defines.py new file mode 100644 index 0000000..668b197 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/defines.py @@ -0,0 +1,63 @@ +#!/usr/bin/python +import struct +UBI_CRC32_INIT = 4294967295L +UBI_MAX_VOLUMES = 128 +UBI_INTERNAL_VOL_START = 2147479551 +UBI_EC_HDR_MAGIC = 'UBI#' +EC_HDR_FORMAT = '>4sB3sQIII32sI' +EC_HDR_FIELDS = ['magic', + 'version', + 'padding', + 'ec', + 'vid_hdr_offset', + 'data_offset', + 'image_seq', + 'padding2', + 'hdr_crc'] +UBI_EC_HDR_SZ = struct.calcsize(EC_HDR_FORMAT) +UBI_VID_HDR_MAGIC = 'UBI!' +VID_HDR_FORMAT = '>4sBBBBII4sIIII4sQ12sI' +VID_HDR_FIELDS = ['magic', + 'version', + 'vol_type', + 'copy_flag', + 'compat', + 'vol_id', + 'lnum', + 'padding', + 'data_size', + 'used_ebs', + 'data_pad', + 'data_crc', + 'padding2', + 'sqnum', + 'padding3', + 'hdr_crc'] +UBI_VID_HDR_SZ = struct.calcsize(VID_HDR_FORMAT) +VTBL_REC_FORMAT = '>IIIBBH128sB23sI' +VTBL_REC_FIELDS = ['reserved_pebs', + 'alignment', + 'data_pad', + 'vol_type', + 'upd_marker', + 'name_len', + 'name', + 'flags', + 'padding', + 'crc'] +UBI_VTBL_REC_SZ = struct.calcsize(VTBL_REC_FORMAT) +UBI_VID_DYNAMIC = 1 +UBI_VID_STATIC = 2 +PRINT_VOL_TYPE_LIST = [0, 'dynamic', 'static'] +UBI_VTBL_AUTORESIZE_FLG = 1 +UBI_COMPAT_DELETE = 1 +UBI_COMPAT_RO = 2 +UBI_COMPAT_PRESERVE = 4 +UBI_COMPAT_REJECT = 5 +PRINT_COMPAT_LIST = [0, + 'Delete', + 'Read Only', + 0, + 'Preserve', + 'Reject'] +FILE_CHUNK_SZ = 5242880 \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/display.py b/NeoBoot/ubi_reader_mips/ubi/display.py new file mode 100644 index 0000000..8081041 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/display.py @@ -0,0 +1,108 @@ +#!/usr/bin/python +from ubi.defines import PRINT_COMPAT_LIST, PRINT_VOL_TYPE_LIST, UBI_VTBL_AUTORESIZE_FLG + +def ubi(ubi, tab = ''): + print '%sUBI File' % tab + print '%s---------------------' % tab + print '\t%sMin I/O: %s' % (tab, ubi.min_io_size) + print '\t%sLEB Size: %s' % (tab, ubi.leb_size) + print '\t%sPEB Size: %s' % (tab, ubi.peb_size) + print '\t%sTotal Block Count: %s' % (tab, ubi.block_count) + print '\t%sData Block Count: %s' % (tab, len(ubi.data_blocks_list)) + print '\t%sLayout Block Count: %s' % (tab, len(ubi.layout_blocks_list)) + print '\t%sInternal Volume Block Count: %s' % (tab, len(ubi.int_vol_blocks_list)) + print '\t%sUnknown Block Count: %s' % (tab, len(ubi.unknown_blocks_list)) + print '\t%sFirst UBI PEB Number: %s' % (tab, ubi.first_peb_num) + + +def image(image, tab = ''): + print '%s%s' % (tab, image) + print '%s---------------------' % tab + print '\t%sImage Sequence Num: %s' % (tab, image.image_seq) + for volume in image.volumes: + print '\t%sVolume Name:%s' % (tab, volume) + + print '\t%sPEB Range: %s - %s' % (tab, image.peb_range[0], image.peb_range[1]) + + +def volume(volume, tab = ''): + print '%s%s' % (tab, volume) + print '%s---------------------' % tab + print '\t%sVol ID: %s' % (tab, volume.vol_id) + print '\t%sName: %s' % (tab, volume.name) + print '\t%sBlock Count: %s' % (tab, volume.block_count) + print '\n' + print '\t%sVolume Record' % tab + print '\t%s---------------------' % tab + vol_rec(volume.vol_rec, '\t\t%s' % tab) + print '\n' + + +def block(block, tab = '\t'): + print '%s%s' % (tab, block) + print '%s---------------------' % tab + print '\t%sFile Offset: %s' % (tab, block.file_offset) + print '\t%sPEB #: %s' % (tab, block.peb_num) + print '\t%sLEB #: %s' % (tab, block.leb_num) + print '\t%sBlock Size: %s' % (tab, block.size) + print '\t%sInternal Volume: %s' % (tab, block.is_internal_vol) + print '\t%sIs Volume Table: %s' % (tab, block.is_vtbl) + print '\t%sIs Valid: %s' % (tab, block.is_valid) + if not block.ec_hdr.errors: + print '\n' + print '\t%sErase Count Header' % tab + print '\t%s---------------------' % tab + ec_hdr(block.ec_hdr, '\t\t%s' % tab) + if block.vid_hdr and not block.vid_hdr.errors: + print '\n' + print '\t%sVID Header Header' % tab + print '\t%s---------------------' % tab + vid_hdr(block.vid_hdr, '\t\t%s' % tab) + if block.vtbl_recs: + print '\n' + print '\t%sVolume Records' % tab + print '\t%s---------------------' % tab + for vol in block.vtbl_recs: + vol_rec(vol, '\t\t%s' % tab) + + print '\n' + + +def ec_hdr(ec_hdr, tab = ''): + for key, value in ec_hdr: + if key == 'errors': + value = ','.join(value) + print '%s%s: %r' % (tab, key, value) + + +def vid_hdr(vid_hdr, tab = ''): + for key, value in vid_hdr: + if key == 'errors': + value = ','.join(value) + elif key == 'compat': + if value in PRINT_COMPAT_LIST: + value = PRINT_COMPAT_LIST[value] + else: + value = -1 + elif key == 'vol_type': + if value < len(PRINT_VOL_TYPE_LIST): + value = PRINT_VOL_TYPE_LIST[value] + else: + value = -1 + print '%s%s: %s' % (tab, key, value) + + +def vol_rec(vol_rec, tab = ''): + for key, value in vol_rec: + if key == 'errors': + value = ','.join(value) + elif key == 'vol_type': + if value < len(PRINT_VOL_TYPE_LIST): + value = PRINT_VOL_TYPE_LIST[value] + else: + value = -1 + elif key == 'flags' and value == UBI_VTBL_AUTORESIZE_FLG: + value = 'autoresize' + elif key == 'name': + value = value.strip('\x00') + print '%s%s: %s' % (tab, key, value) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/headers/__init__.py b/NeoBoot/ubi_reader_mips/ubi/headers/__init__.py new file mode 100644 index 0000000..474a369 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/headers/__init__.py @@ -0,0 +1,89 @@ +#!/usr/bin/python +import struct +from ubi.defines import * +from ubi.headers import errors + +class ec_hdr(object): + + def __init__(self, buf): + fields = dict(zip(EC_HDR_FIELDS, struct.unpack(EC_HDR_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + + def __repr__(self): + return 'Error Count Header' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class vid_hdr(object): + + def __init__(self, buf): + fields = dict(zip(VID_HDR_FIELDS, struct.unpack(VID_HDR_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + def __repr__(self): + return 'VID Header' + + +class vtbl_rec(object): + + def __init__(self, buf): + fields = dict(zip(VTBL_REC_FIELDS, struct.unpack(VTBL_REC_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + setattr(self, 'rec_index', -1) + + def __repr__(self): + return 'Volume Table Record: %s' % getattr(self, 'name') + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +def extract_ec_hdr(buf): + ec_hdr_buf = buf + ec_hdr_ret = ec_hdr(ec_hdr_buf) + errors.ec_hdr(ec_hdr_ret, ec_hdr_buf) + return ec_hdr_ret + + +def extract_vid_hdr(buf): + vid_hdr_buf = buf + vid_hdr_ret = vid_hdr(vid_hdr_buf) + errors.vid_hdr(vid_hdr_ret, vid_hdr_buf) + return vid_hdr_ret + + +def extract_vtbl_rec(buf): + data_buf = buf + vtbl_recs = [] + vtbl_rec_ret = '' + for i in range(0, UBI_MAX_VOLUMES): + offset = i * UBI_VTBL_REC_SZ + vtbl_rec_buf = data_buf[offset:offset + UBI_VTBL_REC_SZ] + if len(vtbl_rec_buf) == UBI_VTBL_REC_SZ: + vtbl_rec_ret = vtbl_rec(vtbl_rec_buf) + errors.vtbl_rec(vtbl_rec_ret, vtbl_rec_buf) + if len(vtbl_rec_ret.errors) == 0: + vtbl_rec_ret.rec_index = i + vtbl_recs.append(vtbl_rec_ret) + + return vtbl_recs \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/headers/__init__.pyo b/NeoBoot/ubi_reader_mips/ubi/headers/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..f68e6bf679518cd75b1d58c518292eafcfbe6c91 GIT binary patch literal 4756 zcmdT{TW=dh6h5<#oj6TsdP_=qNy0@|Rn-C^Ayt5AE~phviY93S5!K4^u9Hn1+u0eH z6gd)7ka&d`o>3q9d;9?SzO%k0?E?>Bx7a)5GqdA4bIyF{miu#h^7r3<`K~J6PY%Cd zpt+yXMR<(VMRqbekh+mg&gP^Z$Wcyqa$=$}iN~a7B+AQAB4;As?&KvZ^k&EVvjvGJ zdb7p;?6^de9PCU;bV-S#L{myklK)0&8fQuV!e_l?Kzeq!GqM0OPSa-Uypq*$KT7-3 zaN!b~dzZ_=0*4gcIpEG@nv*C{VodBtiQ-oSbYp1Ta2d@(eDTWH2jX*bFeW}P9V2If zK1NOhIa!oWAS+LA$!Sh-n2ty%$0_u0pFvN@CE3pA!FmshqV5FZk>9%ISxe*OMBY(S z_24A(L(=k;e|0&0uwuh6AFe)H*-%-XPup0;Q??teO7-xE65Tn*P0(#P!JO)M5O*gmt2w3SMrzv|LYi%W)&wJF0wCZaw$=%|`j_dV4Qv zxbo_Wj~gy&f?SWAOU?`SOji&eKk zC2u`kIp<<5#kT5?F1%E~VvBgG4kd%rC9a)fH&S3JHg19KtBzw>7H4NDxhn1oz<5H_wzyZz~)jzsU`UqV2Yj&Ax)gSQa)SYC$z}^69XW6Oc)97{Kh%J8(d~c!+ zEI+Sq>Y3lIBe+%R%Jst#wS@LBbBqIQF`OKun{y!J$qjN2T78ytc-k@qLR^mG6HT); z4LRo>=zX^~mmY-{SxA_ajL@6KWF&-0 z>}IoUaNQ9JTg`g=D4yS}?AGIX8&{iYbZ`EBr|A^KR+ez6AK<>DO+C~+KBgF%9St?* zcrzW~CzSrBtm0))^15;e2B_P;^C5?rDCYEr7)00gPH`Qra*oNzrY$o zlRyJ%L!q{wg&U1I1Y8!87=|@{f;FQI3Yp&%`Q2d}`+*Z3a^~deyyFv}R;oVC_|3C{g(5!soW>&SpuA8K(8qSYLst2O3r-$x=RxtIdBA9A18CE#_0V0FL z9zdbRDyqtpUx^O5C*T4eYUSyVaylj*RHK1hKh=t~gFesk+`?&rwQ8rpf&vqVfuxHp z0J9kusd-kiEK;#15X03dZu9&DnD7rTxH~38)U$ycjFZM&bNoV%7x`=}B&qjx91UeU zyV3+Y?2fonX`uL^4xTJM4A<^|6K*|z^ki*yqd(V=D;qmn!qnr2rN!ul+IP4S?Yh!x z#f>NnOnSj&5mkIeZK&Iku` literal 0 HcmV?d00001 diff --git a/NeoBoot/ubi_reader_mips/ubi/headers/errors.py b/NeoBoot/ubi_reader_mips/ubi/headers/errors.py new file mode 100644 index 0000000..eee0ebd --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/headers/errors.py @@ -0,0 +1,28 @@ +#!/usr/bin/python +from zlib import crc32 +from ubi.defines import * + +def ec_hdr(ec_hdr, buf): + if ec_hdr.hdr_crc != ~crc32(buf[:-4]) & 4294967295L: + ec_hdr.errors.append('crc') + return ec_hdr + + +def vid_hdr(vid_hdr, buf): + vid_hdr.errors = [] + if vid_hdr.hdr_crc != ~crc32(buf[:-4]) & 4294967295L: + vid_hdr.errors.append('crc') + return vid_hdr + + +def vtbl_rec(vtbl_rec, buf): + likely_vtbl = True + if vtbl_rec.name_len != len(vtbl_rec.name.strip('\x00')): + likely_vtbl = False + elif vtbl_rec.vol_type not in (1, 2): + likely_vtbl = False + if vtbl_rec.crc != ~crc32(buf[:-4]) & 4294967295L: + vtbl_rec.errors.append('crc') + if not likely_vtbl: + vtbl_rec.errors = ['False'] + return vtbl_rec \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/image.py b/NeoBoot/ubi_reader_mips/ubi/image.py new file mode 100644 index 0000000..b613ce4 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/image.py @@ -0,0 +1,38 @@ +#!/usr/bin/python +from ubi import display +from ubi.volume import get_volumes +from ubi.block import get_blocks_in_list + +class description(object): + + def __init__(self, blocks, layout_info): + self._image_seq = blocks[layout_info[0]].ec_hdr.image_seq + self.vid_hdr_offset = blocks[layout_info[0]].ec_hdr.vid_hdr_offset + self.version = blocks[layout_info[0]].ec_hdr.version + self._start_peb = min(layout_info[2]) + self._end_peb = max(layout_info[2]) + self._volumes = get_volumes(blocks, layout_info) + + def __repr__(self): + return 'Image: %s' % self.image_seq + + def get_blocks(self, blocks): + return get_blocks_in_list(blocks, range(self._start_peb, self._end_peb + 1)) + + def _get_peb_range(self): + return [self._start_peb, self._end_peb] + + peb_range = property(_get_peb_range) + + def _get_image_seq(self): + return self._image_seq + + image_seq = property(_get_image_seq) + + def _get_volumes(self): + return self._volumes + + volumes = property(_get_volumes) + + def display(self, tab = ''): + display.image(self, tab) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/volume/__init__.py b/NeoBoot/ubi_reader_mips/ubi/volume/__init__.py new file mode 100644 index 0000000..70d3e76 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi/volume/__init__.py @@ -0,0 +1,67 @@ +#!/usr/bin/python +from ubi import display +from ubi.block import sort, get_blocks_in_list + +class description(object): + + def __init__(self, vol_id, vol_rec, block_list): + self._vol_id = vol_id + self._vol_rec = vol_rec + self._name = self._vol_rec.name + self._block_list = block_list + + def __repr__(self): + return 'Volume: %s' % self.name + + def _get_name(self): + return self._name + + name = property(_get_name) + + def _get_vol_id(self): + return self._vol_id + + vol_id = property(_get_vol_id) + + def _get_block_count(self): + return len(self._block_list) + + block_count = property(_get_block_count) + + def _get_vol_rec(self): + return self._vol_rec + + vol_rec = property(_get_vol_rec) + + def _get_block_list(self): + return self._block_list + + block_list = property(_get_block_list) + + def get_blocks(self, blocks): + return get_blocks_in_list(blocks, self._block_list) + + def display(self, tab = ''): + display.volume(self, tab) + + def reader(self, ubi): + last_leb = 0 + for block in sort.by_leb(self.get_blocks(ubi.blocks)): + if block == 'x': + last_leb += 1 + yield '\xff' * ubi.leb_size + else: + last_leb += 1 + yield ubi.file.read_block_data(ubi.blocks[block]) + + +def get_volumes(blocks, layout_info): + volumes = {} + vol_blocks_lists = sort.by_vol_id(blocks, layout_info[2]) + for vol_rec in blocks[layout_info[0]].vtbl_recs: + vol_name = vol_rec.name.strip('\x00') + if vol_rec.rec_index not in vol_blocks_lists: + vol_blocks_lists[vol_rec.rec_index] = [] + volumes[vol_name] = description(vol_rec.rec_index, vol_rec, vol_blocks_lists[vol_rec.rec_index]) + + return volumes \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi/volume/__init__.pyo b/NeoBoot/ubi_reader_mips/ubi/volume/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..07e081478ab385170eae42fbe978868b9c86a090 GIT binary patch literal 3655 zcmc&%TW=dh6h3>g6FW&0N{I*$fTAK931uZDgj7`smGZztEi{oD)uLM2-c49%?R7ol zlAz=%eMRDlXZVf$fbxB3*0B+NDN+;1b24*wX7*gZb8+;Wo{|+j$~`f+?EViwd56Ev?EztneT}?>`;wi48lR#zr(NxAQypLh@_Z=I??4Q zkda?Ta)B>4#MJLlt=R1}a8PZTzO2f$$lN*@I-li3wdtfk&K+TxOGQUOlQRm&^wR?(Jv!EFBk9%XNZx&Bu9?!r_HW(*xY1y3}imW66-9g}?1! zNEmTk8&MJBttPU2sIcl<%KlXEe(>pMR?TLprk}Mq!?;0xX8ClMrdxQYrRcKMgxV+^ zs4QGPTKbuf4B59JHf@wLA_<@!EZ$abV(b>=R;W{MkLVBHAo(?R=nm(N9x#*_@x=`; z0x9!}A^dJZ51L%jPEmHSY_%9$CZuThB83RjGt}k^rmWP-UmlgJNtZFDhc2uYTsC5rqJVGr( zQi5_&i;ci)j2NC=ln>-_O}<7Iq;*_>a8uf;Bwyg2i}0X2%s?DN@_zwAXK)$H*=VU3 z%Pfj*#OTNO@$)BgsWlh9!)Yk9C#=h88NSB3EY`iT+olo@8K@p zbfgwz40a0;aZKrF1*s)@tsRo#)MMg2E%Sld#o91+X*C2VwZ*TwR_x=V%pD=hQd-ya ztnd0-)0ehKarI~W*6~Vh1{85O8tBKt4x|| z&yl9%Dw~&B8YXDNgN7RG*6FO8<}-J$<=im#43Ta0E++q#d}-e26EY3aY?ze1Z7~tE z53;m|&faZrV;B_#gZ&t!8Md0Os1RD?;$jSTHxA8 zDzLk^2V_5fek7LwZA^fV&_OE9FB{4MjpTFDyD^@F`DY(cbO z%Zmd!!t_uf*DV-o3T{QTtRR}1U~s-@Qn`BR2HIR&b)SOLIyU!wh^7;LUzVS#ojO$9 z2LU~ZpA6O9;rVf;t*`GKts??hV|+H%R@JJ@6)k*1Xf56RZau6&SnBQr3DG`)be19# z`Mbe~!Cf@5JHh?1+gS(Guq^s4N&_Hh4^$6L2wFHaimJf~{kU4iFqW3u+yH3Rjt_lE QenVedI%X%>4R^o#2bbzH00000 literal 0 HcmV?d00001 diff --git a/NeoBoot/ubi_reader_mips/ubi_extract_files.py b/NeoBoot/ubi_reader_mips/ubi_extract_files.py new file mode 100644 index 0000000..154454d --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi_extract_files.py @@ -0,0 +1,64 @@ +#!/usr/bin/python + +import os +import sys +import argparse +from ubi import ubi, get_peb_size +from ubifs import ubifs +from ubi_io import ubi_file, leb_virtual_file +from ui.common import extract_files, output_dir +if __name__ == '__main__': + description = 'Extract contents of UBI image.' + usage = 'ubi_extract_files.py [options] filepath' + parser = argparse.ArgumentParser(usage=usage, description=description) + parser.add_argument('-l', '--log-file', dest='logpath', help='Log output to file output/LOGPATH. (default: ubifs_output.log)') + parser.add_argument('-k', '--keep-permissions', action='store_true', dest='permissions', help='Maintain file permissions, requires running as root. (default: False)') + parser.add_argument('-q', '--quiet', action='store_true', dest='quiet', help='Suppress warnings and non-fatal errors. (default: False)') + parser.add_argument('-p', '--peb-size', type=int, dest='block_size', help='Specify PEB size.') + parser.add_argument('-o', '--output-dir', dest='output_path', help='Specify output directory path.') + parser.add_argument('filepath', help='File to extract contents of.') + if len(sys.argv) == 1: + parser.print_help() + sys.exit() + args = parser.parse_args() + if args.filepath: + path = args.filepath + if not os.path.exists(path): + parser.error("File path doesn't exist.") + if args.output_path: + output_path = args.output_path + else: + img_name = os.path.splitext(os.path.basename(path))[0] + output_path = os.path.join(output_dir, img_name) + if args.logpath: + log_to_file = True + log_file = args.logpath + else: + log_to_file = None + log_file = None + if args.block_size: + block_size = args.block_size + else: + block_size = get_peb_size(path) + perms = args.permissions + quiet = args.quiet + if not os.path.exists(output_path): + os.makedirs(output_path) + ufile = ubi_file(path, block_size) + uubi = ubi(ufile) + for image in uubi.images: + for volume in image.volumes: + vol_out_path = os.path.join(output_path, volume) + if not os.path.exists(vol_out_path): + os.makedirs(vol_out_path) + elif os.listdir(vol_out_path): + parser.error('Volume output directory is not empty. %s' % vol_out_path) + ufsfile = leb_virtual_file(uubi, image.volumes[volume]) + uubifs = ubifs(ufsfile) + uubifs.log.log_file = log_file + uubifs.log.log_to_file = log_to_file + uubifs.log.quiet = quiet + print 'Writing to: %s' % vol_out_path + extract_files(uubifs, vol_out_path, perms) + + sys.exit(0) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi_io/__init__.py b/NeoBoot/ubi_reader_mips/ubi_io/__init__.py new file mode 100644 index 0000000..9f3bd62 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubi_io/__init__.py @@ -0,0 +1,116 @@ +#!/usr/bin/python +from ubi.block import sort + +class ubi_file(object): + + def __init__(self, path, block_size, start_offset = 0, end_offset = None): + self._fhandle = open(path, 'rb') + self._start_offset = start_offset + if end_offset: + self._end_offset = end_offset + else: + self._fhandle.seek(0, 2) + self._end_offset = self.tell() + self._block_size = block_size + if start_offset >= self._end_offset: + raise Exception('Start offset larger than file size!') + self._fhandle.seek(self._start_offset) + + def _set_start(self, i): + self._start_offset = i + + def _get_start(self): + return self._start_offset + + start_offset = property(_get_start, _set_start) + + def _get_end(self): + return self._end_offset + + end_offset = property(_get_end) + + def _get_block_size(self): + return self._block_size + + block_size = property(_get_block_size) + + def seek(self, offset): + self._fhandle.seek(offset) + + def read(self, size): + return self._fhandle.read(size) + + def tell(self): + return self._fhandle.tell() + + def reset(self): + self._fhandle.seek(self.start_offset) + + def reader(self): + self.reset() + while True: + cur_loc = self._fhandle.tell() + if self.end_offset and cur_loc > self.end_offset: + break + elif self.end_offset and self.end_offset - cur_loc < self.block_size: + chunk_size = self.end_offset - cur_loc + else: + chunk_size = self.block_size + buf = self.read(chunk_size) + if not buf: + break + yield buf + + def read_block(self, block): + self.seek(block.file_offset) + return self._fhandle.read(block.size) + + def read_block_data(self, block): + self.seek(block.file_offset + block.ec_hdr.data_offset) + buf = self._fhandle.read(block.size - block.ec_hdr.data_offset - block.vid_hdr.data_pad) + return buf + + +class leb_virtual_file: + + def __init__(self, ubi, volume): + self._ubi = ubi + self._volume = volume + self._blocks = sort.by_leb(self._volume.get_blocks(self._ubi.blocks)) + self._seek = 0 + self.leb_data_size = len(self._blocks) * self._ubi.leb_size + self._last_leb = -1 + self._last_buf = '' + + def read(self, i): + buf = '' + leb = int(self.tell() / self._ubi.leb_size) + offset = self.tell() % self._ubi.leb_size + if leb == self._last_leb: + self.seek(self.tell() + i) + return self._last_buf[offset:offset + i] + else: + buf = self._ubi.file.read_block_data(self._ubi.blocks[self._blocks[leb]]) + self._last_buf = buf + self._last_leb = leb + self.seek(self.tell() + i) + return buf[offset:offset + i] + + def reset(self): + self.seek(0) + + def seek(self, offset): + self._seek = offset + + def tell(self): + return self._seek + + def reader(self): + last_leb = 0 + for block in self._blocks: + while 0 != self._ubi.blocks[block].leb_num - last_leb: + last_leb += 1 + yield '\xff' * self._ubi.leb_size + + last_leb += 1 + yield self._ubi.file.read_block_data(self._ubi.blocks[block]) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubi_io/__init__.pyo b/NeoBoot/ubi_reader_mips/ubi_io/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..439d3b99b0106ae4540240c892d66edfed9b148e GIT binary patch literal 5903 zcmcgwTW=dh6h5=QBzBV~P1{_cP?th6Dy>BUwL+z;+5!?nRsBB7P-T_>A3>vVS= zr6_qJeM5*xUU=az@mKf(<@?U;u3efJketLbJ~KNzbLO1y++6y5zWzx?q$k;53EvOV zlF!lk_!t?8>>1fKVthveNBTzmlDrT(5&2=WBz{@^8SyK{6vkEAXwG7X@Fo7522@(+ zuERJ@IX~)#UOyZJublgcEB-_m2#@3G^JL(KBRt080h`!d58tdvP?Z3ESx&G39F%pz ztj^EM33#q$Y;D$cvaXZo$R4+vBi|%&%B&LS#jh!`AbwqmMe)xmaY6h!C6>h9Xr2d` zA)53cJYl2Y9-}3{qDw`NZ~;Tkjzl~oMN2 z+C@ipmuj}lPDyqv5+6vam&QeZHWKM#yAfY^cvk}%ZZyeWJ9W^zBud!`)N3glvfLtV9-}$zmsmKbu5~AXO6p0 z9?R$BQ=1rxcF8)Z)+mWvgRt8QqHt@kbEmccJl!5ft@XiZD~yuX7l&yOB{)54wS(cK z;V^9xpK;LfgILLM*z&wE3RBO!jhBhwd|U;cTtX*i$<$2M%sCg$0;mQ2_bBMRDLN=I zK!bW!``S?BXlw6MQB5v)DaMp$6Hfasl$;0cTQy$9C?N-8dOSXF%KHo^2rXiY4<@@}`uh&97pG`~seD{ts?x9%skx0#5VD?bz5F6HMn&=C?wE zz_*Zq=K-z@pJVZ%Sf&ebiJb{(QwP>#Oj-VV@OwBdN6BkfSj5ABT_J~e!M-{o`h$rp zsAq!%oAw1(D7lFXLM{HOH7aR8Ti8$=Ep@=)}}Dtgf1}xoQ?2hS)0T*MsbJEVjCVP-zs%gg92ka0)4-DS{aF zt!_e76DB@c@?s@L(YQQ+!uI)!ddO*ufzg>_u>SZVMhUefX3<`o+F*N(mVAY7^4h$q zUU?-KK$-C3H1Lx@TqQLlJF~KiWyF_Lh=##OMdMxtrAi5U-nJjBsQgaaIbBppOhpbt zUzZYUx^y4@lgw(K;5JCTg>Kq1B+AD!^vKE+OeKVvm^aJ^rrl)TlcjZ0XD{$Pg}vwP z4gC@D;HmYrhf&}%T)0c@ig)&7WX5s&T>X^GkZ3LIGAT7LwL%3Fg`xK7zD?>HyBp}n zLQrZdd8?Z{v4m$=orU>Ysa9HWYNffXag6_kS~=xC2SL|62;+3r8N6Dpaid3Q$pdsj zUah?Vff5D<8;H{iHs4lg)x0X3VJSs5^l}^*Sbm0C026RVo}AS`Mo`4SwG!jNtd>wn zMp-GTjdL;fwr|Z)pIlkxQxf>p=PC`iG52wMxyZr88>Po-gc1HRFt*WLp+WH zHJPG9@&=tG)kA2Lc0@N^*pqHX1}RU=-xyQVffFI}4O+tZEbz@W^Df#IH1)~!l9cFU zwB#>zP!0SGq)K&Yu0ld}dYQf_SM7;ip%0dip=bL5!PAj=U*CosEA}u_I5_w@l9j)oBL+G!wfkVwlvl-4D?>HF8oPVU%hTN~WAhY6zV6|;;e zyJD7{8>-)xaamZTb7Ym$RsBMw_D2U5jGB_o+<5sj%i+|+_HbgJzLA@}DI95Kg?~{^ z(x+t=?Z+U;(f&*%Px188a)!xG-jrc3uu{&e6Fzp8Riy~OY2#xSXHch;ToUoLauxRp z2wJ(3!-I_7CqM4e>JLB5JTqOlCK+pV^rR`<_9@Z{q$uAko965!PuzT551Eir@%cR|@XQsQ2Mtjy&@AJ8aWZumF62p7v z4%lsAFl|9IK;w7U+_hGb?=_JAUUce4e~)wD$3vG~*n~uL3#R$j$&g=7Fvff;HJvzc z6Q_NRmhfk}s#B}g&f7$yZI5Rh(4YAbo^ERp97oP!cPHqjnwhxV=PVf3MDM;$?HRK z6va>F9iDjRzwjgY89eX<;GDbJIu$%nq(s8bjOU*DI(O#Iy*I%h-S#g(|McBNPCo&D zKSL>UR1y9>NkoP(+nx+P#eGS9dB_ogB!SFpGOUS5xh6?n<_#G(O1Un{n#`LrY(j2G z)RJgTeh_&f^6fB?s7YZ6)RX;Q8{5Wz;xp)ZXgXFm%4QwSG>dFeifa(KU9 z(lrI!3bqwom#D5_N5PJQU4iPHzM9tkdjr#Xmu{4t63I;cW| zdcI~FCpKh?T8A)?Qxj*Vh`+av zE1RvCaiL}$rj3av)8jcuuhNb z4eVF&Jmue0rur94nMY$txmX<8e4J#H!)t(EmpHHKVu^26#OI^J!Jznb-uYiJzw{5x zZ@u>)sPoNV?4frn>Xk3yt9o5qp;x(B+ACXGdCU)2%zNxVbv@~5ZjDjTXUsf{774_V zR~BBbMjhoD-imvUFd(8noG#n(DXm_S8e~W(;M7;ItTenrke7GHbZ>=k0th)YyvmBc zWaYE8b#87qq$1p~xQ?pfw_2^Bm_k|Ty?$Qz~3UmmSGW*bcqP-$qcChk^&?G zzIc><<|&BsSC55ty$90#654uifbhVDK2U6wT+Ti3Aa$+9lTzlm$eY>k(7 zQs?S>PkxmpA~w(#_gJE@EwgoYpCE=q?8w!3vDFe&nvySB&${9^QK($y9)kyax6S>}zqq%ns}*jPyO7aU z-^L`H&$HA#jq;GT;AlMbz{Wj4DmN`NnEf5Yh0d&dijYZwNr_Fv27cA@b*D*^6;?AP zrFt}SPc?y^>Lz?{WllpkqVcK}NiEhT$BU^>n1>$#(?upAs){0gQcYk+u=cUBX{2+C zak_eJ=l0I@(KFaq?(-wExQR-T+HB$5^%~waw67uMxsH^ljqlq)FZ*4fEl3@|?Uht{ z0O9+nN@ZNWm^i&}O{;E37Po2(ecR>5(Ycg;`X4} XlhVUDh7~jR2ipJxQ->7D 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 literal 0 HcmV?d00001 diff --git a/NeoBoot/ubi_reader_mips/ubifs/misc.py b/NeoBoot/ubi_reader_mips/ubifs/misc.py new file mode 100644 index 0000000..a4127bb --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubifs/misc.py @@ -0,0 +1,46 @@ +#!/usr/bin/python +import lzo +import struct +import zlib +from ubifs.defines import * +ino_types = ['file', + 'dir', + 'lnk', + 'blk', + 'chr', + 'fifo', + 'sock'] +node_types = ['ino', + 'data', + 'dent', + 'xent', + 'trun', + 'pad', + 'sb', + 'mst', + 'ref', + 'idx', + 'cs', + 'orph'] +key_types = ['ino', + 'data', + 'dent', + 'xent'] + +def parse_key(key): + hkey, lkey = struct.unpack('> UBIFS_S_KEY_BLOCK_BITS + khash = lkey + return {'type': key_type, + 'ino_num': ino_num, + 'khash': khash} + + +def decompress(ctype, unc_len, data): + if ctype == UBIFS_COMPR_LZO: + return lzo.decompress(''.join(('\xf0', struct.pack('>I', unc_len), data))) + elif ctype == UBIFS_COMPR_ZLIB: + return zlib.decompress(data, -11) + else: + return data \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.py b/NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.py new file mode 100644 index 0000000..d2b3346 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.py @@ -0,0 +1,151 @@ +#!/usr/bin/python +import struct +from ubifs.defines import * +from ubifs.misc import parse_key + +class common_hdr(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_COMMON_HDR_FIELDS, struct.unpack(UBIFS_COMMON_HDR_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'errors', []) + + def __repr__(self): + return 'UBIFS Common Header' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class sb_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_SB_NODE_FIELDS, struct.unpack(UBIFS_SB_NODE_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + def __repr__(self): + return 'UBIFS Super Block Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class mst_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_MST_NODE_FIELDS, struct.unpack(UBIFS_MST_NODE_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + def __repr__(self): + return 'UBIFS Master Block Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class dent_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_DENT_NODE_FIELDS, struct.unpack(UBIFS_DENT_NODE_FORMAT, buf))) + for key in fields: + if key == 'key': + setattr(self, key, parse_key(fields[key])) + else: + setattr(self, key, fields[key]) + + setattr(self, 'name', '') + + def __repr__(self): + return 'UBIFS Directory Entry Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class data_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_DATA_NODE_FIELDS, struct.unpack(UBIFS_DATA_NODE_FORMAT, buf))) + for key in fields: + if key == 'key': + setattr(self, key, parse_key(fields[key])) + else: + setattr(self, key, fields[key]) + + setattr(self, 'offset', 0) + setattr(self, 'compr_len', 0) + + def __repr__(self): + return 'UBIFS Data Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class idx_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_IDX_NODE_FIELDS, struct.unpack(UBIFS_IDX_NODE_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + setattr(self, 'branches', []) + + def __repr__(self): + return 'UBIFS Index Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class ino_node(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_INO_NODE_FIELDS, struct.unpack(UBIFS_INO_NODE_FORMAT, buf))) + for key in fields: + if key == 'key': + setattr(self, key, parse_key(fields[key])) + else: + setattr(self, key, fields[key]) + + setattr(self, 'data', '') + + def __repr__(self): + return 'UBIFS Ino Node' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) + + +class branch(object): + + def __init__(self, buf): + fields = dict(zip(UBIFS_BRANCH_FIELDS, struct.unpack(UBIFS_BRANCH_FORMAT, buf))) + for key in fields: + setattr(self, key, fields[key]) + + def __repr__(self): + return 'UBIFS Branch' + + def __iter__(self): + for key in dir(self): + if not key.startswith('_'): + yield (key, getattr(self, key)) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.pyo b/NeoBoot/ubi_reader_mips/ubifs/nodes/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..cab95510af0006e9bf4364d6ed1d214c2eb7e617 GIT binary patch literal 9150 zcmd^FTW=dh6h6Do{nDnlP>KN4zF1XNqduVuA>uft0pg%>pb$~59Pc{W#@qpE_Wl`#<(qV(`;BW!rr)K3iM!v%qZp(ifwUZp*ks`szZ zlLDDB+9TR4fW-aV`@8}VOLWiDne`?w0ak@rOYp1lUs%K>i4$EK2R}&QhfTx$h<*rn z%v=2X>&o(-y0^Hxva(w9?pBp|XL;$%YF$38P15D*_?~XG(`arV@`+Wovan{rLkFf| zOi}_X;irRkOZaVcTk=J%FlhT)NNna3&m-x?B;~G7%I$EY97N$}r*W&i^Vn>~QTeNO zcQcH1d1==Kkq%=X)`GYa$EMuf2)!g|_(9@z!X1t0mM%xJALz2@g;8ic?Ez9SJiA0Gujl}3jq1h4_*zCCg#1N~fGdz0TrU?x@gm<1fYq&2t z7o4+B31;beLe%I4o+k=;UMKduZGKd+rJ6%`iMzhgGCE-wRj?R@6^X~($??g84XOp(eO92TTz> zQ9xh;66-}X_{1!_*XmE=5?7dQ&yN5YN5aKC&$n<<@9qRivC@v4+r=6$qID_Q>h&Uq zIQ9Eb173E*NTJR#3jqp+2vk5%g>@D*9ReswG+$)_o&^Jil~ULTha38rSpu{)^hY`L z5gi?E-q_d&g4)<$sjnRp{0Gg+UG!g17ltHVI5PUPw5qt$(7X@jCH%|K|F{Ef$0Pk^f)~3X&eyV5#C(i%%;;9+B9C4|}+p zZU@l|uxDXy;gCdT0DJnA@`*jGtg%K7HHbZPM;A4yjeF?Bt}}ed!5P}=g`E4)KBtg# zjb&R&3^?o+d7(j^H>d`2Y&FP~^o=TiYSn2;=;vg?c;UpeDnEVJOPHkE9 z6x!z$Om47j-Bi9_Sp!k+77dt@7i#_rw>RLfB)enuDr%v&c=!3MlILgiLq8`8#Luv` zb(xpCDFHy(c&|uqg*}3XaHA^sBfmoUQycBSL;IXY`-d#sPpNzy?R-B{lDj}`_68%l z_rK`}tuP9-TZ7UjPW;*AG)EBv%ai*L(cmDkR9RFOJpXbq~e*uAbmDm6P literal 0 HcmV?d00001 diff --git a/NeoBoot/ubi_reader_mips/ubifs/nodes/extract.py b/NeoBoot/ubi_reader_mips/ubifs/nodes/extract.py new file mode 100644 index 0000000..9f8f7b0 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubifs/nodes/extract.py @@ -0,0 +1,48 @@ +#!/usr/bin/python +from ubifs import nodes +from ubifs.defines import * + +def common_hdr(ubifs, lnum, offset = 0): + ubifs.file.seek(ubifs.leb_size * lnum + offset) + return nodes.common_hdr(ubifs.file.read(UBIFS_COMMON_HDR_SZ)) + + +def ino_node(ubifs, lnum, offset = 0): + ubifs.file.seek(ubifs.leb_size * lnum + offset) + inon = nodes.ino_node(ubifs.file.read(UBIFS_INO_NODE_SZ)) + inon.data = ubifs.file.read(inon.data_len) + return inon + + +def mst_node(ubifs, lnum, offset = 0): + ubifs.file.seek(ubifs.leb_size * lnum + offset) + return nodes.mst_node(ubifs.file.read(UBIFS_MST_NODE_SZ)) + + +def sb_node(ubifs, offset = 0): + ubifs.file.seek(offset) + return nodes.sb_node(ubifs.file.read(UBIFS_SB_NODE_SZ)) + + +def dent_node(ubifs, lnum, offset = 0): + ubifs.file.seek(ubifs.leb_size * lnum + offset) + den = nodes.dent_node(ubifs.file.read(UBIFS_DENT_NODE_SZ)) + den.name = '%s' % ubifs.file.read(den.nlen) + return den + + +def data_node(ubifs, lnum, offset = 0, node_len = 0): + ubifs.file.seek(ubifs.leb_size * lnum + offset) + datn = nodes.data_node(ubifs.file.read(UBIFS_DATA_NODE_SZ)) + datn.offset = ubifs.leb_size * lnum + offset + UBIFS_DATA_NODE_SZ + datn.compr_len = node_len - UBIFS_COMMON_HDR_SZ - UBIFS_DATA_NODE_SZ + return datn + + +def idx_node(ubifs, lnum, offset = 0): + ubifs.file.seek(ubifs.leb_size * lnum + offset) + idxn = nodes.idx_node(ubifs.file.read(UBIFS_IDX_NODE_SZ)) + for i in range(0, idxn.child_cnt): + idxn.branches.append(nodes.branch(ubifs.file.read(UBIFS_BRANCH_SZ))) + + return idxn \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubifs/output.py b/NeoBoot/ubi_reader_mips/ubifs/output.py new file mode 100644 index 0000000..dd3f4f4 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubifs/output.py @@ -0,0 +1,114 @@ +#!/usr/bin/python +import os +import struct +from ubifs.defines import * +from ubifs.misc import decompress + +def dents(ubifs, inodes, dent_node, path = '', perms = False): + inode = inodes[dent_node.inum] + dent_path = os.path.join(path, dent_node.name) + if dent_node.type == UBIFS_ITYPE_DIR: + try: + if not os.path.exists(dent_path): + os.mkdir(dent_path) + if perms: + set_file_perms(dent_path, inode) + except Exception as e: + ubifs.log.write('DIR Fail: %s' % e) + + if 'dent' in inode: + for dnode in inode['dent']: + dents(ubifs, inodes, dnode, dent_path, perms) + + elif dent_node.type == UBIFS_ITYPE_REG: + try: + if inode['ino'].nlink > 1: + if 'hlink' not in inode: + inode['hlink'] = dent_path + buf = process_reg_file(ubifs, inode, dent_path) + write_reg_file(dent_path, buf) + else: + os.link(inode['hlink'], dent_path) + else: + buf = process_reg_file(ubifs, inode, dent_path) + write_reg_file(dent_path, buf) + if perms: + set_file_perms(dent_path, inode) + except Exception as e: + ubifs.log.write('FILE Fail: %s' % e) + + elif dent_node.type == UBIFS_ITYPE_LNK: + try: + os.symlink('%s' % inode['ino'].data, dent_path) + except Exception as e: + ubifs.log.write('SYMLINK Fail: %s : %s' % (inode['ino'].data, dent_path)) + + elif dent_node.type in [UBIFS_ITYPE_BLK, UBIFS_ITYPE_CHR]: + try: + dev = struct.unpack(' len(buf): + buf += '\x00' * (inode['ino'].size - len(buf)) + return buf \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ubifs/walk.py b/NeoBoot/ubi_reader_mips/ubifs/walk.py new file mode 100644 index 0000000..d8b8020 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ubifs/walk.py @@ -0,0 +1,33 @@ +#!/usr/bin/python +from ubifs import extract +from ubifs.defines import * + +def index(ubifs, lnum, offset, inodes = {}): + chdr = extract.common_hdr(ubifs, lnum, offset) + if chdr.node_type == UBIFS_IDX_NODE: + idxn = extract.idx_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ) + for branch in idxn.branches: + index(ubifs, branch.lnum, branch.offs, inodes) + + elif chdr.node_type == UBIFS_INO_NODE: + inon = extract.ino_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ) + ino_num = inon.key['ino_num'] + if ino_num not in inodes: + inodes[ino_num] = {} + inodes[ino_num]['ino'] = inon + elif chdr.node_type == UBIFS_DATA_NODE: + datn = extract.data_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ, chdr.len) + ino_num = datn.key['ino_num'] + if ino_num not in inodes: + inodes[ino_num] = {} + if 'data' not in inodes[ino_num]: + inodes[ino_num]['data'] = [] + inodes[ino_num]['data'].append(datn) + elif chdr.node_type == UBIFS_DENT_NODE: + dn = extract.dent_node(ubifs, lnum, offset + UBIFS_COMMON_HDR_SZ) + ino_num = dn.key['ino_num'] + if ino_num not in inodes: + inodes[ino_num] = {} + if 'dent' not in inodes[ino_num]: + inodes[ino_num]['dent'] = [] + inodes[ino_num]['dent'].append(dn) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_mips/ui/__init__.py b/NeoBoot/ubi_reader_mips/ui/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ui/__init__.py @@ -0,0 +1 @@ + diff --git a/NeoBoot/ubi_reader_mips/ui/__init__.pyo b/NeoBoot/ubi_reader_mips/ui/__init__.pyo new file mode 100644 index 0000000000000000000000000000000000000000..63a124d5e862e61eb7aec8ab9131f28468a29541 GIT binary patch literal 163 zcmZSn%*$oM%D|A!00oRd+5w1*S%5?e14FO|NW@PANHCxg#XdkW{nFwh{hZ7s{nWh7 z^xQ-v{esGpjQl+PfSl6w%)DZK*NT$VyyDD!Ak!~3-zh)8M87mCGrlM_F(tJ~zcf=n gK0Y%qvm`!V52%p?XrN7QeoARhsvXGMVjyM!0FSCAiU0rr literal 0 HcmV?d00001 diff --git a/NeoBoot/ubi_reader_mips/ui/common.py b/NeoBoot/ubi_reader_mips/ui/common.py new file mode 100644 index 0000000..c8669fd --- /dev/null +++ b/NeoBoot/ubi_reader_mips/ui/common.py @@ -0,0 +1,88 @@ +#!/usr/bin/python +import os +from ubi_io import leb_virtual_file +from ubifs import ubifs, walk, output +from ubifs.defines import PRINT_UBIFS_KEY_HASH, PRINT_UBIFS_COMPR +from ubi.defines import PRINT_VOL_TYPE_LIST, UBI_VTBL_AUTORESIZE_FLG +output_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'output') + +def extract_files(ubifs, out_path, perms = False): + try: + inodes = {} + walk.index(ubifs, ubifs.master_node.root_lnum, ubifs.master_node.root_offs, inodes) + for dent in inodes[1]['dent']: + output.dents(ubifs, inodes, dent, out_path, perms) + + except Exception as e: + import traceback + ubifs.log.write('%s' % e) + traceback.print_exc() + + +def get_ubi_params(ubi): + ubi_flags = {'min_io_size': '-m', + 'max_bud_bytes': '-j', + 'leb_size': '-e', + 'default_compr': '-x', + 'sub_page_size': '-s', + 'fanout': '-f', + 'key_hash': '-k', + 'orph_lebs': '-p', + 'log_lebs': '-l', + 'max_leb_cnt': '-c', + 'peb_size': '-p', + 'sub_page_size': '-s', + 'vid_hdr_offset': '-O', + 'version': '-x', + 'image_seq': '-Q', + 'alignment': '-a', + 'vol_id': '-n', + 'name': '-N'} + ubi_params = {} + ubi_args = {} + ini_params = {} + for image in ubi.images: + img_seq = image.image_seq + ubi_params[img_seq] = {} + ubi_args[img_seq] = {} + ini_params[img_seq] = {} + for volume in image.volumes: + ubi_args[img_seq][volume] = {} + ini_params[img_seq][volume] = {} + ini_params[img_seq][volume]['vol_type'] = PRINT_VOL_TYPE_LIST[image.volumes[volume].vol_rec.vol_type] + if image.volumes[volume].vol_rec.flags == UBI_VTBL_AUTORESIZE_FLG: + ini_params[img_seq][volume]['vol_flags'] = 'autoresize' + else: + ini_params[img_seq][volume]['vol_flags'] = image.volumes[volume].vol_rec.flags + ini_params[img_seq][volume]['vol_id'] = image.volumes[volume].vol_id + ini_params[img_seq][volume]['vol_name'] = image.volumes[volume].name.rstrip('\x00') + ini_params[img_seq][volume]['vol_alignment'] = image.volumes[volume].vol_rec.alignment + ini_params[img_seq][volume]['vol_size'] = image.volumes[volume].vol_rec.reserved_pebs * ubi.leb_size + ufsfile = leb_virtual_file(ubi, image.volumes[volume]) + uubifs = ubifs(ufsfile) + for key, value in uubifs.superblock_node: + if key == 'key_hash': + value = PRINT_UBIFS_KEY_HASH[value] + elif key == 'default_compr': + value = PRINT_UBIFS_COMPR[value] + if key in ubi_flags: + ubi_args[img_seq][volume][key] = value + + for key, value in image.volumes[volume].vol_rec: + if key == 'name': + value = value.rstrip('\x00') + if key in ubi_flags: + ubi_args[img_seq][volume][key] = value + + ubi_args[img_seq][volume]['version'] = image.version + ubi_args[img_seq][volume]['vid_hdr_offset'] = image.vid_hdr_offset + ubi_args[img_seq][volume]['sub_page_size'] = ubi_args[img_seq][volume]['vid_hdr_offset'] + ubi_args[img_seq][volume]['sub_page_size'] = ubi_args[img_seq][volume]['vid_hdr_offset'] + ubi_args[img_seq][volume]['image_seq'] = image.image_seq + ubi_args[img_seq][volume]['peb_size'] = ubi.peb_size + ubi_args[img_seq][volume]['vol_id'] = image.volumes[volume].vol_id + ubi_params[img_seq][volume] = {'flags': ubi_flags, + 'args': ubi_args[img_seq][volume], + 'ini': ini_params[img_seq][volume]} + + return ubi_params \ No newline at end of file