1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2019 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * This is a Bacula plugin for backup/restore Docker using native tools.
21 *
22 * Author: Radosław Korzeniewski, MMXIX
23 * radoslaw@korzeniewski.net, radekk@inteos.pl
24 * Inteos Sp. z o.o. http://www.inteos.pl/
25 */
26
27 #include "dkid.h"
28
29 /*
30 * DKID class constructor, does default initialization.
31 */
DKID()32 DKID::DKID()
33 {
34 bmemzero(Digest, DKIDDIGESTSIZE + 1);
35 ShortD = DKIDInvalid;
36 shortonly = false;
37 };
38
39 /*
40 * DKID class constructor, does parm initialization.
41 */
DKID(const char * data)42 DKID::DKID(const char* data)
43 {
44 init(data);
45 };
46
47 /*
48 * DKID class constructor, does parm initialization.
49 */
DKID(POOL_MEM & data)50 DKID::DKID(POOL_MEM& data)
51 {
52 init(data.c_str());
53 };
54
55 /*
56 * DKID initialization from string.
57 * as the usable area of short sha256 version used in Docker is 6bytes/48bits
58 * and we are using a 64bit (signed) integer then we have a plenty of space to mark
59 * invalid sha256 conversion with a negative ShortD value.
60 */
init(const char * data)61 void DKID::init(const char* data)
62 {
63 int len;
64 int a;
65 unsigned char c;
66 bool valid = true;
67 char *dig = (char*)data;
68
69 if (dig != NULL){
70 /* check for sha256: prefix*/
71 if (strstr(dig, "sha256:") == dig){
72 dig += 7;
73 }
74 len = strlen(dig);
75 /* check for invalid input data */
76 for (a = 0; a < (len > DKIDDIGESTShortSIZE ? DKIDDIGESTShortSIZE : len); a++){
77 // we are checking for ASCII codes, a subset of UTF-8 for short digest only
78 c = (unsigned char)dig[a];
79 if (c > 'f' || (c > '9' && c < 'A') || (c > 'F' && c < 'a')){
80 valid = false;
81 break;
82 }
83 }
84 if (valid){
85 if (len > DKIDDIGESTShortSIZE){
86 /* initialize from full data */
87 memcpy(Digest, dig, DKIDDIGESTSIZE);
88 Digest[DKIDDIGESTSIZE] = 0;
89 shortonly = false;
90 } else {
91 /* handle short data */
92 memcpy(Digest, dig, len);
93 memcpy(Digest + len, "(...)\0", 6);
94 shortonly = true;
95 }
96 memcpy(DigestShort, dig, DKIDDIGESTShortSIZE);
97 DigestShort[DKIDDIGESTShortSIZE] = 0;
98 ShortD = strtol(DigestShort, NULL, 16);
99 } else {
100 ShortD = DKIDInvalid;
101 shortonly = false;
102 }
103 }
104 };
105
106 /*
107 * Basic assignment operator overloading for string.
108 *
109 * in:
110 * data - the null terminated string where up to 64 chars will be used
111 * out:
112 * reinitialized DKID class
113 */
114 DKID& DKID::operator= (char* data)
115 {
116 init(data);
117 return *this;
118 };
119
120 /*
121 * Basic assignment operator overloading for POOL_MEM class.
122 *
123 * in:
124 * data - a reference to POOL_MEM class instance which is used as a source
125 * of null terminated string for initialization
126 * out:
127 * reinitialized DKID class
128 */
129 DKID& DKID::operator =(POOL_MEM &data)
130 {
131 init(data.c_str());
132 return *this;
133 }
134
135 /*
136 * Basic assignment operator overloading for DKID class.
137 *
138 * in:
139 * other - a reference to another DKID class instance which will be used for
140 * assignment
141 * out:
142 * reinitialized DKID class
143 */
144 DKID& DKID::operator =(DKID &other)
145 {
146 memcpy(Digest, other.Digest, DKIDDIGESTSIZE);
147 memcpy(DigestShort, other.DigestShort, DKIDDIGESTShortSIZE);
148 Digest[DKIDDIGESTSIZE] = 0;
149 DigestShort[DKIDDIGESTShortSIZE] = 0;
150 ShortD = other.ShortD;
151 shortonly = other.shortonly;
152 return *this;
153 }
154
155 /*
156 * Equal to operator overloading for DKID class.
157 *
158 * in:
159 * other - a reference to another DKID class instance which will be used for
160 * comparison
161 * out:
162 * true - if both ShortD are the same
163 * false - if ShortD variables differ or any DKID is invalid
164 */
165 bool DKID::operator ==(DKID &other)
166 {
167 if (ShortD >= 0 && other.ShortD >= 0 && ShortD == other.ShortD &&
168 (shortonly || other.shortonly || bstrcmp(Digest, other.Digest))){
169 return true;
170 }
171 return false;
172 }
173
174 /*
175 * Not-Equal to operator overloading for DKID class.
176 *
177 * in:
178 * other - a reference to another DKID class instance which will be used for
179 * comparison
180 * out:
181 * true - if ShortD variables differ and none of them are invalid
182 * false - if both ShortD are the same or any DKID is invalid
183 */
184 bool DKID::operator !=(DKID &other)
185 {
186 if (ShortD >= 0 && other.ShortD >= 0 && ShortD != other.ShortD){
187 return true;
188 }
189 if (!shortonly && !other.shortonly && !bstrcmp(Digest, other.Digest)){
190 return true;
191 }
192 return false;
193 }
194
195 #ifndef TEST_PROGRAM
196 #define TEST_PROGRAM_A
197 #endif
198
199 #ifdef TEST_PROGRAM
200 #include "unittests.h"
201
dump()202 void DKID::dump()
203 {
204 printf ("%p::ShortD: %ld\n", this, ShortD);
205 printf ("%p::Digest: %s\n", this, Digest);
206 printf ("%p::shortonly: %s\n", this, shortonly?"true":"false");
207 printf ("%p::DigestShort: %s\n", this, DigestShort);
208 };
209
210 const char *dig1 = "66f45d8601bae26a6b2ffeb46922318534d3b3905377b3a224693bd78601cb3b";
211 const char *sdig1 = "66f45d8601ba";
212 const int64_t vdig1 = 0x66f45d8601ba;
213 const char *dig2 = "B546087C43F75A2C1484B4AEE0737499AA69A09067B04237907FCCD4BDE938C7";
214 const char *sdig2 = "B546087C43F7";
215 const int64_t vdig2 = 0xb546087c43f7;
216 const char *sdig3 = "0f601bcb1ef5";
217 const int64_t vdig3 = 0x0f601bcb1ef5;
218 const char *sdig4 = "00571da76d";
219 const int64_t vdig4 = 0x00571da76d;
220 const char *dig5 = "sha256:daabf4372f900cb1ad0db17d26abf3acce55224275d1850f02459180e4dacf1d";
221 const char *tdig5 = "daabf4372f900cb1ad0db17d26abf3acce55224275d1850f02459180e4dacf1d";
222 const char *sdig5 = "daabf4372f90";
223 const int64_t vdig5 = 0xdaabf4372f90;
224 const char *sinv1 = "Invalid initialization string";
225 const char *sinv2 = "brave_edison";
226 const char *sinv3 = "0xDEADBEEF";
227 const char *sinv4 = "c0a478d317195b…";
228 const char *sinv5 = "a478d317195b…";
229 const char *sinv6 = "78d317195b…";
230
main()231 int main()
232 {
233 Unittests dkid_test("dkid_test");
234 DKID *id;
235 DKID id2(dig2);
236 char *p;
237 int64_t v;
238 POOL_MEM m(PM_FNAME);
239
240 Pmsg0(0, "Initialize tests ...\n");
241
242 id = New(DKID);
243 ok(id && id->id() == DKIDInvalid, "Check default initialization short");
244 ok(id && strlen(id->digest()) == 0, "Check default initialization full");
245 ok(id && strlen(id->digest_short()) == 0, "Check short default initialization full");
246 delete(id);
247
248 id = New(DKID(dig1));
249 ok(id && id->id() == vdig1, "Check param initialization short");
250 ok(id && bstrcmp(id->digest(), dig1), "Check param initialization full");
251 ok(id && bstrcmp(id->digest_short(), sdig1), "Check short param initialization");
252 delete(id);
253
254 id = New(DKID(dig2));
255 ok(id && id->id() == vdig2, "Check param initialization short upper");
256 ok(id && bstrcmp(id->digest(), dig2), "Check param initialization full upper");
257 ok(id && bstrcmp(id->digest_short(), sdig2), "Check short param initialization full upper");
258 delete(id);
259
260 Mmsg(m, "%s", dig1);
261 id = New(DKID(m));
262 ok(id && id->id() == vdig1, "Check pool_mem initialization short");
263 ok(id && bstrcmp(id->digest(), dig1), "Check pool_mem initialization full");
264 ok(id && bstrcmp(id->digest_short(), sdig1), "Check short pool_mem initialization full");
265 delete(id);
266
267 id = New(DKID(sdig3));
268 ok(id && id->id() == vdig3, "Check short digest initialization");
269 Mmsg(m, "%s(...)", sdig3);
270 ok(id && bstrcmp(id->digest(), m.c_str()), "Check short digest initialization full str");
271 ok(id && bstrcmp(id->digest_short(), sdig3), "Check short for short digest initialization");
272 delete(id);
273
274 id = New(DKID(sdig4));
275 ok(id && id->id() == vdig4, "Check shorter digest initialization");
276 Mmsg(m, "%s(...)", sdig4);
277 ok(id && bstrcmp(id->digest(), m.c_str()), "Check shorter digest initialization full str");
278 ok(id && bstrcmp(id->digest_short(), sdig4), "Check short for shorter digest initialization");
279 delete(id);
280
281 id = New(DKID(dig5));
282 ok(id && id->id() == vdig5, "Check param initialization with sha256: prefix");
283 ok(id && bstrcmp(id->digest(), tdig5), "Check param initialization full with sha256: prefix");
284 ok(id && bstrcmp(id->digest_short(), sdig5), "Check short param initialization with sha256: prefix");
285 delete(id);
286
287 Pmsg0(0, "Invalid initialization tests ...\n");
288
289 id = New(DKID(sinv1));
290 ok(id && id->id() < 0, "Checking invalid digest string long");
291 delete(id);
292
293 id = New(DKID(sinv2));
294 ok(id && id->id() < 0, "Checking invalid digest string short");
295 delete(id);
296
297 id = New(DKID(sinv3));
298 ok(id && id->id() < 0, "Checking invalid digest string hex");
299 delete(id);
300
301 id = New(DKID(sinv4));
302 ok(id && id->id() >= 0, "Checking digest string with ellipsis");
303 delete(id);
304
305 id = New(DKID(sinv5));
306 ok(id && id->id() >= 0, "Checking digest string with ellipsis short");
307 delete(id);
308
309 id = New(DKID(sinv6));
310 ok(id && id->id() < 0, "Checking invalid digest string with ellipsis short");
311 delete(id);
312
313 Pmsg0(0, "Operators tests ...\n");
314
315 id = New(DKID(dig1));
316 p = (char*)id;
317 ok(bstrcmp(p, dig1), "Checking operator char* ()");
318 v = *id;
319 ok(v == vdig1, "Checking operator int64_t ()");
320
321 id2 = *id;
322 ok(id2.id() == vdig1, "Checking operator= (DKID&)");
323 ok(id2 == *id, "Checking operator== on the same");
324 nok(id2 != *id, "Checking operator!= on the same");
325
326 *id = (char*)dig2;
327 ok(id->id() == vdig2, "Checking operator= (char*)");
328 nok(id2 == *id, "Checking operator== on different");
329 ok(id2 != *id, "Checking operator!= on different");
330
331 *id = m;
332 ok(id2.id() == vdig1, "Checking operator= (POOL_MEM&)");
333
334 id2 = (char*)dig2;
335 ok(id2.id() == vdig2, "Checking operator= (char*)");
336 delete(id);
337
338 id = New(DKID(sinv1));
339 id2 = *id;
340 nok (id2 == *id, "Checking operator== on invalid digest");
341 nok (id2 != *id, "Checking operator!= on invalid digest");
342 delete(id);
343
344 id = New(DKID(sdig1));
345 id2 = (char*)dig1;
346 ok (id2 == *id, "Checking operator== on full and short digest");
347 nok (id2 != *id, "Checking operator!= on full and short digest");
348 delete(id);
349
350 return report();
351 };
352
353 #endif /* TEST_PROGRAM */