Annotation of libaitsync/src/aitsync.c, revision 1.4
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.4 ! misho 6: * $Id: aitsync.c,v 1.3.2.4 2012/11/13 13:53:14 misho Exp $
1.1 misho 7: *
1.2 misho 8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
1.3 misho 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
1.2 misho 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
1.1 misho 46: #include "global.h"
47: #include "tool.h"
48: #include "zc.h"
49: #include "patch.h"
50: #include "file.h"
51:
52:
53: static int sync_Errno;
54: static char sync_Error[STRSIZ];
55:
56:
1.3 misho 57: static inline int
58: func_comp(sync_tag_t const *t1, sync_tag_t const *t2)
1.1 misho 59: {
60: return t1->st_tag - t2->st_tag;
61: }
62:
1.4 ! misho 63: /*
! 64: * Error maintenance functions ...
! 65: */
1.1 misho 66:
67: // sync_GetErrno() Get error code of last operation
1.3 misho 68: inline int
69: sync_GetErrno()
1.1 misho 70: {
71: return sync_Errno;
72: }
73:
74: // sync_GetError() Get error text of last operation
1.3 misho 75: inline const char *
76: sync_GetError()
1.1 misho 77: {
78: return sync_Error;
79: }
80:
81: // sync_SetErr() Set error to variables for internal use!!!
1.3 misho 82: inline void
1.4 ! misho 83: sync_SetErr(int eno, char *estr, ...)
1.1 misho 84: {
85: va_list lst;
86:
87: sync_Errno = eno;
1.4 ! misho 88: memset(sync_Error, 0, sizeof sync_Error);
1.1 misho 89: va_start(lst, estr);
1.4 ! misho 90: vsnprintf(sync_Error, sizeof sync_Error, estr, lst);
1.1 misho 91: va_end(lst);
92: }
93:
1.4 ! misho 94: /* ---------------------------------------------------------- */
1.1 misho 95:
96: /*
1.4 ! misho 97: * syncSignature() - Calculate and create signature for diff
! 98: *
! 99: * @csInput = Input target file name for calculating check sums
1.1 misho 100: * @csSig = Output Signature file name
1.2 misho 101: * @compress = 2 compress signatures output, 0 not compressed
1.1 misho 102: * return: -1 error, 0 ok
103: */
1.3 misho 104: int
105: syncSignature(const char *csInput, const char *csSig, int compress)
1.1 misho 106: {
1.2 misho 107: int inf, outf, f, ret;
1.1 misho 108: u_char buf[CHUNK_MAX];
109: register int i = 0;
110: off_t off = 0ll;
111: sync_chunk_t sc;
1.2 misho 112: char szTemp[MAXPATHLEN];
1.1 misho 113:
1.4 ! misho 114: /* open work files */
! 115: inf = sync_Open(csInput, O_RDONLY, 0);
1.1 misho 116: if (inf == -1)
117: return inf;
1.2 misho 118: if (compress & 2)
1.4 ! misho 119: f = sync_Temp(szTemp, sizeof szTemp);
1.2 misho 120: else
1.4 ! misho 121: f = sync_Open(csSig, O_WRONLY, 0);
1.2 misho 122: if (f == -1) {
1.4 ! misho 123: sync_Close(inf);
1.2 misho 124: return f;
1.1 misho 125: }
126:
127: for (i = 0, off = 0ll, ret = -1; ret; i++, off += ret) {
128: memset(buf, 0, CHUNK_MAX);
129: ret = read(inf, buf, CHUNK_MAX);
130: if (ret == -1) {
1.4 ! misho 131: LOGERR;
1.1 misho 132: break;
133: }
134:
1.4 ! misho 135: /* fill chunk */
1.1 misho 136: sync_mksig(i, off, buf, ret, &sc);
137:
1.2 misho 138: if (write(f, &sc, sizeof sc) == -1) {
1.4 ! misho 139: LOGERR;
1.1 misho 140: break;
141: }
142: }
143:
1.4 ! misho 144: /* Signatures are READY */
1.2 misho 145:
146: if (compress & 2) {
1.4 ! misho 147: /* build compressed delta file */
! 148: outf = sync_Open(csSig, O_WRONLY, 0);
1.2 misho 149: if (outf == -1) {
150: ret = outf;
151: goto end;
152: }
153: if (sync_Deflate(f, outf, Z_DEFAULT_COMPRESSION) == -1) {
1.4 ! misho 154: sync_Close(outf);
1.2 misho 155: unlink(csSig);
156: ret = -1;
157: goto end;
158: }
1.4 ! misho 159: sync_Close(outf);
1.2 misho 160: }
161: end:
1.4 ! misho 162: sync_Close(f);
1.2 misho 163: if (compress & 2)
164: unlink(szTemp);
1.4 ! misho 165: sync_Close(inf);
1.1 misho 166: return ret;
167: }
168:
169: /*
1.4 ! misho 170: * syncDelta() - Create Delta patch file
! 171: *
1.1 misho 172: * @csInput = Input original source file name for make delta patch file
1.4 ! misho 173: * @csSig = Input target Signature file name
1.1 misho 174: * @csDelta = Output Delta patch file name
1.2 misho 175: * @compress = 3 everything compress, 2 compressed signatures, 1 compress delta output, 0 not compressed
1.1 misho 176: * return: -1 error, 0 ok
177: */
1.3 misho 178: int
179: syncDelta(const char *csInput, const char *csSig, const char *csDelta, int compress)
1.1 misho 180: {
181: int inf, outf, f, sigf, ret, cnt;
182: size_t blk;
183: register int i, j, c, cx;
184: struct stat sb, sb_f;
185: u_long tags[TABLESIZ];
186: sync_tag_t *tag_table;
187: sync_chunk_t *chunks, *find, sc;
188: u_char buf[CHUNK_MAX];
189: off_t off;
190: char szTemp[MAXPATHLEN];
191:
192: /* load signatures */
193:
1.2 misho 194: if (compress & 2) {
1.4 ! misho 195: f = sync_Open(csSig, O_RDONLY, 0);
1.2 misho 196: if (-1 == f)
197: return f;
1.4 ! misho 198: sigf = sync_Temp(szTemp, sizeof szTemp);
1.2 misho 199: if (-1 == sigf) {
1.4 ! misho 200: sync_Close(f);
1.2 misho 201: return sigf;
202: }
203:
204: if (sync_Inflate(f, sigf) == -1) {
1.4 ! misho 205: sync_Close(sigf);
! 206: sync_Close(f);
1.2 misho 207: unlink(szTemp);
208: return -1;
209: } else
1.4 ! misho 210: sync_Close(f);
1.2 misho 211: } else {
1.4 ! misho 212: sigf = sync_Open(csSig, O_RDONLY, 0);
1.2 misho 213: if (-1 == sigf)
214: return sigf;
1.1 misho 215: }
1.2 misho 216:
1.1 misho 217: if (fstat(sigf, &sb) == -1) {
1.4 ! misho 218: LOGERR;
! 219: sync_Close(sigf);
1.2 misho 220: if (compress & 2)
221: unlink(szTemp);
1.1 misho 222: return -1;
223: } else {
224: if (!sb.st_size) {
1.4 ! misho 225: sync_Close(sigf);
1.2 misho 226: if (compress & 2)
227: unlink(szTemp);
1.1 misho 228: return 1;
229: }
230:
231: cnt = sb.st_size / sizeof(sync_chunk_t);
232: if (sb.st_size % sizeof(sync_chunk_t)) {
1.4 ! misho 233: sync_SetErr(ENOEXEC, "Error:: signature file is broken!\n");
! 234: sync_Close(sigf);
1.2 misho 235: if (compress & 2)
236: unlink(szTemp);
1.1 misho 237: return -1;
238: }
239: }
240: chunks = (sync_chunk_t*) mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, sigf, 0);
241: if (MAP_FAILED == chunks) {
1.4 ! misho 242: LOGERR;
! 243: sync_Close(sigf);
1.2 misho 244: if (compress & 2)
245: unlink(szTemp);
1.1 misho 246: return -1;
1.2 misho 247: } else {
1.4 ! misho 248: sync_Close(sigf);
1.2 misho 249: if (compress & 2)
250: unlink(szTemp);
1.1 misho 251: }
252:
253: /* build from signatures sorted index and hashes */
254:
1.4 ! misho 255: /* init first stage tags array index */
1.1 misho 256: for (i = 0; i < TABLESIZ; i++)
257: tags[i] = NULL_TAG;
258:
1.4 ! misho 259: /* build second index from signature blocks */
1.1 misho 260: tag_table = (sync_tag_t*) calloc(cnt, sizeof(sync_tag_t));
261: if (!tag_table) {
1.4 ! misho 262: LOGERR;
1.1 misho 263: munmap(chunks, sb.st_size);
264: return -1;
265: } else {
266: for (i = 0; i < cnt; i++) {
267: tag_table[i].st_id = i;
268: tag_table[i].st_tag = GETTAG(chunks[i].sc_roll);
269: }
270:
1.4 ! misho 271: qsort(tag_table, cnt, sizeof(sync_tag_t),
! 272: (int (*)(const void *, const void *)) func_comp);
1.1 misho 273: }
1.4 ! misho 274: /* assign less id position in tag_table to tags.
! 275: * It made relation between 1st & 2nd indexes */
1.1 misho 276: for (i = cnt - 1; i > -1; i--)
277: tags[tag_table[i].st_tag] = i;
278:
1.4 ! misho 279:
1.1 misho 280: /* build delta patch */
281:
1.4 ! misho 282: inf = sync_Open(csInput, O_RDONLY, 0);
1.1 misho 283: if (inf == -1) {
284: free(tag_table);
285: munmap(chunks, sb.st_size);
286: return inf;
287: }
1.2 misho 288: if (compress & 1)
1.4 ! misho 289: f = sync_Temp(szTemp, sizeof szTemp);
1.1 misho 290: else
1.4 ! misho 291: f = sync_Open(csDelta, O_WRONLY, 0);
1.1 misho 292: if (f == -1) {
1.4 ! misho 293: sync_Close(inf);
1.1 misho 294: free(tag_table);
295: munmap(chunks, sb.st_size);
296: return f;
297: }
298:
1.4 ! misho 299: for (i = 0, off = 0ll, ret = -1, blk = 0;
! 300: (ret = read(inf, buf, CHUNK_MAX)); i++, off += ret) {
1.1 misho 301: if (ret == -1) {
1.4 ! misho 302: LOGERR;
1.1 misho 303: break;
304: }
305: find = NULL;
306:
1.4 ! misho 307: #if 0
! 308: printf("+ find=%p off=%llu i=%d blk=%d\n", find, off, i, blk);
! 309: #endif
1.1 misho 310:
1.4 ! misho 311: /* check chunk for differences with signature */
1.1 misho 312: sync_mksig(i, off, buf, ret, &sc);
313: cx = GETTAG(sc.sc_roll);
1.4 ! misho 314: /* find in hash -> hash_sorted_table */
1.1 misho 315: if (NULL_TAG != tags[cx] && tag_table[tags[cx]].st_tag == cx) {
1.4 ! misho 316: /* find in hash_sorted_table crc == -> real chunks id */
! 317: for (j = 0, c = tag_table[tags[cx]].st_id;
! 318: tag_table[tags[cx] + j].st_tag == cx;
1.1 misho 319: j++, c = tag_table[tags[cx] + j].st_id) {
1.4 ! misho 320: if (chunks[c].sc_magic == sc.sc_magic &&
! 321: chunks[c].sc_len == sc.sc_len &&
1.1 misho 322: chunks[c].sc_roll == sc.sc_roll &&
323: !memcmp(chunks[c].sc_cksum, sc.sc_cksum, MD5_DIGEST_LENGTH)) {
324: find = &chunks[c];
325: break;
326: }
327: }
328: }
329:
1.4 ! misho 330: #if 0
! 331: printf("+ find=%p off=%llu i=%d blk=%d\n", find, off, i, blk);
! 332: #endif
1.1 misho 333:
1.4 ! misho 334: /* if match chunk, check for previous match */
1.1 misho 335: if (!blk && find)
336: continue;
1.4 ! misho 337: /* if not find chunk in signature skip write to delta patch */
1.1 misho 338: if (!find) {
1.4 ! misho 339: /* different piece, write it!
! 340: * Write signature of current chunk */
1.1 misho 341: ret = write(f, &sc, sizeof sc);
342: if (-1 == ret) {
1.4 ! misho 343: LOGERR;
1.1 misho 344: break;
345: }
1.4 ! misho 346: /* if write chunk len is differnt from requested len */
1.1 misho 347: if (ret != sizeof sc) {
1.4 ! misho 348: sync_SetErr(ENOEXEC, "Error:: delta file signature is broken!\n");
1.1 misho 349: ret = -1;
350: break;
351: }
1.4 ! misho 352: /* write current chunk data ... */
1.1 misho 353: ret = write(f, buf, sc.sc_len);
354: if (-1 == ret) {
1.4 ! misho 355: LOGERR;
1.1 misho 356: break;
357: }
1.4 ! misho 358: /* if write chunk len is differnt from requested len */
1.1 misho 359: if (ret != sc.sc_len) {
1.4 ! misho 360: sync_SetErr(ENOEXEC, "Error:: delta file data is broken!\n");
1.1 misho 361: ret = -1;
362: break;
363: }
364: blk += sc.sc_len;
365:
366: continue;
367: }
1.4 ! misho 368: /* match 1st block after difference and copy signature from B */
1.1 misho 369: memcpy(&sc, find, sizeof sc);
370: sc.sc_magic = SIGSYNC_MAGIC;
371: sc.sc_len = blk;
372:
1.4 ! misho 373: /* write signature from chunk B */
1.1 misho 374: blk = write(f, &sc, sizeof sc);
375: if (-1 == blk) {
1.4 ! misho 376: LOGERR;
1.1 misho 377: break;
378: }
1.4 ! misho 379: /* if write chunk len is differnt from requested len */
1.1 misho 380: if (blk != sizeof sc) {
1.4 ! misho 381: sync_SetErr(ENOEXEC, "Error:: delta file end signature is broken!\n");
1.1 misho 382: ret = -1;
383: break;
384: }
385:
386: blk ^= blk;
387: }
388:
1.4 ! misho 389: /* check for error or empty delta file */
1.1 misho 390: if (ret == -1)
391: goto end;
392: fsync(f);
393: if (fstat(f, &sb_f) == -1) {
1.4 ! misho 394: LOGERR;
1.1 misho 395: ret = -1;
396: goto end;
397: }
398:
1.4 ! misho 399: /* No deferences, not needed delta.patch !!! */
1.1 misho 400: if (!sb_f.st_size) {
401: ret = 1;
402: goto end;
403: }
404:
405: /* Delta patch is READY */
406:
1.4 ! misho 407: /* build compressed delta file */
1.2 misho 408: if (compress & 1) {
1.4 ! misho 409: outf = sync_Open(csDelta, O_WRONLY, 0);
1.1 misho 410: if (outf == -1) {
411: ret = outf;
412: goto end;
413: }
414: if (sync_Deflate(f, outf, Z_DEFAULT_COMPRESSION) == -1) {
1.4 ! misho 415: sync_Close(outf);
1.1 misho 416: unlink(csDelta);
417: ret = -1;
418: goto end;
419: }
1.4 ! misho 420: sync_Close(outf);
1.1 misho 421: }
422:
423: end:
1.4 ! misho 424: sync_Close(f);
1.2 misho 425: if (compress & 1)
426: unlink(szTemp);
1.4 ! misho 427: sync_Close(inf);
1.1 misho 428: free(tag_table);
429: munmap(chunks, sb.st_size);
430: return ret;
431: }
432:
433: /*
1.4 ! misho 434: * syncPatch() - Apply delta patch file to target
! 435: *
1.1 misho 436: * @csInput = Input target file name for patch
437: * @csDelta = Input Delta patch file name
438: * @csPatch = After applied patch create new alternate target file, if != NULL
1.2 misho 439: * @compress = 1 compress delta input, 0 not compressed
1.1 misho 440: * return: -1 error, 0 ok, create delta patch, 1 ok, no differences and not create patch
441: */
1.3 misho 442: int
443: syncPatch(const char *csInput, const char *csDelta, const char *csPatch, int compress)
1.1 misho 444: {
445: int inf, outf, f, d, ret, readlen;
446: char szTemp[MAXPATHLEN];
447: u_char *buffer, buf[CHUNK_MAX];
448: struct stat sb;
449: void *delta;
450: struct tagPiece *piece, *pieces = NULL;
451: register int i;
452: off_t off;
453: sync_chunk_t sc, *suffix;
454:
1.2 misho 455: if (compress & 1) {
1.4 ! misho 456: f = sync_Open(csDelta, O_RDONLY, 0);
1.1 misho 457: if (f == -1)
458: return f;
1.4 ! misho 459: d = sync_Temp(szTemp, sizeof szTemp);
1.1 misho 460: if (d == -1) {
1.4 ! misho 461: sync_Close(f);
1.1 misho 462: return d;
463: }
464:
465: if (sync_Inflate(f, d) == -1) {
1.4 ! misho 466: sync_Close(d);
! 467: sync_Close(f);
1.1 misho 468: unlink(szTemp);
469: return -1;
470: } else
1.4 ! misho 471: sync_Close(f);
1.1 misho 472: } else {
1.4 ! misho 473: d = sync_Open(csDelta, O_RDONLY, 0);
1.1 misho 474: if (d == -1)
475: return d;
476: }
477:
478: if (fstat(d, &sb) == -1) {
1.4 ! misho 479: LOGERR;
! 480: sync_Close(d);
1.2 misho 481: if (compress & 1)
1.1 misho 482: unlink(szTemp);
483: return -1;
484: }
485: delta = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, d, 0);
486: if (MAP_FAILED == delta) {
1.4 ! misho 487: LOGERR;
! 488: sync_Close(d);
1.2 misho 489: if (compress & 1)
1.1 misho 490: unlink(szTemp);
491: return -1;
492: } else {
1.4 ! misho 493: sync_Close(d);
1.2 misho 494: if (compress & 1)
1.1 misho 495: unlink(szTemp);
496: }
497:
498: if (sync_buildPatch(delta, sb.st_size, &pieces) == -1 || !pieces) {
1.4 ! misho 499: sync_SetErr(ENOEXEC, "Error:: patch file is broken!\n");
1.1 misho 500: munmap(delta, sb.st_size);
501: return -1;
502: }
503:
1.4 ! misho 504: inf = sync_Open(csInput, O_RDONLY, 0);
1.1 misho 505: if (inf == -1) {
506: if (pieces)
507: free(pieces);
508: munmap(delta, sb.st_size);
509: return inf;
510: }
1.4 ! misho 511: outf = sync_Open(csPatch, O_WRONLY, 0);
1.1 misho 512: if (outf == -1) {
1.4 ! misho 513: sync_Close(inf);
1.1 misho 514: if (pieces)
515: free(pieces);
516: munmap(delta, sb.st_size);
517: return outf;
518: }
519:
520: if (fstat(inf, &sb) == -1) {
1.4 ! misho 521: LOGERR;
1.1 misho 522: ret = -1;
523: goto end;
524: } else {
525: if (!sb.st_size) {
526: ret = -1;
527: goto end;
528: }
529: }
530:
531: ret = readlen = 0;
532: buffer = NULL;
1.4 ! misho 533: for (i = 0, off = 0ll, suffix = NULL, piece = pieces; piece->pfx;
! 534: i++, off += readlen) {
! 535: #if 0
! 536: printf("i=%d off=%llu sfx=%p piece=%p\n", i, off, suffix, piece);
! 537: #endif
1.1 misho 538:
1.4 ! misho 539: /* if input offset is less then input file size */
1.1 misho 540: if (off < sb.st_size) {
541: readlen = read(inf, buf, CHUNK_MAX);
542: if (readlen == -1) {
1.4 ! misho 543: LOGERR;
1.1 misho 544: ret = -1;
545: break;
546: }
1.4 ! misho 547: /* if suffix find, check for correct patch */
1.1 misho 548: if (suffix) {
1.4 ! misho 549: if (suffix->sc_len != readlen ||
! 550: suffix->sc_off != off) {
! 551: sync_SetErr(ENOEXEC, "Error:: patch file is broken! "
! 552: "(wrong suffix pos)\n");
1.1 misho 553: ret = -1;
554: break;
555: }
556: sync_mksig(i, off, buf, readlen, &sc);
557: if (sc.sc_roll != suffix->sc_roll ||
1.4 ! misho 558: memcmp(sc.sc_cksum, suffix->sc_cksum,
! 559: MD5_DIGEST_LENGTH)) {
! 560: sync_SetErr(ENOEXEC, "Error:: patch file is broken! "
! 561: "(wrong suffix crc)\n");
1.1 misho 562: ret = -1;
563: break;
564: }
565:
566: suffix = NULL;
567: }
568:
569: buffer = buf;
570: }
571:
1.4 ! misho 572: #if 0
! 573: printf("i=%d off=%llu sfx=%p piece=%p pfx=%p pfx_off=%llu\n", i, off,
! 574: suffix, piece, piece ? piece->pfx : 0l,
! 575: piece->pfx ? piece->pfx->sc_off : 0l);
! 576: #endif
1.1 misho 577:
1.4 ! misho 578: /* if delta chunk match! */
1.1 misho 579: if (piece->pfx && piece->pfx->sc_off == off) {
580: if (!piece->buf) {
1.4 ! misho 581: sync_SetErr(ENOEXEC, "Error:: patch file is broken! "
! 582: "(missing data)\n");
1.1 misho 583: ret = -1;
584: break;
585: }
586:
587: buffer = piece->buf;
588: readlen = piece->pfx->sc_len;
589: suffix = piece->sfx ? piece->sfx : NULL;
590:
591: piece++;
592:
593: if (suffix && off >= sb.st_size) {
1.4 ! misho 594: sync_SetErr(ENOEXEC, "Error:: patch file is broken! "
! 595: "(after eof find suffix)\n");
1.1 misho 596: ret = -1;
597: break;
598: }
1.4 ! misho 599: } else if (off >= sb.st_size) {
! 600: if (piece->pfx) {
! 601: sync_SetErr(ENOEXEC, "Error:: patch file is broken! "
! 602: "(after eof find prefix)\n");
! 603: ret = -1;
! 604: }
1.1 misho 605:
1.4 ! misho 606: break;
! 607: }
1.1 misho 608:
609: ret = write(outf, buffer, readlen);
610: if (ret == -1 || ret != readlen) {
1.4 ! misho 611: LOGERR;
1.1 misho 612: break;
613: }
614: }
615:
616: end:
1.4 ! misho 617: sync_Close(inf);
! 618: sync_Close(outf);
1.1 misho 619: if (pieces)
620: free(pieces);
621: munmap(delta, sb.st_size);
622: return ret;
623: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>