File:  [ELWIX - Embedded LightWeight unIX -] / libaitsync / src / aitsync.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Wed Mar 24 16:00:15 2010 UTC (14 years, 3 months ago) by misho
Branches: MAIN
CVS tags: HEAD
Initial revision

    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: aitsync.c,v 1.1 2010/03/24 16:00:15 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>