tahoe-lafs/src/allmydata/mutable.py

131 lines
4.9 KiB
Python
Raw Normal View History

import struct
from zope.interface import implements
from twisted.internet import defer
from allmydata.interfaces import IMutableFileNode, IMutableFileURI
from allmydata.util import hashutil
from allmydata.uri import WriteableSSKFileURI
class MutableFileNode:
implements(IMutableFileNode)
def __init__(self, client):
self._client = client
self._pubkey = None # filled in upon first read
self._privkey = None # filled in if we're mutable
self._sharemap = {} # known shares, shnum-to-nodeid
def init_from_uri(self, myuri):
self._uri = IMutableFileURI(myuri)
return self
def create(self, initial_contents):
"""Call this when the filenode is first created. This will generate
the keys, generate the initial shares, allocate shares, and upload
the initial contents. Returns a Deferred that fires (with the
MutableFileNode instance you should use) when it completes.
"""
self._privkey = "very private"
self._pubkey = "public"
self._writekey = hashutil.ssk_writekey_hash(self._privkey)
self._fingerprint = hashutil.ssk_pubkey_fingerprint_hash(self._pubkey)
self._uri = WriteableSSKFileURI(self._writekey, self._fingerprint)
d = defer.succeed(None)
return d
def get_uri(self):
return self._uri.to_string()
def is_mutable(self):
return self._uri.is_mutable()
def __hash__(self):
return hash((self.__class__, self.uri))
def __cmp__(self, them):
if cmp(type(self), type(them)):
return cmp(type(self), type(them))
if cmp(self.__class__, them.__class__):
return cmp(self.__class__, them.__class__)
return cmp(self.uri, them.uri)
def get_verifier(self):
return IMutableFileURI(self._uri).get_verifier()
def check(self):
verifier = self.get_verifier()
return self._client.getServiceNamed("checker").check(verifier)
def download(self, target):
#downloader = self._client.getServiceNamed("downloader")
#return downloader.download(self.uri, target)
raise NotImplementedError
def download_to_data(self):
#downloader = self._client.getServiceNamed("downloader")
#return downloader.download_to_data(self.uri)
return defer.succeed("this isn't going to fool you, is it")
def replace(self, newdata):
return defer.succeed(None)
def unpack_data(self, data):
offsets = {}
(version,
seqnum,
root_hash,
k, N, segsize, datalen,
offsets['signature'],
offsets['share_hash_chain'],
offsets['block_hash_tree'],
offsets['IV'],
offsets['share_data'],
offsets['enc_privkey']) = struct.unpack(">BQ32s" + "BBQQ" + "LLLLLQ")
assert version == 0
signature = data[offsets['signature']:offsets['share_hash_chain']]
share_hash_chain = data[offsets['share_hash_chain']:offsets['block_hash_tree']]
block_hash_tree = data[offsets['block_hash_tree']:offsets['IV']]
IV = data[offsets['IV']:offsets['share_data']]
share_data = data[offsets['share_data']:offsets['share_data']+datalen]
enc_privkey = data[offsets['enc_privkey']:]
def pack_data(self):
# dummy values to satisfy pyflakes until we wire this all up
seqnum, root_hash, k, N, segsize, datalen = 0,0,0,0,0,0
(verification_key, signature, share_hash_chain, block_hash_tree,
IV, share_data, enc_privkey) = ["0"*16] * 7
seqnum += 1
newbuf = [struct.pack(">BQ32s" + "BBQQ",
0, # version byte
seqnum,
root_hash,
k, N, segsize, datalen)]
post_offset = struct.calcsize(">BQ32s" + "BBQQ" + "LLLLLQ")
offsets = {}
o1 = offsets['signature'] = post_offset + len(verification_key)
o2 = offsets['share_hash_chain'] = o1 + len(signature)
o3 = offsets['block_hash_tree'] = o2 + len(share_hash_chain)
assert len(IV) == 16
o4 = offsets['IV'] = o3 + len(block_hash_tree)
o5 = offsets['share_data'] = o4 + len(IV)
o6 = offsets['enc_privkey'] = o5 + len(share_data)
newbuf.append(struct.pack(">LLLLLQ",
offsets['signature'],
offsets['share_hash_chain'],
offsets['block_hash_tree'],
offsets['IV'],
offsets['share_data'],
offsets['enc_privkey']))
newbuf.extend([verification_key,
signature,
share_hash_chain,
block_hash_tree,
IV,
share_data,
enc_privkey])
return "".join(newbuf)
# use client.create_mutable_file() to make one of these