]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/uri.py
fix several methods to handle LIT URIs correctly, rather than assuming that all filen...
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / uri.py
1
2 import re
3 from allmydata.util import idlib, hashutil
4
5 def get_uri_type(uri):
6     assert uri.startswith("URI:")
7     if uri.startswith("URI:DIR:"):
8         return "DIR"
9     if uri.startswith("URI:DIR-RO:"):
10         return "DIR-RO"
11     if uri.startswith("URI:LIT:"):
12         return "LIT"
13     return "CHK"
14
15 def is_filenode_uri(uri):
16     return get_uri_type(uri) in ("LIT", "CHK")
17
18 def get_filenode_size(uri):
19     assert is_filenode_uri(uri)
20     t = get_uri_type(uri)
21     if t == "LIT":
22         return len(unpack_lit(uri))
23     return unpack_uri(uri)['size']
24
25
26 # the URI shall be an ascii representation of the file. It shall contain
27 # enough information to retrieve and validate the contents. It shall be
28 # expressed in a limited character set (namely [TODO]).
29
30 def pack_uri(storage_index, key, uri_extension_hash,
31              needed_shares, total_shares, size):
32     # applications should pass keyword parameters into this
33     assert isinstance(storage_index, str)
34     assert len(storage_index) == 32 # sha256 hash
35
36     assert isinstance(uri_extension_hash, str)
37     assert len(uri_extension_hash) == 32 # sha56 hash
38
39     assert isinstance(key, str)
40     assert len(key) == 16 # AES-128
41     assert isinstance(needed_shares, int)
42     assert isinstance(total_shares, int)
43     assert isinstance(size, (int,long))
44
45     return "URI:%s:%s:%s:%d:%d:%d" % (idlib.b2a(storage_index), idlib.b2a(key),
46                                       idlib.b2a(uri_extension_hash),
47                                       needed_shares, total_shares, size)
48
49
50 def unpack_uri(uri):
51     assert uri.startswith("URI:"), uri
52     d = {}
53     (header,
54      storage_index_s, key_s, uri_extension_hash_s,
55      needed_shares_s, total_shares_s, size_s) = uri.split(":")
56     assert header == "URI"
57     d['storage_index'] = idlib.a2b(storage_index_s)
58     d['key'] = idlib.a2b(key_s)
59     d['uri_extension_hash'] = idlib.a2b(uri_extension_hash_s)
60     d['needed_shares'] = int(needed_shares_s)
61     d['total_shares'] = int(total_shares_s)
62     d['size'] = int(size_s)
63     return d
64
65
66 def pack_extension(data):
67     pieces = []
68     for k in sorted(data.keys()):
69         value = data[k]
70         if isinstance(value, (int, long)):
71             value = "%d" % value
72         assert isinstance(value, str), k
73         assert re.match(r'^[a-zA-Z_\-]+$', k)
74         pieces.append(k + ":" + hashutil.netstring(value))
75     uri_extension = "".join(pieces)
76     return uri_extension
77
78 def unpack_extension(data):
79     d = {}
80     while data:
81         colon = data.index(":")
82         key = data[:colon]
83         data = data[colon+1:]
84
85         colon = data.index(":")
86         number = data[:colon]
87         length = int(number)
88         data = data[colon+1:]
89
90         value = data[:length]
91         assert data[length] == ","
92         data = data[length+1:]
93
94         d[key] = value
95
96     # convert certain things to numbers
97     for intkey in ("size", "segment_size", "num_segments",
98                    "needed_shares", "total_shares"):
99         if intkey in d:
100             d[intkey] = int(d[intkey])
101     return d
102
103
104 def unpack_extension_readable(data):
105     unpacked = unpack_extension(data)
106     for k in sorted(unpacked.keys()):
107         if "hash" in k:
108             unpacked[k] = idlib.b2a(unpacked[k])
109     return unpacked
110
111 def pack_lit(data):
112     return "URI:LIT:%s" % idlib.b2a(data)
113
114 def unpack_lit(uri):
115     assert uri.startswith("URI:LIT:")
116     data_s = uri[len("URI:LIT:"):]
117     return idlib.a2b(data_s)
118
119
120 def is_dirnode_uri(uri):
121     return uri.startswith("URI:DIR:") or uri.startswith("URI:DIR-RO:")
122 def is_mutable_dirnode_uri(uri):
123     return uri.startswith("URI:DIR:")
124 def unpack_dirnode_uri(uri):
125     assert is_dirnode_uri(uri)
126     # URI:DIR:furl:key
127     #  but note that the furl contains colons
128     for prefix in ("URI:DIR:", "URI:DIR-RO:"):
129         if uri.startswith(prefix):
130             uri = uri[len(prefix):]
131             break
132     else:
133         assert 0
134     colon = uri.rindex(":")
135     furl = uri[:colon]
136     key = uri[colon+1:]
137     return furl, idlib.a2b(key)
138
139 def make_immutable_dirnode_uri(mutable_uri):
140     assert is_mutable_dirnode_uri(mutable_uri)
141     furl, writekey = unpack_dirnode_uri(mutable_uri)
142     readkey = hashutil.dir_read_key_hash(writekey)
143     return "URI:DIR-RO:%s:%s" % (furl, idlib.b2a(readkey))
144
145 def pack_dirnode_uri(furl, writekey):
146     return "URI:DIR:%s:%s" % (furl, idlib.b2a(writekey))