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

View File

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