Annotation of libaitsync/src/aitsync.c, revision 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>