from optparse import OptionParser
import lbs
+# We support up to "LBS Snapshot v0.6" formats, but are also limited by the lbs
+# module.
+FORMAT_VERSION = min(lbs.FORMAT_VERSION, (0, 6))
+
+def check_version(format):
+ ver = lbs.parse_metadata_version(format)
+ if ver > FORMAT_VERSION:
+ raise RuntimeError("Unsupported LBS format: " + format)
+
parser = OptionParser(usage="%prog [option]... command [arg]...")
parser.add_option("-v", action="store_true", dest="verbose", default=False,
help="increase verbosity")
previous = set()
for s in sorted(lowlevel.list_snapshots()):
d = lbs.parse_full(store.load_snapshot(s))
+ check_version(d['Format'])
segments = d['Segments'].split()
(size, added, removed) = (0, 0, 0)
for seg in segments:
store = lbs.ObjectStore(lowlevel)
for s in snapshots:
d = lbs.parse_full(store.load_snapshot(s))
+ check_version(d['Format'])
print d
print d['Segments'].split()
store.cleanup()
lowlevel = lbs.LowlevelDataStore(options.store)
store = lbs.ObjectStore(lowlevel)
d = lbs.parse_full(store.load_snapshot(snapshot))
+ check_version(d['Format'])
metadata = lbs.read_metadata(store, d['Root'])
for l in metadata:
sys.stdout.write(l)
lowlevel = lbs.LowlevelDataStore(options.store)
store = lbs.ObjectStore(lowlevel)
for s in snapshots:
+ lbs.accessed_segments.clear()
print "#### Snapshot", s
d = lbs.parse_full(store.load_snapshot(s))
+ check_version(d['Format'])
print "## Root:", d['Root']
metadata = lbs.iterate_metadata(store, d['Root'])
for m in metadata:
- if m.fields['type'] != '-': continue
+ if m.fields['type'] not in ('-', 'f'): continue
print "%s [%d bytes]" % (m.fields['name'], int(m.fields['size']))
verifier = lbs.ChecksumVerifier(m.fields['checksum'])
size = 0
raise ValueError("File size does not match!")
if not verifier.valid():
raise ValueError("Bad checksum found")
+
+ # Verify that the list of segments included with the snapshot was
+ # actually accurate: covered all segments that were really read, and
+ # doesn't contain duplicates.
+ listed_segments = set(d['Segments'].split())
+ if lbs.accessed_segments - listed_segments:
+ print "Error: Some segments not listed in descriptor!"
+ print sorted(list(lbs.accessed_segments - listed_segments))
+ if listed_segments - lbs.accessed_segments :
+ print "Warning: Extra unused segments listed in descriptor!"
+ print sorted(list(listed_segments - lbs.accessed_segments))
store.cleanup()
# Restore a snapshot, or some subset of files from it
lowlevel = lbs.LowlevelDataStore(options.store)
store = lbs.ObjectStore(lowlevel)
snapshot = lbs.parse_full(store.load_snapshot(args[0]))
+ check_version(snapshot['Format'])
destdir = args[1]
paths = args[2:]
if not os.path.isdir(path):
os.makedirs(path)
- if m.items.type == '-':
+ if m.items.type in ('-', 'f'):
file = open(destpath, 'wb')
verifier = lbs.ChecksumVerifier(m.items.checksum)
size = 0
if filename != '.':
os.mkdir(destpath)
elif m.items.type == 'l':
- os.symlink(m.items.contents, destpath)
+ try:
+ target = m.items.target
+ except:
+ # Old (v0.2 format) name for 'target'
+ target = m.items.contents
+ os.symlink(target, destpath)
elif m.items.type == 'p':
os.mkfifo(destpath)
elif m.items.type in ('c', 'b'):