Improve error handling

This commit is contained in:
Jarno Seppänen 2014-05-01 20:32:30 +03:00
parent 2d4a93d9fe
commit 22014090c6

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
import fuse # fusepy from fuse import FUSE, FuseOSError, Operations
import gnupg # python-gnupg import gnupg # python-gnupg
import zlib import zlib
import errno import errno
@ -142,18 +142,20 @@ class LoggingMixIn:
rtxt = rtxt[:10] rtxt = rtxt[:10]
log.debug('<- %s %s', op, rtxt) log.debug('<- %s %s', op, rtxt)
class GpgFs(LoggingMixIn, fuse.Operations): class GpgFs(LoggingMixIn, Operations):
#class GpgFs(fuse.Operations): #class GpgFs(Operations):
def __init__(self, encroot, keyid): def __init__(self, encroot, keyid):
''' '''
:param encroot: Encrypted root directory :param encroot: Encrypted root directory
''' '''
self.encroot = encroot self.encroot = encroot.rstrip('/')
assert os.path.exists(self.encroot)
assert os.path.isdir(self.encroot)
self.keyid = keyid self.keyid = keyid
#self.cache = cache #self.cache = cache
self.gpg = gnupg.GPG() self.gpg = gnupg.GPG()
self.index_path = encroot + '/index' self.index_path = self.encroot + '/index'
if os.path.exists(self.index_path): if os.path.exists(self.index_path):
self.root = read_index(self.gpg, self.index_path) self.root = read_index(self.gpg, self.index_path)
else: else:
@ -176,9 +178,14 @@ class GpgFs(LoggingMixIn, fuse.Operations):
node = self.root node = self.root
path = path[1:].split('/') path = path[1:].split('/')
if parent: if parent:
basename = path[-1]
path = path[:-1] path = path[:-1]
for name in path: for name in path:
if name not in node.children:
raise FuseOSError(errno.ENOENT)
node = node.children[name] node = node.children[name]
if parent:
return node, basename
return node return node
def _clear_write_cache(self): def _clear_write_cache(self):
@ -199,14 +206,14 @@ class GpgFs(LoggingMixIn, fuse.Operations):
os.chmod(encpath, mode) os.chmod(encpath, mode)
def chown(self, path, uid, gid): def chown(self, path, uid, gid):
raise fuse.FuseOSError(errno.ENOSYS) raise FuseOSError(errno.ENOSYS)
def create(self, path, mode): def create(self, path, mode):
encpath = hexlify(os.urandom(20)) encpath = hexlify(os.urandom(20))
encpath = encpath[:2] + '/' + encpath[2:] encpath = encpath[:2] + '/' + encpath[2:]
dir = self._find(path, parent=True) dir, path = self._find(path, parent=True)
path = path.rsplit('/', 1)[-1] if path in dir.children:
assert path not in dir.children raise FuseOSError(errno.EEXIST)
dir.children[path] = Entry(type=ENT_FILE, path=encpath, st_size=0) dir.children[path] = Entry(type=ENT_FILE, path=encpath, st_size=0)
log.debug('new path %s => %s', path, encpath) log.debug('new path %s => %s', path, encpath)
encdir = self.encroot + '/' + encpath[:2] encdir = self.encroot + '/' + encpath[:2]
@ -235,10 +242,7 @@ class GpgFs(LoggingMixIn, fuse.Operations):
return 0 return 0
def getattr(self, path, fh = None): def getattr(self, path, fh = None):
try: ent = self._find(path)
ent = self._find(path)
except KeyError:
raise fuse.FuseOSError(errno.ENOENT)
if ent.type == ENT_DIR: if ent.type == ENT_DIR:
return dict(st_mode = stat.S_IFDIR | ent.st_mode, st_size = 0, return dict(st_mode = stat.S_IFDIR | ent.st_mode, st_size = 0,
st_ctime = ent.st_ctime, st_mtime = ent.st_mtime, st_ctime = ent.st_ctime, st_mtime = ent.st_mtime,
@ -252,15 +256,15 @@ class GpgFs(LoggingMixIn, fuse.Operations):
st_ctime = s.st_ctime, st_nlink = s.st_nlink) st_ctime = s.st_ctime, st_nlink = s.st_nlink)
def getxattr(self, path, name, position = 0): def getxattr(self, path, name, position = 0):
raise fuse.FuseOSError(errno.ENODATA) # ENOATTR raise FuseOSError(errno.ENODATA) # ENOATTR
def listxattr(self, path): def listxattr(self, path):
return [] return []
def mkdir(self, path, mode): def mkdir(self, path, mode):
dir = self._find(path, parent=True) dir, path = self._find(path, parent=True)
path = path.rsplit('/', 1)[-1] if path in dir.children:
assert path not in dir.children raise FuseOSError(errno.EEXIST)
dir.children[path] = Entry(type=ENT_DIR, children={}, dir.children[path] = Entry(type=ENT_DIR, children={},
st_mode=(mode & 0777), st_mode=(mode & 0777),
st_mtime=int(time.time()), st_mtime=int(time.time()),
@ -283,45 +287,47 @@ class GpgFs(LoggingMixIn, fuse.Operations):
return ['.', '..'] + list(dir.children) return ['.', '..'] + list(dir.children)
def readlink(self, path): def readlink(self, path):
raise fuse.FuseOSError(errno.ENOSYS) raise FuseOSError(errno.ENOSYS)
def removexattr(self, path, name): def removexattr(self, path, name):
raise fuse.FuseOSError(errno.ENOSYS) raise FuseOSError(errno.ENOSYS)
def rename(self, old, new): def rename(self, old, new):
self.flush(old, 0) self.flush(old, 0)
self._clear_write_cache() self._clear_write_cache()
old_dir = self._find(old, parent=True) old_dir, old_name = self._find(old, parent=True)
old_name = old.rsplit('/', 1)[-1] if old_name not in old_dir.children:
new_dir = self._find(new, parent=True) raise FuseOSError(errno.ENOENT)
new_name = new.rsplit('/', 1)[-1] new_dir, new_name = self._find(new, parent=True)
if new_name in new_dir.children: if new_name in new_dir.children:
ent = new_dir.children[new_name] ent = new_dir.children[new_name]
if ent.type == ENT_FILE: if ent.type == ENT_FILE:
os.remove(self.encroot + '/' + ent.path) os.remove(self.encroot + '/' + ent.path)
elif ent.children:
raise FuseOSError(errno.ENOTEMPTY)
new_dir.children[new_name] = old_dir.children.pop(old_name) new_dir.children[new_name] = old_dir.children.pop(old_name)
self._write_index() self._write_index()
def rmdir(self, path): def rmdir(self, path):
parent = self._find(path, parent=True) parent, path = self._find(path, parent=True)
path = path.rsplit('/', 1)[-1] if path not in parent.children:
assert path in parent.children raise FuseOSError(errno.ENOENT)
ent = parent.children[path] ent = parent.children[path]
if ent.type != ENT_DIR: if ent.type != ENT_DIR:
raise fuse.FuseOSError(errno.ENOTDIR) raise FuseOSError(errno.ENOTDIR)
if ent.children: if ent.children:
raise fuse.FuseOSError(errno.ENOTEMPTY) raise FuseOSError(errno.ENOTEMPTY)
del parent.children[path] del parent.children[path]
self._write_index() self._write_index()
def setxattr(self, path, name, value, options, position = 0): def setxattr(self, path, name, value, options, position = 0):
raise fuse.FuseOSError(errno.ENOSYS) raise FuseOSError(errno.ENOSYS)
def statfs(self, path): def statfs(self, path):
raise fuse.FuseOSError(errno.ENOSYS) raise FuseOSError(errno.ENOSYS)
def symlink(self, target, source): def symlink(self, target, source):
raise fuse.FuseOSError(errno.ENOSYS) raise FuseOSError(errno.ENOSYS)
def truncate(self, path, length, fh = None): def truncate(self, path, length, fh = None):
self.flush(path, 0) self.flush(path, 0)
@ -342,8 +348,9 @@ class GpgFs(LoggingMixIn, fuse.Operations):
if self.write_path == path: if self.write_path == path:
# no need to flush afterwards # no need to flush afterwards
self._clear_write_cache() self._clear_write_cache()
dir = self._find(path, parent=True) dir, name = self._find(path, parent=True)
name = path.rsplit('/', 1)[-1] if name not in dir.children:
raise FuseOSError(errno.ENOENT)
encpath = self.encroot + '/' + dir.children[name].path encpath = self.encroot + '/' + dir.children[name].path
os.remove(encpath) os.remove(encpath)
del dir.children[name] del dir.children[name]
@ -391,4 +398,4 @@ if __name__ == '__main__':
log.addHandler(logging.FileHandler(logpath, 'w')) log.addHandler(logging.FileHandler(logpath, 'w'))
log.setLevel(logging.DEBUG) log.setLevel(logging.DEBUG)
fs = GpgFs(sys.argv[2], sys.argv[1]) fs = GpgFs(sys.argv[2], sys.argv[1])
fuse.FUSE(fs, sys.argv[3], foreground=True) FUSE(fs, sys.argv[3], foreground=True)