mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-28 16:58:53 +00:00
306 lines
7.9 KiB
Python
306 lines
7.9 KiB
Python
from kernel import *
|
|
import stat, errno, os, time
|
|
from cStringIO import StringIO
|
|
from OrderedDict import OrderedDict
|
|
|
|
INFINITE = 86400.0
|
|
|
|
|
|
class Wrapper(object):
|
|
def __init__(self, obj):
|
|
self.obj = obj
|
|
|
|
def getuid(self):
|
|
return uid(self.obj)
|
|
|
|
def __hash__(self):
|
|
return hash(self.obj)
|
|
|
|
def __eq__(self, other):
|
|
return self.obj == other
|
|
|
|
def __ne__(self, other):
|
|
return self.obj != other
|
|
|
|
|
|
class BaseDir(object):
|
|
|
|
def join(self, name):
|
|
"Return a file or subdirectory object"
|
|
for item in self.listdir():
|
|
if isinstance(item, tuple):
|
|
subname, subnode = item
|
|
if subname == name:
|
|
return subnode
|
|
raise KeyError(name)
|
|
|
|
def listdir(self):
|
|
"Return a list of names, or a list of (name, object)"
|
|
raise NotImplementedError
|
|
|
|
def create(self, name):
|
|
"Create a file"
|
|
raise NotImplementedError
|
|
|
|
def mkdir(self, name):
|
|
"Create a subdirectory"
|
|
raise NotImplementedError
|
|
|
|
def symlink(self, name, target):
|
|
"Create a symbolic link"
|
|
raise NotImplementedError
|
|
|
|
def unlink(self, name):
|
|
"Remove a file or subdirectory."
|
|
raise NotImplementedError
|
|
|
|
def rename(self, newname, olddirnode, oldname):
|
|
"Move another node into this directory."
|
|
raise NotImplementedError
|
|
|
|
def getuid(self):
|
|
return uid(self)
|
|
|
|
def getattr(self, fs):
|
|
return fs.newattr(stat.S_IFDIR, self.getuid(), mode=0777), INFINITE
|
|
|
|
def setattr(self, **kwds):
|
|
pass
|
|
|
|
def getentries(self):
|
|
entries = OrderedDict()
|
|
for name in self.listdir():
|
|
if isinstance(name, tuple):
|
|
name, subnode = name
|
|
else:
|
|
subnode = None
|
|
entries[name] = subnode
|
|
return entries
|
|
|
|
|
|
class BaseFile(object):
|
|
|
|
def size(self):
|
|
"Return the size of the file, or None if not known yet"
|
|
f = self.open()
|
|
if isinstance(f, str):
|
|
return len(f)
|
|
f.seek(0, 2)
|
|
return f.tell()
|
|
|
|
def open(self):
|
|
"Return the content as a string or a file-like object"
|
|
raise NotImplementedError
|
|
|
|
def getuid(self):
|
|
return uid(self)
|
|
|
|
def getattr(self, fs):
|
|
sz = self.size()
|
|
attr = fs.newattr(stat.S_IFREG, self.getuid())
|
|
if sz is None:
|
|
timeout = 0
|
|
else:
|
|
attr.size = sz
|
|
timeout = INFINITE
|
|
return attr, timeout
|
|
|
|
def setattr(self, size, **kwds):
|
|
f = self.open()
|
|
if self.size() == size:
|
|
return
|
|
if isinstance(f, str):
|
|
raise IOError(errno.EPERM)
|
|
f.seek(size)
|
|
f.truncate()
|
|
|
|
|
|
class BaseSymLink(object):
|
|
|
|
def readlink(self):
|
|
"Return the symlink's target, as a string"
|
|
raise NotImplementedError
|
|
|
|
def getuid(self):
|
|
return uid(self)
|
|
|
|
def getattr(self, fs):
|
|
target = self.readlink()
|
|
attr = fs.newattr(stat.S_IFLNK, self.getuid())
|
|
attr.size = len(target)
|
|
attr.mode |= 0777
|
|
return attr, INFINITE
|
|
|
|
def setattr(self, **kwds):
|
|
pass
|
|
|
|
# ____________________________________________________________
|
|
|
|
class Dir(BaseDir):
|
|
def __init__(self, **contents):
|
|
self.contents = contents
|
|
def listdir(self):
|
|
return self.contents.items()
|
|
def join(self, name):
|
|
return self.contents[name]
|
|
def create(self, fs, name):
|
|
node = fs.File()
|
|
self.contents[name] = node
|
|
return node
|
|
def mkdir(self, fs, name):
|
|
node = fs.Dir()
|
|
self.contents[name] = node
|
|
return node
|
|
def symlink(self, fs, name, target):
|
|
node = fs.SymLink(target)
|
|
self.contents[name] = node
|
|
return node
|
|
def unlink(self, name):
|
|
del self.contents[name]
|
|
def rename(self, newname, olddirnode, oldname):
|
|
oldnode = olddirnode.join(oldname)
|
|
olddirnode.unlink(oldname)
|
|
self.contents[newname] = oldnode
|
|
|
|
class File(BaseFile):
|
|
def __init__(self):
|
|
self.data = StringIO()
|
|
def size(self):
|
|
self.data.seek(0, 2)
|
|
return self.data.tell()
|
|
def open(self):
|
|
return self.data
|
|
|
|
class SymLink(BaseFile):
|
|
def __init__(self, target):
|
|
self.target = target
|
|
def readlink(self):
|
|
return self.target
|
|
|
|
# ____________________________________________________________
|
|
|
|
|
|
class RWObjectFs(object):
|
|
"""A simple read-write file system based on Python objects."""
|
|
|
|
UID = os.getuid()
|
|
GID = os.getgid()
|
|
UMASK = os.umask(0); os.umask(UMASK)
|
|
|
|
Dir = Dir
|
|
File = File
|
|
SymLink = SymLink
|
|
|
|
def __init__(self, rootnode):
|
|
self.nodes = {FUSE_ROOT_ID: rootnode}
|
|
self.starttime = time.time()
|
|
|
|
def newattr(self, s, ino, mode=0666):
|
|
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):
|
|
return node.getattr(self)
|
|
|
|
def setattr(self, node, mode, uid, gid, size, atime, mtime):
|
|
node.setattr(mode=mode, uid=uid, gid=gid, size=size,
|
|
atime=atime, mtime=mtime)
|
|
|
|
def listdir(self, node):
|
|
entries = node.getentries()
|
|
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):
|
|
try:
|
|
subnode = node.join(name)
|
|
except KeyError:
|
|
raise IOError(errno.ENOENT, name)
|
|
else:
|
|
res = uid(subnode)
|
|
self.nodes[res] = subnode
|
|
return res, INFINITE
|
|
|
|
def mknod(self, dirnode, filename, mode):
|
|
node = dirnode.create(filename)
|
|
return self.newnodeid(node), INFINITE
|
|
|
|
def mkdir(self, dirnode, subdirname, mode):
|
|
node = dirnode.mkdir(subdirname)
|
|
return self.newnodeid(node), INFINITE
|
|
|
|
def symlink(self, dirnode, linkname, target):
|
|
node = dirnode.symlink(linkname, target)
|
|
return self.newnodeid(node), INFINITE
|
|
|
|
def unlink(self, dirnode, filename):
|
|
try:
|
|
dirnode.unlink(filename)
|
|
except KeyError:
|
|
raise IOError(errno.ENOENT, filename)
|
|
|
|
rmdir = unlink
|
|
|
|
def open(self, node, mode):
|
|
f = node.open()
|
|
if isinstance(f, str):
|
|
f = StringIO(f)
|
|
return f
|
|
|
|
def readlink(self, node):
|
|
return node.readlink()
|
|
|
|
def rename(self, olddirnode, oldname, newdirnode, newname):
|
|
try:
|
|
newdirnode.rename(newname, olddirnode, oldname)
|
|
except KeyError:
|
|
raise IOError(errno.ENOENT, oldname)
|
|
|
|
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))
|