tahoe-lafs/allmydata/filetable.py

99 lines
3.3 KiB
Python

import os, shutil
from zope.interface import implements
from foolscap import Referenceable
from allmydata.interfaces import RIMutableDirectoryNode
from twisted.application import service
from twisted.python import log
class DeadDirectoryNodeError(Exception):
"""The directory referenced by this node has been deleted."""
class BadDirectoryError(Exception):
"""There was a problem with the directory being referenced."""
class BadFileError(Exception):
"""The file being referenced does not exist."""
class MutableDirectoryNode(Referenceable):
implements(RIMutableDirectoryNode)
def __init__(self, basedir):
self._basedir = basedir
def validate_name(self, name):
if name == "." or name == ".." or "/" in name:
raise DeadDirectoryNodeError("bad filename component")
# this is private
def get_child(self, name):
self.validate_name(name)
absname = os.path.join(self._basedir, name)
if os.path.isdir(absname):
return MutableDirectoryNode(absname)
raise DeadDirectoryNodeError("no such directory")
# these are the public methods, available to anyone who holds a reference
def list(self):
log.msg("Dir(%s).list" % self._basedir)
results = []
if not os.path.isdir(self._basedir):
raise DeadDirectoryNodeError("This directory has been deleted")
for name in os.listdir(self._basedir):
absname = os.path.join(self._basedir, name)
if os.path.isdir(absname):
results.append( (name, MutableDirectoryNode(absname)) )
elif os.path.isfile(absname):
f = open(absname, "rb")
data = f.read()
f.close()
results.append( (name, data) )
# anything else is ignored
return results
remote_list = list
def add_directory(self, name):
self.validate_name(name)
absname = os.path.join(self._basedir, name)
if os.path.isdir(absname):
raise BadDirectoryError("the directory '%s' already exists" % name)
if os.path.exists(absname):
raise BadDirectoryError("the directory '%s' already exists "
"(but isn't a directory)" % name)
os.mkdir(absname)
return MutableDirectoryNode(absname)
remote_add_directory = add_directory
def add_file(self, name, data):
self.validate_name(name)
f = open(os.path.join(self._basedir, name), "wb")
f.write(data)
f.close()
remote_add_file = add_file
def remove(self, name):
self.validate_name(name)
absname = os.path.join(self._basedir, name)
if os.path.isdir(absname):
shutil.rmtree(absname)
elif os.path.isfile(absname):
os.unlink(absname)
else:
raise BadFileError("Cannot delete non-existent file '%s'" % name)
class GlobalVirtualDrive(service.MultiService):
name = "filetable"
VDRIVEDIR = "vdrive"
def __init__(self, basedir="."):
service.MultiService.__init__(self)
vdrive_dir = os.path.join(basedir, self.VDRIVEDIR)
if not os.path.exists(vdrive_dir):
os.mkdir(vdrive_dir)
self._root = MutableDirectoryNode(vdrive_dir)
def get_root(self):
return self._root