Ported gpgfs to Python 3.5. Whooo!

This commit is contained in:
Jan Philipp Timme 2015-12-08 00:15:47 +01:00
parent 295a642522
commit 4b22f7014e
2 changed files with 50 additions and 49 deletions

View File

@ -8,12 +8,12 @@ import sys
import logging import logging
import struct import struct
import time import time
from cStringIO import StringIO from io import BytesIO
import gpgstore import gpgstore
from contextlib import contextmanager from contextlib import contextmanager
from threading import Lock from threading import Lock
magic = 'GPGFS1\n' magic = b'GPGFS1\n'
log = logging.getLogger('gpgfs') log = logging.getLogger('gpgfs')
@ -22,30 +22,31 @@ class Entry:
Filesystem object, either file or directory. Filesystem object, either file or directory.
''' '''
def __init__(self, **kwargs): def __init__(self, **kwargs):
for k,v in kwargs.iteritems(): for k,v in kwargs.items():
setattr(self, k, v) setattr(self, k, v)
def read_index(store, path): def read_index(store, path):
if not store.exists(path): if not store.exists(path):
now = time.time() now = time.time()
root = Entry(children={}, nlink=3, size=0, root = Entry(children={}, nlink=3, size=0,
mode=stat.S_IFDIR | 0755, mode=stat.S_IFDIR | 0o755,
mtime=now, ctime=now) mtime=now, ctime=now)
write_index(store, path, root) write_index(store, path, root)
log.info('created %s', path) log.info('created %s', path)
return root return root
data = store.get(path, format=gpgstore.FMT_GPG) data = store.get(path, format=gpgstore.FMT_GPG)
buf = StringIO(data) buf = BytesIO(data)
if buf.read(len(magic)) != magic: temp = buf.read(len(magic))
raise IOError, 'index parse error: %s' % path if temp != magic:
raise IOError('index parse error: %s' % path)
read_atom(buf) read_atom(buf)
root = Entry(**read_dict(buf)) root = Entry(**read_dict(buf))
return root return root
def write_index(store, path, root): def write_index(store, path, root):
buf = StringIO() buf = BytesIO()
buf.write(magic) buf.write(magic)
header = '' header = b''
write_atom(buf, header) write_atom(buf, header)
write_dict(buf, root) write_dict(buf, root)
store.put(buf.getvalue(), path=path, format=gpgstore.FMT_GPG) store.put(buf.getvalue(), path=path, format=gpgstore.FMT_GPG)
@ -53,36 +54,36 @@ def write_index(store, path, root):
def write_dict(fd, dct): def write_dict(fd, dct):
# breadth-first # breadth-first
children = [] children = []
buf = StringIO() buf = BytesIO()
if not isinstance(dct, dict): if not isinstance(dct, dict):
dct = dct.__dict__ dct = dct.__dict__
for key in dct: for key in dct:
write_atom(buf, key.encode('utf8')) write_atom(buf, key.encode('utf-8'))
val = dct[key] val = dct[key]
if isinstance(val, dict): if isinstance(val, dict):
buf.write('D') buf.write(b'D')
children.append(val) children.append(val)
elif isinstance(val, Entry): elif isinstance(val, Entry):
buf.write('E') buf.write(b'E')
children.append(val) children.append(val)
elif isinstance(val, (int, long)): elif isinstance(val, (int)):
if val < 2**32: if val < 2**32:
buf.write('I') buf.write(b'I')
buf.write(struct.pack('<I', val)) buf.write(struct.pack('<I', val))
else: else:
buf.write('L') buf.write(b'L')
buf.write(struct.pack('<Q', val)) buf.write(struct.pack('<Q', val))
elif isinstance(val, float): elif isinstance(val, float):
buf.write('F') buf.write(b'F')
buf.write(struct.pack('<d', val)) buf.write(struct.pack('<d', val))
elif isinstance(val, str): elif isinstance(val, bytes):
buf.write('B') buf.write(b'')
write_atom(buf, val) write_atom(buf, val)
elif isinstance(val, unicode): elif isinstance(val, str):
buf.write('S') buf.write(b'S')
write_atom(buf, val.encode('utf8')) write_atom(buf, val.encode('utf-8'))
else: else:
raise TypeError, type(val) raise TypeError(type(val))
write_atom(fd, buf.getvalue()) write_atom(fd, buf.getvalue())
for c in children: for c in children:
write_dict(fd, c) write_dict(fd, c)
@ -91,23 +92,23 @@ def read_dict(fd):
dct = {} dct = {}
buf = read_atom(fd) buf = read_atom(fd)
buflen = len(buf) buflen = len(buf)
buf = StringIO(buf) buf = BytesIO(buf)
while buf.tell() < buflen: while buf.tell() < buflen:
key = read_atom(buf).decode('utf8') key = read_atom(buf).decode('utf-8')
tag = buf.read(1) tag = buf.read(1)
if tag == 'D': val = read_dict(fd) if tag == b'D': val = read_dict(fd)
elif tag == 'E': val = Entry(**read_dict(fd)) elif tag == b'E': val = Entry(**read_dict(fd))
elif tag == 'I': val = struct.unpack('<I', buf.read(4))[0] elif tag == b'I': val = struct.unpack('<I', buf.read(4))[0]
elif tag == 'L': val = struct.unpack('<Q', buf.read(8))[0] elif tag == b'L': val = struct.unpack('<Q', buf.read(8))[0]
elif tag == 'F': val = struct.unpack('<d', buf.read(8))[0] elif tag == b'F': val = struct.unpack('<d', buf.read(8))[0]
elif tag == 'B': val = read_atom(buf) elif tag == b'': val = read_atom(buf)
elif tag == 'S': val = read_atom(buf).decode('utf8') elif tag == b'S': val = read_atom(buf).decode('utf-8')
else: raise TypeError, tag else: raise TypeError(tag)
dct[key] = val dct[key] = val
return dct return dct
def write_atom(fd, atom): def write_atom(fd, atom):
assert isinstance(atom, str) assert isinstance(atom, bytes)
fd.write(struct.pack('<I', len(atom))) fd.write(struct.pack('<I', len(atom)))
fd.write(atom) fd.write(atom)
@ -126,7 +127,7 @@ class LoggingMixIn:
try: try:
ret = getattr(self, op)(path, *args) ret = getattr(self, op)(path, *args)
return ret return ret
except OSError, e: except OSError as e:
ret = str(e) ret = str(e)
raise raise
except: except:
@ -207,16 +208,16 @@ class GpgFs(LoggingMixIn, Operations):
def chmod(self, path, mode): def chmod(self, path, mode):
# sanitize mode (clear setuid/gid/sticky bits) # sanitize mode (clear setuid/gid/sticky bits)
mode &= 0777 mode &= 0o777
with self.transaction(): with self.transaction():
ent = self._find(path) ent = self._find(path)
ent.mode = mode | (ent.mode & 0170000) ent.mode = mode | (ent.mode & 0o170000)
def chown(self, path, uid, gid): def chown(self, path, uid, gid):
raise FuseOSError(errno.ENOSYS) raise FuseOSError(errno.ENOSYS)
def create(self, path, mode): def create(self, path, mode):
mode &= 0777 mode &= 0o777
mode |= stat.S_IFREG mode |= stat.S_IFREG
with self.transaction() as putx: with self.transaction() as putx:
parent, name = self._find(path, parent=True) parent, name = self._find(path, parent=True)
@ -237,7 +238,7 @@ class GpgFs(LoggingMixIn, Operations):
log.debug('nothing to flush') log.debug('nothing to flush')
return 0 return 0
with self.transaction() as putx: with self.transaction() as putx:
buf = ''.join(self.write_buf) buf = b''.join(self.write_buf)
self.write_buf = [buf] self.write_buf = [buf]
ent = self._find(self.write_path) ent = self._find(self.write_path)
ent.size = len(buf) ent.size = len(buf)
@ -265,7 +266,7 @@ class GpgFs(LoggingMixIn, Operations):
return [] return []
def mkdir(self, path, mode): def mkdir(self, path, mode):
mode &= 0777 mode &= 0o777
mode |= stat.S_IFDIR mode |= stat.S_IFDIR
with self.transaction(): with self.transaction():
parent, name = self._find(path, parent=True) parent, name = self._find(path, parent=True)
@ -349,7 +350,7 @@ class GpgFs(LoggingMixIn, Operations):
with self.transaction() as putx: with self.transaction() as putx:
ent = self._find(path) ent = self._find(path)
if length == 0: if length == 0:
buf = '' buf = b''
else: else:
buf = self.store.get(ent.encpath, format=ent.encformat) buf = self.store.get(ent.encpath, format=ent.encformat)
buf = buf[:length] buf = buf[:length]
@ -389,7 +390,7 @@ class GpgFs(LoggingMixIn, Operations):
self.write_buf.append(data) self.write_buf.append(data)
self.write_len += len(data) self.write_len += len(data)
else: else:
buf = ''.join(self.write_buf) buf = b''.join(self.write_buf)
buf = buf[:offset] + data + buf[offset + len(data):] buf = buf[:offset] + data + buf[offset + len(data):]
self.write_buf = [buf] self.write_buf = [buf]
self.write_len = len(buf) self.write_len = len(buf)

View File

@ -18,22 +18,22 @@ class GpgStore(object):
def put(self, data, path=None, format=FMT_GPG): def put(self, data, path=None, format=FMT_GPG):
assert format == FMT_GPG assert format == FMT_GPG
if not path: if not path:
path = hexlify(os.urandom(20)) path = hexlify(os.urandom(20)).decode('utf-8')
path = path[:2] + '/' + path[2:] path = path[:2] + '/' + path[2:]
encdir = self.encroot + '/' + path[:2] encdir = self.encroot + '/' + path[:2]
if not os.path.exists(encdir): if not os.path.exists(encdir):
os.mkdir(encdir, 0755) os.mkdir(encdir, 0o755)
res = self.gpg.encrypt(data, self.keyid, armor=False) res = self.gpg.encrypt(data, self.keyid, armor=False)
if not res.ok: if not res.ok:
log.error("encryption failed (keyid %s), %s: %s", log.error("encryption failed (keyid %s), %s: %s",
self.keyid, res.status, path) self.keyid, res.status, path)
raise OSError(errno.EIO) raise OSError(errno.EIO)
try: try:
with file(self.encroot + '/' + path + '.tmp', 'w') as fd: with open(self.encroot + '/' + path + '.tmp', 'wb') as fd:
fd.write(res.data) fd.write(res.data)
os.rename(self.encroot + '/' + path + '.tmp', os.rename(self.encroot + '/' + path + '.tmp',
self.encroot + '/' + path) self.encroot + '/' + path)
except IOError, err: except IOError as err:
log.error("write failed: %s: %s", path, str(err)) log.error("write failed: %s: %s", path, str(err))
raise OSError(err.errno) raise OSError(err.errno)
finally: finally:
@ -45,8 +45,8 @@ class GpgStore(object):
def get(self, path, format=FMT_GPG): def get(self, path, format=FMT_GPG):
assert format == FMT_GPG assert format == FMT_GPG
try: try:
data = file(self.encroot + '/' + path).read() data = open(self.encroot + '/' + path, 'rb').read()
except OSError, err: except OSError as err:
log.error("read failed: %s: %s", path, str(err)) log.error("read failed: %s: %s", path, str(err))
raise raise
if not data: if not data:
@ -56,7 +56,7 @@ class GpgStore(object):
log.error("decryption failed, %s: %s", res.status, path) log.error("decryption failed, %s: %s", res.status, path)
raise OSError(errno.EIO) raise OSError(errno.EIO)
log.debug('decrypted %s' % path) log.debug('decrypted %s' % path)
return data return res.data
def delete(self, path): def delete(self, path):
os.remove(self.encroot + '/' + path) os.remove(self.encroot + '/' + path)