Annotation of libaitsync/src/aitsync.c, revision 1.1.1.1.2.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 $
1.1.1.1.2.1! misho       6: * $Id: aitsync.c,v 1.1.1.1 2010/03/24 16:00:15 misho Exp $
1.1       misho       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
1.1.1.1.2.1! misho      59:  * @compress = 2 compress signatures output, 0 not compressed
1.1       misho      60:  * return: -1 error, 0 ok
                     61:  */
1.1.1.1.2.1! misho      62: int syncSignature(const char *csInput, const char *csSig, int compress)
1.1       misho      63: {
1.1.1.1.2.1! misho      64:        int inf, outf, f, ret;
1.1       misho      65:        u_char buf[CHUNK_MAX];
                     66:        register int i = 0;
                     67:        off_t off = 0ll;
                     68:        sync_chunk_t sc;
1.1.1.1.2.1! misho      69:        char szTemp[MAXPATHLEN];
1.1       misho      70: 
                     71:        inf = syncOpen(csInput, O_RDONLY);
                     72:        if (inf == -1)
                     73:                return inf;
1.1.1.1.2.1! misho      74:        if (compress & 2)
        !            75:                f = syncTemp(szTemp, MAXPATHLEN);
        !            76:        else
        !            77:                f = syncOpen(csSig, O_WRONLY);
        !            78:        if (f == -1) {
1.1       misho      79:                syncClose(inf);
1.1.1.1.2.1! misho      80:                return f;
1.1       misho      81:        }
                     82: 
                     83:        for (i = 0, off = 0ll, ret = -1; ret; i++, off += ret) {
                     84:                memset(buf, 0, CHUNK_MAX);
                     85:                ret = read(inf, buf, CHUNK_MAX);
                     86:                if (ret == -1) {
                     87:                        SETERR;
                     88:                        break;
                     89:                }
                     90: 
                     91:                // fill chunk
                     92:                sync_mksig(i, off, buf, ret, &sc);
                     93: 
1.1.1.1.2.1! misho      94:                if (write(f, &sc, sizeof sc) == -1) {
1.1       misho      95:                        SETERR;
                     96:                        break;
                     97:                }
                     98:        }
                     99: 
1.1.1.1.2.1! misho     100:        /* Signatures is READY */
        !           101: 
        !           102:        // build compressed delta file
        !           103:        if (compress & 2) {
        !           104:                outf = syncOpen(csSig, O_WRONLY);
        !           105:                if (outf == -1) {
        !           106:                        ret = outf;
        !           107:                        goto end;
        !           108:                }
        !           109:                if (sync_Deflate(f, outf, Z_DEFAULT_COMPRESSION) == -1) {
        !           110:                        syncClose(outf);
        !           111:                        unlink(csSig);
        !           112:                        ret = -1;
        !           113:                        goto end;
        !           114:                }
        !           115:                syncClose(outf);
        !           116:        }
        !           117: end:
        !           118:        syncClose(f);
        !           119:        if (compress & 2)
        !           120:                unlink(szTemp);
        !           121: 
1.1       misho     122:        syncClose(inf);
                    123:        return ret;
                    124: }
                    125: 
                    126: /*
                    127:  * syncDelta() Create Delta patch file
                    128:  * @csInput = Input original source file name for make delta patch file
                    129:  * @csSig = Input Signature file name
                    130:  * @csDelta = Output Delta patch file name
1.1.1.1.2.1! misho     131:  * @compress = 3 everything compress, 2 compressed signatures, 1 compress delta output, 0 not compressed
1.1       misho     132:  * return: -1 error, 0 ok
                    133:  */
                    134: int syncDelta(const char *csInput, const char *csSig, const char *csDelta, int compress)
                    135: {
                    136:        int inf, outf, f, sigf, ret, cnt;
                    137:        size_t blk;
                    138:        register int i, j, c, cx;
                    139:        struct stat sb, sb_f;
                    140:        u_long tags[TABLESIZ];
                    141:        sync_tag_t *tag_table;
                    142:        sync_chunk_t *chunks, *find, sc;
                    143:        u_char buf[CHUNK_MAX];
                    144:        off_t off;
                    145:        char szTemp[MAXPATHLEN];
                    146: 
                    147:        /* load signatures */
                    148: 
1.1.1.1.2.1! misho     149:        if (compress & 2) {
        !           150:                f = syncOpen(csSig, O_RDONLY);
        !           151:                if (-1 == f)
        !           152:                        return f;
        !           153:                sigf = syncTemp(szTemp, MAXPATHLEN);
        !           154:                if (-1 == sigf) {
        !           155:                        syncClose(f);
        !           156:                        return sigf;
        !           157:                }
        !           158: 
        !           159:                if (sync_Inflate(f, sigf) == -1) {
        !           160:                        syncClose(sigf);
        !           161:                        syncClose(f);
        !           162:                        unlink(szTemp);
        !           163:                        return -1;
        !           164:                } else
        !           165:                        syncClose(f);
        !           166:        } else {
        !           167:                sigf = syncOpen(csSig, O_RDONLY);
        !           168:                if (-1 == sigf)
        !           169:                        return sigf;
1.1       misho     170:        }
1.1.1.1.2.1! misho     171: 
1.1       misho     172:        if (fstat(sigf, &sb) == -1) {
                    173:                SETERR;
                    174:                syncClose(sigf);
1.1.1.1.2.1! misho     175:                if (compress & 2)
        !           176:                        unlink(szTemp);
1.1       misho     177:                return -1;
                    178:        } else {
                    179:                if (!sb.st_size) {
                    180:                        syncClose(sigf);
1.1.1.1.2.1! misho     181:                        if (compress & 2)
        !           182:                                unlink(szTemp);
1.1       misho     183:                        return 1;
                    184:                }
                    185: 
                    186:                cnt = sb.st_size / sizeof(sync_chunk_t);
                    187:                if (sb.st_size % sizeof(sync_chunk_t)) {
                    188:                        syncSetErr(ENOEXEC, "Error:: signature file is broken!\n");
                    189:                        syncClose(sigf);
1.1.1.1.2.1! misho     190:                        if (compress & 2)
        !           191:                                unlink(szTemp);
1.1       misho     192:                        return -1;
                    193:                }
                    194:        }
                    195:        chunks = (sync_chunk_t*) mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, sigf, 0);
                    196:        if (MAP_FAILED == chunks) {
                    197:                SETERR;
                    198:                syncClose(sigf);
1.1.1.1.2.1! misho     199:                if (compress & 2)
        !           200:                        unlink(szTemp);
1.1       misho     201:                return -1;
1.1.1.1.2.1! misho     202:        } else {
        !           203:                syncClose(sigf);
        !           204:                if (compress & 2)
        !           205:                        unlink(szTemp);
1.1       misho     206:        }
                    207: 
                    208:        /* build from signatures sorted index and hashes */
                    209: 
                    210:        // init tags array
                    211:        for (i = 0; i < TABLESIZ; i++)
                    212:                tags[i] = NULL_TAG;
                    213: 
                    214:        // build index from signature blocks
                    215:        tag_table = (sync_tag_t*) calloc(cnt, sizeof(sync_tag_t));
                    216:        if (!tag_table) {
                    217:                SETERR;
                    218:                munmap(chunks, sb.st_size);
                    219:                return -1;
                    220:        } else {
                    221:                for (i = 0; i < cnt; i++) {
                    222:                        tag_table[i].st_id = i;
                    223:                        tag_table[i].st_tag = GETTAG(chunks[i].sc_roll);
                    224:                }
                    225: 
                    226:                qsort(tag_table, cnt, sizeof(sync_tag_t), (int (*)(const void *, const void *)) func_comp);
                    227:        }
                    228:        // assign less id position in tag_table to tags
                    229:        for (i = cnt - 1; i > -1; i--)
                    230:                tags[tag_table[i].st_tag] = i;
                    231: 
                    232:        /* build delta patch */
                    233: 
                    234:        inf = syncOpen(csInput, O_RDONLY);
                    235:        if (inf == -1) {
                    236:                free(tag_table);
                    237:                munmap(chunks, sb.st_size);
                    238:                return inf;
                    239:        }
1.1.1.1.2.1! misho     240:        if (compress & 1)
1.1       misho     241:                f = syncTemp(szTemp, MAXPATHLEN);
                    242:        else
                    243:                f = syncOpen(csDelta, O_WRONLY);
                    244:        if (f == -1) {
                    245:                syncClose(inf);
                    246:                free(tag_table);
                    247:                munmap(chunks, sb.st_size);
                    248:                return f;
                    249:        }
                    250: 
                    251:        for (i = 0, off = 0ll, ret = -1, blk = 0; (ret = read(inf, buf, CHUNK_MAX)); i++, off += ret) {
                    252:                if (ret == -1) {
                    253:                        SETERR;
                    254:                        break;
                    255:                }
                    256:                find = NULL;
                    257: 
                    258:                // printf("+ find=%p off=%llu i=%d blk=%d\n", find, off, i, blk);
                    259: 
                    260:                // check chunk for differences with signature
                    261:                sync_mksig(i, off, buf, ret, &sc);
                    262:                cx = GETTAG(sc.sc_roll);
                    263:                // find in hash -> hash_sorted_table
                    264:                if (NULL_TAG != tags[cx] && tag_table[tags[cx]].st_tag == cx) {
                    265:                        // find in hash_sorted_table crc == -> real chunks id
                    266:                        for (j = 0, c = tag_table[tags[cx]].st_id; tag_table[tags[cx] + j].st_tag == cx; 
                    267:                                        j++, c = tag_table[tags[cx] + j].st_id) {
                    268:                                if (chunks[c].sc_magic == sc.sc_magic && chunks[c].sc_len == sc.sc_len && 
                    269:                                                chunks[c].sc_roll == sc.sc_roll && 
                    270:                                                !memcmp(chunks[c].sc_cksum, sc.sc_cksum, MD5_DIGEST_LENGTH)) {
                    271:                                        find = &chunks[c];
                    272:                                        break;
                    273:                                }
                    274:                        }
                    275:                }
                    276: 
                    277:                // printf("+ find=%p off=%llu i=%d blk=%d\n", find, off, i, blk);
                    278: 
                    279:                // if match chunk, check for previous match
                    280:                if (!blk && find)
                    281:                        continue;
                    282:                // if not find chunk in signature skip write to delta patch
                    283:                if (!find) {
                    284:                        /* different piece, write it! */
                    285:                        // write signature of current chunk
                    286:                        ret = write(f, &sc, sizeof sc);
                    287:                        if (-1 == ret) {
                    288:                                SETERR;
                    289:                                break;
                    290:                        }
                    291:                        // if write chunk len is differnt from requested len
                    292:                        if (ret != sizeof sc) {
                    293:                                syncSetErr(ENOEXEC, "Error:: delta file signature is broken!\n");
                    294:                                ret = -1;
                    295:                                break;
                    296:                        }
                    297:                        // write current chunk ...
                    298:                        ret = write(f, buf, sc.sc_len);
                    299:                        if (-1 == ret) {
                    300:                                SETERR;
                    301:                                break;
                    302:                        }
                    303:                        // if write chunk len is differnt from requested len
                    304:                        if (ret != sc.sc_len) {
                    305:                                syncSetErr(ENOEXEC, "Error:: delta file data is broken!\n");
                    306:                                ret = -1;
                    307:                                break;
                    308:                        }
                    309:                        blk += sc.sc_len;
                    310: 
                    311:                        continue;
                    312:                }
                    313:                // match 1st block after difference and copy signature from B
                    314:                memcpy(&sc, find, sizeof sc);
                    315:                sc.sc_magic = SIGSYNC_MAGIC;
                    316:                sc.sc_len = blk;
                    317: 
                    318:                // write signature from chunk B
                    319:                blk = write(f, &sc, sizeof sc);
                    320:                if (-1 == blk) {
                    321:                        SETERR;
                    322:                        break;
                    323:                }
                    324:                // if write chunk len is differnt from requested len
                    325:                if (blk != sizeof sc) {
                    326:                        syncSetErr(ENOEXEC, "Error:: delta file end signature is broken!\n");
                    327:                        ret = -1;
                    328:                        break;
                    329:                }
                    330: 
                    331:                blk ^= blk;
                    332:        }
                    333: 
                    334:        // check for error or empty delta file
                    335:        if (ret == -1)
                    336:                goto end;
                    337:        fsync(f);
                    338:        if (fstat(f, &sb_f) == -1) {
                    339:                SETERR;
                    340:                ret = -1;
                    341:                goto end;
                    342:        }
                    343: 
                    344:        // No deferences, not needed delta.patch !!!
                    345:        if (!sb_f.st_size) {
                    346:                ret = 1;
                    347:                goto end;
                    348:        }
                    349: 
                    350:        /* Delta patch is READY */
                    351: 
                    352:        // build compressed delta file
1.1.1.1.2.1! misho     353:        if (compress & 1) {
1.1       misho     354:                outf = syncOpen(csDelta, O_WRONLY);
                    355:                if (outf == -1) {
                    356:                        ret = outf;
                    357:                        goto end;
                    358:                }
                    359:                if (sync_Deflate(f, outf, Z_DEFAULT_COMPRESSION) == -1) {
                    360:                        syncClose(outf);
                    361:                        unlink(csDelta);
                    362:                        ret = -1;
                    363:                        goto end;
                    364:                }
                    365:                syncClose(outf);
                    366:        }
                    367: 
                    368: end:
                    369:        syncClose(f);
1.1.1.1.2.1! misho     370:        if (compress & 1)
        !           371:                unlink(szTemp);
1.1       misho     372: 
                    373:        syncClose(inf);
                    374:        free(tag_table);
                    375:        munmap(chunks, sb.st_size);
                    376:        return ret;
                    377: }
                    378: 
                    379: /*
                    380:  * syncPatch() Apply delta patch file to target
                    381:  * @csInput = Input target file name for patch
                    382:  * @csDelta = Input Delta patch file name
                    383:  * @csPatch = After applied patch create new alternate target file, if != NULL
1.1.1.1.2.1! misho     384:  * @compress = 1 compress delta input, 0 not compressed
1.1       misho     385:  * return: -1 error, 0 ok, create delta patch, 1 ok, no differences and not create patch
                    386:  */
                    387: int syncPatch(const char *csInput, const char *csDelta, const char *csPatch, int compress)
                    388: {
                    389:        int inf, outf, f, d, ret, readlen;
                    390:        char szTemp[MAXPATHLEN];
                    391:        u_char *buffer, buf[CHUNK_MAX];
                    392:        struct stat sb;
                    393:        void *delta;
                    394:        struct tagPiece *piece, *pieces = NULL;
                    395:        register int i;
                    396:        off_t off;
                    397:        sync_chunk_t sc, *suffix;
                    398: 
1.1.1.1.2.1! misho     399:        if (compress & 1) {
1.1       misho     400:                f = syncOpen(csDelta, O_RDONLY);
                    401:                if (f == -1)
                    402:                        return f;
                    403:                d = syncTemp(szTemp, MAXPATHLEN);
                    404:                if (d == -1) {
                    405:                        syncClose(f);
                    406:                        return d;
                    407:                }
                    408:                
                    409:                if (sync_Inflate(f, d) == -1) {
                    410:                        syncClose(d);
                    411:                        syncClose(f);
                    412:                        unlink(szTemp);
                    413:                        return -1;
                    414:                } else
                    415:                        syncClose(f);
                    416:        } else {
                    417:                d = syncOpen(csDelta, O_RDONLY);
                    418:                if (d == -1)
                    419:                        return d;
                    420:        }
                    421: 
                    422:        if (fstat(d, &sb) == -1) {
                    423:                SETERR;
                    424:                syncClose(d);
1.1.1.1.2.1! misho     425:                if (compress & 1)
1.1       misho     426:                        unlink(szTemp);
                    427:                return -1;
                    428:        }
                    429:        delta = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, d, 0);
                    430:        if (MAP_FAILED == delta) {
                    431:                SETERR;
                    432:                syncClose(d);
1.1.1.1.2.1! misho     433:                if (compress & 1)
1.1       misho     434:                        unlink(szTemp);
                    435:                return -1;
                    436:        } else {
                    437:                syncClose(d);
1.1.1.1.2.1! misho     438:                if (compress & 1)
1.1       misho     439:                        unlink(szTemp);
                    440:        }
                    441: 
                    442:        if (sync_buildPatch(delta, sb.st_size, &pieces) == -1 || !pieces) {
                    443:                syncSetErr(ENOEXEC, "Error:: patch file is broken!\n");
                    444:                munmap(delta, sb.st_size);
                    445:                return -1;
                    446:        }
                    447: 
                    448:        inf = syncOpen(csInput, O_RDONLY);
                    449:        if (inf == -1) {
                    450:                if (pieces)
                    451:                        free(pieces);
                    452:                munmap(delta, sb.st_size);
                    453:                return inf;
                    454:        }
                    455:        outf = syncOpen(csPatch, O_WRONLY);
                    456:        if (outf == -1) {
                    457:                syncClose(inf);
                    458:                if (pieces)
                    459:                        free(pieces);
                    460:                munmap(delta, sb.st_size);
                    461:                return outf;
                    462:        }
                    463: 
                    464:        if (fstat(inf, &sb) == -1) {
                    465:                SETERR;
                    466:                ret = -1;
                    467:                goto end;
                    468:        } else {
                    469:                if (!sb.st_size) {
                    470:                        ret = -1;
                    471:                        goto end;
                    472:                }
                    473:        }
                    474: 
                    475:        ret = readlen = 0;
                    476:        buffer = NULL;
                    477:        for (i = 0, off = 0ll, suffix = NULL, piece = pieces; piece->pfx; i++, off += readlen) {
                    478: 
                    479:                // printf("i=%d off=%llu sfx=%p piece=%p\n", i, off, suffix, piece);
                    480: 
                    481:                // if input offset is less then input file size
                    482:                if (off < sb.st_size) {
                    483:                        readlen = read(inf, buf, CHUNK_MAX);
                    484:                        if (readlen == -1) {
                    485:                                SETERR;
                    486:                                ret = -1;
                    487:                                break;
                    488:                        }
                    489:                        // if suffix find, check for correct patch
                    490:                        if (suffix) {
                    491:                                if (suffix->sc_len != readlen || suffix->sc_off != off) {
                    492:                                        syncSetErr(ENOEXEC, "Error:: patch file is broken! (wrong suffix pos)\n");
                    493:                                        ret = -1;
                    494:                                        break;
                    495:                                }
                    496:                                sync_mksig(i, off, buf, readlen, &sc);
                    497:                                if (sc.sc_roll != suffix->sc_roll || 
                    498:                                                memcmp(sc.sc_cksum, suffix->sc_cksum, MD5_DIGEST_LENGTH)) {
                    499:                                        syncSetErr(ENOEXEC, "Error:: patch file is broken! (wrong suffix crc)\n");
                    500:                                        ret = -1;
                    501:                                        break;
                    502:                                }
                    503: 
                    504:                                suffix = NULL;
                    505:                        }
                    506: 
                    507:                        buffer = buf;
                    508:                }
                    509: 
                    510:                // printf("i=%d off=%llu sfx=%p piece=%p pfx=%p pfx_off=%llu\n", i, off, suffix, piece, 
                    511:                //              piece ? piece->pfx : 0l, piece->pfx ? piece->pfx->sc_off : 0l);
                    512: 
                    513:                // if delta chunk match!
                    514:                if (piece->pfx && piece->pfx->sc_off == off) {
                    515:                        if (!piece->buf) {
                    516:                                syncSetErr(ENOEXEC, "Error:: patch file is broken! (missing data)\n");
                    517:                                ret = -1;
                    518:                                break;
                    519:                        }
                    520: 
                    521:                        buffer = piece->buf;
                    522:                        readlen = piece->pfx->sc_len;
                    523:                        suffix = piece->sfx ? piece->sfx : NULL;
                    524: 
                    525:                        piece++;
                    526: 
                    527:                        if (suffix && off >= sb.st_size) {
                    528:                                syncSetErr(ENOEXEC, "Error:: patch file is broken! (after eof find suffix)\n");
                    529:                                ret = -1;
                    530:                                break;
                    531:                        }
                    532:                } else
                    533:                        if (off >= sb.st_size) {
                    534:                               if (piece->pfx) {
                    535:                                        syncSetErr(ENOEXEC, "Error:: patch file is broken! (after eof find prefix)\n");
                    536:                                        ret = -1;
                    537:                                }
                    538: 
                    539:                                break;
                    540:                        }
                    541: 
                    542:                ret = write(outf, buffer, readlen);
                    543:                if (ret == -1 || ret != readlen) {
                    544:                        SETERR;
                    545:                        break;
                    546:                }
                    547:        }
                    548: 
                    549: end:
                    550:        syncClose(inf);
                    551:        syncClose(outf);
                    552:        if (pieces)
                    553:                free(pieces);
                    554:        munmap(delta, sb.st_size);
                    555:        return ret;
                    556: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>