From ab51d5778a1f19c204c935de231737df2e62c20c Mon Sep 17 00:00:00 2001 From: Michael Vrable Date: Wed, 12 Dec 2007 10:16:39 -0800 Subject: [PATCH] Snapshot format change: extend the slice syntax with a length-only form. Change slice format so that in addition to +, it is possible to specify just . This isn't needed (0+) could be used instead, but looks more pleasing if lengths are specified more frequently on objects. Also update the various tools to correctly parse the new syntax. This is part of the new v0.6 format. --- contrib/restore.pl | 13 +++++++++---- doc/format.txt | 10 +++++++--- lbs.py | 12 ++++++++---- ref.cc | 37 ++++++++++++++++++++++++------------- ref.h | 3 ++- 5 files changed, 50 insertions(+), 25 deletions(-) diff --git a/contrib/restore.pl b/contrib/restore.pl index 96cf4b4..f9c55ce 100755 --- a/contrib/restore.pl +++ b/contrib/restore.pl @@ -88,8 +88,8 @@ sub load_ref { my $ref_str = shift; # Check for special objects before attempting general parsing. - if ($ref_str =~ m/^zero\[(\d+)\+(\d+)\]$/) { - return "\0" x ($2 + 0); + if ($ref_str =~ m/^zero\[((\d+)\+)?(\d+)\]$/) { + return "\0" x ($3 + 0); } # Try to parse the object reference string into constituent pieces. The @@ -122,12 +122,17 @@ sub load_ref { # If a range was specified, then only a subset of the bytes of the object # are desired. Extract just the desired bytes. if ($range) { - if ($range !~ m/^\[(\d+)\+(\d+)\]$/) { + if ($range !~ m/^\[((\d+)\+)?(\d+)\]$/) { die "Malformed object range: $range"; } my $object_size = length $contents; - my ($start, $length) = ($1 + 0, $2 + 0); + my ($start, $length); + if ($1 ne "") { + ($start, $length) = ($2 + 0, $3 + 0); + } else { + ($start, $length) = (0, $3 + 0); + } if ($start >= $object_size || $start + $length > $object_size) { die "Object range $range falls outside object bounds " . "(actual size $object_size)"; diff --git a/doc/format.txt b/doc/format.txt index 7449681..5072981 100644 --- a/doc/format.txt +++ b/doc/format.txt @@ -116,7 +116,11 @@ is invalid to select using the slice syntax a range of bytes that does not fall within the original object. The slice specification should be appended to an object name, for example: a704eeae-97f2-4f30-91a4-d4473956366b/000001ad[264+1000] -selects only bytes 264..1263 from the original object. +selects only bytes 264..1263 from the original object. As an +abbreviation, the slice syntax + [] +is shorthand for + [0+] Both a checksum and a slice can be used. In this case, the checksum is given first, followed by the slice. The checksum is computed over the @@ -130,9 +134,9 @@ special name "zero" may be used instead of segment/sequence number. This represents an object consisting entirely of zeroes. The zero object must have a slice specification appended to indicate the size of the object. For example - zero[0+1024] + zero[1024] represents a block consisting of 1024 null bytes. A checksum should not -be given. +be given. The slice syntax should use the abbreviated length-only form. FILE METADATA LISTING diff --git a/lbs.py b/lbs.py index 3108998..80240e7 100644 --- a/lbs.py +++ b/lbs.py @@ -139,11 +139,11 @@ class ObjectStore: @staticmethod def parse_ref(refstr): - m = re.match(r"^zero\[(\d+)\+(\d+)\]$", refstr) + m = re.match(r"^zero\[(\d+)\]$", refstr) if m: - return ("zero", None, None, (int(m.group(1)), int(m.group(2)))) + return ("zero", None, None, (0, int(m.group(1)))) - m = re.match(r"^([-0-9a-f]+)\/([0-9a-f]+)(\(\S+\))?(\[(\d+)\+(\d+)\])?$", refstr) + m = re.match(r"^([-0-9a-f]+)\/([0-9a-f]+)(\(\S+\))?(\[((\d+)\+)?(\d+)\])?$", refstr) if not m: return segment = m.group(1) @@ -155,7 +155,11 @@ class ObjectStore: checksum = checksum.lstrip("(").rstrip(")") if slice is not None: - slice = (int(m.group(5)), int(m.group(6))) + if m.group(5) is None: + # Abbreviated slice + slice = (0, int(m.group(7))) + else: + slice = (int(m.group(6)), int(m.group(7))) return (segment, object, checksum, slice) diff --git a/ref.cc b/ref.cc index 80f4d1d..8ed747d 100644 --- a/ref.cc +++ b/ref.cc @@ -78,7 +78,11 @@ string ObjectReference::to_string() const if (range_valid) { char buf[64]; - sprintf(buf, "[%zu+%zu]", range_start, range_length); + if (range_start == 0) { + sprintf(buf, "[%zu]", range_length); + } else { + sprintf(buf, "[%zu+%zu]", range_start, range_length); + } result += buf; } @@ -143,21 +147,28 @@ ObjectReference ObjectReference::parse(const std::string& str) s = t; while (*t >= '0' && *t <= '9') t++; - if (*t != '+') - return ObjectReference(); - string val(s, t - s); - range1 = atoll(val.c_str()); + // Abbreviated-length only range? + if (*t == ']') { + string val(s, t - s); + range2 = atoll(val.c_str()); + } else { + if (*t != '+') + return ObjectReference(); - t++; - s = t; - while (*t >= '0' && *t <= '9') - t++; - if (*t != ']') - return ObjectReference(); + string val(s, t - s); + range1 = atoll(val.c_str()); - val = string(s, t - s); - range2 = atoll(val.c_str()); + t++; + s = t; + while (*t >= '0' && *t <= '9') + t++; + if (*t != ']') + return ObjectReference(); + + val = string(s, t - s); + range2 = atoll(val.c_str()); + } have_range = true; } diff --git a/ref.h b/ref.h index e499e6e..9a565ee 100644 --- a/ref.h +++ b/ref.h @@ -39,7 +39,8 @@ * range specifier is given, then by default the entire object is used. * ::= "+" * Both and are decimal values. If included, the range is - * enclosed in brackets. + * enclosed in brackets. As an abbreviation, if is 0 then the range + * can be given as just (no "+" needed). * * When both a checksum and a range are included, note that the checksum is * taken over the entire original object, before the range is taken into -- 2.20.1