tahoe-lafs/contrib/fuse/impl_b/pyfuse/objectfs.py

175 lines
5.2 KiB
Python

from kernel import *
import stat, errno, os, time
from cStringIO import StringIO
from OrderedDict import OrderedDict
class ObjectFs:
"""A simple read-only file system based on Python objects.
Interface of Directory objects:
* join(name) returns a file or subdirectory object
* listdir() returns a list of names, or a list of (name, object)
join() is optional if listdir() returns a list of (name, object).
Alternatively, Directory objects can be plain dictionaries {name: object}.
Interface of File objects:
* size() returns the size
* read() returns the data
Alternatively, File objects can be plain strings.
Interface of SymLink objects:
* readlink() returns the symlink's target, as a string
"""
INFINITE = 86400.0
USE_DIR_CACHE = True
def __init__(self, rootnode):
self.nodes = {FUSE_ROOT_ID: rootnode}
if self.USE_DIR_CACHE:
self.dircache = {}
self.starttime = time.time()
self.uid = os.getuid()
self.gid = os.getgid()
self.umask = os.umask(0); os.umask(self.umask)
def newattr(self, s, ino, mode=0666):
if ino < 0:
ino = ~ino
return fuse_attr(ino = ino,
size = 0,
mode = s | (mode & ~self.umask),
nlink = 1, # even on dirs! this confuses 'find' in
# a good way :-)
atime = self.starttime,
mtime = self.starttime,
ctime = self.starttime,
uid = self.uid,
gid = self.gid)
def getnode(self, nodeid):
try:
return self.nodes[nodeid]
except KeyError:
raise IOError(errno.ESTALE, nodeid)
def getattr(self, node):
timeout = self.INFINITE
if isinstance(node, str):
attr = self.newattr(stat.S_IFREG, id(node))
attr.size = len(node)
elif hasattr(node, 'readlink'):
target = node.readlink()
attr = self.newattr(stat.S_IFLNK, id(node))
attr.size = len(target)
attr.mode |= 0777
elif hasattr(node, 'size'):
sz = node.size()
attr = self.newattr(stat.S_IFREG, id(node))
if sz is None:
timeout = 0
else:
attr.size = sz
else:
attr = self.newattr(stat.S_IFDIR, id(node), mode=0777)
#print 'getattr(%s) -> %s, %s' % (node, attr, timeout)
return attr, timeout
def getentries(self, node):
if isinstance(node, dict):
return node
try:
if not self.USE_DIR_CACHE:
raise KeyError
return self.dircache[node]
except KeyError:
entries = OrderedDict()
if hasattr(node, 'listdir'):
for name in node.listdir():
if isinstance(name, tuple):
name, subnode = name
else:
subnode = None
entries[name] = subnode
if self.USE_DIR_CACHE:
self.dircache[node] = entries
return entries
def listdir(self, node):
entries = self.getentries(node)
for name, subnode in entries.items():
if subnode is None:
subnode = node.join(name)
self.nodes[uid(subnode)] = subnode
entries[name] = subnode
if isinstance(subnode, str):
yield name, TYPE_REG
elif hasattr(subnode, 'readlink'):
yield name, TYPE_LNK
elif hasattr(subnode, 'size'):
yield name, TYPE_REG
else:
yield name, TYPE_DIR
def lookup(self, node, name):
entries = self.getentries(node)
try:
subnode = entries.get(name)
if subnode is None:
if hasattr(node, 'join'):
subnode = node.join(name)
entries[name] = subnode
else:
raise KeyError
except KeyError:
raise IOError(errno.ENOENT, name)
else:
return self.reply(subnode)
def reply(self, node):
res = uid(node)
self.nodes[res] = node
return res, self.INFINITE
def open(self, node, mode):
if not isinstance(node, str):
node = node.read()
if not hasattr(node, 'read'):
node = StringIO(node)
return node
def readlink(self, node):
return node.readlink()
def getxattrs(self, node):
return getattr(node, '__dict__', {})
# ____________________________________________________________
import struct
try:
HUGEVAL = 256 ** struct.calcsize('P')
except struct.error:
HUGEVAL = 0
def fixid(result):
if result < 0:
result += HUGEVAL
return result
def uid(obj):
"""
Return the id of an object as an unsigned number so that its hex
representation makes sense
"""
return fixid(id(obj))
class SymLink(object):
def __init__(self, target):
self.target = target
def readlink(self):
return self.target