dirnode.pack_children(): add deep_immutable= argument
This will be used by DIR2:CHK to enforce the deep-immutability requirement.
This commit is contained in:
parent
768c76aa5f
commit
2695af91a7
|
@ -135,23 +135,35 @@ def _encrypt_rwcap(filenode, rwcap):
|
||||||
# The MAC is not checked by readers in Tahoe >= 1.3.0, but we still
|
# The MAC is not checked by readers in Tahoe >= 1.3.0, but we still
|
||||||
# produce it for the sake of older readers.
|
# 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:
|
"""Take a dict that maps:
|
||||||
children[unicode_name] = (IFileSystemNode, metadata_dict)
|
children[unicode_name] = (IFileSystemNode, metadata_dict)
|
||||||
and pack it into a single string, for use as the contents of the backing
|
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
|
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
|
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
|
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)
|
has_aux = isinstance(children, AuxValueDict)
|
||||||
entries = []
|
entries = []
|
||||||
for name in sorted(children.keys()):
|
for name in sorted(children.keys()):
|
||||||
assert isinstance(name, unicode)
|
assert isinstance(name, unicode)
|
||||||
entry = None
|
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:
|
if has_aux:
|
||||||
entry = children.get_aux(name)
|
entry = children.get_aux(name)
|
||||||
if not entry:
|
if not entry:
|
||||||
(child, metadata) = children[name]
|
|
||||||
assert IFilesystemNode.providedBy(child), (name,child)
|
assert IFilesystemNode.providedBy(child), (name,child)
|
||||||
assert isinstance(metadata, dict)
|
assert isinstance(metadata, dict)
|
||||||
rwcap = child.get_uri() # might be RO if the child is not writeable
|
rwcap = child.get_uri() # might be RO if the child is not writeable
|
||||||
|
|
|
@ -760,6 +760,10 @@ class Dirnode(GridTestMixin, unittest.TestCase,
|
||||||
d.addCallback(_then)
|
d.addCallback(_then)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
class MinimalFakeMutableFile:
|
||||||
|
def get_writekey(self):
|
||||||
|
return "writekey"
|
||||||
|
|
||||||
class Packing(unittest.TestCase):
|
class Packing(unittest.TestCase):
|
||||||
# This is a base32-encoded representation of the directory tree
|
# This is a base32-encoded representation of the directory tree
|
||||||
# root/file1
|
# root/file1
|
||||||
|
@ -823,6 +827,54 @@ class Packing(unittest.TestCase):
|
||||||
self.failUnlessEqual(file1_rwcap,
|
self.failUnlessEqual(file1_rwcap,
|
||||||
children[u'file1'][0].get_uri())
|
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:
|
class FakeMutableFile:
|
||||||
counter = 0
|
counter = 0
|
||||||
def __init__(self, initial_contents=""):
|
def __init__(self, initial_contents=""):
|
||||||
|
|
Loading…
Reference in New Issue