Initial support for efficient sub-file incrementals.
[cumulus.git] / ref.h
1 /* Cumulus: Smart Filesystem Backup to Dumb Servers
2  *
3  * Copyright (C) 2007-2008  The Regents of the University of California
4  * Written by Michael Vrable <mvrable@cs.ucsd.edu>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 /* Backups are structured as a collection of objects, which may refer to other
22  * objects.  Object references are used to name other objects or parts of them.
23  * This file defines the class for representing object references and the
24  * textual representation of these references. */
25
26 #ifndef _LBS_REF_H
27 #define _LBS_REF_H
28
29 #include <string>
30
31 /* ======================== Object Reference Syntax ========================
32  *
33  * Segments are groups of objects.  Segments are named by UUID, which is a
34  * 128-bit value.  The text representation is
35  *    <segment> ::= xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxx
36  * where each <x> is a lowercase hexadecimal digit ([0-9a-f]).
37  *
38  * Each object within a segment is assigned a sequence number, which is given
39  * as a hexadecimal value:
40  *    <object-seq> ::= xxxxxxxx
41  *
42  * An object can be uniquely named by the combination of segment name and
43  * object sequence number:
44  *    <object-name> ::= <segment> "/" <object-seq>
45  * Example: "cf47429e-a503-43ac-9c31-bb3175fbb820/0000002b"
46  *
47  * An object name may optionally be suffixed with a checksum, which allows
48  * checking the integrity of the referenced object.
49  *    <checksum> ::= <checksum-alg> "=" <checksum-value>
50  * Currently the only checksum-alg is "sha1", but others may be defined later.
51  * <checksum-value> is a hexadecimal string.  If included, the checksum is
52  * enclosed in parentheses.
53  *
54  * Each object is stored as a string of bytes, and object reference may specify
55  * a substring rather than the entire string using a range specifier.  If no
56  * range specifier is given, then by default the entire object is used.
57  *    <range> ::= <start> "+" <length>
58  * Both <start> and <length> are decimal values.  If included, the range is
59  * enclosed in brackets.  As an abbreviation, if <start> is 0 then the range
60  * can be given as just <length> (no "+" needed).
61  *
62  * When both a checksum and a range are included, note that the checksum is
63  * taken over the entire original object, before the range is taken into
64  * account.
65  *
66  * The full syntax for an object reference is:
67  *    <object-reference>
68  *      ::= <object-name> [ "(" <checksum> ")" ] [ "[" <range> "]" ]
69  * Example: "cf47429e-a503-43ac-9c31-bb3175fbb820/0000002b(sha1=b9f5d0a21b8d07356723f041f5463dec892654af)[1024+512]"
70  *
71  * Finally, in specific circumstances, and indirect reference may be used.  In
72  * cases where data could be listed directly, instead an object reference can
73  * be given, prefixed with "@", which indicates that the data stored at the
74  * referenced object should be treated as being included.
75  *    <indirect-reference> ::= "@" <object-reference>
76  */
77
78 /* Generate a fresh UUID, suitable for use as a segment name. */
79 std::string generate_uuid();
80
81 /* Class representing an object reference, which allows it to be manipulated
82  * and converted to and from the text representation. */
83 class ObjectReference {
84 public:
85     enum RefType { REF_NULL, REF_ZERO, REF_NORMAL };
86
87     ObjectReference();
88     ObjectReference(RefType t);
89     ObjectReference(const std::string& segment, int sequence);
90     ObjectReference(const std::string& segment, const std::string& sequence);
91
92     bool is_null() const { return type == REF_NULL; }
93     bool is_normal() const { return type == REF_NORMAL; }
94     std::string to_string() const;
95     static ObjectReference parse(const std::string& s);
96
97     std::string get_segment() const { return segment; }
98     std::string get_sequence() const { return object; }
99     std::string get_basename() const { return segment + "/" + object; }
100     ObjectReference base() const { return ObjectReference(segment, object); }
101
102     bool has_checksum() const { return checksum_valid; }
103     std::string get_checksum() const { return checksum; }
104     void clear_checksum() { checksum = ""; checksum_valid = false; }
105     void set_checksum(const std::string& checksum)
106         { this->checksum = checksum; checksum_valid = true; }
107
108     bool has_range() const { return range_valid; }
109     size_t get_range_start() const { return range_start; }
110     size_t get_range_length() const { return range_length; }
111     void clear_range() { range_start = range_length = 0; range_valid = false; }
112     void set_range(size_t start, size_t length)
113         { range_start = start; range_length = length; range_valid = true; }
114
115     bool merge(ObjectReference ref);
116
117     // Maybe provide non-string implementations?
118     bool operator==(const ObjectReference &x) const
119         { return to_string() == x.to_string(); }
120     bool operator<(const ObjectReference &x) const
121         { return to_string() < x.to_string(); }
122
123 private:
124     RefType type;
125     std::string segment, object, checksum;
126     size_t range_start, range_length;
127     bool checksum_valid, range_valid;
128 };
129
130 #endif // _LBS_REF_H