from twisted.internet import defer
from foolscap import Referenceable
from allmydata import uri
-from allmydata.interfaces import RIVirtualDriveServer, IDirectoryNode, IFileNode
+from allmydata.interfaces import RIVirtualDriveServer, \
+ IDirectoryNode, IFileNode, IFileURI, IDirnodeURI, IURI
from allmydata.util import bencode, idlib, hashutil, fileutil
from allmydata.Crypto.Cipher import AES
def get_public_root_uri(self):
if self._root:
- return uri.pack_dirnode_uri(self._myfurl, self._root)
+ u = uri.DirnodeURI(self._myfurl, self._root)
+ return u.to_string()
raise NoPublicRootError
remote_get_public_root_uri = get_public_root_uri
def create_directory_node(client, diruri):
- assert uri.is_dirnode_uri(diruri)
- if uri.is_mutable_dirnode_uri(diruri):
- dirnode_class = MutableDirectoryNode
- else:
- dirnode_class = ImmutableDirectoryNode
- (furl, key) = uri.unpack_dirnode_uri(diruri)
- d = client.tub.getReference(furl)
+ u = IURI(diruri)
+ assert IDirnodeURI.providedBy(u)
+ d = client.tub.getReference(u.furl)
def _got(rref):
- dirnode = dirnode_class(diruri, client, rref, key)
- return dirnode
+ if isinstance(u, uri.DirnodeURI):
+ return MutableDirectoryNode(u, client, rref)
+ else: # uri.ReadOnlyDirnodeURI
+ return ImmutableDirectoryNode(u, client, rref)
d.addCallback(_got)
return d
class ImmutableDirectoryNode:
implements(IDirectoryNode)
- def __init__(self, myuri, client, rref, readkey):
- self._uri = myuri
+ def __init__(self, myuri, client, rref):
+ u = IDirnodeURI(myuri)
+ assert u.is_readonly()
+ self._uri = u.to_string()
self._client = client
self._tub = client.tub
self._rref = rref
- self._readkey = readkey
+ self._readkey = u.readkey
self._writekey = None
self._write_enabler = None
self._index = hashutil.dir_index_hash(self._readkey)
def get_immutable_uri(self):
# return the dirnode URI for a read-only form of this directory
- if self._mutable:
- return uri.make_immutable_dirnode_uri(self._uri)
- else:
- return self._uri
+ return IDirnodeURI(self._uri).get_readonly().to_string()
def __hash__(self):
return hash((self.__class__, self._uri))
E_name = self._encrypt(self._readkey, name)
E_write = ""
if self._writekey and write_child:
+ assert isinstance(write_child, str)
E_write = self._encrypt(self._writekey, write_child)
+ assert isinstance(read_child, str)
E_read = self._encrypt(self._readkey, read_child)
d = self._rref.callRemote("set", self._index, self._write_enabler,
H_name, E_name, E_write, E_read)
return d
def _create_node(self, child_uri):
- if uri.is_dirnode_uri(child_uri):
- return create_directory_node(self._client, child_uri)
+ u = IURI(child_uri)
+ if IDirnodeURI.providedBy(u):
+ return create_directory_node(self._client, u)
else:
- return defer.succeed(FileNode(child_uri, self._client))
+ return defer.succeed(FileNode(u, self._client))
def _split_uri(self, child_uri):
- if uri.is_dirnode_uri(child_uri):
- if uri.is_mutable_dirnode_uri(child_uri):
- write = child_uri
- read = uri.make_immutable_dirnode_uri(child_uri)
- else:
- write = None
- read = child_uri
- return (write, read)
- return (None, child_uri) # file
+ u = IURI(child_uri)
+ if u.is_mutable() and not u.is_readonly():
+ write = u.to_string()
+ else:
+ write = None
+ read = u.get_readonly().to_string()
+ return (write, read)
def create_empty_directory(self, name):
if not self._mutable:
return defer.fail(NotMutableError())
child_writekey = hashutil.random_key()
- my_furl, parent_writekey = uri.unpack_dirnode_uri(self._uri)
- child_uri = uri.pack_dirnode_uri(my_furl, child_writekey)
- child = MutableDirectoryNode(child_uri, self._client, self._rref,
- child_writekey)
+ furl = IDirnodeURI(self._uri).furl
+ u = uri.DirnodeURI(furl, child_writekey)
+ child = MutableDirectoryNode(u, self._client, self._rref)
d = self._rref.callRemote("create_directory",
child._index, child._write_enabler)
d.addCallback(lambda index: self.set_node(name, child))
return d
def get_refresh_capability(self):
- ro_uri = self.get_immutable_uri()
- furl, rk = uri.unpack_dirnode_uri(ro_uri)
+ u = IDirnodeURI(self._uri).get_readonly()
+ rk = u.readkey
wk, we, rk, index = hashutil.generate_dirnode_keys_from_readkey(rk)
return "DIR-REFRESH:%s" % idlib.b2a(index)
class MutableDirectoryNode(ImmutableDirectoryNode):
implements(IDirectoryNode)
- def __init__(self, myuri, client, rref, writekey):
- readkey = hashutil.dir_read_key_hash(writekey)
- ImmutableDirectoryNode.__init__(self, myuri, client, rref, readkey)
- self._writekey = writekey
- self._write_enabler = hashutil.dir_write_enabler_hash(writekey)
+ def __init__(self, myuri, client, rref):
+ u = IDirnodeURI(myuri)
+ assert not u.is_readonly()
+ self._writekey = u.writekey
+ self._write_enabler = hashutil.dir_write_enabler_hash(u.writekey)
+ readkey = hashutil.dir_read_key_hash(u.writekey)
+ self._uri = u.to_string()
+ self._client = client
+ self._tub = client.tub
+ self._rref = rref
+ self._readkey = readkey
+ self._index = hashutil.dir_index_hash(self._readkey)
self._mutable = True
def create_directory(client, furl):
write_key = hashutil.random_key()
(wk, we, rk, index) = \
hashutil.generate_dirnode_keys_from_writekey(write_key)
- myuri = uri.pack_dirnode_uri(furl, wk)
+ u = uri.DirnodeURI(furl, wk)
d = client.tub.getReference(furl)
def _got_vdrive_server(vdrive_server):
- node = MutableDirectoryNode(myuri, client, vdrive_server, wk)
+ node = MutableDirectoryNode(u, client, vdrive_server)
d2 = vdrive_server.callRemote("create_directory", index, we)
d2.addCallback(lambda res: node)
return d2
implements(IFileNode)
def __init__(self, uri, client):
- self.uri = uri
+ u = IFileURI(uri)
+ self.uri = u.to_string()
self._client = client
def get_uri(self):
return self.uri
+ def get_size(self):
+ return IFileURI(self.uri).get_size()
+
def __hash__(self):
return hash((self.__class__, self.uri))
def __cmp__(self, them):
return cmp(self.uri, them.uri)
def get_refresh_capability(self):
- t = uri.get_uri_type(self.uri)
- if t == "CHK":
- d = uri.unpack_uri(self.uri)
- return "CHK-REFRESH:%s" % idlib.b2a(d['storage_index'])
+ u = IFileURI(self.uri)
+ if isinstance(u, uri.CHKFileURI):
+ return "CHK-REFRESH:%s" % idlib.b2a(u.storage_index)
return None
def download(self, target):
from allmydata.util.assertutil import _assert
from allmydata import codec, hashtree, storage, uri
from allmydata.Crypto.Cipher import AES
-from allmydata.interfaces import IDownloadTarget, IDownloader
+from allmydata.interfaces import IDownloadTarget, IDownloader, IFileURI
from allmydata.encode import NotEnoughPeersError
class HaveAllPeersError(Exception):
def __init__(self, client, u, downloadable):
self._client = client
- d = uri.unpack_uri(u)
- self._storage_index = d['storage_index']
- self._uri_extension_hash = d['uri_extension_hash']
- self._total_shares = d['total_shares']
- self._size = d['size']
- self._num_needed_shares = d['needed_shares']
+ u = IFileURI(u)
+ self._storage_index = u.storage_index
+ self._uri_extension_hash = u.uri_extension_hash
+ self._total_shares = u.total_shares
+ self._size = u.size
+ self._num_needed_shares = u.needed_shares
- self._output = Output(downloadable, d['key'], self._size)
+ self._output = Output(downloadable, u.key, self._size)
self.active_buckets = {} # k: shnum, v: bucket
self._share_buckets = [] # list of (sharenum, bucket) tuples
return self._output.finish()
class LiteralDownloader:
- def __init__(self, client, uri, downloadable):
- self._uri = uri
+ def __init__(self, client, u, downloadable):
+ self._uri = IFileURI(u)
+ assert isinstance(self._uri, uri.LiteralFileURI)
self._downloadable = downloadable
def start(self):
- data = uri.unpack_lit(self._uri)
+ data = self._uri.data
self._downloadable.open(len(data))
self._downloadable.write(data)
self._downloadable.close()
implements(IDownloadTarget)
def __init__(self, filename):
self._filename = filename
+ self.f = None
def open(self, size):
self.f = open(self._filename, "wb")
return self.f
def write(self, data):
self.f.write(data)
def close(self):
- self.f.close()
+ if self.f:
+ self.f.close()
def fail(self, why):
- self.f.close()
- os.unlink(self._filename)
+ if self.f:
+ self.f.close()
+ os.unlink(self._filename)
def register_canceller(self, cb):
pass # we won't use it
def finish(self):
def download(self, u, t):
assert self.parent
assert self.running
+ u = IFileURI(u)
t = IDownloadTarget(t)
assert t.write
assert t.close
- utype = uri.get_uri_type(u)
- if utype == "CHK":
- dl = FileDownloader(self.parent, u, t)
- elif utype == "LIT":
+ if isinstance(u, uri.LiteralFileURI):
dl = LiteralDownloader(self.parent, u, t)
+ elif isinstance(u, uri.CHKFileURI):
+ dl = FileDownloader(self.parent, u, t)
+ else:
+ raise RuntimeError("I don't know how to download a %s" % u)
d = dl.start()
return d
"""
+class IURI(Interface):
+ def init_from_string(uri):
+ """Accept a string (as created by my to_string() method) and populate
+ this instance with its data. I am not normally called directly,
+ please use the module-level uri.from_string() function to convert
+ arbitrary URI strings into IURI-providing instances."""
+
+ def is_readonly():
+ """Return False if this URI be used to modify the data. Return True
+ if this URI cannot be used to modify the data."""
+
+ def is_mutable():
+ """Return True if the data can be modified by *somebody* (perhaps
+ someone who has a more powerful URI than this one)."""
+
+ def get_readonly():
+ """Return another IURI instance, which represents a read-only form of
+ this one. If is_readonly() is True, this returns self."""
+
+ def to_string():
+ """Return a string of printable ASCII characters, suitable for
+ passing into init_from_string."""
+
+class IDirnodeURI(Interface):
+ """I am a URI which represents a dirnode."""
+
+class IFileURI(Interface):
+ """I am a URI which represents a filenode."""
+ def get_size():
+ """Return the length (in bytes) of the file that I represent."""
+
+
class IFileNode(Interface):
def download(target):
"""Download the file's contents to a given IDownloadTarget"""
"""Return the URI that can be used by others to get access to this
file.
"""
+ def get_size():
+ """Return the length (in bytes) of the data this node represents."""
def get_refresh_capability():
"""Return a string that represents the 'refresh capability' for this
"""
def get_node(uri):
- """Transform a URI into an IDirectoryNode or IFileNode.
+ """Transform a URI (or IURI) into an IDirectoryNode or IFileNode.
This returns a Deferred that will fire with an instance that provides
either IDirectoryNode or IFileNode, as appropriate."""
try:
f = open(root_dirnode_file, "rb")
key = f.read()
- rooturi = uri.pack_dirnode_uri("fakeFURL", key)
- print >>out, rooturi
+ rooturi = uri.DirnodeURI("fakeFURL", key)
+ print >>out, rooturi.to_string()
return 0
except EnvironmentError:
print >>out, "unable to read root dirnode file from %s" % \
return 1
def dump_directory_node(config, out=sys.stdout, err=sys.stderr):
- from allmydata import uri, dirnode
+ from allmydata import dirnode
from allmydata.util import hashutil, idlib
+ from allmydata.interfaces import IDirnodeURI
basedir = config['basedirs'][0]
- dir_uri = config['uri']
+ dir_uri = IDirnodeURI(config['uri'])
verbose = config['verbose']
- furl, key = uri.unpack_dirnode_uri(dir_uri)
- if uri.is_mutable_dirnode_uri(dir_uri):
- wk, we, rk, index = hashutil.generate_dirnode_keys_from_writekey(key)
+ if dir_uri.is_readonly():
+ wk, we, rk, index = \
+ hashutil.generate_dirnode_keys_from_readkey(dir_uri.readkey)
else:
- wk, we, rk, index = hashutil.generate_dirnode_keys_from_readkey(key)
+ wk, we, rk, index = \
+ hashutil.generate_dirnode_keys_from_writekey(dir_uri.writekey)
filename = os.path.join(basedir, "vdrive", idlib.b2a(index))
print >>out
- print >>out, "dirnode uri: %s" % dir_uri
+ print >>out, "dirnode uri: %s" % dir_uri.to_string()
print >>out, "filename : %s" % filename
print >>out, "index : %s" % idlib.b2a(index)
if wk:
from twisted.python import failure
from allmydata import uri, dirnode
from allmydata.util import hashutil
-from allmydata.interfaces import IDirectoryNode
+from allmydata.interfaces import IDirectoryNode, IDirnodeURI
from allmydata.scripts import runner
from allmydata.dirnode import VirtualDriveServer, \
ChildAlreadyPresentError, BadWriteEnablerError, NoPublicRootError
vds.set_furl("myFURL")
root_uri = vds.get_public_root_uri()
- self.failUnless(uri.is_dirnode_uri(root_uri))
- self.failUnless(uri.is_mutable_dirnode_uri(root_uri))
- furl, key = uri.unpack_dirnode_uri(root_uri)
- self.failUnlessEqual(furl, "myFURL")
- self.failUnlessEqual(len(key), hashutil.KEYLEN)
+ u = IDirnodeURI(root_uri)
+ self.failIf(u.is_readonly())
+ self.failUnlessEqual(u.furl, "myFURL")
+ self.failUnlessEqual(len(u.writekey), hashutil.KEYLEN)
- wk, we, rk, index = hashutil.generate_dirnode_keys_from_writekey(key)
+ wk, we, rk, index = \
+ hashutil.generate_dirnode_keys_from_writekey(u.writekey)
empty_list = vds.list(index)
self.failUnlessEqual(empty_list, [])
vds2 = VirtualDriveServer(basedir)
vds2.set_furl("myFURL")
root_uri2 = vds.get_public_root_uri()
- self.failUnless(uri.is_mutable_dirnode_uri(root_uri2))
- furl2, key2 = uri.unpack_dirnode_uri(root_uri2)
+ u2 = IDirnodeURI(root_uri2)
+ self.failIf(u2.is_readonly())
(wk2, we2, rk2, index2) = \
- hashutil.generate_dirnode_keys_from_writekey(key2)
+ hashutil.generate_dirnode_keys_from_writekey(u2.writekey)
self.failUnlessEqual(sorted(vds2.list(index2)),
[ ("name2", "", "read2"),
])
self.failUnlessEqual(res, {})
d.addCallback(_listed)
- file1 = uri.pack_uri("11" + " "*30, "k"*16, "e"*32, 25, 100, 12345)
- file2 = uri.pack_uri("2i" + " "*30, "k"*16, "e"*32, 25, 100, 12345)
+ file1 = uri.CHKFileURI(storage_index="11" + " "*30,
+ key="k"*16,
+ uri_extension_hash="e"*32,
+ needed_shares=25,
+ total_shares=100,
+ size=12345).to_string()
+ file2 = uri.CHKFileURI(storage_index="2i" + " "*30,
+ key="k"*16,
+ uri_extension_hash="e"*32,
+ needed_shares=25,
+ total_shares=100,
+ size=12345).to_string()
file2_node = dirnode.FileNode(file2, None)
d.addCallback(lambda res: rootnode.set_uri("foo", file1))
# root/
from twisted.trial import unittest
from twisted.internet import defer
from twisted.python.failure import Failure
-from allmydata import encode, upload, download, hashtree
+from allmydata import encode, upload, download, hashtree, uri
from allmydata.util import hashutil
-from allmydata.uri import pack_uri
-from allmydata.Crypto.Cipher import AES
from allmydata.interfaces import IStorageBucketWriter, IStorageBucketReader
-from cStringIO import StringIO
class LostPeerError(Exception):
pass
if "corrupt_key" in recover_mode:
key = flip_bit(key)
- URI = pack_uri(storage_index="S" * 32,
- key=key,
- uri_extension_hash=uri_extension_hash,
- needed_shares=e.required_shares,
- total_shares=e.num_shares,
- size=e.file_size)
+ URI = uri.CHKFileURI(storage_index="S" * 32,
+ key=key,
+ uri_extension_hash=uri_extension_hash,
+ needed_shares=e.required_shares,
+ total_shares=e.num_shares,
+ size=e.file_size).to_string()
client = None
target = download.Data()
fd = download.FileDownloader(client, URI, target)
from allmydata.introducer_and_vdrive import IntroducerAndVdrive
from allmydata.util import idlib, fileutil, testutil
from allmydata.scripts import runner
-from allmydata.interfaces import IDirectoryNode, IFileNode
+from allmydata.interfaces import IDirectoryNode, IFileNode, IFileURI
from allmydata.dirnode import NotMutableError
from foolscap.eventual import flushEventualQueue
from twisted.python import log
def mangle_uri(self, gooduri):
# change the storage index, which means we'll be asking about the
# wrong file, so nobody will have any shares
- d = uri.unpack_uri(gooduri)
- assert len(d['storage_index']) == 32
- d['storage_index'] = self.flip_bit(d['storage_index'])
- return uri.pack_uri(**d)
+ u = IFileURI(gooduri)
+ u2 = uri.CHKFileURI(storage_index=self.flip_bit(u.storage_index),
+ key=u.key,
+ uri_extension_hash=u.uri_extension_hash,
+ needed_shares=u.needed_shares,
+ total_shares=u.total_shares,
+ size=u.size)
+ return u2.to_string()
# TODO: add a test which mangles the uri_extension_hash instead, and
# should fail due to not being able to get a valid uri_extension block.
from twisted.internet import defer
from cStringIO import StringIO
-from allmydata import upload, encode
-from allmydata.uri import unpack_uri, unpack_lit
+from allmydata import upload, encode, uri
+from allmydata.interfaces import IFileURI
from allmydata.util.assertutil import precondition
from foolscap import eventual
self.u.running = True
self.u.parent = self.node
- def _check_small(self, uri, size):
- self.failUnless(isinstance(uri, str))
- self.failUnless(uri.startswith("URI:LIT:"))
- d = unpack_lit(uri)
- self.failUnlessEqual(len(d), size)
-
- def _check_large(self, uri, size):
- self.failUnless(isinstance(uri, str))
- self.failUnless(uri.startswith("URI:"))
- d = unpack_uri(uri)
- self.failUnless(isinstance(d['storage_index'], str))
- self.failUnlessEqual(len(d['storage_index']), 32)
- self.failUnless(isinstance(d['key'], str))
- self.failUnlessEqual(len(d['key']), 16)
- self.failUnlessEqual(d['size'], size)
+ def _check_small(self, newuri, size):
+ u = IFileURI(newuri)
+ self.failUnless(isinstance(u, uri.LiteralFileURI))
+ self.failUnlessEqual(len(u.data), size)
+
+ def _check_large(self, newuri, size):
+ u = IFileURI(newuri)
+ self.failUnless(isinstance(u, uri.CHKFileURI))
+ self.failUnless(isinstance(u.storage_index, str))
+ self.failUnlessEqual(len(u.storage_index), 32)
+ self.failUnless(isinstance(u.key, str))
+ self.failUnlessEqual(len(u.key), 16)
+ self.failUnlessEqual(u.size, size)
def get_data(self, size):
return DATA[:size]
from twisted.trial import unittest
from allmydata import uri
from allmydata.util import hashutil
+from allmydata.interfaces import IURI, IFileURI, IDirnodeURI
-class LIT(unittest.TestCase):
+class Literal(unittest.TestCase):
def test_pack(self):
data = "This is some small data"
- u = uri.pack_lit(data)
- self.failUnlessEqual(uri.get_uri_type(u), "LIT")
- self.failUnlessEqual(uri.unpack_lit(u), data)
- self.failUnless(uri.is_filenode_uri(u))
- self.failUnlessEqual(uri.get_filenode_size(u), len(data))
+ u = uri.LiteralFileURI(data)
+ self.failUnless(IURI.providedBy(u))
+ self.failUnless(IFileURI.providedBy(u))
+ self.failIf(IDirnodeURI.providedBy(u))
+ self.failUnlessEqual(u.data, data)
+ self.failUnlessEqual(u.get_size(), len(data))
+ self.failUnless(u.is_readonly())
+ self.failIf(u.is_mutable())
+
+ u2 = uri.from_string(u.to_string())
+ self.failUnless(IURI.providedBy(u2))
+ self.failUnless(IFileURI.providedBy(u2))
+ self.failIf(IDirnodeURI.providedBy(u2))
+ self.failUnlessEqual(u2.data, data)
+ self.failUnlessEqual(u2.get_size(), len(data))
+ self.failUnless(u.is_readonly())
+ self.failIf(u.is_mutable())
def test_nonascii(self):
data = "This contains \x00 and URI:LIT: and \n, oh my."
- u = uri.pack_lit(data)
- self.failUnlessEqual(uri.get_uri_type(u), "LIT")
- self.failUnlessEqual(uri.unpack_lit(u), data)
+ u = uri.LiteralFileURI(data)
+ self.failUnless(IURI.providedBy(u))
+ self.failUnless(IFileURI.providedBy(u))
+ self.failIf(IDirnodeURI.providedBy(u))
+ self.failUnlessEqual(u.data, data)
+ self.failUnlessEqual(u.get_size(), len(data))
+ self.failUnless(u.is_readonly())
+ self.failIf(u.is_mutable())
+
+ u2 = uri.from_string(u.to_string())
+ self.failUnless(IURI.providedBy(u2))
+ self.failUnless(IFileURI.providedBy(u2))
+ self.failIf(IDirnodeURI.providedBy(u2))
+ self.failUnlessEqual(u2.data, data)
+ self.failUnlessEqual(u2.get_size(), len(data))
+ self.failUnless(u.is_readonly())
+ self.failIf(u.is_mutable())
-class CHK(unittest.TestCase):
+class CHKFile(unittest.TestCase):
def test_pack(self):
storage_index = hashutil.tagged_hash("foo", "bar")
key = "\x00" * 16
needed_shares = 25
total_shares = 100
size = 1234
- u = uri.pack_uri(storage_index=storage_index,
- key=key,
- uri_extension_hash=uri_extension_hash,
- needed_shares=needed_shares,
- total_shares=total_shares,
- size=size)
- self.failUnlessEqual(uri.get_uri_type(u), "CHK")
- d = uri.unpack_uri(u)
- self.failUnlessEqual(d['storage_index'], storage_index)
- self.failUnlessEqual(d['key'], key)
- self.failUnlessEqual(d['uri_extension_hash'], uri_extension_hash)
- self.failUnlessEqual(d['needed_shares'], needed_shares)
- self.failUnlessEqual(d['total_shares'], total_shares)
- self.failUnlessEqual(d['size'], size)
+ u = uri.CHKFileURI(storage_index=storage_index,
+ key=key,
+ uri_extension_hash=uri_extension_hash,
+ needed_shares=needed_shares,
+ total_shares=total_shares,
+ size=size)
+ self.failUnlessEqual(u.storage_index, storage_index)
+ self.failUnlessEqual(u.key, key)
+ self.failUnlessEqual(u.uri_extension_hash, uri_extension_hash)
+ self.failUnlessEqual(u.needed_shares, needed_shares)
+ self.failUnlessEqual(u.total_shares, total_shares)
+ self.failUnlessEqual(u.size, size)
+ self.failUnless(u.is_readonly())
+ self.failIf(u.is_mutable())
+ self.failUnless(IURI.providedBy(u))
+ self.failUnless(IFileURI.providedBy(u))
+ self.failIf(IDirnodeURI.providedBy(u))
+ self.failUnlessEqual(u.get_size(), 1234)
+ self.failUnless(u.is_readonly())
+ self.failIf(u.is_mutable())
- self.failUnless(uri.is_filenode_uri(u))
- self.failUnlessEqual(uri.get_filenode_size(u), size)
+ u2 = uri.from_string(u.to_string())
+ self.failUnlessEqual(u2.storage_index, storage_index)
+ self.failUnlessEqual(u2.key, key)
+ self.failUnlessEqual(u2.uri_extension_hash, uri_extension_hash)
+ self.failUnlessEqual(u2.needed_shares, needed_shares)
+ self.failUnlessEqual(u2.total_shares, total_shares)
+ self.failUnlessEqual(u2.size, size)
+ self.failUnless(u2.is_readonly())
+ self.failIf(u2.is_mutable())
+ self.failUnless(IURI.providedBy(u2))
+ self.failUnless(IFileURI.providedBy(u2))
+ self.failIf(IDirnodeURI.providedBy(u2))
+ self.failUnlessEqual(u2.get_size(), 1234)
+ self.failUnless(u2.is_readonly())
+ self.failIf(u2.is_mutable())
class Extension(unittest.TestCase):
def test_pack(self):
furl = "pb://stuff@morestuff:stuff/andstuff"
writekey = "\x01" * 16
- u = uri.pack_dirnode_uri(furl, writekey)
- self.failUnless(uri.is_dirnode_uri(u))
- self.failIf(uri.is_dirnode_uri("NOT A DIRNODE URI"))
- self.failIf(uri.is_dirnode_uri("URI:stuff"))
- self.failUnless(uri.is_mutable_dirnode_uri(u))
- self.failIf(uri.is_mutable_dirnode_uri("NOT A DIRNODE URI"))
- self.failIf(uri.is_mutable_dirnode_uri("URI:stuff"))
- self.failUnlessEqual(uri.get_uri_type(u), "DIR")
+ u = uri.DirnodeURI(furl, writekey)
+ self.failUnlessEqual(u.furl, furl)
+ self.failUnlessEqual(u.writekey, writekey)
+ self.failIf(u.is_readonly())
+ self.failUnless(u.is_mutable())
+ self.failUnless(IURI.providedBy(u))
+ self.failIf(IFileURI.providedBy(u))
+ self.failUnless(IDirnodeURI.providedBy(u))
- rou = uri.make_immutable_dirnode_uri(u)
- self.failUnless(uri.is_dirnode_uri(rou))
- self.failIf(uri.is_mutable_dirnode_uri(rou))
- self.failUnlessEqual(uri.get_uri_type(rou), "DIR-RO")
+ u2 = uri.from_string(u.to_string())
+ self.failUnlessEqual(u2.furl, furl)
+ self.failUnlessEqual(u2.writekey, writekey)
+ self.failIf(u2.is_readonly())
+ self.failUnless(u2.is_mutable())
+ self.failUnless(IURI.providedBy(u2))
+ self.failIf(IFileURI.providedBy(u2))
+ self.failUnless(IDirnodeURI.providedBy(u2))
- d = uri.unpack_dirnode_uri(u)
- self.failUnlessEqual(d[0], furl)
- self.failUnlessEqual(d[1], writekey)
+ u3 = u2.get_readonly()
+ readkey = hashutil.dir_read_key_hash(writekey)
+ self.failUnlessEqual(u3.furl, furl)
+ self.failUnlessEqual(u3.readkey, readkey)
+ self.failUnless(u3.is_readonly())
+ self.failUnless(u3.is_mutable())
+ self.failUnless(IURI.providedBy(u3))
+ self.failIf(IFileURI.providedBy(u3))
+ self.failUnless(IDirnodeURI.providedBy(u3))
- d2 = uri.unpack_dirnode_uri(rou)
- self.failUnlessEqual(d2[0], furl)
- rk = hashutil.dir_read_key_hash(writekey)
- self.failUnlessEqual(d2[1], rk)
+ u4 = uri.ReadOnlyDirnodeURI(furl, readkey)
+ self.failUnlessEqual(u4.furl, furl)
+ self.failUnlessEqual(u4.readkey, readkey)
+ self.failUnless(u4.is_readonly())
+ self.failUnless(u4.is_mutable())
+ self.failUnless(IURI.providedBy(u4))
+ self.failIf(IFileURI.providedBy(u4))
+ self.failUnless(IDirnodeURI.providedBy(u4))
uri_counter = itertools.count()
+def make_newuri(data):
+ n = uri_counter.next()
+ assert len(str(n)) < 5
+ newuri = uri.CHKFileURI(storage_index="SI%05d" % n + "i"*25,
+ key="K"*16,
+ uri_extension_hash="EH" + "h"*30,
+ needed_shares=25,
+ total_shares=100,
+ size=len(data))
+ return newuri.to_string()
+
class MyUploader(service.Service):
implements(interfaces.IUploader)
name = "uploader"
d.addCallback(lambda size: uploadable.read(size))
d.addCallback(lambda data: "".join(data))
def _got_data(data):
- uri = str(uri_counter.next())
- self.files[uri] = data
+ newuri = make_newuri(data)
+ self.files[newuri] = data
uploadable.close()
d.addCallback(_got_data)
return d
class MyDirectoryNode(dirnode.MutableDirectoryNode):
- def __init__(self, nodes, files, client, uri=None):
+ def __init__(self, nodes, files, client, myuri=None):
self._my_nodes = nodes
self._my_files = files
self._my_client = client
- if uri is None:
- uri = "URI:DIR:stuff/%s" % str(uri_counter.next())
- self._uri = str(uri)
+ if myuri is None:
+ u = uri.DirnodeURI("furl", "idx%s" % str(uri_counter.next()))
+ myuri = u.to_string()
+ self._uri = myuri
self._my_nodes[self._uri] = self
self.children = {}
self._mutable = True
- def get_immutable_uri(self):
- return self.get_uri() + "RO"
-
- def get_refresh_capability(self):
- return "refresh:" + self.get_uri()
-
def get(self, name):
def _try():
uri = self.children[name]
d.addCallback(lambda size: uploadable.read(size))
d.addCallback(lambda data: "".join(data))
def _got_data(data):
- uri = str(uri_counter.next())
- self._my_files[uri] = data
- self._my_nodes[uri] = MyFileNode(uri, self._my_client)
- self.children[name] = uri
+ newuri = make_newuri(data)
+ self._my_files[newuri] = data
+ self._my_nodes[newuri] = MyFileNode(newuri, self._my_client)
+ self.children[name] = newuri
uploadable.close()
- return self._my_nodes[uri]
+ return self._my_nodes[newuri]
d.addCallback(_got_data)
return d
def makefile(self, number):
n = str(number)
assert len(n) == 1
- newuri = uri.pack_uri("SI" + n*30,
- "K" + n*15,
- "EH" + n*30,
- 25, 100, 123+number)
+ newuri = uri.CHKFileURI(storage_index="SI" + n*30,
+ key="K" + n*15,
+ uri_extension_hash="EH" + n*30,
+ needed_shares=25,
+ total_shares=100,
+ size=123+number).to_string()
assert newuri not in self.nodes
assert newuri not in self.files
node = MyFileNode(newuri, self.s)
n = str(number)
assert len(n) == 1
contents = "small data %s\n" % n
- newuri = uri.pack_lit(contents)
+ newuri = uri.LiteralFileURI(contents).to_string()
assert newuri not in self.nodes
assert newuri not in self.files
node = MyFileNode(newuri, self.s)
from foolscap import Referenceable
from allmydata.util import idlib, hashutil
-from allmydata import encode, storage, hashtree
-from allmydata.uri import pack_uri, pack_lit
+from allmydata import encode, storage, hashtree, uri
from allmydata.interfaces import IUploadable, IUploader
from cStringIO import StringIO
self._encoder.set_shareholders(buckets)
def _compute_uri(self, uri_extension_hash):
- return pack_uri(storage_index=self._storage_index,
- key=self._encryption_key,
- uri_extension_hash=uri_extension_hash,
- needed_shares=self.needed_shares,
- total_shares=self.total_shares,
- size=self._size,
- )
+ u = uri.CHKFileURI(storage_index=self._storage_index,
+ key=self._encryption_key,
+ uri_extension_hash=uri_extension_hash,
+ needed_shares=self.needed_shares,
+ total_shares=self.total_shares,
+ size=self._size,
+ )
+ return u.to_string()
def read_this_many_bytes(uploadable, size, prepend_data=[]):
if size == 0:
def start(self):
d = self._uploadable.get_size()
d.addCallback(lambda size: read_this_many_bytes(self._uploadable, size))
- d.addCallback(lambda data: pack_lit("".join(data)))
+ d.addCallback(lambda data: uri.LiteralFileURI("".join(data)))
+ d.addCallback(lambda u: u.to_string())
return d
def close(self):
import re
+from zope.interface import implements
+from twisted.python.components import registerAdapter
from allmydata.util import idlib, hashutil
-
-def get_uri_type(uri):
- assert uri.startswith("URI:")
- if uri.startswith("URI:DIR:"):
- return "DIR"
- if uri.startswith("URI:DIR-RO:"):
- return "DIR-RO"
- if uri.startswith("URI:LIT:"):
- return "LIT"
- return "CHK"
-
-def is_filenode_uri(uri):
- return get_uri_type(uri) in ("LIT", "CHK")
-
-def get_filenode_size(uri):
- assert is_filenode_uri(uri)
- t = get_uri_type(uri)
- if t == "LIT":
- return len(unpack_lit(uri))
- return unpack_uri(uri)['size']
-
+from allmydata.interfaces import IURI, IDirnodeURI, IFileURI
# the URI shall be an ascii representation of the file. It shall contain
# enough information to retrieve and validate the contents. It shall be
# expressed in a limited character set (namely [TODO]).
-def pack_uri(storage_index, key, uri_extension_hash,
- needed_shares, total_shares, size):
- # applications should pass keyword parameters into this
- assert isinstance(storage_index, str)
- assert len(storage_index) == 32 # sha256 hash
- assert isinstance(uri_extension_hash, str)
- assert len(uri_extension_hash) == 32 # sha56 hash
+class _BaseURI:
+ def __hash__(self):
+ return hash((self.__class__, self.to_string()))
+ 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.to_string(), them.to_string())
+
+class CHKFileURI(_BaseURI):
+ implements(IURI, IFileURI)
+
+ def __init__(self, **kwargs):
+ # construct me with kwargs, since there are so many of them
+ if not kwargs:
+ return
+ for name in ("storage_index", "key", "uri_extension_hash",
+ "needed_shares", "total_shares", "size"):
+ value = kwargs[name]
+ setattr(self, name, value)
+
+ def init_from_string(self, uri):
+ assert uri.startswith("URI:CHK:"), uri
+ d = {}
+ (header_uri, header_chk,
+ storage_index_s, key_s, uri_extension_hash_s,
+ needed_shares_s, total_shares_s, size_s) = uri.split(":")
+ assert header_uri == "URI"
+ assert header_chk == "CHK"
+ self.storage_index = idlib.a2b(storage_index_s)
+ self.key = idlib.a2b(key_s)
+ self.uri_extension_hash = idlib.a2b(uri_extension_hash_s)
+ self.needed_shares = int(needed_shares_s)
+ self.total_shares = int(total_shares_s)
+ self.size = int(size_s)
+ return self
+
+ def to_string(self):
+ assert isinstance(self.storage_index, str)
+ assert len(self.storage_index) == 32 # sha256 hash
+
+ assert isinstance(self.uri_extension_hash, str)
+ assert len(self.uri_extension_hash) == 32 # sha56 hash
+
+ assert isinstance(self.key, str)
+ assert len(self.key) == 16 # AES-128
+ assert isinstance(self.needed_shares, int)
+ assert isinstance(self.total_shares, int)
+ assert isinstance(self.size, (int,long))
+
+ return ("URI:CHK:%s:%s:%s:%d:%d:%d" %
+ (idlib.b2a(self.storage_index),
+ idlib.b2a(self.key),
+ idlib.b2a(self.uri_extension_hash),
+ self.needed_shares,
+ self.total_shares,
+ self.size))
+
+ def is_readonly(self):
+ return True
+ def is_mutable(self):
+ return False
+ def get_readonly(self):
+ return self
+
+ def get_size(self):
+ return self.size
+
+class LiteralFileURI(_BaseURI):
+ implements(IURI, IFileURI)
+
+ def __init__(self, data=None):
+ if data is not None:
+ self.data = data
+
+ def init_from_string(self, uri):
+ assert uri.startswith("URI:LIT:")
+ data_s = uri[len("URI:LIT:"):]
+ self.data = idlib.a2b(data_s)
+ return self
+
+ def to_string(self):
+ return "URI:LIT:%s" % idlib.b2a(self.data)
+
+ def is_readonly(self):
+ return True
+ def is_mutable(self):
+ return False
+ def get_readonly(self):
+ return self
+
+ def get_size(self):
+ return len(self.data)
+
+class DirnodeURI(_BaseURI):
+ implements(IURI, IDirnodeURI)
+
+ def __init__(self, furl=None, writekey=None):
+ if furl is not None or writekey is not None:
+ assert furl is not None
+ assert writekey is not None
+ self.furl = furl
+ self.writekey = writekey
+
+ def init_from_string(self, uri):
+ # URI:DIR:furl:key
+ # but note that the furl contains colons
+ prefix = "URI:DIR:"
+ assert uri.startswith(prefix)
+ uri = uri[len(prefix):]
+ colon = uri.rindex(":")
+ self.furl = uri[:colon]
+ self.writekey = idlib.a2b(uri[colon+1:])
+ return self
+
+ def to_string(self):
+ return "URI:DIR:%s:%s" % (self.furl, idlib.b2a(self.writekey))
+
+ def is_readonly(self):
+ return False
+ def is_mutable(self):
+ return True
+ def get_readonly(self):
+ u = ReadOnlyDirnodeURI()
+ u.furl = self.furl
+ u.readkey = hashutil.dir_read_key_hash(self.writekey)
+ return u
+
+class ReadOnlyDirnodeURI(_BaseURI):
+ implements(IURI, IDirnodeURI)
+
+ def __init__(self, furl=None, readkey=None):
+ if furl is not None or readkey is not None:
+ assert furl is not None
+ assert readkey is not None
+ self.furl = furl
+ self.readkey = readkey
+
+ def init_from_string(self, uri):
+ # URI:DIR-RO:furl:key
+ # but note that the furl contains colons
+ prefix = "URI:DIR-RO:"
+ assert uri.startswith(prefix)
+ uri = uri[len(prefix):]
+ colon = uri.rindex(":")
+ self.furl = uri[:colon]
+ self.readkey = idlib.a2b(uri[colon+1:])
+ return self
+
+ def to_string(self):
+ return "URI:DIR-RO:%s:%s" % (self.furl, idlib.b2a(self.readkey))
+
+ def is_readonly(self):
+ return True
+ def is_mutable(self):
+ return True
+ def get_readonly(self):
+ return self
+
+def from_string(s):
+ if s.startswith("URI:CHK:"):
+ return CHKFileURI().init_from_string(s)
+ elif s.startswith("URI:LIT:"):
+ return LiteralFileURI().init_from_string(s)
+ elif s.startswith("URI:DIR:"):
+ return DirnodeURI().init_from_string(s)
+ elif s.startswith("URI:DIR-RO:"):
+ return ReadOnlyDirnodeURI().init_from_string(s)
+ else:
+ raise RuntimeError("unknown URI type: %s.." % s[:10])
- assert isinstance(key, str)
- assert len(key) == 16 # AES-128
- assert isinstance(needed_shares, int)
- assert isinstance(total_shares, int)
- assert isinstance(size, (int,long))
+registerAdapter(from_string, str, IURI)
- return "URI:%s:%s:%s:%d:%d:%d" % (idlib.b2a(storage_index), idlib.b2a(key),
- idlib.b2a(uri_extension_hash),
- needed_shares, total_shares, size)
+def from_string_dirnode(s):
+ u = from_string(s)
+ assert IDirnodeURI.providedBy(u)
+ return u
+registerAdapter(from_string_dirnode, str, IDirnodeURI)
-def unpack_uri(uri):
- assert uri.startswith("URI:"), uri
- d = {}
- (header,
- storage_index_s, key_s, uri_extension_hash_s,
- needed_shares_s, total_shares_s, size_s) = uri.split(":")
- assert header == "URI"
- d['storage_index'] = idlib.a2b(storage_index_s)
- d['key'] = idlib.a2b(key_s)
- d['uri_extension_hash'] = idlib.a2b(uri_extension_hash_s)
- d['needed_shares'] = int(needed_shares_s)
- d['total_shares'] = int(total_shares_s)
- d['size'] = int(size_s)
- return d
+def from_string_filenode(s):
+ u = from_string(s)
+ assert IFileURI.providedBy(u)
+ return u
+
+registerAdapter(from_string_filenode, str, IFileURI)
def pack_extension(data):
unpacked[k] = idlib.b2a(unpacked[k])
return unpacked
-def pack_lit(data):
- return "URI:LIT:%s" % idlib.b2a(data)
-
-def unpack_lit(uri):
- assert uri.startswith("URI:LIT:")
- data_s = uri[len("URI:LIT:"):]
- return idlib.a2b(data_s)
-
-
-def is_dirnode_uri(uri):
- return uri.startswith("URI:DIR:") or uri.startswith("URI:DIR-RO:")
-def is_mutable_dirnode_uri(uri):
- return uri.startswith("URI:DIR:")
-def unpack_dirnode_uri(uri):
- assert is_dirnode_uri(uri)
- # URI:DIR:furl:key
- # but note that the furl contains colons
- for prefix in ("URI:DIR:", "URI:DIR-RO:"):
- if uri.startswith(prefix):
- uri = uri[len(prefix):]
- break
- else:
- assert 0
- colon = uri.rindex(":")
- furl = uri[:colon]
- key = uri[colon+1:]
- return furl, idlib.a2b(key)
-
-def make_immutable_dirnode_uri(mutable_uri):
- assert is_mutable_dirnode_uri(mutable_uri)
- furl, writekey = unpack_dirnode_uri(mutable_uri)
- readkey = hashutil.dir_read_key_hash(writekey)
- return "URI:DIR-RO:%s:%s" % (furl, idlib.b2a(readkey))
-
-def pack_dirnode_uri(furl, writekey):
- return "URI:DIR:%s:%s" % (furl, idlib.b2a(writekey))
import os
from twisted.application import service
from zope.interface import implements
-from allmydata.interfaces import IVirtualDrive
-from allmydata import dirnode, uri
+from allmydata.interfaces import IVirtualDrive, IDirnodeURI, IURI
+from allmydata import dirnode
from twisted.internet import defer
class NoGlobalVirtualDriveError(Exception):
return self.get_node(self._private_uri)
def get_node(self, node_uri):
- if uri.is_dirnode_uri(node_uri):
+ node_uri = IURI(node_uri)
+ if IDirnodeURI.providedBy(node_uri):
return dirnode.create_directory_node(self.parent, node_uri)
else:
return defer.succeed(dirnode.FileNode(node_uri, self.parent))
from nevow.static import File as nevow_File # TODO: merge with static.File?
from allmydata.util import idlib, fileutil
import simplejson
-from allmydata.uri import unpack_uri, is_dirnode_uri
from allmydata.interfaces import IDownloadTarget, IDirectoryNode, IFileNode
-from allmydata import upload, download, uri
+from allmydata import upload, download
from zope.interface import implements, Interface
import urllib
from formless import webform
T.a(href=dlurl)[html.escape(name)])
ctx.fillSlots("type", "FILE")
-
- #uri = target.uri
- #dl_uri_url = url.root.child("download_uri").child(uri)
- ## add a filename= query argument to give it a Content-Type
- #dl_uri_url = dl_uri_url.add("filename", name)
- #ctx.fillSlots("uri", T.a(href=dl_uri_url)[html.escape(uri)])
-
- #extract and display file size
- try:
- size = uri.get_filenode_size(target.get_uri())
- except AssertionError:
- size = "?"
- ctx.fillSlots("size", size)
+ ctx.fillSlots("size", target.get_size())
text_plain_link = "/uri/%s?filename=foo.txt" % uri_link
text_plain_tag = T.a(href=text_plain_link)["text/plain"]
data = ("filenode",
{'mutable': False,
'uri': file_uri,
- 'size': uri.get_filenode_size(file_uri),
+ 'size': filenode.get_size(),
})
return simplejson.dumps(data, indent=1)
kiddata = ("filenode",
{'mutable': False,
'uri': kiduri,
- 'size': uri.get_filenode_size(kiduri),
+ 'size': childnode.get_size(),
})
else:
assert IDirectoryNode.providedBy(childnode)
newuri = req.args["uri"][0]
else:
newuri = req.fields["uri"].value
- # sanity checking
- assert(is_dirnode_uri(newuri) or unpack_uri(newuri))
d = self._node.set_uri(name, newuri)
def _done(res):
return newuri