Sat Feb 20 22:25:27 MST 2010  zooko@zooko.com
  * minor code clean-up in dirnode.py
  Impose micro-POLA by passing only the writekey instead of the whole node object to {{{_encrypt_rw_uri()}}}. Remove DummyImmutableFileNode in nodemaker.py, which is obviated by this. Add micro-optimization by precomputing the netstring of the empty string and branching on whether the writekey is present or not outside of {{{_encrypt_rw_uri()}}}. Add doc about writekey to docstring.

New patches:

[minor code clean-up in dirnode.py
zooko@zooko.com**20100221052527
 Ignore-this: b01bfb47638f5a64256bb306e0022066
 Impose micro-POLA by passing only the writekey instead of the whole node object to {{{_encrypt_rw_uri()}}}. Remove DummyImmutableFileNode in nodemaker.py, which is obviated by this. Add micro-optimization by precomputing the netstring of the empty string and branching on whether the writekey is present or not outside of {{{_encrypt_rw_uri()}}}. Add doc about writekey to docstring.
] {
hunk ./src/allmydata/dirnode.py 137
         new_contents = self.node._pack_contents(children)
         return new_contents
 
-def _encrypt_rw_uri(filenode, rw_uri):
-    assert isinstance(rw_uri, str)
-    writekey = filenode.get_writekey()
-    if not writekey:
-        return ""
+def _encrypt_rw_uri(writekey, rw_uri):
+    precondition(isinstance(rw_uri, str), rw_uri)
+    precondition(isinstance(writekey, str), writekey)
+
     salt = hashutil.mutable_rwcap_salt_hash(rw_uri)
     key = hashutil.mutable_rwcap_key_hash(salt, writekey)
     cryptor = AES(key)
hunk ./src/allmydata/dirnode.py 151
     # 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, deep_immutable=False):
+ZERO_LEN_NETSTR=netstring('')
+
+def pack_children(children, writekey=None, 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
hunk ./src/allmydata/dirnode.py 162
     as the pre-packed entry, which is faster than re-packing everything each
     time.
 
+    If writekey is provided then I will superencrypt the child's writecap with
+    writekey.
+
     If deep_immutable is True, I will require that all my children are deeply
     immutable, and will raise a MustBeDeepImmutableError if not.
     """
hunk ./src/allmydata/dirnode.py 168
+    precondition((writekey is None) or isinstance(writekey, str), writekey)
 
     has_aux = isinstance(children, AuxValueDict)
     entries = []
hunk ./src/allmydata/dirnode.py 196
             if ro_uri is None:
                 ro_uri = ""
             assert isinstance(ro_uri, str), ro_uri
+            if writekey is not None:
+                writecap = netstring(_encrypt_rw_uri(writekey, rw_uri))
+            else:
+                writecap = ZERO_LEN_NETSTR
             entry = "".join([netstring(name.encode("utf-8")),
                              netstring(strip_prefix_for_ro(ro_uri, deep_immutable)),
hunk ./src/allmydata/dirnode.py 202
-                             netstring(_encrypt_rw_uri(filenode, rw_uri)),
+                             writecap,
                              netstring(simplejson.dumps(metadata))])
         entries.append(netstring(entry))
     return "".join(entries)
hunk ./src/allmydata/dirnode.py 315
 
     def _pack_contents(self, children):
         # expects children in the same format as _unpack_contents
-        return pack_children(self._node, children)
+        return pack_children(children, self._node.get_writekey())
 
     def is_readonly(self):
         return self._node.is_readonly()
hunk ./src/allmydata/nodemaker.py 106
                          "create_new_mutable_directory requires metadata to be a dict, not None", metadata)
             node.raise_error()
         d = self.create_mutable_file(lambda n:
-                                     pack_children(n, initial_children))
+                                     pack_children(initial_children, n.get_writekey()))
         d.addCallback(self._create_dirnode)
         return d
 
hunk ./src/allmydata/nodemaker.py 119
             node.raise_error()
             if not node.is_allowed_in_immutable_directory():
                 raise MustBeDeepImmutableError("%s is not immutable" % (node,), name)
-        n = DummyImmutableFileNode() # writekey=None
-        packed = pack_children(n, children)
+        packed = pack_children(children)
         uploadable = Data(packed, convergence)
         d = self.uploader.upload(uploadable, history=self.history)
         d.addCallback(lambda results: self.create_from_cap(None, results.uri))
hunk ./src/allmydata/test/test_dirnode.py 1123
 
         kids = self._make_kids(nm, ["imm", "lit", "write", "read",
                                     "dirwrite", "dirread"])
-        packed = dirnode.pack_children(fn, kids, deep_immutable=False)
+        packed = dirnode.pack_children(kids, fn.get_writekey(), deep_immutable=False)
         self.failUnlessIn("lit", packed)
 
         kids = self._make_kids(nm, ["imm", "lit"])
hunk ./src/allmydata/test/test_dirnode.py 1127
-        packed = dirnode.pack_children(fn, kids, deep_immutable=True)
+        packed = dirnode.pack_children(kids, fn.get_writekey(), deep_immutable=True)
         self.failUnlessIn("lit", packed)
 
         kids = self._make_kids(nm, ["imm", "lit", "write"])
hunk ./src/allmydata/test/test_dirnode.py 1133
         self.failUnlessRaises(dirnode.MustBeDeepImmutableError,
                               dirnode.pack_children,
-                              fn, kids, deep_immutable=True)
+                              kids, fn.get_writekey(), deep_immutable=True)
 
         # read-only is not enough: all children must be immutable
         kids = self._make_kids(nm, ["imm", "lit", "read"])
hunk ./src/allmydata/test/test_dirnode.py 1139
         self.failUnlessRaises(dirnode.MustBeDeepImmutableError,
                               dirnode.pack_children,
-                              fn, kids, deep_immutable=True)
+                              kids, fn.get_writekey(), deep_immutable=True)
 
         kids = self._make_kids(nm, ["imm", "lit", "dirwrite"])
         self.failUnlessRaises(dirnode.MustBeDeepImmutableError,
hunk ./src/allmydata/test/test_dirnode.py 1144
                               dirnode.pack_children,
-                              fn, kids, deep_immutable=True)
+                              kids, fn.get_writekey(), deep_immutable=True)
 
         kids = self._make_kids(nm, ["imm", "lit", "dirread"])
         self.failUnlessRaises(dirnode.MustBeDeepImmutableError,
hunk ./src/allmydata/test/test_dirnode.py 1149
                               dirnode.pack_children,
-                              fn, kids, deep_immutable=True)
+                              kids, fn.get_writekey(), deep_immutable=True)
 
 class FakeMutableFile:
     implements(IMutableFileNode)
}

Context:

[setup: comment-out the dependency on pycrypto, see #953
zooko@zooko.com**20100215050844
 Ignore-this: 2751120921ff35b8189d8fcd896da149
] 
[Add tests for #939
Kevan Carstensen <kevan@isnotajoke.com>**20100212062137
 Ignore-this: 5459e8c64ba76cca70aa720e68549637
] 
[Alter CLI utilities to handle nonexistent aliases better
Kevan Carstensen <kevan@isnotajoke.com>**20100211024318
 Ignore-this: e698ea4a57f5fe27c24336581ca0cf65
] 
[adding pycrypto to the auto dependencies
secorp@allmydata.com**20100206054314
 Ignore-this: b873fc00a6a5b001d30d479e6053cf2f
] 
[docs running.html - "tahoe run ." does not work with the current installation, replaced with "tahoe start ."
secorp@allmydata.com**20100206165320
 Ignore-this: fdb2dcb0e417d303cd43b1951a4f8c03
] 
[web/storage.py: display total-seen on the last-complete-cycle line. For #940.
Brian Warner <warner@lothar.com>**20100208002010
 Ignore-this: c0ed860f3e9628d3171d2b055d96c5aa
] 
[code coverage: replace figleaf with coverage.py, should work on py2.6 now.
Brian Warner <warner@lothar.com>**20100203165421
 Ignore-this: 46ab590360be6a385cb4fc4e68b6b42c
 
 It still lacks the right HTML report (the builtin report is very pretty, but
 lacks the "lines uncovered" numbers that I want), and the half-finished
 delta-from-last-run measurements.
] 
[More comprehensive changes and ticket references for NEWS
david-sarah@jacaranda.org**20100202061256
 Ignore-this: 696cf0106e8a7fd388afc5b55fba8a1b
] 
[docs: install.html: link into Python 2.5.5 download page
zooko@zooko.com**20100202065852
 Ignore-this: 1a9471b8175b7de5741d8445a7ede29d
] 
[TAG allmydata-tahoe-1.6.0
zooko@zooko.com**20100202061125
 Ignore-this: dee6ade7ac1452cf5d1d9c69a8146d84
] 
Patch bundle hash:
77b4d4157ad48fdc10c05c2bf979c0f8b8220402