From: Brian Warner Date: Mon, 26 Oct 2009 16:28:09 +0000 (-0700) Subject: dirnode.pack_children(): add deep_immutable= argument X-Git-Tag: trac-4100~8 X-Git-Url: https://git.rkrishnan.org/pf/content/en/nxhtml.html?a=commitdiff_plain;h=2695af91a73661bfe986c3627a0b4b1f0565687e;p=tahoe-lafs%2Ftahoe-lafs.git dirnode.pack_children(): add deep_immutable= argument This will be used by DIR2:CHK to enforce the deep-immutability requirement. --- diff --git a/src/allmydata/dirnode.py b/src/allmydata/dirnode.py index ce05477b..de271551 100644 --- a/src/allmydata/dirnode.py +++ b/src/allmydata/dirnode.py @@ -135,23 +135,35 @@ def _encrypt_rwcap(filenode, rwcap): # The MAC is not checked by readers in Tahoe >= 1.3.0, but we still # produce it for the sake of older readers. -def pack_children(filenode, children): +class MustBeDeepImmutable(Exception): + """You tried to add a non-deep-immutable node to a deep-immutable + directory.""" + +def pack_children(filenode, children, deep_immutable=False): """Take a dict that maps: children[unicode_name] = (IFileSystemNode, metadata_dict) and pack it into a single string, for use as the contents of the backing file. This is the same format as is returned by _unpack_contents. I also accept an AuxValueDict, in which case I'll use the auxilliary cached data as the pre-packed entry, which is faster than re-packing everything each - time.""" + time. + + If deep_immutable is True, I will require that all my children are deeply + immutable, and will raise a MustBeDeepImmutable exception if not. + """ + has_aux = isinstance(children, AuxValueDict) entries = [] for name in sorted(children.keys()): assert isinstance(name, unicode) entry = None + (child, metadata) = children[name] + if deep_immutable and child.is_mutable(): + # TODO: consider adding IFileSystemNode.is_deep_immutable() + raise MustBeDeepImmutable("child '%s' is mutable" % (name,)) if has_aux: entry = children.get_aux(name) if not entry: - (child, metadata) = children[name] assert IFilesystemNode.providedBy(child), (name,child) assert isinstance(metadata, dict) rwcap = child.get_uri() # might be RO if the child is not writeable diff --git a/src/allmydata/test/test_dirnode.py b/src/allmydata/test/test_dirnode.py index e4116567..13e7ac47 100644 --- a/src/allmydata/test/test_dirnode.py +++ b/src/allmydata/test/test_dirnode.py @@ -760,6 +760,10 @@ class Dirnode(GridTestMixin, unittest.TestCase, d.addCallback(_then) return d +class MinimalFakeMutableFile: + def get_writekey(self): + return "writekey" + class Packing(unittest.TestCase): # This is a base32-encoded representation of the directory tree # root/file1 @@ -823,6 +827,54 @@ class Packing(unittest.TestCase): self.failUnlessEqual(file1_rwcap, children[u'file1'][0].get_uri()) + def _make_kids(self, nm, which): + caps = {"imm": "URI:CHK:n7r3m6wmomelk4sep3kw5cvduq:os7ijw5c3maek7pg65e5254k2fzjflavtpejjyhshpsxuqzhcwwq:3:20:14861", + "lit": "URI:LIT:n5xgk", # LIT for "one" + "write": "URI:SSK:vfvcbdfbszyrsaxchgevhmmlii:euw4iw7bbnkrrwpzuburbhppuxhc3gwxv26f6imekhz7zyw2ojnq", + "read": "URI:SSK-RO:e3mdrzfwhoq42hy5ubcz6rp3o4:ybyibhnp3vvwuq2vaw2ckjmesgkklfs6ghxleztqidihjyofgw7q", + "dirwrite": "URI:DIR2:n6x24zd3seu725yluj75q5boaa:mm6yoqjhl6ueh7iereldqxue4nene4wl7rqfjfybqrehdqmqskvq", + "dirread": "URI:DIR2-RO:b7sr5qsifnicca7cbk3rhrhbvq:mm6yoqjhl6ueh7iereldqxue4nene4wl7rqfjfybqrehdqmqskvq", + } + kids = {} + for name in which: + kids[unicode(name)] = (nm.create_from_cap(caps[name]), {}) + return kids + + def test_deep_immutable(self): + nm = NodeMaker(None, None, None, None, None, None, {"k": 3, "n": 10}, + None) + fn = MinimalFakeMutableFile() + + kids = self._make_kids(nm, ["imm", "lit", "write", "read", + "dirwrite", "dirread"]) + packed = dirnode.pack_children(fn, kids, deep_immutable=False) + self.failUnlessIn("lit", packed) + + kids = self._make_kids(nm, ["imm", "lit"]) + packed = dirnode.pack_children(fn, kids, deep_immutable=True) + self.failUnlessIn("lit", packed) + + kids = self._make_kids(nm, ["imm", "lit", "write"]) + e = self.failUnlessRaises(dirnode.MustBeDeepImmutable, + dirnode.pack_children, + fn, kids, deep_immutable=True) + + # read-only is not enough: all children must be immutable + kids = self._make_kids(nm, ["imm", "lit", "read"]) + e = self.failUnlessRaises(dirnode.MustBeDeepImmutable, + dirnode.pack_children, + fn, kids, deep_immutable=True) + + kids = self._make_kids(nm, ["imm", "lit", "dirwrite"]) + e = self.failUnlessRaises(dirnode.MustBeDeepImmutable, + dirnode.pack_children, + fn, kids, deep_immutable=True) + + kids = self._make_kids(nm, ["imm", "lit", "dirread"]) + e = self.failUnlessRaises(dirnode.MustBeDeepImmutable, + dirnode.pack_children, + fn, kids, deep_immutable=True) + class FakeMutableFile: counter = 0 def __init__(self, initial_contents=""):