3 * Copyright (C)2007-2008 Versabanq Innovations Inc. and contributors.
4 * See the included file named LICENSE for license information.
9 using System
.Collections
.Generic
;
10 using System
.Security
.Cryptography
;
14 // The checksums for a single database element (table, procedure, etc).
15 // Can have multiple checksum values - a table has one checksum per column,
17 // Note: This class is immutable.
18 // FIXME: Have separate type member?
19 internal class VxSchemaChecksum
26 readonly IEnumerable
<ulong> _checksums
;
27 public IEnumerable
<ulong> checksums
{
28 get { return _checksums; }
31 public VxSchemaChecksum(VxSchemaChecksum copy
)
34 var list
= new List
<ulong>();
35 foreach (ulong sum
in copy
.checksums
)
40 public VxSchemaChecksum(string newkey
)
43 _checksums
= new List
<ulong>();
46 public VxSchemaChecksum(string newkey
, ulong newchecksum
)
49 var list
= new List
<ulong>();
50 list
.Add(newchecksum
);
54 public VxSchemaChecksum(string newkey
, IEnumerable
<ulong> sumlist
)
58 // Tables need to maintain their checksums in sorted order, as the
59 // columns might get out of order when the tables are otherwise
62 VxSchemaChecksums
.ParseKey(newkey
, out type
, out name
);
65 List
<ulong> sorted
= sumlist
.ToList();
73 public string GetSumString()
75 List
<string> l
= new List
<string>();
76 foreach (ulong sum
in checksums
)
77 l
.Add("0x" + sum
.ToString("x8"));
81 // Write the checksum values to DBus
82 public void Write(WvDbusWriter writer
)
85 writer
.WriteArray(8, _checksums
, (w2
, sum
) => {
90 // Note: this is only safe to override because the class is immutable.
91 public override bool Equals(object other_obj
)
93 if (other_obj
== null)
96 if (!(other_obj
is VxSchemaChecksum
))
99 var other
= (VxSchemaChecksum
)other_obj
;
101 if (this.key
!= other
.key
)
104 // FIXME: This can be replaced with Linq's SequenceEquals(), once
105 // we're using a version of mono that implements it (>= 1.9).
106 ulong[] mysums
= this.checksums
.ToArray();
107 ulong[] theirsums
= other
.checksums
.ToArray();
109 if (mysums
.Count() != theirsums
.Count())
112 for (int i
= 0; i
< mysums
.Count(); i
++)
113 if (mysums
[i
] != theirsums
[i
])
119 public override int GetHashCode()
121 ulong xor
= checksums
.Aggregate((cur
, next
) => cur ^ next
);
122 return ((int)xor ^
(int)(xor
>>32));
125 // Given a string containing database sums, returns their parsed version.
126 // Leading "0x" prefixes are optional, though all numbers are assumed to
127 // be hex. The sums must be separated by spaces, e.g. "0xdeadbeef badf00d"
128 // Prints an error message and ignores any unparseable elements.
129 public static IEnumerable
<ulong> ParseSumString(string dbsums
)
131 return ParseSumString(dbsums
, null);
134 // Acts just like ParseSumString(dbsums), but allows for providing
135 // some context for errors. If errctx isn't null, it's printed before any
136 // error messages produced. A suitable string might be "Error while
137 // reading file $filename: ".
138 public static IEnumerable
<ulong> ParseSumString(string dbsums
,
142 return new List
<ulong>();
144 string[] sums
= dbsums
.Split(' ');
145 var sumlist
= new List
<ulong>();
146 foreach (string sumstr
in sums
)
148 // Ignore trailing spaces.
149 if (sumstr
.Length
== 0)
152 // C#'s hex parser doesn't like 0x prefixes.
153 string stripped
= sumstr
.ToLower();
154 if (stripped
.StartsWith("0x"))
155 stripped
= stripped
.Remove(0, 2);
158 if (UInt64
.TryParse(stripped
,
159 System
.Globalization
.NumberStyles
.HexNumber
, null,
162 sumlist
.Add(longsum
);
166 WvLog log
= new WvLog("ParseSumString");
167 string msg
= wv
.fmt("Failed to parse database sums '{0}' " +
168 "due to the malformed element '{1}'.\n",
170 log
.print("{0}{1}", errctx
== null ? "" : errctx
, msg
);
176 public static string GetDbusSignature()
182 // The checksum values for a set of database elements
183 internal class VxSchemaChecksums
: Dictionary
<string, VxSchemaChecksum
>
185 public VxSchemaChecksums()
189 public VxSchemaChecksums(VxSchemaChecksums copy
)
191 foreach (KeyValuePair
<string,VxSchemaChecksum
> p
in copy
)
192 this.Add(p
.Key
, new VxSchemaChecksum(p
.Value
));
195 // Read an array of checksums from a DBus message.
197 public VxSchemaChecksums(WvDbusMsg reply
)
199 var array
= reply
.iter().pop();
201 foreach (WvAutoCast i
in array
)
203 var ii
= i
.GetEnumerator();
204 string key
= ii
.pop();
205 var sums
= ii
.pop().Cast
<UInt64
>();
206 var cs
= new VxSchemaChecksum(key
, sums
);
211 // Write the list of checksums to DBus in a(sat) format.
212 public void WriteChecksums(WvDbusWriter writer
)
214 writer
.WriteArray(8, this, (w2
, p
) => {
219 public void AddSum(string key
, ulong checksum
)
221 if (this.ContainsKey(key
))
223 VxSchemaChecksum old
= this[key
];
225 List
<ulong> list
= new List
<ulong>(old
.checksums
);
228 this[key
] = new VxSchemaChecksum(key
, list
);
231 this.Add(key
, new VxSchemaChecksum(key
, checksum
));
234 public static string GetDbusSignature()
236 return String
.Format("a({0})", VxSchemaChecksum
.GetDbusSignature());
239 public static void ParseKey(string key
, out string type
, out string name
)
241 string[] parts
= key
.split("/", 2);
242 if (parts
.Length
!= 2)