Check LBS format version when reading snapshots in the tools.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Wed, 7 Nov 2007 22:25:37 +0000 (14:25 -0800)
committerMichael Vrable <mvrable@turin.ucsd.edu>
Wed, 7 Nov 2007 22:25:37 +0000 (14:25 -0800)
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
lbs.py

index 24db4d6..5c12438 100755 (executable)
--- 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 (file)
--- 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."""