from __future__ import with_statement
+import binascii as _B
import errno as _E
import os as _OS
-from cStringIO import StringIO as _StringIO
+import sys as _SYS
+
+if _SYS.version_info >= (3,): from io import StringIO as _StringIO
+else: from cStringIO import StringIO as _StringIO
import catacomb as _C
###--------------------------------------------------------------------------
### Python version portability.
-def _iterkeys(dict): return dict.iterkeys()
-def _itervalues(dict): return dict.itervalues()
-def _iteritems(dict): return dict.iteritems()
-
-def _bin(text): return text
-def _text(bin): return bin
+if _SYS.version_info >= (3,):
+ def _iterkeys(dict): return dict.keys()
+ def _itervalues(dict): return dict.values()
+ def _iteritems(dict): return dict.items()
+ def _bin(text): return text.encode(errors = "surrogateescape")
+ def _text(bin): return bin.decode(errors = "surrogateescape")
+else:
+ def _iterkeys(dict): return dict.iterkeys()
+ def _itervalues(dict): return dict.itervalues()
+ def _iteritems(dict): return dict.iteritems()
+ def _bin(text): return text
+ def _text(bin): return bin
_NUL = _bin('\0')
_CIPHER = _bin('cipher:')
_MAC = _bin('mac:')
+def _with_metaclass(meta, *supers):
+ return meta("#<anonymous base %s>" % meta.__name__,
+ supers or (object,), dict())
+
def _excval(): return _SYS.exc_info()[1]
+_M600 = int("600", 8)
+_M700 = int("700", 8)
+
###--------------------------------------------------------------------------
### Text encoding utilities.
def _b64(s):
"""Encode S as base64, without newlines, and trimming `=' padding."""
- return s.encode('base64').replace('\n', '').rstrip('=')
+ return _text(_B.b2a_base64(s)).replace('\n', '').rstrip('=')
def _unb64(s):
"""Decode S as base64 with trimmed `=' padding."""
- return (s + '='*((4 - len(s))%4)).decode('base64')
+ return _B.a2b_base64(s + '='*((4 - len(s))%4))
def _enc_metaval(val):
"""Encode VAL as a metadata item value, returning the result."""
Register a new concrete StorageBackend subclass.
"""
super(StorageBackendClass, me).__init__(name, supers, dict)
- if me.NAME is not None: StorageBackend.register_concrete_subclass(me)
+ try: name = me.NAME
+ except AttributeError: pass
+ else: StorageBackend.register_concrete_subclass(me)
-class StorageBackend (object):
+class StorageBackend (_with_metaclass(StorageBackendClass)):
"""
I provide basic protocol for password storage backends.
priority order when opening an existing database.
"""
- __metaclass__ = StorageBackendClass
- NAME = None
PRIO = 10
## The registry of subclasses.
except _G.error: raise StorageBackendRefusal(_excval())
def _create(me, file):
- me._db = _G.open(file, 'n', 0600)
+ me._db = _G.open(file, 'n', _M600)
def _close(me, abruptp):
me._db.close()
('unknown database schema version (%d > %d)' % (ver, me.VERSION))
def _create(me, file):
- fd = _OS.open(file, _OS.O_WRONLY | _OS.O_CREAT | _OS.O_EXCL, 0600)
+ fd = _OS.open(file, _OS.O_WRONLY | _OS.O_CREAT | _OS.O_EXCL, _M600)
_OS.close(fd)
try:
me._db = _Q.connect(file)
me._dirtyp = False
super(PlainTextBackend, me).__init__(*args, **kw)
- def _create_file(me, file, mode = 0600, freshp = False):
+ def _create_file(me, file, mode = _M600, freshp = False):
"""
Make sure FILE exists, creating it with the given MODE if necessary.
if not line or line.startswith('#'): continue
me._parse_line(line)
- def _write_file(me, file, writebody, mode = 0600, magic = None):
+ def _write_file(me, file, writebody, mode = _M600, magic = None):
"""
Update FILE atomically.
me._parse_meta(line)
def _create(me, file):
- _OS.mkdir(file, 0700)
- _OS.mkdir(_OS.path.join(file, 'pw'), 0700)
- _OS.mkdir(_OS.path.join(file, 'tmp'), 0700)
+ _OS.mkdir(file, _M700)
+ _OS.mkdir(_OS.path.join(file, 'pw'), _M700)
+ _OS.mkdir(_OS.path.join(file, 'tmp'), _M700)
me._mark_dirty()
me._dir = file
with f: return f.read()
def _put_passwd(me, label, payload):
new = me._pwfile(label, 'tmp')
- fd = _OS.open(new, _OS.O_WRONLY | _OS.O_CREAT | _OS.O_TRUNC, 0600)
+ fd = _OS.open(new, _OS.O_WRONLY | _OS.O_CREAT | _OS.O_TRUNC, _M600)
_OS.close(fd)
with open(new, 'wb') as f: f.write(payload)
_OS.rename(new, me._pwfile(label))