From 36921fedb3163b7022d473e4f408c69d83c65cd1 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Thu, 1 Nov 2007 16:57:58 -0700 Subject: [PATCH] mutable: implement most remaining dirnode methods. No tests yet. --- src/allmydata/mutable.py | 89 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/src/allmydata/mutable.py b/src/allmydata/mutable.py index 78c0e050..a5e831df 100644 --- a/src/allmydata/mutable.py +++ b/src/allmydata/mutable.py @@ -7,7 +7,7 @@ from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\ IMutableFileURI, INewDirectoryURI, IURI, IFileNode, NotMutableError from allmydata.util import hashutil from allmydata.util.hashutil import netstring -from allmydata.dirnode import IntegrityCheckError +from allmydata.dirnode import IntegrityCheckError, FileNode from allmydata.uri import WriteableSSKFileURI, NewDirectoryURI from allmydata.Crypto.Cipher import AES @@ -208,6 +208,8 @@ class NewDirectoryNode: entries.append(netstring(entry)) return "".join(entries) + def is_readonly(self): + return self._node.is_readonly() def is_mutable(self): return self._node.is_mutable() @@ -222,7 +224,7 @@ class NewDirectoryNode: def check(self): """Perform a file check. See IChecker.check for details.""" - pass + pass # TODO def list(self): """I return a Deferred that fires with a dictionary mapping child @@ -254,6 +256,19 @@ class NewDirectoryNode: path-name elements. """ + if not path: + return defer.succeed(self) + if isinstance(path, (str, unicode)): + path = path.split("/") + childname = path[0] + remaining_path = path[1:] + d = self.get(childname) + if remaining_path: + def _got(node): + return node.get_child_at_path(remaining_path) + d.addCallback(_got) + return d + def set_uri(self, name, child_uri, metadata={}): """I add a child (by URI) at the specific name. I return a Deferred that fires when the operation finishes. I will replace any existing @@ -274,7 +289,7 @@ class NewDirectoryNode: If this directory node is read-only, the Deferred will errback with a NotMutableError.""" - if self._node.is_readonly(): + if self.is_readonly(): return defer.fail(NotMutableError()) d = self._read() def _add(children): @@ -290,24 +305,90 @@ class NewDirectoryNode: resulting FileNode to the directory at the given name. I return a Deferred that fires (with the IFileNode of the uploaded file) when the operation completes.""" + if self.is_readonly(): + return defer.fail(NotMutableError()) + uploader = self._client.getServiceNamed("uploader") + d = uploader.upload(uploadable) + d.addCallback(lambda uri: self.set_node(name, + FileNode(uri, self._client))) + return d def delete(self, name): """I remove the child at the specific name. I return a Deferred that fires when the operation finishes.""" + if self.is_readonly(): + return defer.fail(NotMutableError()) + d = self._read() + def _delete(children): + del children[name] + new_contents = self._pack_contents(children) + return self._node.replace(new_contents) + d.addCallback(_delete) + d.addCallback(lambda res: None) + return d def create_empty_directory(self, name): """I create and attach an empty directory at the given name. I return a Deferred that fires when the operation finishes.""" + if self.is_readonly(): + return defer.fail(NotMutableError()) + d = self._client.create_empty_dirnode() + d.addCallback(lambda child: self.set_node(name, child)) + return d - def move_child_to(self, current_child_name, new_parent, new_child_name=None): + def move_child_to(self, current_child_name, new_parent, + new_child_name=None): """I take one of my children and move them to a new parent. The child is referenced by name. On the new parent, the child will live under 'new_child_name', which defaults to 'current_child_name'. I return a Deferred that fires when the operation finishes.""" + if self.is_readonly() or new_parent.is_readonly(): + return defer.fail(NotMutableError()) + if new_child_name is None: + new_child_name = current_child_name + d = self.get(current_child_name) + d.addCallback(lambda child: new_parent.set_node(new_child_name, child)) + d.addCallback(lambda child: self.delete(current_child_name)) + return d def build_manifest(self): """Return a frozenset of verifier-capability strings for all nodes (directories and files) reachable from this one.""" + # this is just a tree-walker, except that following each edge + # requires a Deferred. + + manifest = set() + manifest.add(self.get_verifier()) + + d = self._build_manifest_from_node(self, manifest) + def _done(res): + # LIT nodes have no verifier-capability: their data is stored + # inside the URI itself, so there is no need to refresh anything. + # They indicate this by returning None from their get_verifier + # method. We need to remove any such Nones from our set. We also + # want to convert all these caps into strings. + return frozenset([cap.to_string() + for cap in manifest + if cap is not None]) + d.addCallback(_done) + return d + + def _build_manifest_from_node(self, node, manifest): + d = node.list() + def _got_list(res): + dl = [] + for name, child in res.iteritems(): + verifier = child.get_verifier() + if verifier not in manifest: + manifest.add(verifier) + if IDirectoryNode.providedBy(child): + dl.append(self._build_manifest_from_node(child, + manifest)) + if dl: + return defer.DeferredList(dl) + d.addCallback(_got_list) + return d + # use client.create_dirnode() to make one of these -- 2.45.2