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>