From 54314416ce2ae6486231036dcdbb77922eca0ab1 Mon Sep 17 00:00:00 2001 From: gutosie Date: Tue, 7 Jan 2020 11:13:30 +0200 Subject: [PATCH] Add files via upload --- NeoBoot/ubi_reader_arm/argparse_neo.py | 1506 +++++++++++++++++ NeoBoot/ubi_reader_arm/argparse_neo.pyo | Bin 0 -> 61812 bytes 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/layout.pyo | Bin 0 -> 1083 bytes NeoBoot/ubi_reader_arm/ubi/block/sort.py | 84 + NeoBoot/ubi_reader_arm/ubi/block/sort.pyo | Bin 0 -> 3008 bytes NeoBoot/ubi_reader_arm/ubi/defines.py | 63 + NeoBoot/ubi_reader_arm/ubi/defines.pyo | Bin 0 -> 1670 bytes NeoBoot/ubi_reader_arm/ubi/display.py | 108 ++ NeoBoot/ubi_reader_arm/ubi/display.pyo | Bin 0 -> 4488 bytes .../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/headers/errors.pyo | Bin 0 -> 1375 bytes NeoBoot/ubi_reader_arm/ubi/image.py | 38 + NeoBoot/ubi_reader_arm/ubi/image.pyo | Bin 0 -> 2379 bytes 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/defines.pyo | Bin 0 -> 6177 bytes NeoBoot/ubi_reader_arm/ubifs/log.py | 33 + NeoBoot/ubi_reader_arm/ubifs/log.pyo | Bin 0 -> 1719 bytes NeoBoot/ubi_reader_arm/ubifs/lzo.so | Bin 0 -> 11560 bytes NeoBoot/ubi_reader_arm/ubifs/misc.py | 46 + NeoBoot/ubi_reader_arm/ubifs/misc.pyo | Bin 0 -> 1303 bytes .../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 + .../ubi_reader_arm/ubifs/nodes/extract.pyo | Bin 0 -> 2805 bytes NeoBoot/ubi_reader_arm/ubifs/output.py | 114 ++ NeoBoot/ubi_reader_arm/ubifs/output.pyo | Bin 0 -> 3904 bytes NeoBoot/ubi_reader_arm/ubifs/walk.py | 33 + NeoBoot/ubi_reader_arm/ubifs/walk.pyo | Bin 0 -> 1342 bytes NeoBoot/ubi_reader_arm/ui/__init__.pyo | Bin 0 -> 163 bytes NeoBoot/ubi_reader_arm/ui/common.py | 88 + NeoBoot/ubi_reader_arm/ui/common.pyo | Bin 0 -> 3282 bytes 45 files changed, 3195 insertions(+) create mode 100644 NeoBoot/ubi_reader_arm/argparse_neo.py create mode 100644 NeoBoot/ubi_reader_arm/argparse_neo.pyo 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/layout.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubi/block/sort.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/block/sort.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubi/defines.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/defines.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubi/display.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/display.pyo 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/headers/errors.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubi/image.py create mode 100644 NeoBoot/ubi_reader_arm/ubi/image.pyo 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/defines.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubifs/log.py create mode 100644 NeoBoot/ubi_reader_arm/ubifs/log.pyo 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/misc.pyo 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/nodes/extract.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubifs/output.py create mode 100644 NeoBoot/ubi_reader_arm/ubifs/output.pyo create mode 100644 NeoBoot/ubi_reader_arm/ubifs/walk.py create mode 100644 NeoBoot/ubi_reader_arm/ubifs/walk.pyo 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_arm/ui/common.pyo 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/argparse_neo.pyo b/NeoBoot/ubi_reader_arm/argparse_neo.pyo new file mode 100644 index 0000000000000000000000000000000000000000..9b45bc95773e603379e63fb64ac58d4ef7f6e3e7 GIT binary patch literal 61812 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 (rJ1?D}Wq>MJ%)|yq#0Cqpag6tZ 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 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%tJ@36gH2V(8k&p$v2_Wmi@$eQNHGl9K3f%b~rQ61*REuIe_`WCSZ!{}hg31mCGk{#sT1!~` zV7G+FqiF-{02T&T5=PTcuidH9B>C(<&~tryIs~t*ea5 z;Qyqs>6!EQF;v7$+xn>UM1^tQ-`l!flsC4mb>^vM;R!>5h42Gx+-KaW)-|dyiPDwH z%lL(=m;TgN>ZoXQQ#tiv;dSMV#qC(zch-8AVf{Fia#v=ha#b2c@x*BcOhf<(AL>>%?`L|=}(*`s+w@eWx$=4L|Y dCNx$5px)$|>|&?arOnzxzag!7P!8l?_!sDQ_oDy+ literal 0 HcmV?d00001 diff --git a/NeoBoot/ubi_reader_arm/ubi/block/sort.py b/NeoBoot/ubi_reader_arm/ubi/block/sort.py new file mode 100644 index 0000000..6687f9e --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubi/block/sort.py @@ -0,0 +1,84 @@ +#!/usr/bin/python +def list_by_list(blist, slist): + slist_blocks = [] + for block in blist: + if block in slist: + slist_blocks.append(block) + + return slist_blocks + + +def by_image_seq(blocks, image_seq): + seq_blocks = [] + for block in blocks: + if blocks[block].ec_hdr.image_seq == image_seq: + seq_blocks.append(block) + + return seq_blocks + + +def by_range(blocks, block_range): + peb_range = range(block_range[0], block_range[1]) + return [ i for i in blocks if i in peb_range ] + + +def by_leb(blocks): + slist_len = len(blocks) + slist = ['x'] * slist_len + for block in blocks: + if blocks[block].leb_num >= 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/block/sort.pyo b/NeoBoot/ubi_reader_arm/ubi/block/sort.pyo new file mode 100644 index 0000000000000000000000000000000000000000..ab7f768675d353dadd248c8521fb1c21d08a7c65 GIT binary patch literal 3008 zcmcguU2hvj6uqUq`8- zJV7ZRq8f;tdUEu>oQQ1gz9XkKIl<4!ep8B;oOrS)?0I3tj9P-Tr46K-Ei=(yCRewTM2of?k^U_seP$%nn9GtMY4D-EmoT)1=ppvt%#~KkgnJ z+vj=K{U#j`lC120d1T|POmdjpasEY~+wQoR1VtQ1aY3`I8+6OOupi-FZcGn?-f_Su zK`5`F64Nv-vuIYle*^P5hAUt`alm}2z$g-J0J3KkB5wkb_x}(PZG|ZA2hXFzE})$Z z!$BOB@yJI*9BM?-VdKxiwDb`(D!hCmdkIhhrKxjQ>A?)D+h?JoJIbMT7#6sIo<`by zc+!61kyJoXNp*KZDo;supIH6i$>=_4M0BJa#Hk-Drr#45zxtCr7n5j1D3ZH(S>LIvT`y9WUylhovu z$TRp;m!IjI+3C>dZOaoJX#^|}upb}mq1a8qETfc+05=f0E9Wx+37aAq*?6cC^q0`# zta(}}av|#G>Kkb|>_y?`18%~doSt}&G|v2+c&h%G5#q@5mBhvc&RFW{9lt0`m!S9( z53Q2Z{1HY`5U24l&TOe?nH}vyPNk^;=_>BE=@rQ)$W$$Sm(4A6!(2DFytA=7^aaQP`~ry6_kpZR;Tv&Vx7fOcW zfE2O=Qsvg}XOk$cpNZ1Cj8=sxSFq!j*00oVkj;?Fd!I~7mOdFVqM*Y8MV(61rPq9;&wx8ucX8t8;gx*0T_V^%v46}TIilKF1r;~eT$*{D{l6S+a8Gg6*|EbUH z;Pd~6&!hXyeR{0zJd6D`cD>DtLZ69UtqaM*^Vnx&m`CF@-qe4M)XM@tjfHEA*A}n- E4Se5l_W%F@ literal 0 HcmV?d00001 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/defines.pyo b/NeoBoot/ubi_reader_arm/ubi/defines.pyo new file mode 100644 index 0000000000000000000000000000000000000000..b005c1866d8367ca6470f348b1c39f63bbe28bfb GIT binary patch literal 1670 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 CxvIVZ literal 0 HcmV?d00001 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 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 literal 0 HcmV?d00001 diff --git a/NeoBoot/ubi_reader_arm/ubifs/log.py b/NeoBoot/ubi_reader_arm/ubifs/log.py new file mode 100644 index 0000000..1c2d15b --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubifs/log.py @@ -0,0 +1,33 @@ +#!/usr/bin/python +import os +import sys +import ui + +class log: + + def __init__(self): + self.log_to_file = False + self.log_file = 'ubifs_output.log' + self.exit_on_except = False + self.quiet = False + + def _out(self, s): + if not self.quiet: + if self.log_to_file: + with open(os.path.join(ui.common.output_dir, self.log_file), 'a') as f: + f.write('%s\n' % s) + f.close() + else: + print '%s' % s + if self.exit_on_except: + sys.exit() + + def write(self, s): + self._out(s) + + def write_node(self, n): + buf = '%s\n' % n + for key, value in n: + buf += '\t%s: %s\n' % (key, value) + + self._out(buf) \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubifs/log.pyo b/NeoBoot/ubi_reader_arm/ubifs/log.pyo new file mode 100644 index 0000000000000000000000000000000000000000..66489627de057bbfaf117cab14ba4733c5285039 GIT binary patch literal 1719 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 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/misc.pyo b/NeoBoot/ubi_reader_arm/ubifs/misc.pyo new file mode 100644 index 0000000000000000000000000000000000000000..1915b7de97e462762ca78741bc92294d2e1c59f0 GIT binary patch literal 1303 zcmcIiO>fgc5FI;7(}c8?kG32T--n1pEpf=Hf;LrAqqJ#dmjh8H%kgXyH;x^7*HVj; z6G$BS7yLoQ8QyM^QX#I`o|(6^p4r(qQ~0q~J^%joBBaGrgWZG3Z%~ZSqL`?AgDvV> z#&1(>(>WK2i^L`372-1SDshDdW$MCTCB8#kBVHq3C%#L(L41$+KJf$Mhs2vSs8JW; zxBeUysf%n|^aZCP=e7aJY>`)ggqosXcsg|pP-*pA6`}i4EK~u2qs-Vi85!G)=QbQ> ziy!-`0WuBeJ5e%saG(OS!y-`zTrGjh^2B7D1gvbFB70^zmde;n^o@=9%4~vuI}1)FR~Dn-yq^%_6;<6*ZcbD1r-w z6{s;a%r~YWt3(a2uFvR5O~G!f6~X90sOyPPWdK~$Px7(Sb&Q6A9M&~bI!xkzp)xQ} zCINWSQ}ChLdhhvO+dn?+sLekPzkT@8Kic<>{F8mJt+xK!X&#>*wEbr5d|r~_WhAam zF~cQ@0bHF^twLep>pESXs}7kf*#>fQnK^OPb3_si#=#qBa;=7G;+)0#AWEcjc%?)l zqZF_s(q@_}C+|gmCIS|jhJERbBN^@>u7Z4%Ad|w!iBGVQ>riApwW@emAZ07m3@*j= z>lGYm6IwR1DSND^?h-Asb^FjX56EM}bn3zAL_aZ}b)7(MK+Q=!I6XOY{qAwAX=wO_ z`=}~*S%m3$k_jp25xOJcO~>*i^kb2@y6peQiu-brUg}YxLe1K+>$)rMwpK5o)Ebnb za)(7fN`y32>WR|DN^_SaWwBW5f|os&?lY`z4*8E4F{89QPC1XoTipQJfT~$F^tEv7 Nt=z)@@>lFi^*28;7U2K@ literal 0 HcmV?d00001 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{yy0|UDDxSVd?)eRT?rI?8I5EmtV}5Z>tR!X_+W0pUfEU*W8D*16mWEf+Oy8WD zLF7Kf`geyX-}J+yv(wYFUih*bg#8PjM(R1{!+31<{Un`FV1P(A9$VvlaH7PXgX_%g ztdqpUj!EOo$>6ij^p(5H($2TZ{4!2$=lI5%)W#Xup2-fg%yl3-q!DIDc5FL}S;ySC z*eOkV{AlEd0p#)S0O0Ft@l{Gh-lyjVPaARkrQ9#P(+{#=o{UH#B>v|ZbKoJ zTG~KZ_r1LwS{`!=?SBxP?*(sS-CFQY`{xCC8iT>RFl_>zU0^_Ou7Zvcz_CQ;DJH9+ z(~R_7MXr}YRb%qJo2rbG5*(O`WBS@*2?*-Wqo{wl#6bg4aiG&S0l^2*^N6)cWsDL2g9IsuFrMJ4dg3+*`(xrdC=c zU^tULu`z$jMe5om`+U^DVwjm`%sZ*)nRbZJ9^3M!8(sJVqi+@c;AUPkw+gx(KC#a zE1!5zD?MKWk 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/output.pyo b/NeoBoot/ubi_reader_arm/ubifs/output.pyo new file mode 100644 index 0000000000000000000000000000000000000000..8075cbc9fbc916b2c2d36f4cbfad72ecd76b9744 GIT binary patch literal 3904 zcmcInTW=dh6h5=-OY9`Qpv$oTuRe2#%W->c-=3KsW=A0Az@8R_F z<1ardQ}@Tl-*++e$CzCFDyk8!_ScG5mF!zovuK$qY^vE*kI`z3lp7;2PHvnYS+trU zH$jhZJ4tR*76arC$RfpzmvSix@&CckLQY|6c)AoV(=6XBhxJC&)7s#R%5hAC7)gv< z82VSJ+fmf9Xp<kF7*asA5?r8|NmDgV&2LEUBuRCMHV0{Qh;8a5X&mfSpy-}!@zrXA znosTR*LaPc%=ClPv@<|vm~fAk7nzW^8;6XaXyxHkJNVOL?V<4z(fCKz{#NeWl-WE= zK)DM2<`jTt2}x>RQIVq9xo(aLYn;I}n|4xUj*A_s$c|0LFr5&Famp|i%nQ!Ze_Uit zK3DrNVL+g750D?!0YCs=7Z6b03sOC^M#QXfs|}&hWt0Pi@nQSMXuPY^v#d{82Ur8P z{squitO$6K^PTF#H%?}P)-7?uUsijU%p`4Q$c10~mtnk{M)ahK4SZy=LMOX^7llqy zC(S@gP&~0107O?eD4tls#V)?)v=AzRlX*q7{Qx=u)*lBg8Wf?){igiZi`_E<*|Ob! zLm)f5UqkjFi_F?D^UtDv0K}mei7fX-o)eKz?e>MPh3;_Qwy$0)=;woij<6tk8R8(x zCri1bc*F~O2=jEo$dzNe=w_H)?)R)x%iL7UpOAH?)PF zDXquwXX*a!`NG0n|18TaHFLUNDERn8`Z%WPnGX+;oWSmEVfN1cZHHNl#HBm8_PFM< z*cL_opj9_a6h?|SN@hb2HbXyc8(y=n;aZ}Z?XuS}ei#TkwQyaoY&Cu3$%=u~&q;A+-jmaS z0mM5eYBa+#GHbEvt&0eeCv5h%*b#E!pwjaTbB439Zr9~pJXSKL=j7g;pL=fa*87pg z+B92bBgVIaMyXuw8XttNz*P@jPmBbisQfH!>?yfguU7m@_}n>rE62q`n6}pZiWYK& zlj}uDGEznUbOw5K5zOoZp%cJ`OuWir*aexdiEeAHiu`rGPjWaWne=U}@-5xW*Zj4- z7x?S-(wq54+iZkEezDeC_XC}u**0FF;Ygid@WPv6X!1}K;Fnyl$;*n)hb_}+naho~ zGXjo+xRgRQtR~e_WvdfdCDa7glh%+ruCf;Ij;JA(#@R7z!ip$HL2*jX&S90a#z1uj zH&0@WSRz z1W298rYpe&DW%{QE|etM;R{7lIq{5h{A3p#jx2o&6K4m{&CX)ZF5)%#TCn5Sonv4e zp2XSZ4MdJ}e(y8fiXKbLcg0uhzU%N4$gw%%eCHB>VjP=ufCA%z`Rg z$|*oly@&;{10cW(Kz=<+JHQ9+06@kLnu`^e=!1Khmc)VuNk3a_@*yuLYpAjFY$)JAQ zESlTFEfrbwg5yasj}5XBGhA;Mq^>y}6jBrAT~xhxnInV;KaC{}%{i3Kmw3$dB94^w(M~lm+}!^s^LMhViCRnsV50YP{&b@xjV1&bcrW6(Yegi4NM3M7$gc7T`sar zT`Or*6c30K6h>o_?~@SSl8;JmL{PflYAl$wOfs4*0x36zr~>bR9c0UE>JB+AK@ zl~J##$UsTcXK@ez{18cnyX<-uKR`ido1z_L_Hu+32ia_?rah^C4yRCu^NVP)XQr(F f|B@R88cIp4=H1}upt&O(lG1w2Iy##gNX7pJbtMqa literal 0 HcmV?d00001 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/ubifs/walk.pyo b/NeoBoot/ubi_reader_arm/ubifs/walk.pyo new file mode 100644 index 0000000000000000000000000000000000000000..b10bcf2a3dfd35e37e1a7cf4f47bb6efd8fa1577 GIT binary patch literal 1342 zcmcJO&2G~`5XWa7CvDS)rhJIz)E=WAYKa4<3eh$NDpUuhK|lqv+<4PEb=JY&h(tncqw%xnHGX^Yhi)7ELY-&&N3F7DRws zP(;)fbRtNwZBb-VGlZ6-k8tNGu<5v(M|k)fS5-jM3lMUk6ThW12Ya_#Hsmr+0cRg4 z{RzJ&>IfPUjUX+$%+c7UkxdK%e81$qF6YPq!DM1Bq48;T?N0m;Q zlV0MtQdiR%t{Ipg2IlrW49~DgqvDMiU;e_t{If!g@og5vp2M&+jADjiwkX>V*Q`aT zVo&wE_-U~*D%QLcfv^2ckxEzZz|+7XU4&@G-EOSB^B~bnFjX8#PY-)i--7jW@9@d7 zcUXJvx%JwCUW6+Q1|A1#PLsXguOA)NUGG_~;T@ltpwq-xt#g@Tk(eUDt};i&V64RL zb~;~!OxAIV2Nwv?&LqGA8tU`URCG8Tono0Xe1VnR&(ft`#MzdBvIeK&D@6zEggFiGFEPW_(dEEXkqmSg{>DO!Gq^7XlKfMdDa)oVc>PQlgrOd$8gjQcLX* zwR={f3h_z-dg&)9P~;+yP@s>{C+HjWKF9;4-^@}H=?3UcB5Kdi%$zxMX1+6XNPjM6F`%P^c(!sO6AiUWvjIMI~yXEmNyZ(G<0&3SODQ z3Psb@nx?2qt!hD?qHu(K zf118k)VfN3mA-|QD{SsgV+N)NKjCk?p)j;dXhO5EkAu|aUZ^`kXc{Hv@M-h?pp)4$ zM&Eehp{-z$>LFrJp?B*|pa|hZg@#lP`Clx?4MsTU+|kli#~+Pn(^n3k zf2M$FSRxBoDLN(o?>W>foe#=%TB5TusX>!Ra6;X8sQ&Q9It|Nw%3ej5VF5&;!l5&S z>F6Wc+lzloWjjrWHA??RYRJ)p1~{xrLs`|Epgh8EFs5eVzL@HMFCy4Ge z*pJ(RIGY{mo7hSKGIrs;tTBhq6?d{^5c_6eXEBPr%$iikiEk`NElm=u!#IyFXGy1% ziE|`atT_|r)}U?rHb`Qb+0<*BeXo6J*@a=!73pu%z!r-8X%Jg&2JHsB*A+{v7$MTS z@7V(p@0&Er1ONeBl({TnS=P9VXdC#7Ci@(tW}c1lDwFJl~|vJZQF)C`#h@v1}gd;1V3d3OX}(Mz)NGR7q9T z9kr@%JBw;gt*AB|#13Vo3P}EiGY7a0iV*b;4qqAF6yd6D;ELdKZ1^+e*U-(9KZkCf z`~`H2eIqWn9Tyv}qUQLW`65m`I7kD%nLk zt@4(`85;EH6h71Hq|r#yG4{ zdc%Qu5i4;mIGaZ|9Q^MMUQD{};fpUO_k2TC|C2RvG7-P<#^d^5{+#}o&e2O}kDY#X zd~cvpBC#?-yawV0PU-+|eS8XY$EQET6?BfvT*ngNcXeWy)naSFmk|dLjBN=J1eoF` zHfUp<@iwMoK>7`)f`7sA(Z6Z$=J72ZK?3F7ZpBYmObek zTZ3XRw@GT)Wul9DozUxM8E0A&bD1WKIaBlGV#5oztmpD3Yh^nx?PgMtf;ecbu`bTp za)8Xe$8$Mj66O)A4fD@A-4z0^ag zWVG>A&dEHS^PI<;<)m_?AnNMO9G!;+=M{3^$@noQ`PERE`M0EIAkDuewSeDURadLdy1J?EsdaTb#&J@-M%ca}xeTYgq>48YM_&B)K5lpr14S2M zm1_sy1&8q^ND^$ytA~Yq37$p_Fh58y?gt(zp-6CuwY*8RmdjGSjWvWNM31~MGcG@D o-G^u{gC(P1`klnqY(|Nnhvs+epo~K}2fyEhhu74H&fNTe0q$+0;Q#;t literal 0 HcmV?d00001