CasperSecurity

Current Path : /lib/python3/dist-packages/landscape/lib/
Upload File :
Current File : //lib/python3/dist-packages/landscape/lib/persist.py

#
# Copyright (c) 2006 Canonical
# Copyright (c) 2004 Conectiva, Inc.
#
# Written by Gustavo Niemeyer <gustavo@niemeyer.net>
#
# This Python module is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This Python module is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this Python module; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
import os
import sys
import copy
import re

from twisted.python.compat import StringType  # Py2: basestring, Py3: str


__all__ = ["Persist", "PickleBackend", "BPickleBackend",
           "path_string_to_tuple", "path_tuple_to_string", "RootedPersist",
           "PersistError", "PersistReadOnlyError"]


NOTHING = object()


class PersistError(Exception):
    pass


class PersistReadOnlyError(PersistError):
    pass


class Persist(object):

    """Persist a hierarchical database of key=>value pairs.

    There are three different kinds of option maps, regarding the
    persistence and priority that maps are queried.

      - hard - Options are persistent.
      - soft - Options are not persistent, and have a higher priority
           than persistent options.
      - weak - Options are not persistent, and have a lower priority
           than persistent options.

    @ivar filename: The name of the file where persist data is saved
        or None if no filename is available.

    """

    def __init__(self, backend=None, filename=None):
        """
        @param backend: The backend to use. If none is specified,
            L{BPickleBackend} will be used.
        @param filename: The default filename to save to and load from. If
            specified, and the file exists, it will be immediately
            loaded. Specifying this will also allow L{save} to be called
            without any arguments to save the persist.
        """
        if backend is None:
            backend = BPickleBackend()
        self._backend = backend
        self._hardmap = backend.new()
        self._softmap = {}
        self._weakmap = {}
        self._readonly = False
        self._modified = False
        self._config = self
        self.filename = filename
        if filename is not None and os.path.exists(filename):
            self.load(filename)

    def _get_readonly(self):
        return self._readonly

    def _set_readonly(self, flag):
        self._readonly = bool(flag)

    def _get_modified(self):
        return self._modified

    readonly = property(_get_readonly, _set_readonly)
    modified = property(_get_modified)

    def reset_modified(self):
        """Set the database status as non-modified."""
        self._modified = False

    def assert_writable(self):
        """Assert if the object is writable

        @raise: L{PersistReadOnlyError}
        """
        if self._readonly:
            raise PersistReadOnlyError("Configuration is in readonly mode.")

    def load(self, filepath):
        """Load a persisted database."""

        def load_old():
            filepathold = filepath + ".old"
            if (os.path.isfile(filepathold) and
                os.path.getsize(filepathold) > 0
                ):

                # warning("Broken configuration file at %s" % filepath)
                # warning("Trying backup at %s" % filepathold)
                try:
                    self._hardmap = self._backend.load(filepathold)
                except Exception:
                    raise PersistError("Broken configuration file at %s" %
                                       filepathold)
                return True
            return False

        filepath = os.path.expanduser(filepath)
        if not os.path.isfile(filepath):
            if load_old():
                return
            raise PersistError("File not found: %s" % filepath)
        if os.path.getsize(filepath) == 0:
            load_old()
            return
        try:
            self._hardmap = self._backend.load(filepath)
        except Exception:
            if load_old():
                return
            raise PersistError("Broken configuration file at %s" % filepath)

    def save(self, filepath=None):
        """Save the persist to the given C{filepath}.

        If None is specified, then the filename passed during construction will
        be used.

        If the destination file already exists, it will be renamed
        to C{<filepath>.old}.
        """
        if filepath is None:
            if self.filename is None:
                raise PersistError("Need a filename!")
            filepath = self.filename
        filepath = os.path.expanduser(filepath)
        if os.path.isfile(filepath):
            os.rename(filepath, filepath + ".old")
        dirname = os.path.dirname(filepath)
        if dirname and not os.path.isdir(dirname):
            os.makedirs(dirname)
        self._backend.save(filepath, self._hardmap)

    def _traverse(self, obj, path, default=NOTHING, setvalue=NOTHING):
        if setvalue is not NOTHING:
            setvalue = self._backend.copy(setvalue)
        queue = list(path)
        marker = NOTHING
        newobj = obj
        while queue:
            obj = newobj
            elem = queue.pop(0)
            newobj = self._backend.get(obj, elem)
            if newobj is NotImplemented:
                if queue:
                    path = path[:-len(queue)]
                raise PersistError("Can't traverse %r (%r): %r" %
                                   (type(obj), path_tuple_to_string(path),
                                    str(obj)))
            if newobj is marker:
                break
        if newobj is not marker:
            if setvalue is not marker:
                newobj = self._backend.set(obj, elem, setvalue)
        else:
            if setvalue is marker:
                newobj = default
            else:
                while True:
                    if len(queue) > 0:
                        if type(queue[0]) is int:
                            newvalue = []
                        else:
                            newvalue = {}
                    else:
                        newvalue = setvalue
                    newobj = self._backend.set(obj, elem, newvalue)
                    if newobj is NotImplemented:
                        raise PersistError("Can't traverse %r with %r" %
                                           (type(obj), type(elem)))
                    if not queue:
                        break
                    obj = newobj
                    elem = queue.pop(0)
        return newobj

    def _getvalue(self, path, soft=False, hard=False, weak=False):
        if isinstance(path, StringType):
            path = path_string_to_tuple(path)
        marker = NOTHING
        if soft:
            value = self._traverse(self._softmap, path, marker)
        elif hard:
            value = self._traverse(self._hardmap, path, marker)
        elif weak:
            value = self._traverse(self._weakmap, path, marker)
        else:
            value = self._traverse(self._softmap, path, marker)
            if value is marker:
                value = self._traverse(self._hardmap, path, marker)
                if value is marker:
                    value = self._traverse(self._weakmap, path, marker)
        return value

    def has(self, path, value=NOTHING, soft=False, hard=False, weak=False):
        obj = self._getvalue(path, soft, hard, weak)
        marker = NOTHING
        if obj is marker:
            return False
        elif value is marker:
            return True
        result = self._backend.has(obj, value)
        if result is NotImplemented:
            raise PersistError("Can't check %r for containment" % type(obj))
        return result

    def keys(self, path, soft=False, hard=False, weak=False):
        obj = self._getvalue(path, soft, hard, weak)
        if obj is NOTHING:
            return []
        result = self._backend.keys(obj)
        if result is NotImplemented:
            raise PersistError("Can't return keys for %s" % type(obj))
        return result

    def get(self, path, default=None, soft=False, hard=False, weak=False):
        value = self._getvalue(path, soft, hard, weak)
        if value is NOTHING:
            return default
        return self._backend.copy(value)

    def set(self, path, value, soft=False, weak=False):
        assert path
        if isinstance(path, StringType):
            path = path_string_to_tuple(path)
        if soft:
            map = self._softmap
        elif weak:
            map = self._weakmap
        else:
            self.assert_writable()
            self._modified = True
            map = self._hardmap
        self._traverse(map, path, setvalue=value)

    def add(self, path, value, unique=False, soft=False, weak=False):
        assert path
        if isinstance(path, StringType):
            path = path_string_to_tuple(path)
        if soft:
            map = self._softmap
        elif weak:
            map = self._weakmap
        else:
            self.assert_writable()
            self._modified = True
            map = self._hardmap
        if unique:
            current = self._traverse(map, path)
            if type(current) is list and value in current:
                return
        path = path + (sys.maxsize,)
        self._traverse(map, path, setvalue=value)

    def remove(self, path, value=NOTHING, soft=False, weak=False):
        assert path
        if isinstance(path, StringType):
            path = path_string_to_tuple(path)
        if soft:
            map = self._softmap
        elif weak:
            map = self._weakmap
        else:
            self.assert_writable()
            self._modified = True
            map = self._hardmap
        marker = NOTHING
        while path:
            if value is marker:
                obj = self._traverse(map, path[:-1])
                elem = path[-1]
                isvalue = False
            else:
                obj = self._traverse(map, path)
                elem = value
                isvalue = True
            result = False
            if obj is not marker:
                result = self._backend.remove(obj, elem, isvalue)
                if result is NotImplemented:
                    raise PersistError("Can't remove %r from %r" %
                                       (elem, type(obj)))
            if self._backend.empty(obj):
                if value is not marker:
                    value = marker
                else:
                    path = path[:-1]
            else:
                break
        return result

    def move(self, oldpath, newpath, soft=False, weak=False):
        if not (soft or weak):
            self.assert_writable()
        if isinstance(oldpath, StringType):
            oldpath = path_string_to_tuple(oldpath)
        if isinstance(newpath, StringType):
            newpath = path_string_to_tuple(newpath)
        result = False
        marker = NOTHING
        value = self._getvalue(oldpath, soft, not (soft or weak), weak)
        if value is not marker:
            self.remove(oldpath, soft=soft, weak=weak)
            self.set(newpath, value, weak, soft)
            result = True
        return result

    def root_at(self, path):
        """
        Rebase the database hierarchy.

        @return: A L{RootedPersist} using this L{Persist} as parent.
        """
        return RootedPersist(self, path)


class RootedPersist(object):
    """Root a L{Persist}'s tree at a particular branch.

    This class shares the same interface of L{Persist} and provides a shortcut
    to access the nodes of a particular branch in a L{Persist}'s tree.

    The chosen branch will be viewed as the root of the tree of the
    L{RootedPersist} and all operations will be forwarded to the parent
    L{Persist} as appropriate.
    """

    def __init__(self, parent, root):
        """
        @param parent: the parent L{Persist}.
        @param root: a branch of the parent L{Persist}'s tree, that
            will be used as root of this L{RootedPersist}.
        """
        self.parent = parent
        if isinstance(root, StringType):
            self.root = path_string_to_tuple(root)
        else:
            self.root = root

    readonly = property(lambda self: self.parent.readonly)
    modified = property(lambda self: self.parent.modified)

    def assert_writable(self):
        self.parent.assert_writable()

    def has(self, path, value=NOTHING, soft=False, hard=False, weak=False):
        if isinstance(path, StringType):
            path = path_string_to_tuple(path)
        return self.parent.has(self.root + path, value, soft, hard, weak)

    def keys(self, path, soft=False, hard=False, weak=False):
        if isinstance(path, StringType):
            path = path_string_to_tuple(path)
        return self.parent.keys(self.root + path, soft, hard, weak)

    def get(self, path, default=None, soft=False, hard=False, weak=False):
        if isinstance(path, StringType):
            path = path_string_to_tuple(path)
        return self.parent.get(self.root + path, default, soft, hard, weak)

    def set(self, path, value, soft=False, weak=False):
        if isinstance(path, StringType):
            path = path_string_to_tuple(path)
        return self.parent.set(self.root + path, value, soft, weak)

    def add(self, path, value, unique=False, soft=False, weak=False):
        if isinstance(path, StringType):
            path = path_string_to_tuple(path)
        return self.parent.add(self.root + path, value, unique, soft, weak)

    def remove(self, path, value=NOTHING, soft=False, weak=False):
        if isinstance(path, StringType):
            path = path_string_to_tuple(path)
        return self.parent.remove(self.root + path, value, soft, weak)

    def move(self, oldpath, newpath, soft=False, weak=False):
        if isinstance(oldpath, StringType):
            oldpath = path_string_to_tuple(oldpath)
        if isinstance(newpath, StringType):
            newpath = path_string_to_tuple(newpath)
        return self.parent.move(self.root + oldpath, self.root + newpath,
                                soft, weak)

    def root_at(self, path):
        if isinstance(path, StringType):
            path = path_string_to_tuple(path)
        return self.parent.root_at(self.root + path)


_splitpath = re.compile(r"(\[-?\d+\])|(?<!\\)\.").split


def path_string_to_tuple(path):
    """Convert a L{Persist} path string to a path tuple.

    Examples:

        >>> path_string_to_tuple("ab")
        ("ab",)
        >>> path_string_to_tuple("ab.cd")
        ("ab", "cd"))
        >>> path_string_to_tuple("ab[0][1]")
        ("ab", 0, 1)
        >>> path_string_to_tuple("ab[0].cd[1]")
        ("ab", 0, "cd", 1)

    Raises L{PersistError} if the given path string is invalid.
    """
    if "." not in path and "[" not in path:
        return (path,)
    result = []
    tokens = _splitpath(path)
    for token in tokens:
        if token:
            if token[0] == "[" and token[-1] == "]":
                try:
                    result.append(int(token[1:-1]))
                except ValueError:
                    raise PersistError("Invalid path index: %r" % token)
            else:
                result.append(token.replace(r"\.", "."))
    return tuple(result)


def path_tuple_to_string(path):
    result = []
    for elem in path:
        if type(elem) is int:
            result[-1] += "[%d]" % elem
        else:
            result.append(str(elem).replace(".", r"\."))
    return ".".join(result)


class Backend(object):
    """
    Base class for L{Persist} backends implementing hierarchical storage
    functionality.

    Each node of the hierarchy is an object of type C{dict}, C{list}
    or C{tuple}. A node can have zero or more children, each child can be
    another node or a leaf value compatible with the backend's serialization
    mechanism.

    Each child element is associated with a unique key, that can be used to
    get, set or remove the child itself from its containing node. If the node
    object is of type C{dict}, then the child keys will be the keys of the
    dictionary, otherwise if the node object is of type C{list} or C{tuple}
    the child element keys are the indexes of the available items, or the value
    of items theselves.

    The root node object is always a C{dict}.

    For example:

        >>> backend = Backend()
        >>> root = backend.new()
        >>> backend.set(root, "foo", "bar")
        'bar'
        >>> egg = backend.set(root, "egg", [1, 2, 3])
        >>> backend.set(egg, 0, 10)
        10
        >>> root
        {'foo': 'bar', 'egg': [10, 2, 3]}
    """

    def new(self):
        raise NotImplementedError

    def load(self, filepath):
        raise NotImplementedError

    def save(self, filepath, map):
        raise NotImplementedError

    def get(self, obj, elem, _marker=NOTHING):
        """Lookup a child in the given node object."""
        if type(obj) is dict:
            newobj = obj.get(elem, _marker)
        elif type(obj) in (tuple, list):
            if type(elem) is int:
                try:
                    newobj = obj[elem]
                except IndexError:
                    newobj = _marker
            elif elem in obj:
                newobj = elem
            else:
                newobj = _marker
        else:
            newobj = NotImplemented
        return newobj

    def set(self, obj, elem, value):
        """Set the value of the given child in the given node object."""
        if type(obj) is dict:
            newobj = obj[elem] = value
        elif type(obj) is list and type(elem) is int:
            lenobj = len(obj)
            if lenobj <= elem:
                obj.append(None)
                elem = lenobj
            elif elem < 0 and abs(elem) > lenobj:
                obj.insert(0, None)
                elem = 0
            newobj = obj[elem] = value
        else:
            newobj = NotImplemented
        return newobj

    def remove(self, obj, elem, isvalue):
        """Remove a the given child in the given node object.

        @param isvalue: In case the node object is a C{list}, a boolean
            indicating if C{elem} is the index of the child or the value
            of the child itself.
        """
        result = False
        if type(obj) is dict:
            if elem in obj:
                del obj[elem]
                result = True
        elif type(obj) is list:
            if not isvalue and type(elem) is int:
                try:
                    del obj[elem]
                    result = True
                except IndexError:
                    pass
            elif elem in obj:
                obj[:] = [x for x in obj if x != elem]
                result = True
        else:
            result = NotImplemented
        return result

    def copy(self, value):
        """Copy a node or a value."""
        if type(value) in (dict, list):
            return copy.deepcopy(value)
        return value

    def empty(self, obj):
        """Whether the given node object has no children."""
        return (not obj)

    def has(self, obj, elem):
        """Whether the given node object contains the given child element."""
        contains = getattr(obj, "__contains__", None)
        if contains:
            return contains(elem)
        return NotImplemented

    def keys(self, obj):
        """Return the keys of the child elements of the given node object."""
        keys = getattr(obj, "keys", None)
        if keys:
            return keys()
        elif type(obj) is list:
            return range(len(obj))
        return NotImplemented


class PickleBackend(Backend):

    def __init__(self):
        from landscape.lib.compat import cPickle
        self._pickle = cPickle

    def new(self):
        return {}

    def load(self, filepath):
        with open(filepath, 'rb') as fd:
            return self._pickle.load(fd)

    def save(self, filepath, map):
        with open(filepath, "wb") as fd:
            self._pickle.dump(map, fd, 2)


class BPickleBackend(Backend):

    def __init__(self):
        from landscape.lib import bpickle
        self._bpickle = bpickle

    def new(self):
        return {}

    def load(self, filepath):
        with open(filepath, "rb") as fd:
            return self._bpickle.loads(fd.read())

    def save(self, filepath, map):
        with open(filepath, "wb") as fd:
            fd.write(self._bpickle.dumps(map))

# vim:ts=4:sw=4:et
Hacker Blog, Shell İndir, Sql İnjection, XSS Attacks, LFI Attacks, Social Hacking, Exploit Bot, Proxy Tools, Web Shell, PHP Shell, Alfa Shell İndir, Hacking Training Set, DDoS Script, Denial Of Service, Botnet, RFI Attacks, Encryption
Telegram @BIBIL_0DAY