Annotation of libaitsync/src/aitsync.c, revision 1.1.1.1
1.1 misho 1: /*************************************************************************
2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
6: * $Id: defs.h,v 1.1.1.1 2008/11/05 17:02:55 misho Exp $
7: *
8: *************************************************************************/
9: #include "global.h"
10: #include "tool.h"
11: #include "zc.h"
12: #include "patch.h"
13: #include "file.h"
14:
15:
16: static int sync_Errno;
17: static char sync_Error[STRSIZ];
18:
19:
20: static inline int func_comp(sync_tag_t const *t1, sync_tag_t const *t2)
21: {
22: return t1->st_tag - t2->st_tag;
23: }
24:
25: //
26: // Error maintenance functions ...
27: //
28:
29: // sync_GetErrno() Get error code of last operation
30: inline int sync_GetErrno()
31: {
32: return sync_Errno;
33: }
34:
35: // sync_GetError() Get error text of last operation
36: inline const char *sync_GetError()
37: {
38: return sync_Error;
39: }
40:
41: // sync_SetErr() Set error to variables for internal use!!!
42: inline void syncSetErr(int eno, char *estr, ...)
43: {
44: va_list lst;
45:
46: sync_Errno = eno;
47: memset(sync_Error, 0, STRSIZ);
48: va_start(lst, estr);
49: vsnprintf(sync_Error, STRSIZ, estr, lst);
50: va_end(lst);
51: }
52:
53: // ----------------------------------------------------------
54:
55: /*
56: * syncSignature() Calculate and create signature for diff
57: * @csInput = Input patched file name for calculating check sums
58: * @csSig = Output Signature file name
59: * return: -1 error, 0 ok
60: */
61: int syncSignature(const char *csInput, const char *csSig)
62: {
63: int inf, outf, ret;
64: u_char buf[CHUNK_MAX];
65: register int i = 0;
66: off_t off = 0ll;
67: sync_chunk_t sc;
68:
69: inf = syncOpen(csInput, O_RDONLY);
70: if (inf == -1)
71: return inf;
72: outf = syncOpen(csSig, O_WRONLY);
73: if (outf == -1) {
74: syncClose(inf);
75: return outf;
76: }
77:
78: for (i = 0, off = 0ll, ret = -1; ret; i++, off += ret) {
79: memset(buf, 0, CHUNK_MAX);
80: ret = read(inf, buf, CHUNK_MAX);
81: if (ret == -1) {
82: SETERR;
83: break;
84: }
85:
86: // fill chunk
87: sync_mksig(i, off, buf, ret, &sc);
88:
89: if (write(outf, &sc, sizeof sc) == -1) {
90: SETERR;
91: break;
92: }
93: }
94:
95: syncClose(outf);
96: syncClose(inf);
97: return ret;
98: }
99:
100: /*
101: * syncDelta() Create Delta patch file
102: * @csInput = Input original source file name for make delta patch file
103: * @csSig = Input Signature file name
104: * @csDelta = Output Delta patch file name
105: * @compress = Compress output, 0 not compressed
106: * return: -1 error, 0 ok
107: */
108: int syncDelta(const char *csInput, const char *csSig, const char *csDelta, int compress)
109: {
110: int inf, outf, f, sigf, ret, cnt;
111: size_t blk;
112: register int i, j, c, cx;
113: struct stat sb, sb_f;
114: u_long tags[TABLESIZ];
115: sync_tag_t *tag_table;
116: sync_chunk_t *chunks, *find, sc;
117: u_char buf[CHUNK_MAX];
118: off_t off;
119: char szTemp[MAXPATHLEN];
120:
121: /* load signatures */
122:
123: sigf = syncOpen(csSig, O_RDONLY);
124: if (sigf == -1) {
125: return sigf;
126: }
127: if (fstat(sigf, &sb) == -1) {
128: SETERR;
129: syncClose(sigf);
130: return -1;
131: } else {
132: if (!sb.st_size) {
133: syncClose(sigf);
134: return 1;
135: }
136:
137: cnt = sb.st_size / sizeof(sync_chunk_t);
138: if (sb.st_size % sizeof(sync_chunk_t)) {
139: syncSetErr(ENOEXEC, "Error:: signature file is broken!\n");
140: syncClose(sigf);
141: return -1;
142: }
143: }
144: chunks = (sync_chunk_t*) mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, sigf, 0);
145: if (MAP_FAILED == chunks) {
146: SETERR;
147: syncClose(sigf);
148: return -1;
149: }
150: syncClose(sigf);
151:
152: /* build from signatures sorted index and hashes */
153:
154: // init tags array
155: for (i = 0; i < TABLESIZ; i++)
156: tags[i] = NULL_TAG;
157:
158: // build index from signature blocks
159: tag_table = (sync_tag_t*) calloc(cnt, sizeof(sync_tag_t));
160: if (!tag_table) {
161: SETERR;
162: munmap(chunks, sb.st_size);
163: return -1;
164: } else {
165: for (i = 0; i < cnt; i++) {
166: tag_table[i].st_id = i;
167: tag_table[i].st_tag = GETTAG(chunks[i].sc_roll);
168: }
169:
170: qsort(tag_table, cnt, sizeof(sync_tag_t), (int (*)(const void *, const void *)) func_comp);
171: }
172: // assign less id position in tag_table to tags
173: for (i = cnt - 1; i > -1; i--)
174: tags[tag_table[i].st_tag] = i;
175:
176: /* build delta patch */
177:
178: inf = syncOpen(csInput, O_RDONLY);
179: if (inf == -1) {
180: free(tag_table);
181: munmap(chunks, sb.st_size);
182: return inf;
183: }
184: if (compress)
185: f = syncTemp(szTemp, MAXPATHLEN);
186: else
187: f = syncOpen(csDelta, O_WRONLY);
188: if (f == -1) {
189: syncClose(inf);
190: free(tag_table);
191: munmap(chunks, sb.st_size);
192: return f;
193: }
194:
195: for (i = 0, off = 0ll, ret = -1, blk = 0; (ret = read(inf, buf, CHUNK_MAX)); i++, off += ret) {
196: if (ret == -1) {
197: SETERR;
198: break;
199: }
200: find = NULL;
201:
202: // printf("+ find=%p off=%llu i=%d blk=%d\n", find, off, i, blk);
203:
204: // check chunk for differences with signature
205: sync_mksig(i, off, buf, ret, &sc);
206: cx = GETTAG(sc.sc_roll);
207: // find in hash -> hash_sorted_table
208: if (NULL_TAG != tags[cx] && tag_table[tags[cx]].st_tag == cx) {
209: // find in hash_sorted_table crc == -> real chunks id
210: for (j = 0, c = tag_table[tags[cx]].st_id; tag_table[tags[cx] + j].st_tag == cx;
211: j++, c = tag_table[tags[cx] + j].st_id) {
212: if (chunks[c].sc_magic == sc.sc_magic && chunks[c].sc_len == sc.sc_len &&
213: chunks[c].sc_roll == sc.sc_roll &&
214: !memcmp(chunks[c].sc_cksum, sc.sc_cksum, MD5_DIGEST_LENGTH)) {
215: find = &chunks[c];
216: break;
217: }
218: }
219: }
220:
221: // printf("+ find=%p off=%llu i=%d blk=%d\n", find, off, i, blk);
222:
223: // if match chunk, check for previous match
224: if (!blk && find)
225: continue;
226: // if not find chunk in signature skip write to delta patch
227: if (!find) {
228: /* different piece, write it! */
229: // write signature of current chunk
230: ret = write(f, &sc, sizeof sc);
231: if (-1 == ret) {
232: SETERR;
233: break;
234: }
235: // if write chunk len is differnt from requested len
236: if (ret != sizeof sc) {
237: syncSetErr(ENOEXEC, "Error:: delta file signature is broken!\n");
238: ret = -1;
239: break;
240: }
241: // write current chunk ...
242: ret = write(f, buf, sc.sc_len);
243: if (-1 == ret) {
244: SETERR;
245: break;
246: }
247: // if write chunk len is differnt from requested len
248: if (ret != sc.sc_len) {
249: syncSetErr(ENOEXEC, "Error:: delta file data is broken!\n");
250: ret = -1;
251: break;
252: }
253: blk += sc.sc_len;
254:
255: continue;
256: }
257: // match 1st block after difference and copy signature from B
258: memcpy(&sc, find, sizeof sc);
259: sc.sc_magic = SIGSYNC_MAGIC;
260: sc.sc_len = blk;
261:
262: // write signature from chunk B
263: blk = write(f, &sc, sizeof sc);
264: if (-1 == blk) {
265: SETERR;
266: break;
267: }
268: // if write chunk len is differnt from requested len
269: if (blk != sizeof sc) {
270: syncSetErr(ENOEXEC, "Error:: delta file end signature is broken!\n");
271: ret = -1;
272: break;
273: }
274:
275: blk ^= blk;
276: }
277:
278: // check for error or empty delta file
279: if (ret == -1)
280: goto end;
281: fsync(f);
282: if (fstat(f, &sb_f) == -1) {
283: SETERR;
284: ret = -1;
285: goto end;
286: }
287:
288: // No deferences, not needed delta.patch !!!
289: if (!sb_f.st_size) {
290: ret = 1;
291: goto end;
292: }
293:
294: /* Delta patch is READY */
295:
296: // build compressed delta file
297: if (compress) {
298: outf = syncOpen(csDelta, O_WRONLY);
299: if (outf == -1) {
300: ret = outf;
301: goto end;
302: }
303: if (sync_Deflate(f, outf, Z_DEFAULT_COMPRESSION) == -1) {
304: syncClose(outf);
305: unlink(csDelta);
306: ret = -1;
307: goto end;
308: }
309: syncClose(outf);
310: }
311:
312: end:
313: syncClose(f);
314: unlink(szTemp);
315:
316: syncClose(inf);
317: free(tag_table);
318: munmap(chunks, sb.st_size);
319: return ret;
320: }
321:
322: /*
323: * syncPatch() Apply delta patch file to target
324: * @csInput = Input target file name for patch
325: * @csDelta = Input Delta patch file name
326: * @csPatch = After applied patch create new alternate target file, if != NULL
327: * @compress = Compress output, 0 not compressed
328: * return: -1 error, 0 ok, create delta patch, 1 ok, no differences and not create patch
329: */
330: int syncPatch(const char *csInput, const char *csDelta, const char *csPatch, int compress)
331: {
332: int inf, outf, f, d, ret, readlen;
333: char szTemp[MAXPATHLEN];
334: u_char *buffer, buf[CHUNK_MAX];
335: struct stat sb;
336: void *delta;
337: struct tagPiece *piece, *pieces = NULL;
338: register int i;
339: off_t off;
340: sync_chunk_t sc, *suffix;
341:
342: if (compress) {
343: f = syncOpen(csDelta, O_RDONLY);
344: if (f == -1)
345: return f;
346: d = syncTemp(szTemp, MAXPATHLEN);
347: if (d == -1) {
348: syncClose(f);
349: return d;
350: }
351:
352: if (sync_Inflate(f, d) == -1) {
353: syncClose(d);
354: syncClose(f);
355: unlink(szTemp);
356: return -1;
357: } else
358: syncClose(f);
359: } else {
360: d = syncOpen(csDelta, O_RDONLY);
361: if (d == -1)
362: return d;
363: }
364:
365: if (fstat(d, &sb) == -1) {
366: SETERR;
367: syncClose(d);
368: if (compress)
369: unlink(szTemp);
370: return -1;
371: }
372: delta = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, d, 0);
373: if (MAP_FAILED == delta) {
374: SETERR;
375: syncClose(d);
376: if (compress)
377: unlink(szTemp);
378: return -1;
379: } else {
380: syncClose(d);
381: if (compress)
382: unlink(szTemp);
383: }
384:
385: if (sync_buildPatch(delta, sb.st_size, &pieces) == -1 || !pieces) {
386: syncSetErr(ENOEXEC, "Error:: patch file is broken!\n");
387: munmap(delta, sb.st_size);
388: return -1;
389: }
390:
391: inf = syncOpen(csInput, O_RDONLY);
392: if (inf == -1) {
393: if (pieces)
394: free(pieces);
395: munmap(delta, sb.st_size);
396: return inf;
397: }
398: outf = syncOpen(csPatch, O_WRONLY);
399: if (outf == -1) {
400: syncClose(inf);
401: if (pieces)
402: free(pieces);
403: munmap(delta, sb.st_size);
404: return outf;
405: }
406:
407: if (fstat(inf, &sb) == -1) {
408: SETERR;
409: ret = -1;
410: goto end;
411: } else {
412: if (!sb.st_size) {
413: ret = -1;
414: goto end;
415: }
416: }
417:
418: ret = readlen = 0;
419: buffer = NULL;
420: for (i = 0, off = 0ll, suffix = NULL, piece = pieces; piece->pfx; i++, off += readlen) {
421:
422: // printf("i=%d off=%llu sfx=%p piece=%p\n", i, off, suffix, piece);
423:
424: // if input offset is less then input file size
425: if (off < sb.st_size) {
426: readlen = read(inf, buf, CHUNK_MAX);
427: if (readlen == -1) {
428: SETERR;
429: ret = -1;
430: break;
431: }
432: // if suffix find, check for correct patch
433: if (suffix) {
434: if (suffix->sc_len != readlen || suffix->sc_off != off) {
435: syncSetErr(ENOEXEC, "Error:: patch file is broken! (wrong suffix pos)\n");
436: ret = -1;
437: break;
438: }
439: sync_mksig(i, off, buf, readlen, &sc);
440: if (sc.sc_roll != suffix->sc_roll ||
441: memcmp(sc.sc_cksum, suffix->sc_cksum, MD5_DIGEST_LENGTH)) {
442: syncSetErr(ENOEXEC, "Error:: patch file is broken! (wrong suffix crc)\n");
443: ret = -1;
444: break;
445: }
446:
447: suffix = NULL;
448: }
449:
450: buffer = buf;
451: }
452:
453: // printf("i=%d off=%llu sfx=%p piece=%p pfx=%p pfx_off=%llu\n", i, off, suffix, piece,
454: // piece ? piece->pfx : 0l, piece->pfx ? piece->pfx->sc_off : 0l);
455:
456: // if delta chunk match!
457: if (piece->pfx && piece->pfx->sc_off == off) {
458: if (!piece->buf) {
459: syncSetErr(ENOEXEC, "Error:: patch file is broken! (missing data)\n");
460: ret = -1;
461: break;
462: }
463:
464: buffer = piece->buf;
465: readlen = piece->pfx->sc_len;
466: suffix = piece->sfx ? piece->sfx : NULL;
467:
468: piece++;
469:
470: if (suffix && off >= sb.st_size) {
471: syncSetErr(ENOEXEC, "Error:: patch file is broken! (after eof find suffix)\n");
472: ret = -1;
473: break;
474: }
475: } else
476: if (off >= sb.st_size) {
477: if (piece->pfx) {
478: syncSetErr(ENOEXEC, "Error:: patch file is broken! (after eof find prefix)\n");
479: ret = -1;
480: }
481:
482: break;
483: }
484:
485: ret = write(outf, buffer, readlen);
486: if (ret == -1 || ret != readlen) {
487: SETERR;
488: break;
489: }
490: }
491:
492: end:
493: syncClose(inf);
494: syncClose(outf);
495: if (pieces)
496: free(pieces);
497: munmap(delta, sb.st_size);
498: return ret;
499: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>