mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-29 09:18:53 +00:00
175 lines
5.2 KiB
Python
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
|