From 0ccc8bda8094a3a3ad9cec58916c0a740dd33628 Mon Sep 17 00:00:00 2001 From: Michael Vrable Date: Wed, 7 Nov 2007 14:25:37 -0800 Subject: [PATCH] Check LBS format version when reading snapshots in the tools. Have the lbs-util command check the version of a snapshot when it is read, and signal an error if the version is newer than what is supported, so that silent failures do not occur if the format is changed in the future. --- lbs-util | 14 ++++++++++++++ lbs.py | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/lbs-util b/lbs-util index 24db4d6..5c12438 100755 --- a/lbs-util +++ b/lbs-util @@ -6,6 +6,15 @@ import getpass, os, stat, sys, time from optparse import OptionParser import lbs +# We support up to "LBS Snapshot v0.2" formats, but are also limited by the lbs +# module. +FORMAT_VERSION = min(lbs.FORMAT_VERSION, (0, 2)) + +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") @@ -66,6 +75,7 @@ def cmd_list_snapshot_sizes(): 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: @@ -99,6 +109,7 @@ def cmd_read_snapshots(snapshots): 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() @@ -109,6 +120,7 @@ def cmd_read_metadata(snapshot): 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) @@ -122,6 +134,7 @@ def cmd_verify_snapshots(snapshots): for s in snapshots: 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: @@ -145,6 +158,7 @@ def cmd_restore_snapshot(args): 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:] diff --git a/lbs.py b/lbs.py index 5077a7a..3f647c4 100644 --- a/lbs.py +++ b/lbs.py @@ -12,6 +12,9 @@ from __future__ import division import os, re, sha, tarfile, tempfile, thread from pysqlite2 import dbapi2 as sqlite3 +# The largest supported snapshot format that can be understood. +FORMAT_VERSION = (0, 2) # LBS Snapshot v0.2 + # Maximum number of nested indirect references allowed in a snapshot. MAX_RECURSION_DEPTH = 3 @@ -261,6 +264,15 @@ def parse_full(lines): except StopIteration: return {} +def parse_metadata_version(s): + """Convert a string with the snapshot version format to a tuple.""" + + m = re.match(r"^LBS Snapshot v(\d+(\.\d+)*)$", s) + if m is None: + return () + else: + return tuple([int(d) for d in m.group(1).split(".")]) + def read_metadata(object_store, root): """Iterate through all lines in the metadata log, following references.""" -- 2.20.1