2 from zope.interface import implements
3 from allmydata.util.assertutil import precondition
4 from allmydata.interfaces import INodeMaker
5 from allmydata.immutable.literal import LiteralFileNode
6 from allmydata.immutable.filenode import ImmutableFileNode, CiphertextFileNode
7 from allmydata.immutable.upload import Data
8 from allmydata.mutable.filenode import MutableFileNode
9 from allmydata.mutable.publish import MutableData
10 from allmydata.dirnode import DirectoryNode, pack_children
11 from allmydata.unknown import UnknownNode
12 from allmydata.blacklist import ProhibitedNode
13 from allmydata import uri
17 implements(INodeMaker)
19 def __init__(self, storage_broker, secret_holder, history,
21 default_encoding_parameters, mutable_file_default,
22 key_generator, blacklist=None):
23 self.storage_broker = storage_broker
24 self.secret_holder = secret_holder
25 self.history = history
26 self.uploader = uploader
27 self.terminator = terminator
28 self.default_encoding_parameters = default_encoding_parameters
29 self.mutable_file_default = mutable_file_default
30 self.key_generator = key_generator
31 self.blacklist = blacklist
33 self._node_cache = weakref.WeakValueDictionary() # uri -> node
35 def _create_lit(self, cap):
36 return LiteralFileNode(cap)
37 def _create_immutable(self, cap):
38 return ImmutableFileNode(cap, self.storage_broker, self.secret_holder,
39 self.terminator, self.history)
40 def _create_immutable_verifier(self, cap):
41 return CiphertextFileNode(cap, self.storage_broker, self.secret_holder,
42 self.terminator, self.history)
43 def _create_mutable(self, cap):
44 n = MutableFileNode(self.storage_broker, self.secret_holder,
45 self.default_encoding_parameters,
47 return n.init_from_cap(cap)
48 def _create_dirnode(self, filenode):
49 return DirectoryNode(filenode, self, self.uploader)
51 def create_from_cap(self, writecap, readcap=None, deep_immutable=False, name=u"<unknown name>"):
52 # this returns synchronously. It starts with a "cap string".
53 assert isinstance(writecap, (str, type(None))), type(writecap)
54 assert isinstance(readcap, (str, type(None))), type(readcap)
56 bigcap = writecap or readcap
58 # maybe the writecap was hidden because we're in a readonly
59 # directory, and the future cap format doesn't have a readcap, or
61 return UnknownNode(None, None) # deep_immutable and name not needed
63 # The name doesn't matter for caching since it's only used in the error
64 # attribute of an UnknownNode, and we don't cache those.
66 memokey = "I" + bigcap
68 memokey = "M" + bigcap
69 if memokey in self._node_cache:
70 node = self._node_cache[memokey]
72 cap = uri.from_string(bigcap, deep_immutable=deep_immutable,
74 node = self._create_from_single_cap(cap)
76 # node is None for an unknown URI, otherwise it is a type for which
77 # is_mutable() is known. We avoid cacheing mutable nodes due to
80 # don't cache UnknownNode
81 node = UnknownNode(writecap, readcap,
82 deep_immutable=deep_immutable, name=name)
83 elif node.is_mutable():
84 self._node_cache[memokey] = node # note: WeakValueDictionary
87 si = node.get_storage_index()
88 # if this node is blacklisted, return the reason, otherwise return None
89 reason = self.blacklist.check_storageindex(si)
90 if reason is not None:
91 # The original node object is cached above, not the ProhibitedNode wrapper.
92 # This ensures that removing the blacklist entry will make the node
93 # accessible if create_from_cap is called again.
94 node = ProhibitedNode(node, reason)
97 def _create_from_single_cap(self, cap):
98 if isinstance(cap, uri.LiteralFileURI):
99 return self._create_lit(cap)
100 if isinstance(cap, uri.CHKFileURI):
101 return self._create_immutable(cap)
102 if isinstance(cap, uri.CHKFileVerifierURI):
103 return self._create_immutable_verifier(cap)
104 if isinstance(cap, (uri.ReadonlySSKFileURI, uri.WriteableSSKFileURI,
105 uri.WriteableMDMFFileURI, uri.ReadonlyMDMFFileURI)):
106 return self._create_mutable(cap)
107 if isinstance(cap, (uri.DirectoryURI,
108 uri.ReadonlyDirectoryURI,
109 uri.ImmutableDirectoryURI,
110 uri.LiteralDirectoryURI,
111 uri.MDMFDirectoryURI,
112 uri.ReadonlyMDMFDirectoryURI)):
113 filenode = self._create_from_single_cap(cap.get_filenode_cap())
114 return self._create_dirnode(filenode)
117 def create_mutable_file(self, contents=None, keysize=None, version=None):
119 version = self.mutable_file_default
120 n = MutableFileNode(self.storage_broker, self.secret_holder,
121 self.default_encoding_parameters, self.history)
122 d = self.key_generator.generate(keysize)
123 d.addCallback(n.create_with_keys, contents, version=version)
124 d.addCallback(lambda res: n)
127 def create_new_mutable_directory(self, initial_children={}, version=None):
128 # initial_children must have metadata (i.e. {} instead of None)
129 for (name, (node, metadata)) in initial_children.iteritems():
130 precondition(isinstance(metadata, dict),
131 "create_new_mutable_directory requires metadata to be a dict, not None", metadata)
133 d = self.create_mutable_file(lambda n:
134 MutableData(pack_children(initial_children,
137 d.addCallback(self._create_dirnode)
140 def create_immutable_directory(self, children, convergence=None):
141 if convergence is None:
142 convergence = self.secret_holder.get_convergence_secret()
143 packed = pack_children(children, None, deep_immutable=True)
144 uploadable = Data(packed, convergence)
145 d = self.uploader.upload(uploadable)
146 d.addCallback(lambda results:
147 self.create_from_cap(None, results.get_uri()))
148 d.addCallback(self._create_dirnode)