Skip to content

Instantly share code, notes, and snippets.

@micoli
Last active December 4, 2015 00:42
Show Gist options
  • Save micoli/27e4d724b6dc9b594421 to your computer and use it in GitHub Desktop.
Save micoli/27e4d724b6dc9b594421 to your computer and use it in GitHub Desktop.
fuse memory fs stored in xml
#!/usr/bin/env python
#sudo pip install lxml
from collections import defaultdict
from errno import ENOENT
from stat import S_IFDIR, S_IFLNK, S_IFREG
from sys import argv, exit,_getframe
from time import time
from datetime import datetime, timedelta
from fuse import FUSE, FuseOSError, Operations, LoggingMixIn
from lxml import etree
from copy import deepcopy
import logging
import json
import os
import base64
import binascii
import collections
import re
if not hasattr(__builtins__, 'bytes'):
bytes = str
class inode():
def __init__(self,node):
self.node = node
def set_text(self,value):
self.node.text = etree.CDATA(base64.encodestring(value))
def getparent(self):
return inode(self.node.getparent())
def remove(self,n):
return self.node.remove(n)
def get_text(self):
return base64.decodestring(self.node.text)
def create_sub(self,type,childName):
node = etree.SubElement(self.node,childName)
node.attrib['type']=type
return inode(node)
def get_attrs(self):
attrs = deepcopy(self.node.attrib)
for k in attrs:
attrs[k]=self.get_attr(k)
return attrs
def set_attr(self,attr,value):
if(attr=='attrs'):
self.node.attrib[attr]=json.dumps(value)
else:
self.node.attrib[attr]=repr(value)
def get_attr(self,attr):
if(attr=='st_ctime') or (attr=='st_mtime' ) or (attr=='st_atime'):
return float(self.node.attrib[attr])
elif(attr=='type'):
return self.node.attrib[attr]
else:
if(attr=='attrs'):
if (attr not in self.node.attrib) or (self.node.attrib[attr] is None) or (self.node.attrib[attr]==""):
return {}
else:
try:
return json.loads(self.node.attrib['attrs'])
except Exception as e:
print("error ["+self.node.attrib['attrs']+']'+repr(e))
return {}
else:
return int(self.node.attrib[attr])
class XmlFS(LoggingMixIn, Operations):
'Memory xml filesystem.'
def __init__(self,xmlFile):
self.root = etree.Element("root")
self.xmlFile = xmlFile
self.fd = 0
now = time()
if(os.path.exists(xmlFile)):
parser = etree.XMLParser()
for line in open(xmlFile):
parser.feed(line)
self.root = parser.close()
self.fs = self.root[0]
self.fd = int(self.root.xpath('count(//*)'))+1
else:
self.fs = etree.SubElement(self.root,'fs')
_inode=inode(self.fs)
_inode.set_attr('st_mode' ,S_IFDIR | 0755)
_inode.set_attr('st_ctime',now)
_inode.set_attr('st_mtime',now)
_inode.set_attr('st_atime',now)
_inode.set_attr('st_nlink',2)
_inode.set_attr('root',1)
def get_node(self,path):
if(path=="/"):
return inode(self.fs)
node = self.root.find('fs'+path)
if node is None:
raise FuseOSError(ENOENT)
return inode(node)
def get_node_name(self,path):
a= ('fs'+path).split('/')
logger.debug(a)
return a.pop(-1)
def get_node_parent(self,path):
a = ('fs'+path).split('/')
a.pop(-1)
return inode(self.root.find('/'.join(a)))
def dumptree(self):
logger.debug(etree.tostring(self.root, pretty_print=True))
def destroy(self,path):
self.save()
logger.info('clean exit, saved')
def save(self):
f = open(self.xmlFile, 'w')
f.write(etree.tostring(self.root, pretty_print=True))
f.close()
####################### fs
def statfs(self, path):
return dict(f_bsize=512, f_blocks=4096, f_bavail=2048)
####################### attribs
def chmod(self, path, mode):
_inode = self.get_node(path)
val = _inode.get_attr('st_mode')
val &= 0770000
val |= mode
_inode.set_attr('st_mode',val)
return 0
def chown(self, path, uid, gid):
_inode = self.get_node(path)
_inode.set_attr('st_uid',uid)
_inode.set_attr('st_gid',gid)
def getattr(self, path, fh=None):
return self.get_node(path).get_attrs()
def utimens(self, path, times=None):
now = time()
atime, mtime = times if times else (now, now)
_node = self.get_node(path)
_node.set_attr('st_atime', atime)
_node.set_attr('st_mtime', mtime)
####################### xattrs
def getxattr(self, path, name, position=0):
logger.debug("get xattr "+path+" "+name)
_node = self.get_node(path)
try:
return _node.get_attr('attrs')[name]
except KeyError:
return '' # Should return ENOATTR
def listxattr(self, path):
return self.get_node(path).get_attr('attrs').keys()
def removexattr(self, path, name):
_node = self.get_node(path)
attrs = _node.get_attr('attrs')
try:
del attrs[name]
_node.set_attr('attrs',attrs)
except KeyError:
pass # Should return ENOATTR
def setxattr(self, path, name, value, options, position=0):
# Ignore options
_node = self.get_node(path)
attrs = _node.get_attr('attrs')
attrs[name] = value
_node.set_attr('attrs',attrs)
####################### files
def create(self, path, mode):
if(path=="/--save"):
self.save()
return False
_parent = self.get_node_parent(path)
_node = _parent.create_sub('file',self.get_node_name(path))
_node.set_attr('st_mode' ,S_IFREG | mode)
_node.set_attr('st_size' ,0)
_node.set_attr('st_ctime',time())
_node.set_attr('st_mtime',time())
_node.set_attr('st_atime',time())
_node.set_attr('st_nlink',1)
_node.set_text("")
self.fd += 1
return self.fd
def open(self, path, flags):
self.fd += 1
return self.fd
def read(self, path, size, offset, fh):
return self.get_node(path).get_text()[offset:offset + size]
def write(self, path, data, offset, fh):
_node = self.get_node(path)
_node.set_text(_node.get_text()[:offset] + data)
_node.set_attr('st_size',len(_node.get_text()))
return len(data)
def truncate(self, path, length, fh=None):
_node = self.get_node(path)
_node.set_text(_node.get_text()[:length])
_node.set_attr('st_size',length)
####################### paths
def readdir(self, path, fh):
_node = self.get_node(path)
return ['.', '..'] + [child.tag for child in _node.node if child.tag != '/']
def rmdir(self, path):
_inode = self.get_node(path)
_parent = _inode.getparent()
_parent.remove(_inode.node)
_parent.set_attr('st_nlink',_parent.get_attr('st_nlink')-1)
def mkdir(self, path, mode):
_parent = self.get_node_parent(path)
_parent.set_attr('st_nlink',_parent.get_attr('st_nlink')+1)
_node = _parent.create_sub('path',self.get_node_name(path))
_node.set_attr('st_ctime',time())
_node.set_attr('st_mtime',time())
_node.set_attr('st_atime',time())
_node.set_attr('st_mode' ,S_IFDIR | mode)
_node.set_attr('st_size' ,0)
_node.set_attr('st_nlink',2)
####################### paths
def rename(self, old, new):
print "rename to do"
#self.files[new] = self.files.pop(old)
def symlink(self, target, source):
_parent = self.get_node_parent(path)
_node = _parent.create_sub('symlink',self.get_node_name(path))
_node.set_attr('st_mode', (S_IFLNK | 0777))
_node.set_attr('st_nlink', 1)
_node.set_attr('st_size', len(source))
_node.set_text(source)
def readlink(self, path):
return self.get_node(path).get_text()
def unlink(self, path):
_inode = self.get_node(path)
_parent = _inode.getparent()
_parent.remove(_inode.node)
_parent.set_attr('st_nlink',_parent.get_attr('st_nlink')-1)
if __name__ == '__main__':
if len(argv) != 3:
print('usage: %s <mountpoint> <xmlfile>' % argv[0])
exit(1)
logging.getLogger().setLevel(logging.DEBUG)
logging.basicConfig()
logger = logging.getLogger()
xmlFS = FUSE(XmlFS(argv[2]), argv[1], foreground=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment