def create_dirnode(self, initial_children={}):
d = self.nodemaker.create_new_mutable_directory(initial_children)
return d
+ def create_immutable_dirnode(self, children):
+ return self.nodemaker.create_immutable_directory(children,
+ self.convergence)
def create_mutable_file(self, contents=None, keysize=None):
return self.nodemaker.create_mutable_file(contents, keysize)
from allmydata.util import hashutil, mathutil, base32, log
from allmydata.util.assertutil import precondition
from allmydata.util.netstring import netstring, split_netstring
-from allmydata.uri import DirectoryURI, ReadonlyDirectoryURI, \
- LiteralFileURI, from_string
+from allmydata.uri import LiteralFileURI, from_string, wrap_dirnode_cap
from pycryptopp.cipher.aes import AES
from allmydata.util.dictutil import AuxValueDict
def _encrypt_rwcap(filenode, rwcap):
assert isinstance(rwcap, str)
+ writekey = filenode.get_writekey()
+ if not writekey:
+ return ""
salt = hashutil.mutable_rwcap_salt_hash(rwcap)
- key = hashutil.mutable_rwcap_key_hash(salt, filenode.get_writekey())
+ key = hashutil.mutable_rwcap_key_hash(salt, writekey)
cryptor = AES(key)
crypttext = cryptor.process(rwcap)
mac = hashutil.hmac(key, salt + crypttext)
def __init__(self, filenode, nodemaker, uploader):
self._node = filenode
filenode_cap = filenode.get_cap()
- if filenode_cap.is_readonly():
- self._uri = ReadonlyDirectoryURI(filenode_cap)
- else:
- self._uri = DirectoryURI(filenode_cap)
+ self._uri = wrap_dirnode_cap(filenode_cap)
self._nodemaker = nodemaker
self._uploader = uploader
self._most_recent_size = None
def __repr__(self):
- return "<%s %s %s>" % (self.__class__.__name__, self.is_readonly() and "RO" or "RW", hasattr(self, '_uri') and self._uri.abbrev())
+ return "<%s %s-%s %s>" % (self.__class__.__name__,
+ self.is_readonly() and "RO" or "RW",
+ self.is_mutable() and "MUT" or "IMM",
+ hasattr(self, '_uri') and self._uri.abbrev())
def get_size(self):
# return the size of our backing mutable file, in bytes, if we've
# fetched it.
+ if not self._node.is_mutable():
+ # TODO?: consider using IMutableFileNode.providedBy(self._node)
+ return self._node.get_size()
return self._most_recent_size
def _set_size(self, data):
return data
def _read(self):
- d = self._node.download_best_version()
- d.addCallback(self._set_size)
+ if self._node.is_mutable():
+ # use the IMutableFileNode API.
+ d = self._node.download_best_version()
+ d.addCallback(self._set_size)
+ else:
+ d = self._node.download_to_data()
d.addCallback(self._unpack_contents)
return d
class IUploader(Interface):
def upload(uploadable):
"""Upload the file. 'uploadable' must impement IUploadable. This
- returns a Deferred which fires with an UploadResults instance, from
+ returns a Deferred which fires with an IUploadResults instance, from
which the URI of the file can be obtained as results.uri ."""
def upload_ssk(write_capability, new_version, uploadable):
from allmydata.util.assertutil import precondition
from allmydata.interfaces import INodeMaker
from allmydata.immutable.filenode import FileNode, LiteralFileNode
+from allmydata.immutable.upload import Data
from allmydata.mutable.filenode import MutableFileNode
from allmydata.dirnode import DirectoryNode, pack_children
from allmydata.unknown import UnknownNode
from allmydata import uri
+class DummyImmutableFileNode:
+ def get_writekey(self):
+ return None
+
class NodeMaker:
implements(INodeMaker)
return self._create_immutable(cap)
if isinstance(cap, (uri.ReadonlySSKFileURI, uri.WriteableSSKFileURI)):
return self._create_mutable(cap)
- if isinstance(cap, (uri.ReadonlyDirectoryURI, uri.DirectoryURI)):
+ if isinstance(cap, (uri.DirectoryURI,
+ uri.ReadonlyDirectoryURI,
+ uri.ImmutableDirectoryURI,
+ uri.LiteralDirectoryURI)):
filenode = self._create_from_cap(cap.get_filenode_cap())
return self._create_dirnode(filenode)
return None
pack_children(n, initial_children))
d.addCallback(self._create_dirnode)
return d
+
+ def create_immutable_directory(self, children, convergence):
+ for (name, (node, metadata)) in children.iteritems():
+ precondition(not isinstance(node, UnknownNode),
+ "create_immutable_directory does not accept UnknownNode", node)
+ precondition(isinstance(metadata, dict),
+ "create_immutable_directory requires metadata to be a dict, not None", metadata)
+ precondition(not node.is_mutable(),
+ "create_immutable_directory requires immutable children", node)
+ n = DummyImmutableFileNode() # writekey=None
+ packed = pack_children(n, children)
+ uploadable = Data(packed, convergence)
+ d = self.uploader.upload(uploadable, history=self.history)
+ def _uploaded(results):
+ filecap = self.create_from_cap(results.uri)
+ return filecap
+ d.addCallback(_uploaded)
+ d.addCallback(self._create_dirnode)
+ return d
def _done(res):
self.failUnless(isinstance(res, dirnode.DirectoryNode))
rep = str(res)
- self.failUnless("RW" in rep)
+ self.failUnless("RW-MUT" in rep)
d.addCallback(_done)
return d
def _created(dn):
self.failUnless(isinstance(dn, dirnode.DirectoryNode))
rep = str(dn)
- self.failUnless("RW" in rep)
+ self.failUnless("RW-MUT" in rep)
return dn.list()
d.addCallback(_created)
def _check_kids(children):
bad_kids2))
return d
+ def test_immutable(self):
+ self.basedir = "dirnode/Dirnode/test_immutable"
+ self.set_up_grid()
+ c = self.g.clients[0]
+ nm = c.nodemaker
+ setup_py_uri = "URI:CHK:n7r3m6wmomelk4sep3kw5cvduq:os7ijw5c3maek7pg65e5254k2fzjflavtpejjyhshpsxuqzhcwwq:3:20:14861"
+ one_uri = "URI:LIT:n5xgk" # LIT for "one"
+ mut_readcap = "URI:SSK-RO:e3mdrzfwhoq42hy5ubcz6rp3o4:ybyibhnp3vvwuq2vaw2ckjmesgkklfs6ghxleztqidihjyofgw7q"
+ mut_writecap = "URI:SSK:vfvcbdfbszyrsaxchgevhmmlii:euw4iw7bbnkrrwpzuburbhppuxhc3gwxv26f6imekhz7zyw2ojnq"
+ kids = {u"one": (nm.create_from_cap(one_uri), {}),
+ u"two": (nm.create_from_cap(setup_py_uri),
+ {"metakey": "metavalue"}),
+ }
+ d = c.create_immutable_dirnode(kids)
+ def _created(dn):
+ self.failUnless(isinstance(dn, dirnode.DirectoryNode))
+ self.failIf(dn.is_mutable())
+ self.failUnless(dn.is_readonly())
+ rep = str(dn)
+ self.failUnless("RO-IMM" in rep)
+ cap = dn.get_cap()
+ self.failUnlessIn("CHK", cap.to_string())
+ self.cap = cap
+ return dn.list()
+ d.addCallback(_created)
+ def _check_kids(children):
+ self.failUnlessEqual(sorted(children.keys()), [u"one", u"two"])
+ one_node, one_metadata = children[u"one"]
+ two_node, two_metadata = children[u"two"]
+ self.failUnlessEqual(one_node.get_size(), 3)
+ self.failUnlessEqual(two_node.get_size(), 14861)
+ self.failUnless(isinstance(one_metadata, dict), one_metadata)
+ self.failUnlessEqual(two_metadata["metakey"], "metavalue")
+ d.addCallback(_check_kids)
+ d.addCallback(lambda ign: nm.create_from_cap(self.cap.to_string()))
+ d.addCallback(lambda dn: dn.list())
+ d.addCallback(_check_kids)
+ future_writecap = "x-tahoe-crazy://I_am_from_the_future."
+ future_readcap = "x-tahoe-crazy-readonly://I_am_from_the_future."
+ future_node = UnknownNode(future_writecap, future_readcap)
+ bad_kids1 = {u"one": (future_node, {})}
+ d.addCallback(lambda ign:
+ self.shouldFail(AssertionError, "bad_kids1",
+ "does not accept UnknownNode",
+ c.create_immutable_dirnode,
+ bad_kids1))
+ bad_kids2 = {u"one": (nm.create_from_cap(one_uri), None)}
+ d.addCallback(lambda ign:
+ self.shouldFail(AssertionError, "bad_kids2",
+ "requires metadata to be a dict",
+ c.create_immutable_dirnode,
+ bad_kids2))
+ bad_kids3 = {u"one": (nm.create_from_cap(mut_writecap), {})}
+ d.addCallback(lambda ign:
+ self.shouldFail(AssertionError, "bad_kids3",
+ "create_immutable_directory requires immutable children",
+ c.create_immutable_dirnode,
+ bad_kids3))
+ bad_kids4 = {u"one": (nm.create_from_cap(mut_readcap), {})}
+ d.addCallback(lambda ign:
+ self.shouldFail(AssertionError, "bad_kids4",
+ "create_immutable_directory requires immutable children",
+ c.create_immutable_dirnode,
+ bad_kids4))
+ d.addCallback(lambda ign: c.create_immutable_dirnode({}))
+ def _created_empty(dn):
+ self.failUnless(isinstance(dn, dirnode.DirectoryNode))
+ self.failIf(dn.is_mutable())
+ self.failUnless(dn.is_readonly())
+ rep = str(dn)
+ self.failUnless("RO-IMM" in rep)
+ cap = dn.get_cap()
+ self.failUnlessIn("LIT", cap.to_string())
+ self.failUnlessEqual(cap.to_string(), "URI:DIR2-LIT:")
+ self.cap = cap
+ return dn.list()
+ d.addCallback(_created_empty)
+ d.addCallback(lambda kids: self.failUnlessEqual(kids, {}))
+ smallkids = {u"o": (nm.create_from_cap(one_uri), {})}
+ d.addCallback(lambda ign: c.create_immutable_dirnode(smallkids))
+ def _created_small(dn):
+ self.failUnless(isinstance(dn, dirnode.DirectoryNode))
+ self.failIf(dn.is_mutable())
+ self.failUnless(dn.is_readonly())
+ rep = str(dn)
+ self.failUnless("RO-IMM" in rep)
+ cap = dn.get_cap()
+ self.failUnlessIn("LIT", cap.to_string())
+ self.failUnlessEqual(cap.to_string(),
+ "URI:DIR2-LIT:gi4tumj2n4wdcmz2kvjesosmjfkdu3rvpbtwwlbqhiwdeot3puwcy")
+ self.cap = cap
+ return dn.list()
+ d.addCallback(_created_small)
+ d.addCallback(lambda kids: self.failUnlessEqual(kids.keys(), [u"o"]))
+ return d
+
def test_check(self):
self.basedir = "dirnode/Dirnode/test_check"
self.set_up_grid()
self.failUnless(str(u2_verifier))
def test_literal(self):
- u1 = uri.LiteralDirectoryURI("data")
+ u0 = uri.LiteralFileURI("data")
+ u1 = uri.LiteralDirectoryURI(u0)
self.failUnless(str(u1))
u1s = u1.to_string()
self.failUnlessEqual(u1.to_string(), "URI:DIR2-LIT:mrqxiyi")
def __init__(self, data=None):
if data is not None:
+ assert isinstance(data, str)
self.data = data
@classmethod
BASE_STRING_RE=re.compile('^'+BASE_STRING)
BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2-LIT'+SEP)
INNER_URI_CLASS=LiteralFileURI
- def __init__(self, data=None):
- filenode_uri = LiteralFileURI(data)
- _ImmutableDirectoryBaseURI.__init__(self, filenode_uri)
def get_verify_cap(self):
# LIT caps have no verifier, since they aren't distributed
return None
+def wrap_dirnode_cap(filecap):
+ if isinstance(filecap, WriteableSSKFileURI):
+ return DirectoryURI(filecap)
+ if isinstance(filecap, ReadonlySSKFileURI):
+ return ReadonlyDirectoryURI(filecap)
+ if isinstance(filecap, CHKFileURI):
+ return ImmutableDirectoryURI(filecap)
+ if isinstance(filecap, LiteralFileURI):
+ return LiteralDirectoryURI(filecap)
+ assert False, "cannot wrap a dirnode around %s" % filecap.__class__
class DirectoryURIVerifier(_DirectoryBaseURI):
implements(IVerifierURI)