2 # do not import any allmydata modules at this level. Do that from inside
3 # individual functions instead.
4 import os, sys, struct, time
5 from twisted.python import usage
6 from allmydata.scripts.common import BasedirMixin
8 class DumpOptions(usage.Options):
10 ["filename", "f", None, "which file to dump"],
13 def parseArgs(self, filename=None):
15 self['filename'] = filename
17 def postOptions(self):
18 if not self['filename']:
19 raise usage.UsageError("<filename> parameter is required")
21 class DumpRootDirnodeOptions(BasedirMixin, usage.Options):
23 ["basedir", "C", None, "the vdrive-server's base directory"],
26 class DumpDirnodeOptions(BasedirMixin, usage.Options):
28 ["uri", "u", None, "the URI of the dirnode to dump."],
29 ["basedir", "C", None, "which directory to create the introducer in"],
32 ["verbose", "v", "be extra noisy (show encrypted data)"],
34 def parseArgs(self, *args):
36 self['uri'] = args[-1]
38 BasedirMixin.parseArgs(self, *args)
40 def postOptions(self):
41 BasedirMixin.postOptions(self)
43 raise usage.UsageError("<uri> parameter is required")
45 def dump_share(config, out=sys.stdout, err=sys.stderr):
46 from allmydata import uri, storage
48 # check the version, to see if we have a mutable or immutable share
49 f = open(config['filename'], "rb")
52 if prefix == storage.MutableShareFile.MAGIC:
53 return dump_mutable_share(config, out, err)
54 # otherwise assume it's immutable
55 f = storage.ShareFile(config['filename'])
56 # use a ReadBucketProxy to parse the bucket and find the uri extension
57 bp = storage.ReadBucketProxy(None)
58 offsets = bp._parse_offsets(f.read_share_data(0, 0x24))
59 seek = offsets['uri_extension']
60 length = struct.unpack(">L", f.read_share_data(seek, 4))[0]
62 data = f.read_share_data(seek, length)
64 unpacked = uri.unpack_extension_readable(data)
65 keys1 = ("size", "num_segments", "segment_size",
66 "needed_shares", "total_shares")
67 keys2 = ("codec_name", "codec_params", "tail_codec_params")
68 keys3 = ("plaintext_hash", "plaintext_root_hash",
69 "crypttext_hash", "crypttext_root_hash",
71 display_keys = {"size": "file_size"}
74 dk = display_keys.get(k, k)
75 print >>out, "%19s: %s" % (dk, unpacked[k])
79 dk = display_keys.get(k, k)
80 print >>out, "%19s: %s" % (dk, unpacked[k])
84 dk = display_keys.get(k, k)
85 print >>out, "%19s: %s" % (dk, unpacked[k])
87 leftover = set(unpacked.keys()) - set(keys1 + keys2 + keys3)
90 print >>out, "LEFTOVER:"
91 for k in sorted(leftover):
92 print >>out, "%s: %s" % (k, unpacked[k])
95 sizes['data'] = bp._data_size
96 sizes['validation'] = (offsets['uri_extension'] -
97 offsets['plaintext_hash_tree'])
98 sizes['uri-extension'] = len(data)
100 print >>out, "Size of data within the share:"
101 for k in sorted(sizes):
102 print >>out, "%19s: %s" % (k, sizes[k])
104 # display lease information too
105 leases = list(f.iter_leases())
107 for i,lease in enumerate(leases):
108 (owner_num, renew_secret, cancel_secret, expiration_time) = lease
109 when = format_expiration_time(expiration_time)
110 print >>out, "Lease #%d: owner=%d, expire in %s" % (i, owner_num,
113 print >>out, "No leases."
118 def format_expiration_time(expiration_time):
120 remains = expiration_time - now
121 when = "%ds" % remains
122 if remains > 24*3600:
123 when += " (%d days)" % (remains / (24*3600))
125 when += " (%d hours)" % (remains / 3600)
129 def dump_mutable_share(config, out, err):
130 from allmydata import storage
131 from allmydata.util import idlib
132 m = storage.MutableShareFile(config['filename'])
133 f = open(config['filename'], "rb")
134 WE, nodeid = m._read_write_enabler_and_nodeid(f)
135 num_extra_leases = m._read_num_extra_leases(f)
136 data_length = m._read_data_length(f)
137 extra_lease_offset = m._read_extra_lease_offset(f)
138 container_size = extra_lease_offset - m.DATA_OFFSET
139 leases = list(m._enumerate_leases(f))
141 share_type = "unknown"
142 f.seek(m.DATA_OFFSET)
143 if f.read(1) == "\x00":
144 # this slot contains an SMDF share
149 print >>out, "Mutable slot found:"
150 print >>out, " share_type: %s" % share_type
151 print >>out, " write_enabler: %s" % idlib.b2a(WE)
152 print >>out, " WE for nodeid: %s" % idlib.nodeid_b2a(nodeid)
153 print >>out, " num_extra_leases: %d" % num_extra_leases
154 print >>out, " container_size: %d" % container_size
155 print >>out, " data_length: %d" % data_length
157 for (leasenum, (oid,et,rs,cs,anid)) in leases:
159 print >>out, " Lease #%d:" % leasenum
160 print >>out, " ownerid: %d" % oid
161 when = format_expiration_time(et)
162 print >>out, " expires in %s" % when
163 print >>out, " renew_secret: %s" % idlib.b2a(rs)
164 print >>out, " cancel_secret: %s" % idlib.b2a(cs)
165 print >>out, " secrets are for nodeid: %s" % idlib.nodeid_b2a(anid)
167 print >>out, "No leases."
170 if share_type == "SDMF":
171 dump_SDMF_share(m.DATA_OFFSET, data_length, config, out, err)
175 def dump_SDMF_share(offset, length, config, out, err):
176 from allmydata import mutable
177 from allmydata.util import idlib
179 f = open(config['filename'], "rb")
181 data = f.read(min(length, 2000))
184 pieces = mutable.unpack_share(data)
186 (seqnum, root_hash, IV, k, N, segsize, datalen,
187 pubkey, signature, share_hash_chain, block_hash_tree,
188 share_data, enc_privkey) = pieces
190 print >>out, " SDMF contents:"
191 print >>out, " seqnum: %d" % seqnum
192 print >>out, " root_hash: %s" % idlib.b2a(root_hash)
193 print >>out, " IV: %s" % idlib.b2a(IV)
194 print >>out, " required_shares: %d" % k
195 print >>out, " total_shares: %d" % N
196 print >>out, " segsize: %d" % segsize
197 print >>out, " datalen: %d" % datalen
198 share_hash_ids = ",".join([str(hid) for (hid,hash) in share_hash_chain])
199 print >>out, " share_hash_chain: %s" % share_hash_ids
200 print >>out, " block_hash_tree: %d nodes" % len(block_hash_tree)
205 def dump_root_dirnode(config, out=sys.stdout, err=sys.stderr):
206 from allmydata import uri
208 basedir = config['basedirs'][0]
209 root_dirnode_file = os.path.join(basedir, "vdrive", "root")
211 f = open(root_dirnode_file, "rb")
213 rooturi = uri.DirnodeURI("fakeFURL", key)
214 print >>out, rooturi.to_string()
216 except EnvironmentError:
217 print >>out, "unable to read root dirnode file from %s" % \
221 def dump_directory_node(config, out=sys.stdout, err=sys.stderr):
222 from allmydata import dirnode
223 from allmydata.util import hashutil, idlib
224 from allmydata.interfaces import IDirnodeURI
225 basedir = config['basedirs'][0]
226 dir_uri = IDirnodeURI(config['uri'])
227 verbose = config['verbose']
229 if dir_uri.is_readonly():
230 wk, we, rk, index = \
231 hashutil.generate_dirnode_keys_from_readkey(dir_uri.readkey)
233 wk, we, rk, index = \
234 hashutil.generate_dirnode_keys_from_writekey(dir_uri.writekey)
236 filename = os.path.join(basedir, "vdrive", idlib.b2a(index))
239 print >>out, "dirnode uri: %s" % dir_uri.to_string()
240 print >>out, "filename : %s" % filename
241 print >>out, "index : %s" % idlib.b2a(index)
243 print >>out, "writekey : %s" % idlib.b2a(wk)
244 print >>out, "write_enabler: %s" % idlib.b2a(we)
246 print >>out, "writekey : None"
247 print >>out, "write_enabler: None"
248 print >>out, "readkey : %s" % idlib.b2a(rk)
252 vds = dirnode.VirtualDriveServer(os.path.join(basedir, "vdrive"), False)
253 data = vds._read_from_file(index)
256 print >>out, "ERROR: write_enabler does not match"
258 for (H_key, E_key, E_write, E_read) in data[1]:
260 print >>out, " H_key %s" % idlib.b2a(H_key)
261 print >>out, " E_key %s" % idlib.b2a(E_key)
262 print >>out, " E_write %s" % idlib.b2a(E_write)
263 print >>out, " E_read %s" % idlib.b2a(E_read)
264 key = dirnode.decrypt(rk, E_key)
265 print >>out, " key %s" % key
266 if hashutil.dir_name_hash(rk, key) != H_key:
267 print >>out, " ERROR: H_key does not match"
269 if len(E_write) < 14:
270 print >>out, " ERROR: write data is short:", idlib.b2a(E_write)
271 write = dirnode.decrypt(wk, E_write)
272 print >>out, " write: %s" % write
273 read = dirnode.decrypt(rk, E_read)
274 print >>out, " read: %s" % read
281 ["dump-share", None, DumpOptions,
282 "Unpack and display the contents of a share (uri_extension and leases)."],
283 ["dump-root-dirnode", None, DumpRootDirnodeOptions,
284 "Compute most of the URI for the vdrive server's root dirnode."],
285 ["dump-dirnode", None, DumpDirnodeOptions,
286 "Unpack and display the contents of a vdrive DirectoryNode."],
290 "dump-share": dump_share,
291 "dump-root-dirnode": dump_root_dirnode,
292 "dump-dirnode": dump_directory_node,