2007-12-05 06:01:37 +00:00
|
|
|
|
|
|
|
import os
|
|
|
|
from zope.interface import implements
|
|
|
|
from twisted.internet import defer
|
|
|
|
from twisted.python import failure
|
2008-01-14 18:58:58 +00:00
|
|
|
from twisted.application import service
|
2008-07-16 20:14:39 +00:00
|
|
|
from allmydata import uri, dirnode
|
2008-06-03 07:03:16 +00:00
|
|
|
from allmydata.interfaces import IURI, IMutableFileNode, IFileNode, \
|
2008-07-17 23:47:09 +00:00
|
|
|
FileTooLargeError, ICheckable
|
2008-07-16 20:14:39 +00:00
|
|
|
from allmydata.immutable import checker
|
|
|
|
from allmydata.immutable.encode import NotEnoughSharesError
|
2008-01-14 18:58:58 +00:00
|
|
|
from allmydata.util import log
|
2007-12-05 06:01:37 +00:00
|
|
|
|
|
|
|
class FakeCHKFileNode:
|
|
|
|
"""I provide IFileNode, but all of my data is stored in a class-level
|
|
|
|
dictionary."""
|
|
|
|
implements(IFileNode)
|
|
|
|
all_contents = {}
|
|
|
|
|
|
|
|
def __init__(self, u, client):
|
|
|
|
self.client = client
|
|
|
|
self.my_uri = u.to_string()
|
|
|
|
|
|
|
|
def get_uri(self):
|
|
|
|
return self.my_uri
|
|
|
|
def get_readonly_uri(self):
|
|
|
|
return self.my_uri
|
|
|
|
def get_verifier(self):
|
|
|
|
return IURI(self.my_uri).get_verifier()
|
2008-07-16 22:42:56 +00:00
|
|
|
def check(self, verify=False, repair=False):
|
|
|
|
r = checker.Results(None)
|
|
|
|
r.healthy = True
|
|
|
|
r.problems = []
|
|
|
|
return defer.succeed(r)
|
2007-12-05 06:01:37 +00:00
|
|
|
def is_mutable(self):
|
|
|
|
return False
|
|
|
|
def is_readonly(self):
|
|
|
|
return True
|
|
|
|
|
|
|
|
def download(self, target):
|
|
|
|
if self.my_uri not in self.all_contents:
|
2008-04-15 23:08:32 +00:00
|
|
|
f = failure.Failure(NotEnoughSharesError())
|
2007-12-05 06:01:37 +00:00
|
|
|
target.fail(f)
|
|
|
|
return defer.fail(f)
|
|
|
|
data = self.all_contents[self.my_uri]
|
|
|
|
target.open(len(data))
|
|
|
|
target.write(data)
|
|
|
|
target.close()
|
|
|
|
return defer.maybeDeferred(target.finish)
|
|
|
|
def download_to_data(self):
|
|
|
|
if self.my_uri not in self.all_contents:
|
2008-04-15 23:08:32 +00:00
|
|
|
return defer.fail(NotEnoughSharesError())
|
2007-12-05 06:01:37 +00:00
|
|
|
data = self.all_contents[self.my_uri]
|
|
|
|
return defer.succeed(data)
|
|
|
|
def get_size(self):
|
|
|
|
data = self.all_contents[self.my_uri]
|
|
|
|
return len(data)
|
|
|
|
|
|
|
|
def make_chk_file_uri(size):
|
|
|
|
return uri.CHKFileURI(key=os.urandom(16),
|
|
|
|
uri_extension_hash=os.urandom(32),
|
|
|
|
needed_shares=3,
|
|
|
|
total_shares=10,
|
|
|
|
size=size)
|
|
|
|
|
|
|
|
def create_chk_filenode(client, contents):
|
|
|
|
u = make_chk_file_uri(len(contents))
|
|
|
|
n = FakeCHKFileNode(u, client)
|
|
|
|
FakeCHKFileNode.all_contents[u.to_string()] = contents
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
|
|
class FakeMutableFileNode:
|
|
|
|
"""I provide IMutableFileNode, but all of my data is stored in a
|
|
|
|
class-level dictionary."""
|
|
|
|
|
2008-07-17 23:47:09 +00:00
|
|
|
implements(IMutableFileNode, ICheckable)
|
2008-06-03 07:03:16 +00:00
|
|
|
MUTABLE_SIZELIMIT = 10000
|
2007-12-05 06:01:37 +00:00
|
|
|
all_contents = {}
|
2008-06-03 07:03:16 +00:00
|
|
|
|
2007-12-05 06:01:37 +00:00
|
|
|
def __init__(self, client):
|
|
|
|
self.client = client
|
|
|
|
self.my_uri = make_mutable_file_uri()
|
|
|
|
self.storage_index = self.my_uri.storage_index
|
2008-04-02 01:45:13 +00:00
|
|
|
def create(self, initial_contents, key_generator=None):
|
2008-06-03 07:03:16 +00:00
|
|
|
if len(initial_contents) > self.MUTABLE_SIZELIMIT:
|
|
|
|
raise FileTooLargeError("SDMF is limited to one segment, and "
|
|
|
|
"%d > %d" % (len(initial_contents),
|
|
|
|
self.MUTABLE_SIZELIMIT))
|
2007-12-05 06:01:37 +00:00
|
|
|
self.all_contents[self.storage_index] = initial_contents
|
|
|
|
return defer.succeed(self)
|
|
|
|
def init_from_uri(self, myuri):
|
|
|
|
self.my_uri = IURI(myuri)
|
|
|
|
self.storage_index = self.my_uri.storage_index
|
|
|
|
return self
|
|
|
|
def get_uri(self):
|
2007-12-05 06:42:54 +00:00
|
|
|
return self.my_uri.to_string()
|
2008-05-20 01:52:19 +00:00
|
|
|
def get_readonly(self):
|
|
|
|
return self.my_uri.get_readonly()
|
2007-12-05 06:42:54 +00:00
|
|
|
def get_readonly_uri(self):
|
|
|
|
return self.my_uri.get_readonly().to_string()
|
2007-12-05 06:01:37 +00:00
|
|
|
def is_readonly(self):
|
|
|
|
return self.my_uri.is_readonly()
|
|
|
|
def is_mutable(self):
|
|
|
|
return self.my_uri.is_mutable()
|
|
|
|
def get_writekey(self):
|
|
|
|
return "\x00"*16
|
2007-12-05 06:57:40 +00:00
|
|
|
def get_size(self):
|
|
|
|
return "?" # TODO: see mutable.MutableFileNode.get_size
|
2007-12-05 06:01:37 +00:00
|
|
|
|
2008-07-17 23:47:09 +00:00
|
|
|
def get_storage_index(self):
|
|
|
|
return self.storage_index
|
|
|
|
|
2008-07-16 00:23:25 +00:00
|
|
|
def check(self, verify=False, repair=False):
|
|
|
|
r = checker.Results(None)
|
|
|
|
r.healthy = True
|
|
|
|
r.problems = []
|
|
|
|
return defer.succeed(r)
|
|
|
|
|
2008-07-17 23:47:09 +00:00
|
|
|
def deep_check(self, verify=False, repair=False):
|
|
|
|
d = self.check(verify, repair)
|
|
|
|
def _done(r):
|
2008-07-18 00:06:20 +00:00
|
|
|
dr = checker.DeepCheckResults(self.storage_index)
|
2008-07-17 23:47:09 +00:00
|
|
|
dr.add_check(r)
|
|
|
|
return dr
|
|
|
|
d.addCallback(_done)
|
|
|
|
return d
|
|
|
|
|
2008-04-18 00:51:38 +00:00
|
|
|
def download_best_version(self):
|
|
|
|
return defer.succeed(self.all_contents[self.storage_index])
|
|
|
|
def overwrite(self, new_contents):
|
2008-06-03 07:03:16 +00:00
|
|
|
if len(new_contents) > self.MUTABLE_SIZELIMIT:
|
|
|
|
raise FileTooLargeError("SDMF is limited to one segment, and "
|
|
|
|
"%d > %d" % (len(new_contents),
|
|
|
|
self.MUTABLE_SIZELIMIT))
|
2007-12-05 06:01:37 +00:00
|
|
|
assert not self.is_readonly()
|
|
|
|
self.all_contents[self.storage_index] = new_contents
|
|
|
|
return defer.succeed(None)
|
2008-04-18 02:57:04 +00:00
|
|
|
def modify(self, modifier):
|
2008-06-03 07:03:16 +00:00
|
|
|
# this does not implement FileTooLargeError, but the real one does
|
2008-04-18 03:06:06 +00:00
|
|
|
return defer.maybeDeferred(self._modify, modifier)
|
|
|
|
def _modify(self, modifier):
|
2008-04-18 02:57:04 +00:00
|
|
|
assert not self.is_readonly()
|
|
|
|
old_contents = self.all_contents[self.storage_index]
|
|
|
|
self.all_contents[self.storage_index] = modifier(old_contents)
|
2008-04-18 03:06:06 +00:00
|
|
|
return None
|
2007-12-05 06:01:37 +00:00
|
|
|
|
2008-05-20 01:38:39 +00:00
|
|
|
def download(self, target):
|
|
|
|
if self.storage_index not in self.all_contents:
|
|
|
|
f = failure.Failure(NotEnoughSharesError())
|
|
|
|
target.fail(f)
|
|
|
|
return defer.fail(f)
|
|
|
|
data = self.all_contents[self.storage_index]
|
|
|
|
target.open(len(data))
|
|
|
|
target.write(data)
|
|
|
|
target.close()
|
|
|
|
return defer.maybeDeferred(target.finish)
|
|
|
|
def download_to_data(self):
|
|
|
|
if self.storage_index not in self.all_contents:
|
|
|
|
return defer.fail(NotEnoughSharesError())
|
|
|
|
data = self.all_contents[self.storage_index]
|
|
|
|
return defer.succeed(data)
|
2007-12-05 06:01:37 +00:00
|
|
|
|
|
|
|
def make_mutable_file_uri():
|
|
|
|
return uri.WriteableSSKFileURI(writekey=os.urandom(16),
|
|
|
|
fingerprint=os.urandom(32))
|
|
|
|
def make_verifier_uri():
|
|
|
|
return uri.SSKVerifierURI(storage_index=os.urandom(16),
|
|
|
|
fingerprint=os.urandom(32))
|
|
|
|
|
2008-03-01 01:40:27 +00:00
|
|
|
class FakeDirectoryNode(dirnode.NewDirectoryNode):
|
2007-12-05 06:01:37 +00:00
|
|
|
"""This offers IDirectoryNode, but uses a FakeMutableFileNode for the
|
|
|
|
backing store, so it doesn't go to the grid. The child data is still
|
|
|
|
encrypted and serialized, so this isn't useful for tests that want to
|
|
|
|
look inside the dirnodes and check their contents.
|
|
|
|
"""
|
|
|
|
filenode_class = FakeMutableFileNode
|
2008-01-14 18:58:58 +00:00
|
|
|
|
|
|
|
class LoggingServiceParent(service.MultiService):
|
|
|
|
def log(self, *args, **kwargs):
|
|
|
|
return log.msg(*args, **kwargs)
|