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 0000000..9b45bc9 Binary files /dev/null and b/NeoBoot/ubi_reader_arm/argparse_neo.pyo differ 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 0000000..65f4724 Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubi/__init__.pyo differ 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 0000000..cd7d5ad Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubi/block/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_arm/ubi/block/layout.py b/NeoBoot/ubi_reader_arm/ubi/block/layout.py new file mode 100644 index 0000000..d2f95de --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubi/block/layout.py @@ -0,0 +1,23 @@ +#!/usr/bin/python +from ubi.block import sort + +def group_pairs(blocks, layout_blocks_list): + layouts_grouped = [[blocks[layout_blocks_list[0]].peb_num]] + for l in layout_blocks_list[1:]: + for lnd in layouts_grouped: + if blocks[l].vtbl_recs[0].name == blocks[lnd[0]].vtbl_recs[0].name: + lnd.append(blocks[l].peb_num) + break + else: + layouts_grouped.append([blocks[l].peb_num]) + + return layouts_grouped + + +def associate_blocks(blocks, layout_pairs, start_peb_num): + seq_blocks = [] + for layout_pair in layout_pairs: + seq_blocks = sort.by_image_seq(blocks, blocks[layout_pair[0]].ec_hdr.image_seq) + layout_pair.append(seq_blocks) + + return layout_pairs \ No newline at end of file diff --git a/NeoBoot/ubi_reader_arm/ubi/block/layout.pyo b/NeoBoot/ubi_reader_arm/ubi/block/layout.pyo new file mode 100644 index 0000000..58a88ee Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubi/block/layout.pyo differ 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 0000000..ab7f768 Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubi/block/sort.pyo differ 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 0000000..b005c18 Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubi/defines.pyo differ 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/display.pyo b/NeoBoot/ubi_reader_arm/ubi/display.pyo new file mode 100644 index 0000000..832d29d Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubi/display.pyo differ 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 0000000..b1f1290 Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubi/headers/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_arm/ubi/headers/errors.py b/NeoBoot/ubi_reader_arm/ubi/headers/errors.py new file mode 100644 index 0000000..eee0ebd --- /dev/null +++ b/NeoBoot/ubi_reader_arm/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_arm/ubi/headers/errors.pyo b/NeoBoot/ubi_reader_arm/ubi/headers/errors.pyo new file mode 100644 index 0000000..c17b1cb Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubi/headers/errors.pyo differ diff --git a/NeoBoot/ubi_reader_arm/ubi/image.py b/NeoBoot/ubi_reader_arm/ubi/image.py new file mode 100644 index 0000000..b613ce4 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/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_arm/ubi/image.pyo b/NeoBoot/ubi_reader_arm/ubi/image.pyo new file mode 100644 index 0000000..91d9670 Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubi/image.pyo differ diff --git a/NeoBoot/ubi_reader_arm/ubi/volume/__init__.py b/NeoBoot/ubi_reader_arm/ubi/volume/__init__.py new file mode 100644 index 0000000..70d3e76 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/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_arm/ubi/volume/__init__.pyo b/NeoBoot/ubi_reader_arm/ubi/volume/__init__.pyo new file mode 100644 index 0000000..ca888de Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubi/volume/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_arm/ubi_extract_files.py b/NeoBoot/ubi_reader_arm/ubi_extract_files.py new file mode 100644 index 0000000..7a94848 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubi_extract_files.py @@ -0,0 +1,65 @@ +#!/usr/bin/python + +import os +import sys +import argparse_neo +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__': + os.system('echo "\n[NeoBoot] Zip file unzipped.\nInstallation in progress, please wait ..."') + description = 'Extract contents of UBI image.' + usage = 'ubi_extract_files.py [options] filepath' + parser = argparse_neo.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 'Wait almost over ...\nLoading the image 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_arm/ubi_io/__init__.py b/NeoBoot/ubi_reader_arm/ubi_io/__init__.py new file mode 100644 index 0000000..9f3bd62 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/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_arm/ubi_io/__init__.pyo b/NeoBoot/ubi_reader_arm/ubi_io/__init__.pyo new file mode 100644 index 0000000..7d403d9 Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubi_io/__init__.pyo differ 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 0000000..78a2626 Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubifs/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_arm/ubifs/defines.py b/NeoBoot/ubi_reader_arm/ubifs/defines.py new file mode 100644 index 0000000..a0b3aa9 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/ubifs/defines.py @@ -0,0 +1,221 @@ +#!/usr/bin/python +import struct +UBIFS_NODE_MAGIC = '1\x18\x10\x06' +UBIFS_CRC32_INIT = 4294967295L +UBIFS_MIN_COMPR_LEN = 128 +UBIFS_MIN_COMPRESS_DIFF = 64 +UBIFS_ROOT_INO = 1 +UBIFS_FIRST_INO = 64 +UBIFS_MAX_NLEN = 255 +UBIFS_MAX_JHEADS = 1 +UBIFS_BLOCK_SIZE = 4096 +UBIFS_BLOCK_SHIFT = 12 +UBIFS_PADDING_BYTE = '\xce' +UBIFS_MAX_KEY_LEN = 16 +UBIFS_SK_LEN = 8 +UBIFS_MIN_FANOUT = 3 +UBIFS_MAX_LEVELS = 512 +UBIFS_MAX_INO_DATA = UBIFS_BLOCK_SIZE +UBIFS_LPT_FANOUT = 4 +UBIFS_LPT_FANOUT_SHIFT = 2 +UBIFS_LPT_CRC_BITS = 16 +UBIFS_LPT_CRC_BYTES = 2 +UBIFS_LPT_TYPE_BITS = 4 +UBIFS_LPT_PNODE = 0 +UBIFS_LPT_NNODE = 1 +UBIFS_LPT_LTAB = 2 +UBIFS_LPT_LSAVE = 3 +UBIFS_LPT_NODE_CNT = 4 +UBIFS_LPT_NOT_A_NODE = (1 << UBIFS_LPT_TYPE_BITS) - 1 +UBIFS_ITYPE_REG = 0 +UBIFS_ITYPE_DIR = 1 +UBIFS_ITYPE_LNK = 2 +UBIFS_ITYPE_BLK = 3 +UBIFS_ITYPE_CHR = 4 +UBIFS_ITYPE_FIFO = 5 +UBIFS_ITYPE_SOCK = 6 +UBIFS_ITYPES_CNT = 7 +UBIFS_KEY_HASH_R5 = 0 +UBIFS_KEY_HASH_TEST = 1 +PRINT_UBIFS_KEY_HASH = ['r5', 'test'] +UBIFS_SIMPLE_KEY_FMT = 0 +UBIFS_S_KEY_BLOCK_BITS = 29 +UBIFS_S_KEY_BLOCK_MASK = 536870911 +UBIFS_S_KEY_HASH_BITS = UBIFS_S_KEY_BLOCK_BITS +UBIFS_S_KEY_HASH_MASK = UBIFS_S_KEY_BLOCK_MASK +UBIFS_INO_KEY = 0 +UBIFS_DATA_KEY = 1 +UBIFS_DENT_KEY = 2 +UBIFS_XENT_KEY = 3 +UBIFS_KEY_TYPES_CNT = 4 +UBIFS_SB_LEBS = 1 +UBIFS_MST_LEBS = 2 +UBIFS_SB_LNUM = 0 +UBIFS_MST_LNUM = UBIFS_SB_LNUM + UBIFS_SB_LEBS +UBIFS_LOG_LNUM = UBIFS_MST_LNUM + UBIFS_MST_LEBS +UBIFS_COMPR_FL = 1 +UBIFS_SYNC_FL = 2 +UBIFS_IMMUTABLE_FL = 4 +UBIFS_APPEND_FL = 8 +UBIFS_DIRSYNC_FL = 16 +UBIFS_XATTR_FL = 32 +UBIFS_FL_MASK = 31 +UBIFS_COMPR_NONE = 0 +UBIFS_COMPR_LZO = 1 +UBIFS_COMPR_ZLIB = 2 +UBIFS_COMPR_TYPES_CNT = 3 +PRINT_UBIFS_COMPR = ['none', 'lzo', 'zlib'] +UBIFS_INO_NODE = 0 +UBIFS_DATA_NODE = 1 +UBIFS_DENT_NODE = 2 +UBIFS_XENT_NODE = 3 +UBIFS_TRUN_NODE = 4 +UBIFS_PAD_NODE = 5 +UBIFS_SB_NODE = 6 +UBIFS_MST_NODE = 7 +UBIFS_REF_NODE = 8 +UBIFS_IDX_NODE = 9 +UBIFS_CS_NODE = 10 +UBIFS_ORPH_NODE = 11 +UBIFS_NODE_TYPES_CNT = 12 +UBIFS_MST_DIRTY = 1 +UBIFS_MST_NO_ORPHS = 2 +UBIFS_MST_RCVRY = 4 +UBIFS_NO_NODE_GROUP = 0 +UBIFS_IN_NODE_GROUP = 1 +UBIFS_LAST_OF_NODE_GROUP = 2 +UBIFS_FLG_BIGLPT = 2 +UBIFS_FLG_SPACE_FIXUP = 4 +UBIFS_COMMON_HDR_FORMAT = '> 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 0000000..1915b7d Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubifs/misc.pyo differ 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 0000000..f674057 Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubifs/nodes/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_arm/ubifs/nodes/extract.py b/NeoBoot/ubi_reader_arm/ubifs/nodes/extract.py new file mode 100644 index 0000000..9f8f7b0 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/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_arm/ubifs/nodes/extract.pyo b/NeoBoot/ubi_reader_arm/ubifs/nodes/extract.pyo new file mode 100644 index 0000000..cbba52c Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubifs/nodes/extract.pyo differ diff --git a/NeoBoot/ubi_reader_arm/ubifs/output.py b/NeoBoot/ubi_reader_arm/ubifs/output.py new file mode 100644 index 0000000..dd3f4f4 --- /dev/null +++ b/NeoBoot/ubi_reader_arm/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_arm/ubifs/output.pyo b/NeoBoot/ubi_reader_arm/ubifs/output.pyo new file mode 100644 index 0000000..8075cbc Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubifs/output.pyo differ 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 0000000..b10bcf2 Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ubifs/walk.pyo differ diff --git a/NeoBoot/ubi_reader_arm/ui/__init__.pyo b/NeoBoot/ubi_reader_arm/ui/__init__.pyo new file mode 100644 index 0000000..0c87ff1 Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ui/__init__.pyo differ diff --git a/NeoBoot/ubi_reader_arm/ui/common.py b/NeoBoot/ubi_reader_arm/ui/common.py new file mode 100644 index 0000000..c8669fd --- /dev/null +++ b/NeoBoot/ubi_reader_arm/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 diff --git a/NeoBoot/ubi_reader_arm/ui/common.pyo b/NeoBoot/ubi_reader_arm/ui/common.pyo new file mode 100644 index 0000000..65ee506 Binary files /dev/null and b/NeoBoot/ubi_reader_arm/ui/common.pyo differ