]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/nodemaker.py
fbf527c2a8c18658aa0921eec786abfdc20bd64b
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / nodemaker.py
1 import weakref
2 from zope.interface import implements
3 from allmydata.util.assertutil import precondition
4 from allmydata.interfaces import INodeMaker, SDMF_VERSION
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
14
15
16 class NodeMaker:
17     implements(INodeMaker)
18
19     def __init__(self, storage_broker, secret_holder, history,
20                  uploader, terminator,
21                  default_encoding_parameters, key_generator,
22                  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.key_generator = key_generator
30         self.blacklist = blacklist
31
32         self._node_cache = weakref.WeakValueDictionary() # uri -> node
33
34     def _create_lit(self, cap):
35         return LiteralFileNode(cap)
36     def _create_immutable(self, cap):
37         return ImmutableFileNode(cap, self.storage_broker, self.secret_holder,
38                                  self.terminator, self.history)
39     def _create_immutable_verifier(self, cap):
40         return CiphertextFileNode(cap, self.storage_broker, self.secret_holder,
41                                   self.terminator, self.history)
42     def _create_mutable(self, cap):
43         n = MutableFileNode(self.storage_broker, self.secret_holder,
44                             self.default_encoding_parameters,
45                             self.history)
46         return n.init_from_cap(cap)
47     def _create_dirnode(self, filenode):
48         return DirectoryNode(filenode, self, self.uploader)
49
50     def create_from_cap(self, writecap, readcap=None, deep_immutable=False, name=u"<unknown name>"):
51         # this returns synchronously. It starts with a "cap string".
52         assert isinstance(writecap, (str, type(None))), type(writecap)
53         assert isinstance(readcap,  (str, type(None))), type(readcap)
54
55         bigcap = writecap or readcap
56         if not bigcap:
57             # maybe the writecap was hidden because we're in a readonly
58             # directory, and the future cap format doesn't have a readcap, or
59             # something.
60             return UnknownNode(None, None)  # deep_immutable and name not needed
61
62         # The name doesn't matter for caching since it's only used in the error
63         # attribute of an UnknownNode, and we don't cache those.
64         if deep_immutable:
65             memokey = "I" + bigcap
66         else:
67             memokey = "M" + bigcap
68         if memokey in self._node_cache:
69             node = self._node_cache[memokey]
70         else:
71             cap = uri.from_string(bigcap, deep_immutable=deep_immutable,
72                                   name=name)
73             node = self._create_from_single_cap(cap)
74             if node:
75                 self._node_cache[memokey] = node  # note: WeakValueDictionary
76             else:
77                 # don't cache UnknownNode
78                 node = UnknownNode(writecap, readcap,
79                                    deep_immutable=deep_immutable, name=name)
80
81         if self.blacklist:
82             si = node.get_storage_index()
83             # if this node is blacklisted, return the reason, otherwise return None
84             reason = self.blacklist.check_storageindex(si)
85             if reason is not None:
86                 # The original node object is cached above, not the ProhibitedNode wrapper.
87                 # This ensures that removing the blacklist entry will make the node
88                 # accessible if create_from_cap is called again.
89                 node = ProhibitedNode(node, reason)
90         return node
91
92     def _create_from_single_cap(self, cap):
93         if isinstance(cap, uri.LiteralFileURI):
94             return self._create_lit(cap)
95         if isinstance(cap, uri.CHKFileURI):
96             return self._create_immutable(cap)
97         if isinstance(cap, uri.CHKFileVerifierURI):
98             return self._create_immutable_verifier(cap)
99         if isinstance(cap, (uri.ReadonlySSKFileURI, uri.WriteableSSKFileURI,
100                             uri.WritableMDMFFileURI, uri.ReadonlyMDMFFileURI)):
101             return self._create_mutable(cap)
102         if isinstance(cap, (uri.DirectoryURI,
103                             uri.ReadonlyDirectoryURI,
104                             uri.ImmutableDirectoryURI,
105                             uri.LiteralDirectoryURI,
106                             uri.MDMFDirectoryURI,
107                             uri.ReadonlyMDMFDirectoryURI)):
108             filenode = self._create_from_single_cap(cap.get_filenode_cap())
109             return self._create_dirnode(filenode)
110         return None
111
112     def create_mutable_file(self, contents=None, keysize=None,
113                             version=SDMF_VERSION):
114         n = MutableFileNode(self.storage_broker, self.secret_holder,
115                             self.default_encoding_parameters, self.history)
116         d = self.key_generator.generate(keysize)
117         d.addCallback(n.create_with_keys, contents, version=version)
118         d.addCallback(lambda res: n)
119         return d
120
121     def create_new_mutable_directory(self, initial_children={},
122                                      version=SDMF_VERSION):
123         # initial_children must have metadata (i.e. {} instead of None)
124         for (name, (node, metadata)) in initial_children.iteritems():
125             precondition(isinstance(metadata, dict),
126                          "create_new_mutable_directory requires metadata to be a dict, not None", metadata)
127             node.raise_error()
128         d = self.create_mutable_file(lambda n:
129                                      MutableData(pack_children(initial_children,
130                                                     n.get_writekey())),
131                                      version=version)
132         d.addCallback(self._create_dirnode)
133         return d
134
135     def create_immutable_directory(self, children, convergence=None):
136         if convergence is None:
137             convergence = self.secret_holder.get_convergence_secret()
138         packed = pack_children(children, None, deep_immutable=True)
139         uploadable = Data(packed, convergence)
140         d = self.uploader.upload(uploadable, history=self.history)
141         d.addCallback(lambda results: self.create_from_cap(None, results.uri))
142         d.addCallback(self._create_dirnode)
143         return d