Add a new object-oriented wrapper for building object references.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Fri, 11 May 2007 05:10:26 +0000 (22:10 -0700)
committerMichael Vrable <mvrable@turin.ucsd.edu>
Fri, 11 May 2007 05:10:26 +0000 (22:10 -0700)
Makefile
ref.cc [new file with mode: 0644]
ref.h [new file with mode: 0644]
store.cc
store.h

index 9f6892b..f29d2a7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ CXXFLAGS=-O -Wall -D_FILE_OFFSET_BITS=64 $(DEBUG) \
         `pkg-config --cflags $(PACKAGES)`
 LDFLAGS=$(DEBUG) -ltar `pkg-config --libs $(PACKAGES)`
 
-SRCS=format.cc scandir.cc sha1.cc store.cc
+SRCS=format.cc ref.cc scandir.cc sha1.cc store.cc
 OBJS=$(SRCS:.cc=.o)
 
 scandir : $(OBJS)
diff --git a/ref.cc b/ref.cc
new file mode 100644 (file)
index 0000000..e996c7d
--- /dev/null
+++ b/ref.cc
@@ -0,0 +1,57 @@
+/* LBS: An LFS-inspired filesystem backup system
+ * Copyright (C) 2007  Michael Vrable
+ *
+ * Backups are structured as a collection of objects, which may refer to other
+ * objects.  Object references are used to name other objects or parts of them.
+ * This file defines the class for representing object references and the
+ * textual representation of these references. */
+
+#include <assert.h>
+#include <stdio.h>
+#include <uuid/uuid.h>
+
+#include <string>
+
+#include "ref.h"
+
+using std::string;
+
+/* Generate a new UUID, and return the text representation of it.  This is
+ * suitable for generating the name for a new segment. */
+string generate_uuid()
+{
+    uint8_t uuid[16];
+    char buf[40];
+
+    uuid_generate(uuid);
+    uuid_unparse_lower(uuid, buf);
+    return string(buf);
+}
+
+
+ObjectReference::ObjectReference(const std::string& segment, int sequence)
+    : segment(segment)
+{
+    char seq_buf[64];
+    sprintf(seq_buf, "%08x", sequence);
+    object = seq_buf;
+
+    clear_checksum();
+    clear_range();
+}
+
+string ObjectReference::to_string() const
+{
+    string result = segment + "/" + object;
+
+    if (checksum_valid)
+        result += "(" + checksum + ")";
+
+    if (range_valid) {
+        char buf[64];
+        sprintf(buf, "[%zu+%zu]", range_start, range_length);
+        result += buf;
+    }
+
+    return result;
+}
diff --git a/ref.h b/ref.h
new file mode 100644 (file)
index 0000000..496fdec
--- /dev/null
+++ b/ref.h
@@ -0,0 +1,93 @@
+/* LBS: An LFS-inspired filesystem backup system
+ * Copyright (C) 2007  Michael Vrable
+ *
+ * Backups are structured as a collection of objects, which may refer to other
+ * objects.  Object references are used to name other objects or parts of them.
+ * This file defines the class for representing object references and the
+ * textual representation of these references. */
+
+#ifndef _LBS_REF_H
+#define _LBS_REF_H
+
+#include <string>
+
+/* ======================== Object Reference Syntax ========================
+ *
+ * Segments are groups of objects.  Segments are named by UUID, which is a
+ * 128-bit value.  The text representation is
+ *    <segment> ::= xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxx
+ * where each <x> is a lowercase hexadecimal digit ([0-9a-f]).
+ *
+ * Each object within a segment is assigned a sequence number, which is given
+ * as a hexadecimal value:
+ *    <object-seq> ::= xxxxxxxx
+ *
+ * An object can be uniquely named by the combination of segment name and
+ * object sequence number:
+ *    <object-name> ::= <segment> "/" <object-seq>
+ * Example: "cf47429e-a503-43ac-9c31-bb3175fbb820/0000002b"
+ *
+ * An object name may optionally be suffixed with a checksum, which allows
+ * checking the integrity of the referenced object.
+ *    <checksum> ::= <checksum-alg> "=" <checksum-value>
+ * Currently the only checksum-alg is "sha1", but others may be defined later.
+ * <checksum-value> is a hexadecimal string.  If included, the checksum is
+ * enclosed in parentheses.
+ *
+ * Each object is stored as a string of bytes, and object reference may specify
+ * a substring rather than the entire string using a range specifier.  If no
+ * range specifier is given, then by default the entire object is used.
+ *    <range> ::= <start> "+" <length>
+ * Both <start> and <length> are decimal values.  If included, the range is
+ * enclosed in brackets.
+ *
+ * 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
+ * account.
+ *
+ * The full syntax for an object reference is:
+ *    <object-reference>
+ *      ::= <object-name> [ "(" <checksum> ")" ] [ "[" <range> "]" ]
+ * Example: "cf47429e-a503-43ac-9c31-bb3175fbb820/0000002b(sha1=b9f5d0a21b8d07356723f041f5463dec892654af)[1024+512]"
+ *
+ * Finally, in specific circumstances, and indirect reference may be used.  In
+ * cases where data could be listed directly, instead an object reference can
+ * be given, prefixed with "@", which indicates that the data stored at the
+ * referenced object should be treated as being included.
+ *    <indirect-reference> ::= "@" <object-reference>
+ */
+
+/* Generate a fresh UUID, suitable for use as a segment name. */
+std::string generate_uuid();
+
+/* Class representing an object reference, which allows it to be manipulated
+ * and converted to and from the text representation. */
+class ObjectReference {
+public:
+    ObjectReference(const std::string& segment, int sequence);
+
+    std::string to_string() const;
+
+    std::string get_segment() const { return segment; }
+    void set_segment(const std::string& segment) { this->segment = segment; }
+
+    bool has_checksum() const { return checksum_valid; }
+    std::string get_checksum() const { return checksum; }
+    void clear_checksum() { checksum = ""; checksum_valid = false; }
+    void set_checksum(const std::string& checksum)
+        { this->checksum = checksum; checksum_valid = true; }
+
+    bool has_range() const { return range_valid; }
+    size_t get_range_start() const { return range_start; }
+    size_t get_range_length() const { return range_length; }
+    void clear_range() { range_start = range_length = 0; range_valid = false; }
+    void set_range(size_t start, size_t length)
+        { range_start = start; range_length = length; range_valid = true; }
+
+private:
+    std::string segment, object, checksum;
+    size_t range_start, range_length;
+    bool checksum_valid, range_valid;
+};
+
+#endif // _LBS_REF_H
index 49f002a..0533630 100644 (file)
--- a/store.cc
+++ b/store.cc
@@ -13,7 +13,6 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <time.h>
-#include <uuid/uuid.h>
 
 #include <list>
 #include <set>
@@ -21,6 +20,7 @@
 #include <iostream>
 
 #include "store.h"
+#include "ref.h"
 
 using std::list;
 using std::set;
@@ -116,11 +116,7 @@ string TarSegmentStore::write_object(const char *data, size_t len, const
     if (segments.find(group) == segments.end()) {
         segment = new segment_info;
 
-        uint8_t uuid[16];
-        char uuid_buf[40];
-        uuid_generate(uuid);
-        uuid_unparse_lower(uuid, uuid_buf);
-        segment->name = uuid_buf;
+        segment->name = generate_uuid();
 
         string filename = path + "/" + segment->name + ".tar";
         segment->file = new Tarfile(filename, segment->name);
diff --git a/store.h b/store.h
index 6906d63..6fec763 100644 (file)
--- a/store.h
+++ b/store.h
@@ -6,8 +6,8 @@
  * is built on top of libtar, and represents segments as TAR files and objects
  * as files within them. */
 
-#ifndef _LBS_TARSTORE_H
-#define _LBS_TARSTORE_H
+#ifndef _LBS_STORE_H
+#define _LBS_STORE_H
 
 #include <stdint.h>
 #include <libtar.h>
@@ -149,4 +149,4 @@ private:
     std::set<std::string> refs;
 };
 
-#endif // _LBS_TARSTORE_H
+#endif // _LBS_STORE_H