File Coverage

bpc_lib.c
Criterion Covered Total %
statement 0 191 0.0
branch 0 116 0.0
condition n/a
subroutine n/a
pod n/a
total 0 307 0.0


line stmt bran cond sub pod time code
1             /*
2             * Library routines
3             *
4             * Copyright (C) 2013 Craig Barratt.
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 3 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, visit the http://fsf.org website.
18             */
19              
20             #include "backuppc.h"
21              
22             char BPC_TopDir[BPC_MAXPATHLEN];
23             char BPC_PoolDir[BPC_MAXPATHLEN];
24             char BPC_CPoolDir[BPC_MAXPATHLEN];
25             char BPC_PoolDir3[BPC_MAXPATHLEN];
26             char BPC_CPoolDir3[BPC_MAXPATHLEN];
27              
28             int BPC_HardLinkMax = 32000;
29             int BPC_PoolV3Enabled = 0;
30             int BPC_TmpFileUnique = -1;
31             int BPC_LogLevel = 0;
32              
33             static char *hexDigits = "0123456789abcdef";
34              
35 0           void bpc_lib_conf_init(char *topDir, int hardLinkMax, int poolV3Enabled, int logLevel)
36             {
37 0 0         if ( logLevel >= 8 ) bpc_logMsgf("bpc_lib_conf_init: topDir = %s, logLevel = %d\n", topDir, logLevel);
38              
39 0           snprintf(BPC_TopDir, sizeof(BPC_TopDir), "%s", topDir);
40 0           snprintf(BPC_CPoolDir, sizeof(BPC_CPoolDir), "%s/%s", BPC_TopDir, "cpool");
41 0           snprintf(BPC_CPoolDir3, sizeof(BPC_CPoolDir3), "%s/%s", BPC_TopDir, "cpool");
42 0           snprintf(BPC_PoolDir, sizeof(BPC_PoolDir), "%s/%s", BPC_TopDir, "pool");
43 0           snprintf(BPC_PoolDir3, sizeof(BPC_PoolDir3), "%s/%s", BPC_TopDir, "pool");
44              
45 0           BPC_HardLinkMax = hardLinkMax;
46 0           BPC_PoolV3Enabled = poolV3Enabled;
47 0           BPC_LogLevel = logLevel;
48 0           }
49              
50 0           void bpc_lib_setTmpFileUnique(int val)
51             {
52 0           BPC_TmpFileUnique = val;
53 0           }
54              
55 0           int bpc_lib_setLogLevel(int logLevel)
56             {
57 0 0         if ( logLevel >= 0 ) {
58 0           BPC_LogLevel = logLevel;
59             }
60 0           return BPC_LogLevel;
61             }
62              
63             /*
64             * Converts a byte to two ascii hex digits at outStr[0] and outStr[1].
65             * Nothing is written at outStr[2]; ie: no NULL termination
66             */
67 0           void bpc_byte2hex(char *outStr, int byte)
68             {
69 0           outStr[0] = hexDigits[(byte >> 4) & 0xf];
70 0           outStr[1] = hexDigits[(byte >> 0) & 0xf];
71 0           }
72              
73 0           static uchar bpc_hexChar2nibble(char c)
74             {
75 0 0         if ( '0' <= c && c <= '9' ) return c - '0';
    0          
76 0 0         if ( 'A' <= c && c <= 'F' ) return 0xa + (c - 'A');
    0          
77 0 0         if ( 'a' <= c && c <= 'f' ) return 0xa + (c - 'a');
    0          
78 0           return 0;
79             }
80              
81 0           uchar bpc_hexStr2byte(char c1, char c2)
82             {
83 0           return (bpc_hexChar2nibble(c1) << 4) | bpc_hexChar2nibble(c2);
84             }
85              
86 0           void bpc_digest_buffer2MD5(bpc_digest *digest, uchar *buffer, size_t bufferLen)
87             {
88             md_context md5;
89 0           md5_begin(&md5);
90 0           md5_update(&md5, buffer, bufferLen);
91 0           md5_result(&md5, digest->digest);
92 0           digest->len = MD5_DIGEST_LEN;
93 0           }
94              
95 0           void bpc_digest_append_ext(bpc_digest *digest, uint32 ext)
96             {
97             int i;
98              
99 0           digest->len = 16;
100 0 0         if ( ext == 0 ) return;
101 0 0         for ( i = 24 ; i >= 0 ; i -= 8 ) {
102 0 0         if ( ext >= (1U << i) ) {
103 0           digest->digest[digest->len++] = (ext >> i) & 0xff;
104             }
105             }
106             }
107              
108             /*
109             * returns 0 if the two digests are equal, non-zero if they are not
110             */
111 0           int bpc_digest_compare(bpc_digest *digest1, bpc_digest *digest2)
112             {
113 0 0         if ( digest1->len != digest2->len ) return digest1->len - digest2->len;
114 0           return memcmp(digest1->digest, digest2->digest, digest1->len);
115             }
116              
117 0           void bpc_digest_digest2str(bpc_digest *digest, char *hexStr)
118             {
119             int i;
120 0           char *out = hexStr;
121              
122 0 0         for ( i = 0 ; i < digest->len ; i++ ) {
123 0           bpc_byte2hex(out, digest->digest[i]);
124 0           out += 2;
125             }
126 0           *out = '\0';
127 0           }
128              
129 0           void bpc_digest_str2digest(bpc_digest *digest, char *hexStr)
130             {
131 0 0         for ( digest->len = 0 ; hexStr[0] && hexStr[1] && digest->len < BPC_DIGEST_LEN_MAX ; hexStr += 2 ) {
    0          
    0          
132 0           digest->digest[digest->len++] = bpc_hexStr2byte(hexStr[0], hexStr[1]);
133             }
134 0           }
135              
136 0           void bpc_digest_md52path(char *path, int compress, bpc_digest *digest)
137             {
138             char *out;
139              
140             /*
141             * MD5 digest of an empty file (ie, md5sum /dev/null)
142             */
143             static uchar emptyFileMD5[] = {
144             0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e
145             };
146             #if 0
147             /*
148             * Test code to create collisions in pool files.
149             * If you turn on this test, you should also force the zeroLenMD5
150             * digest comparison in bpc_poolWrite_write() to true.
151             */
152             bpc_digest fixedDigest = *digest;
153             digest = &fixedDigest;
154             memcpy(digest->digest, emptyFileMD5, sizeof(emptyFileMD5));
155             #endif
156 0 0         if ( digest->len == sizeof(emptyFileMD5) && !memcmp(digest->digest, emptyFileMD5, sizeof(emptyFileMD5)) ) {
    0          
157 0           strcpy(path, "/dev/null");
158 0           return;
159             }
160 0 0         strncpy(path, compress ? BPC_CPoolDir : BPC_PoolDir, BPC_MAXPATHLEN - 32);
161 0           path[BPC_MAXPATHLEN - 48] = '\0';
162 0           out = path + strlen(path);
163 0           *out++ = '/';
164 0           bpc_byte2hex(out, digest->digest[0] & 0xfe); out += 2;
165 0           *out++ = '/';
166 0           bpc_byte2hex(out, digest->digest[1] & 0xfe); out += 2;
167 0           *out++ = '/';
168 0           bpc_digest_digest2str(digest, out);
169             }
170              
171 0           void bpc_digest_md52path_v3(char *path, int compress, bpc_digest *digest)
172             {
173             int i;
174             char hexStr[BPC_DIGEST_LEN_MAX * 2 + 1];
175 0           uint32 ext = 0;
176 0           char n0 = hexDigits[(digest->digest[0] >> 4) & 0xf];
177 0           char n1 = hexDigits[(digest->digest[0] >> 0) & 0xf];
178 0           char n2 = hexDigits[(digest->digest[1] >> 4) & 0xf];
179              
180 0           bpc_digest_digest2str(digest, hexStr);
181 0 0         for ( i = 16 ; i < digest->len ; i++ ) {
182 0           ext |= digest->digest[i - 16] << (8 * (i - 16));
183             }
184 0 0         if ( ext > 0 ) {
185 0 0         snprintf(path, BPC_MAXPATHLEN, "%s/%c/%c/%c/%s_%d", compress ? BPC_CPoolDir3 : BPC_PoolDir3, n0, n1, n2, hexStr, ext);
186             } else {
187 0 0         snprintf(path, BPC_MAXPATHLEN, "%s/%c/%c/%c/%s", compress ? BPC_CPoolDir3 : BPC_PoolDir3, n0, n1, n2, hexStr);
188             }
189 0           }
190              
191 0           void bpc_digest_buffer2MD5_v3(bpc_digest *digest, uchar *buffer, size_t bufferLen)
192             {
193             char lenStr[256];
194              
195             md_context md5;
196 0           md5_begin(&md5);
197 0           sprintf(lenStr, "%llu", (long long unsigned int)bufferLen);
198 0           md5_update(&md5, (uchar*)lenStr, strlen(lenStr));
199 0 0         if ( bufferLen > 262144 ) {
200             /*
201             * add the first and last 131072 bytes of the buffer,
202             * up to 1MB.
203             */
204 0           int seekPosn = (bufferLen > 1048576 ? 1048576 : bufferLen) - 131072;
205 0           md5_update(&md5, buffer, 131072);
206 0           md5_update(&md5, buffer + seekPosn, 131072);
207             } else {
208             /*
209             * add the whole buffer
210             */
211 0           md5_update(&md5, buffer, bufferLen);
212             }
213 0           md5_result(&md5, digest->digest);
214 0           digest->len = MD5_DIGEST_LEN;
215 0           }
216              
217 0           static void bpc_fileNameEltMangle2(char *path, int pathSize, char *pathUM, int stopAtSlash)
218             {
219 0 0         if ( !*pathUM || (stopAtSlash && *pathUM == '/') ) {
    0          
    0          
220 0           *path = '\0';
221 0           return;
222             }
223 0           *path++ = 'f'; pathSize--;
224 0 0         for ( ; *pathUM && pathSize > 4 ; ) {
    0          
225 0 0         if ( stopAtSlash && *pathUM == '/' ) break;
    0          
226 0 0         if ( *pathUM != '%' && *pathUM != '/' && *pathUM != '\n' && *pathUM != '\r' ) {
    0          
    0          
    0          
227 0           *path++ = *pathUM++; pathSize--;
228             } else {
229 0           *path++ = '%'; pathSize--;
230 0           bpc_byte2hex(path, *pathUM++);
231 0           path += 2; pathSize -= 2;
232             }
233             }
234 0           *path = '\0';
235             }
236              
237 0           void bpc_fileNameEltMangle(char *path, int pathSize, char *pathUM)
238             {
239 0           bpc_fileNameEltMangle2(path, pathSize, pathUM, 0);
240 0           }
241              
242 0           void bpc_fileNameMangle(char *path, int pathSize, char *pathUM)
243             {
244             char *p;
245              
246 0 0         for ( ; *pathUM && pathSize > 4 ; ) {
    0          
247             int len;
248              
249 0           bpc_fileNameEltMangle2(path, pathSize, pathUM, 1);
250 0           len = strlen(path);
251 0           path += len; pathSize -= len;
252 0 0         if ( !(p = strchr(pathUM, '/')) ) break;
253 0 0         for ( pathUM = p + 1 ; *pathUM == '/' ; pathUM++ ) { }
254 0 0         if ( *pathUM ) {
255 0           *path++ = '/'; pathSize--;
256             }
257             }
258 0           *path = '\0';
259 0           }
260              
261             /*
262             * Simple logging functions. If you register callbacks, they will be called.
263             * Otherwise, messages are accumulated, and a callback allows the
264             * log strings to be fetched.
265             *
266             * We store the data in a single buffer of '\0'-terminated strings.
267             */
268             typedef struct {
269             char *mesg;
270             size_t mesgSize;
271             size_t mesgLen;
272             unsigned long errorCnt;
273             } LogMsgData;
274              
275             static LogMsgData LogData;
276             static void (*LogMsgCB)(int, char *mesg, size_t mesgLen);
277              
278 0           void bpc_logMsgf(char *fmt, ...)
279             {
280 0           int strLen, pad = 0;
281             va_list args;
282 0           va_start(args, fmt);
283              
284 0 0         if ( !LogData.mesg ) {
285 0           LogData.mesgSize = 8192;
286 0           LogData.mesgLen = 0;
287 0 0         if ( !(LogData.mesg = malloc(LogData.mesgSize)) ) {
288 0           printf("bpc_logMessagef: panic: can't allocate %lu bytes\n", (unsigned long)LogData.mesgSize);
289 0           LogData.errorCnt++;
290 0           return;
291             }
292             }
293 0 0         if ( BPC_TmpFileUnique >= 0 ) pad = 2;
294 0           strLen = vsnprintf(LogData.mesg + LogData.mesgLen + pad, LogData.mesgSize - LogData.mesgLen - pad, fmt, args);
295 0 0         if ( strLen + 2 + pad + LogData.mesgLen > LogData.mesgSize ) {
296 0           LogData.mesgSize += LogData.mesgSize + strLen + 2 + pad;
297 0 0         if ( !(LogData.mesg = realloc(LogData.mesg, LogData.mesgSize)) ) {
298 0           printf("bpc_logMessagef: panic: can't realloc %lu bytes\n", (unsigned long)LogData.mesgSize);
299 0           LogData.errorCnt++;
300 0           return;
301             }
302 0           va_start(args, fmt);
303 0           strLen = vsnprintf(LogData.mesg + LogData.mesgLen + pad, LogData.mesgSize - LogData.mesgLen - pad, fmt, args);
304 0           va_end(args);
305             }
306 0 0         if ( strLen > 0 ) {
307 0 0         if ( pad ) {
308 0 0         LogData.mesg[LogData.mesgLen++] = BPC_TmpFileUnique ? 'G' : 'R';
309 0           LogData.mesg[LogData.mesgLen++] = ' ';
310             }
311 0           LogData.mesgLen += strLen + 1;
312             }
313 0 0         if ( LogMsgCB ) {
314 0           (*LogMsgCB)(0, LogData.mesg, LogData.mesgLen - 1);
315 0           LogData.mesgLen = 0;
316             }
317 0           va_end(args);
318             }
319              
320             /*
321             * For now, this is just the same as bpc_logMsgf(). We can't call a common routine that
322             * does the work, since args might need to be parsed twice when the buffer is grown.
323             */
324 0           void bpc_logErrf(char *fmt, ...)
325             {
326 0           int strLen, pad = 0;
327             va_list args;
328 0           va_start(args, fmt);
329              
330 0 0         if ( !LogData.mesg ) {
331 0           LogData.mesgSize = 8192;
332 0           LogData.mesgLen = 0;
333 0 0         if ( !(LogData.mesg = malloc(LogData.mesgSize)) ) {
334 0           printf("bpc_logMessagef: panic: can't allocate %lu bytes\n", (unsigned long)LogData.mesgSize);
335 0           LogData.errorCnt++;
336 0           return;
337             }
338             }
339 0 0         if ( BPC_TmpFileUnique >= 0 ) pad = 2;
340 0           strLen = vsnprintf(LogData.mesg + LogData.mesgLen + pad, LogData.mesgSize - LogData.mesgLen - pad, fmt, args);
341 0 0         if ( strLen + 2 + pad + LogData.mesgLen > LogData.mesgSize ) {
342 0           LogData.mesgSize += LogData.mesgSize + strLen + 2 + pad;
343 0 0         if ( !(LogData.mesg = realloc(LogData.mesg, LogData.mesgSize)) ) {
344 0           printf("bpc_logMessagef: panic: can't realloc %lu bytes\n", (unsigned long)LogData.mesgSize);
345 0           LogData.errorCnt++;
346 0           return;
347             }
348 0           va_start(args, fmt);
349 0           strLen = vsnprintf(LogData.mesg + LogData.mesgLen + pad, LogData.mesgSize - LogData.mesgLen - pad, fmt, args);
350 0           va_end(args);
351             }
352 0 0         if ( strLen > 0 ) {
353 0 0         if ( pad ) {
354 0 0         LogData.mesg[LogData.mesgLen++] = BPC_TmpFileUnique ? 'G' : 'R';
355 0           LogData.mesg[LogData.mesgLen++] = ' ';
356             }
357 0           LogData.mesgLen += strLen + 1;
358             }
359 0 0         if ( LogMsgCB ) {
360 0           (*LogMsgCB)(0, LogData.mesg, LogData.mesgLen - 1);
361 0           LogData.mesgLen = 0;
362             }
363 0           va_end(args);
364             }
365              
366 0           void bpc_logMsgGet(char **mesg, size_t *mesgLen)
367             {
368 0           *mesg = LogData.mesg;
369 0           *mesgLen = LogData.mesgLen;
370 0           LogData.mesgLen = 0;
371 0           }
372              
373 0           void bpc_logMsgErrorCntGet(unsigned long *errorCnt)
374             {
375 0           *errorCnt = LogData.errorCnt;
376 0           LogData.errorCnt = 0;
377 0           }
378              
379 0           void bpc_logMsgCBSet(void (*cb)(int errFlag, char *mesg, size_t mesgLen))
380             {
381 0           LogMsgCB = cb;
382 0           }