1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1987-2011 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <glenn.s.fowler@gmail.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * Glenn Fowler
23 * AT&T Bell Laboratories
24 *
25 * pax delta archive support
26 */
27
28 #include "pax.h"
29
30 #include <update.h>
31
32 /*
33 * interpret delta header/trailer ops
34 */
35
36 static void
getdeltaops(Archive_t * ap,File_t * f)37 getdeltaops(Archive_t* ap, File_t* f)
38 {
39 register char* s;
40 register char* e;
41 register int n;
42 char c;
43
44 if (state.delta2delta || (ap->format->flags & DELTAINFO))
45 return;
46 s = ap->delta->hdrbuf;
47 e = s + sizeof(ap->delta->hdrbuf) - 1;
48 n = 0;
49 while (f->st->st_size > 0 && bread(ap, &c, (off_t)1, (off_t)1, 1) > 0)
50 {
51 f->st->st_size--;
52 if (c == '\t' || c == '\n')
53 {
54 if (n)
55 {
56 *s = 0;
57 s = ap->delta->hdrbuf;
58 switch (n)
59 {
60 case DELTA_checksum:
61 f->delta.checksum = strtoul(s, NiL, 16);
62 break;
63 case DELTA_index:
64 f->delta.index = strtol(s, NiL, 0);
65 break;
66 case DELTA_trailer:
67 if ((n = strtol(s, NiL, 0)) > 0)
68 {
69 ap->delta->epilogue = -1;
70 ap->delta->trailer = n;
71 f->st->st_size -= n;
72 }
73 break;
74
75 /*
76 * ignore unknown ops for future
77 */
78 }
79 n = 0;
80 }
81 if (c == '\n')
82 break;
83 }
84 else if (!n) n = c;
85 else if (s < e) *s++ = c;
86 }
87 }
88
89 /*
90 * get supplemental delta header info
91 */
92
93 void
getdeltaheader(register Archive_t * ap,register File_t * f)94 getdeltaheader(register Archive_t* ap, register File_t* f)
95 {
96 register char* s;
97 int n;
98 unsigned long sum;
99 Sfio_t* sp;
100 char c;
101
102 if (!(ap->format->flags & COMPRESSED))
103 {
104 if (ap->delta && ap->delta->format && (ap->delta->format->variant == DELTA_94 || ap->delta->format->variant == DELTA_IGNORE && state.delta2delta))
105 {
106 ap->delta->index++;
107 if (ap->delta->tab && f->name && (f->delta.base = (Member_t*)hashget(ap->delta->tab, f->name)))
108 f->delta.base->mark = 1;
109 if (!(ap->format->flags & DELTAINFO))
110 {
111 if (f->st->st_size <= 0 || bread(ap, &c, (off_t)1, (off_t)1, 1) <= 0)
112 f->delta.op = DELTA_create;
113 else
114 {
115 f->st->st_size--;
116 f->delta.op = c;
117 getdeltaops(ap, f);
118 if (f->st->st_size >= 12 && (f->delta.op == DELTA_create || f->delta.op == DELTA_update))
119 {
120 sum = ap->memsum;
121 s = ap->delta->hdrbuf;
122 n = 12;
123 if (bread(ap, s, (off_t)n, (off_t)n, 1) > 0)
124 {
125 if (ap->delta->format->variant == DELTA_88)
126 {
127 unsigned char* u = (unsigned char*)s;
128 int i;
129
130 i = *u++;
131 u += (i >> 3) & 07;
132 f->uncompressed = 0;
133 i &= 07;
134 while (i-- > 0)
135 f->uncompressed = f->uncompressed * 256 + *u++;
136 }
137 else if (sp = sfnew(NiL, s + 4, n, -1, SF_READ|SF_STRING))
138 {
139 f->uncompressed = sfgetu(sp);
140 sfclose(sp);
141 }
142 bunread(ap, s, n);
143 }
144 ap->memsum = sum;
145 }
146 }
147 }
148 }
149 else if (state.operation == (IN|OUT))
150 f->delta.op = DELTA_pass;
151 }
152 }
153
154 /*
155 * get supplemental delta trailer info
156 */
157
158 void
getdeltatrailer(register Archive_t * ap,register File_t * f)159 getdeltatrailer(register Archive_t* ap, register File_t* f)
160 {
161 long n;
162 unsigned long x;
163
164 if (ap->delta && !f->extended)
165 {
166 if (ap->delta->trailer)
167 {
168 f->st->st_size += ap->delta->trailer;
169 ap->delta->trailer = 0;
170 getdeltaops(ap, f);
171 }
172 if (!f->delta.base)
173 {
174 if (ap->parent && ap->parent != ap && f->delta.op != DELTA_create)
175 error(2, "%s: %s: corrupt archive: not in base archive %s", ap->name, f->name, ap->parent->name);
176 }
177 else
178 {
179 x = (ap->format->flags & SUM) ? f->delta.base->info->checksum : ap->memsum;
180 if ((f->delta.checksum ^ x) & 0xffffffff)
181 error(2, "%s: %s: corrupt archive: checksum mismatch -- expected %08lx, got %08lx", ap->name, f->name, f->delta.checksum & 0xffffffff, x & 0xffffffff);
182 }
183 if (n = f->delta.index - ap->delta->index)
184 {
185 if (n > 0)
186 error(2, "%s: %s: corrupt archive: %d missing file%s", ap->name, f->name, n, n == 1 ? "" : "s");
187 else
188 error(2, "%s: %s: corrupt archive: delta index out of sync by %d file%s", ap->name, f->name, -n, -n == 1 ? "" : "s");
189 ap->delta->index = n;
190 }
191 }
192 }
193
194 /*
195 * initialize delta header output info
196 */
197
198 void
setdeltaheader(register Archive_t * ap,register File_t * f)199 setdeltaheader(register Archive_t* ap, register File_t* f)
200 {
201 register char* s;
202 register int n;
203
204 if (f->delta.op && ap->delta)
205 {
206 ap->delta->index++;
207 if (ap->format->flags & STANDARD)
208 {
209 switch (f->delta.op)
210 {
211 case DELTA_create:
212 s = "create";
213 break;
214 case DELTA_delete:
215 s = "delete";
216 break;
217 case DELTA_pass:
218 s = "pass";
219 break;
220 case DELTA_update:
221 s = "update";
222 break;
223 case DELTA_verify:
224 s = "verify";
225 break;
226 }
227 putkey(ap, ap->tmp.extended, &options[OPT_delta_op], s, 0);
228 putkey(ap, ap->tmp.extended, &options[OPT_uncompressed], NiL, f->uncompressed);
229 putkey(ap, ap->tmp.extended, &options[OPT_delta_index], NiL, ap->delta->index);
230 if (ap->delta->tab && (f->delta.base = (Member_t*)hashget(ap->delta->tab, f->name)))
231 putkey(ap, ap->tmp.extended, &options[OPT_delta_checksum], NiL, f->delta.base->info->checksum & 0xffffffff);
232 }
233 else
234 {
235 s = ap->delta->hdrbuf;
236 n = sfsprintf(s, sizeof(ap->delta->hdrbuf), "%c%c%d\t%c%d\n", f->delta.op, DELTA_index, ap->delta->index, DELTA_trailer, DELTA_TRAILER);
237 ap->delta->hdr = s + n;
238 n += DELTA_TRAILER;
239 f->st->st_size += n;
240 ap->memsum = 0;
241 ap->sum = 1;
242 }
243 }
244 }
245
246 /*
247 * output supplementary delta header info
248 */
249
250 void
putdeltaheader(register Archive_t * ap,register File_t * f)251 putdeltaheader(register Archive_t* ap, register File_t* f)
252 {
253 int n;
254
255 if (f->delta.op && ap->delta && (n = ap->delta->hdr - ap->delta->hdrbuf))
256 {
257 bwrite(ap, ap->delta->hdrbuf, n);
258 n += DELTA_TRAILER;
259 f->st->st_size -= n;
260 ap->delta->hdr = ap->delta->hdrbuf;
261 }
262 }
263
264 /*
265 * output supplementary delta trailer info
266 */
267
268 void
putdeltatrailer(register Archive_t * ap,register File_t * f)269 putdeltatrailer(register Archive_t* ap, register File_t* f)
270 {
271 register char* s;
272 register int n;
273
274 if (f->delta.op && ap->delta)
275 {
276 if (!(ap->format->flags & STANDARD))
277 {
278 ap->sum = 0;
279 s = ap->delta->hdrbuf;
280 n = sfsprintf(s, sizeof(ap->delta->hdrbuf), "%c%08X\n", DELTA_checksum, ap->memsum);
281 if (n != DELTA_TRAILER)
282 error(PANIC, "delta trailer size %d shoulda been %d", n, DELTA_TRAILER);
283 bwrite(ap, s, n);
284 }
285 }
286 }
287
288 /*
289 * initialize delta tables
290 */
291
292 void
initdelta(Archive_t * ap,Format_t * dp)293 initdelta(Archive_t* ap, Format_t* dp)
294 {
295 if (!ap->delta && !(ap->delta = newof(0, Delta_t, 1, 0)))
296 nospace();
297 if (!ap->delta->tab && !(ap->delta->tab = hashalloc(NiL, HASH_set, HASH_ALLOCATE, HASH_name, "delta", 0)))
298 nospace();
299 ap->delta->format = dp;
300 }
301
302 /*
303 * get delta base archive info
304 */
305
306 void
deltabase(register Archive_t * ap)307 deltabase(register Archive_t* ap)
308 {
309 register Archive_t* bp;
310 Format_t* fp;
311 struct stat st;
312
313 if (!ap->delta || ap->delta->initialized)
314 return;
315 ap->delta->initialized = 1;
316 if (!(bp = ap->delta->base))
317 bp = ap->delta->base = initarchive("/dev/null", O_RDONLY);
318 binit(bp);
319 bp->parent = ap;
320 if ((bp->io->mode & O_ACCMODE) != O_WRONLY)
321 bp->sum++;
322 if ((bp->io->fd = open(bp->name, bp->io->mode|O_BINARY)) < 0 || fstat(bp->io->fd, &st))
323 error(ERROR_SYSTEM|3, "%s: %s: cannot open base archive", ap->name, bp->name);
324 if (S_ISREG(st.st_mode) && st.st_size > 0)
325 {
326 bp->io->seekable = 1;
327 bp->io->size = st.st_size;
328 }
329 else
330 bp->io->seekable = 0;
331 if (st.st_size)
332 {
333 fp = bp->expected;
334 bp->expected = 0;
335 if (state.ordered)
336 {
337 if (!getprologue(bp))
338 error(3, "%s: %s: base archive is empty", ap->name, bp->name);
339 bp->sum--;
340 bp->checksum = memsum(bp->io->next, bcount(bp), 0L);
341 }
342 else
343 {
344 if (!state.append && !state.update && lseek(bp->io->fd, (off_t)0, SEEK_SET) != 0)
345 error(ERROR_SYSTEM|3, "%s: %s: base archive must be seekable", ap->name, bp->name);
346 copyin(bp);
347 bp->size = bp->io->offset + bp->io->count;
348 }
349 bp->expected = fp;
350 bp->checksum &= 0xffffffff;
351 }
352 if (state.append || state.update)
353 ap->delta->format = st.st_size ? bp->format : ap->format;
354 else if (!ap->delta->format)
355 {
356 ap->delta->format = getformat(FMT_DELTA, 1);
357 ap->delta->compress = !st.st_size;
358 }
359 }
360
361 /*
362 * verify untouched base files
363 */
364
365 void
deltaverify(Archive_t * ap)366 deltaverify(Archive_t* ap)
367 {
368 register int wfd;
369 register Member_t* d;
370 register off_t c;
371 register off_t n;
372 Hash_position_t* pos;
373
374 if (!state.delta.update && !state.list && ap->delta && ap->delta->base != ap && (pos = hashscan(ap->delta->tab, 0)))
375 {
376 message((-2, "verify untouched base files"));
377 while (hashnext(pos))
378 {
379 d = (Member_t*)pos->bucket->value;
380 message((-1, "%s: mark=%d", d->info->name, d->mark));
381 if (!d->mark && selectfile(ap, d->info) && (wfd = openout(ap, d->info)) >= 0)
382 {
383 ap->entries++;
384 if (!d->uncompressed)
385 {
386 if (!state.ordered && lseek(ap->delta->base->io->fd, d->offset, SEEK_SET) != d->offset)
387 error(ERROR_SYSTEM|3, "%s: base archive seek error", ap->delta->base->name);
388 holeinit(wfd);
389 for (c = d->info->st->st_size; c > 0; c -= n)
390 {
391 n = (c > state.buffersize) ? state.buffersize : c;
392 if ((n = state.ordered ? bread(ap, state.tmp.buffer, n, n, 1) : read(ap->delta->base->io->fd, state.tmp.buffer, n)) <= 0)
393 {
394 error(ERROR_SYSTEM|2, "%s: %s: read error", ap->delta->base->name, d->info->name);
395 break;
396 }
397 else ap->io->count += n;
398 if (holewrite(wfd, state.tmp.buffer, n) != n)
399 {
400 error(ERROR_SYSTEM|2, "%s: write error", d->info->name);
401 break;
402 }
403 ap->io->count += n;
404 }
405 holedone(wfd);
406 closeout(ap, d->info, wfd);
407 setfile(ap, d->info);
408 listentry(d->info);
409 }
410 else if (state.ordered) paxdelta(NiL, ap, d->info, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap->delta->base, d->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT|DELTA_LIST, wfd, 0);
411 else paxdelta(NiL, ap, d->info, DELTA_DEL|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ap->delta->base->io->fd, d->offset, d->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT|DELTA_LIST, wfd, 0);
412 }
413 }
414 hashdone(pos);
415 }
416 }
417
418 /*
419 * output prefix dirs to the archive first
420 */
421
422 static void
deltaprefix(Archive_t * ip,Archive_t * op,register Member_t * d)423 deltaprefix(Archive_t* ip, Archive_t* op, register Member_t* d)
424 {
425 register char* s;
426 register Member_t* m;
427
428 d->mark = 1;
429 if (s = strrchr(d->info->path, '/'))
430 {
431 *s = 0;
432 if (!(m = (Member_t*)hashget(ip->delta->tab, d->info->name)))
433 {
434 if (!(m = newof(0, Member_t, 1, 0)))
435 nospace();
436 m->mark = 1;
437 hashput(ip->delta->tab, 0, m);
438 }
439 else if (!m->mark)
440 deltaprefix(ip, op, m);
441 *s = '/';
442 }
443 d->info->fd = -1;
444 fileout(op, d->info);
445 }
446
447 /*
448 * delta file if necessary and copy out
449 */
450
451 void
deltaout(Archive_t * ip,Archive_t * op,register File_t * f)452 deltaout(Archive_t* ip, Archive_t* op, register File_t* f)
453 {
454 register Member_t* d;
455 int dfd;
456 int skip;
457
458 skip = !!ip;
459 f->delta.same = 0;
460 if (d = op->delta && op->delta->tab && f->name ? (Member_t*)hashget(op->delta->tab, f->name) : (Member_t*)0)
461 d->mark = 1;
462 if (op->delta && (op->delta->format->flags & DELTAIO))
463 {
464 if (f->type == X_IFREG && f->linktype == NOLINK && (!d || f->st->st_mtime != d->mtime.tv_sec || (f->st->st_mode & X_IPERM) != (d->mode & X_IPERM)))
465 {
466 if (f->ordered)
467 {
468 f->ordered = 0;
469 fileout(op, f);
470 return;
471 }
472 if (d)
473 {
474 f->delta.op = DELTA_update;
475 f->st->st_dev = d->dev;
476 f->st->st_ino = d->ino;
477 message((-2, "delta: delta: file=%s offset=%ld size=%ld expand=%d", f->name, d->offset, d->size, d->uncompressed));
478 if (state.ordered)
479 {
480 if (!d->uncompressed)
481 paxdelta(ip, op, f, DELTA_SRC|DELTA_BIO|DELTA_SIZE, op->delta->base, d->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_SIZE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
482 else if (!paxdelta(ip, op, d->info, DELTA_DEL|DELTA_BIO|DELTA_SIZE, op->delta->base, d->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &dfd, 0))
483 paxdelta(ip, op, f, DELTA_SRC|DELTA_FD|DELTA_SIZE|DELTA_FREE, dfd, d->uncompressed, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_SIZE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
484 }
485 else if (!d->uncompressed)
486 paxdelta(ip, op, f, DELTA_SRC|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, op->delta->base->io->fd, d->offset, d->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_SIZE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
487 else if (!paxdelta(ip, op, d->info, DELTA_DEL|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, op->delta->base->io->fd, d->offset, d->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &dfd, 0))
488 paxdelta(ip, op, f, DELTA_SRC|DELTA_FD|DELTA_SIZE|DELTA_FREE, dfd, d->uncompressed, DELTA_TAR|DELTA_FD|DELTA_SIZE|DELTA_FREE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
489 }
490 else
491 {
492 f->delta.op = DELTA_create;
493 message((-2, "delta: create: file=%s", f->name));
494 paxdelta(ip, op, f, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_SIZE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
495 }
496 skip = 0;
497 }
498 else
499 {
500 f->delta.op = (d && (f->type == X_IFREG || f->type == X_IFDIR)) ? DELTA_update : DELTA_create;
501 message((-2, "delta: %s: file=%s", f->delta.op == DELTA_update ? "update" : "create", f->name));
502 if (skip)
503 {
504 skip = 0;
505 fileskip(ip, f);
506 }
507 f->st->st_size = 0;
508 if (f->delta.op == DELTA_update && f->type != X_IFREG && f->st->st_mode == d->mode)
509 f->st->st_mtime = d->mtime.tv_sec;
510 }
511 }
512 if (!d || !f->delta.same && d->mtime.tv_sec != f->st->st_mtime)
513 {
514 register char* s;
515
516 if (ip && ip->delta && ip->delta->tab && f->name && (s = strrchr(f->name, '/')))
517 {
518 *s = 0;
519 if ((d = (Member_t*)hashget(ip->delta->tab, f->name)) && !d->mark)
520 deltaprefix(ip, op, d);
521 *s = '/';
522 }
523 fileout(op, f);
524 }
525 else if (f->fd >= 0)
526 close(f->fd);
527 else if (skip)
528 fileskip(ip, f);
529 }
530
531 /*
532 * copy file from input to output archive
533 */
534
535 static void
deltacopy(Archive_t * ip,Archive_t * op,register File_t * f)536 deltacopy(Archive_t* ip, Archive_t* op, register File_t* f)
537 {
538 if (f->delta.base)
539 {
540 f->st->st_size = f->delta.base->size;
541 if (f->delta.base->uncompressed)
542 {
543 if (state.ordered) paxdelta(ip, NiL, f->delta.base->info, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ip->delta->base, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
544 else paxdelta(ip, NiL, f->delta.base->info, DELTA_DEL|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ip->delta->base->io->fd, f->delta.base->offset, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
545 }
546 else if (state.ordered)
547 {
548 f->ap = ip;
549 f->fd = -1;
550 f->ordered = 1;
551 }
552 else if ((f->fd = dup(ip->delta->base->io->fd)) < 0)
553 error(ERROR_SYSTEM|3, "%s: cannot reopen", ip->delta->base->name);
554 else if (lseek(f->fd, f->delta.base->offset, SEEK_SET) < 0)
555 error(ERROR_SYSTEM|3, "%s: base archive seek error", ip->delta->base->name);
556 }
557 deltaout(ip, op, f);
558 }
559
560 /*
561 * copy the delta base archive delete entries
562 */
563
564 void
deltadelete(register Archive_t * ap)565 deltadelete(register Archive_t* ap)
566 {
567 register File_t* f;
568 register Member_t* d;
569 Hash_position_t* pos;
570
571 if (!state.ordered && ap->delta && ap->delta->tab)
572 {
573 if (pos = hashscan(ap->delta->tab, 0))
574 {
575 message((-2, "copy the base delete entries"));
576 f = &ap->file;
577 while (hashnext(pos))
578 {
579 d = (Member_t*)pos->bucket->value;
580 if (!d->mark && (!d->info || !d->info->ro))
581 {
582 ap->selected++;
583 initfile(ap, f, f->st, pos->bucket->name, X_IFREG|X_IRUSR|X_IWUSR|X_IRGRP|X_IROTH);
584 f->delta.op = DELTA_delete;
585 if (d->info && d->info->st)
586 {
587 f->st->st_mode = d->info->st->st_mode;
588 f->st->st_gid = d->info->st->st_gid;
589 f->st->st_uid = d->info->st->st_uid;
590 f->st->st_mtime = d->info->st->st_mtime;
591 }
592 else
593 {
594 f->st->st_gid = state.uid;
595 f->st->st_uid = state.gid;
596 f->st->st_mtime = NOW;
597 }
598 putheader(ap, f);
599 puttrailer(ap, f);
600 }
601 }
602 hashdone(pos);
603 }
604 }
605 }
606
607 /*
608 * update file deltas from archive and output to archive
609 */
610
611 void
deltapass(Archive_t * ip,Archive_t * op)612 deltapass(Archive_t* ip, Archive_t* op)
613 {
614 register File_t* f;
615 register off_t c;
616 register ssize_t n;
617 Member_t* d;
618 Member_t* h;
619 char* p;
620 Filter_t* fp;
621 Hash_position_t* pos;
622
623 if (state.delta2delta != 2)
624 state.delta2delta = 0;
625 message((-1, "delta PASS%s", state.delta2delta ? " delta2delta" : ""));
626 deltabase(ip);
627 deltabase(op);
628 putprologue(op, 0);
629 f = &ip->file;
630 while (getprologue(ip))
631 {
632 while (getheader(ip, f))
633 {
634 f->fd = -1;
635 f->ap = ip;
636 if (f->ro)
637 fileskip(ip, f);
638 else if (state.delta2delta)
639 {
640 if (validout(op, f) && selectfile(op, f))
641 fileout(op, f);
642 else
643 fileskip(ip, f);
644 }
645 else switch (f->delta.op)
646 {
647 case DELTA_create:
648 if (f->type != X_IFREG || f->linktype != NOLINK)
649 {
650 f->st->st_size = 0;
651 goto pass;
652 }
653 if (f->delta.base)
654 error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
655 if (validout(op, f) && selectfile(op, f))
656 {
657 paxdelta(ip, op, f, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &f->fd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ip, f->st->st_size, 0);
658 if (op->delta && (op->delta->format->flags & DELTAIO))
659 {
660 f->delta.op = DELTA_create;
661 paxdelta(ip, op, f, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_SIZE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
662 }
663 else f->delta.op = 0;
664 deltaout(ip, op, f);
665 }
666 else fileskip(ip, f);
667 break;
668 case DELTA_pass:
669 if (validout(op, f) && selectfile(op, f))
670 {
671 if (ip->delta && (ip->delta->format->flags & DELTAIO))
672 {
673 f->delta.op = DELTA_create;
674 paxdelta(ip, op, f, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ip, f->st->st_size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
675 }
676 else if (fp = filter(op, f))
677 {
678 int wfd;
679
680 static char* tmp;
681
682 if (!tmp)
683 tmp = pathtemp(NiL, 0, NiL, error_info.id, NiL);
684 if ((wfd = open(tmp, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR)) < 0)
685 {
686 error(2, "%s: cannot create filter temporary %s", f->path, tmp);
687 fileskip(ip, f);
688 break;
689 }
690 holeinit(wfd);
691 for (c = f->st->st_size; c > 0; c -= state.buffersize)
692 {
693 n = c > state.buffersize ? state.buffersize : c;
694 if (bread(ip, state.tmp.buffer, n, n, 1) <= 0)
695 {
696 error(ERROR_SYSTEM|2, "%s: read error", f->name);
697 break;
698 }
699 if (holewrite(wfd, state.tmp.buffer, n) != n)
700 {
701 error(ERROR_SYSTEM|2, "%s: filter temporary write error to %s", f->name, tmp);
702 break;
703 }
704 }
705 holedone(wfd);
706 close(wfd);
707 p = f->path;
708 f->path = tmp;
709 f->fd = apply(op, f, fp);
710 if (remove(f->path))
711 error(1, "%s: cannot remove filter temporary", p, f->path);
712 f->path = p;
713 f->delta.op = 0;
714 }
715 else f->delta.op = 0;
716 deltaout(ip, op, f);
717 }
718 else fileskip(ip, f);
719 break;
720 case DELTA_delete:
721 if (!f->delta.base)
722 error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
723 if (ip->delta && (d = (Member_t*)hashget(ip->delta->tab, f->name)))
724 d->info->delta.op = DELTA_delete;
725 break;
726 case DELTA_update:
727 if (!f->delta.base)
728 error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
729 if (validout(op, f) && selectfile(op, f))
730 {
731 if (state.ordered) paxdelta(ip, op, f, DELTA_SRC|DELTA_BIO|DELTA_SIZE, ip->delta->base, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &f->fd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ip, f->st->st_size, 0);
732 else paxdelta(ip, op, f, DELTA_SRC|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ip->delta->base->io->fd, f->delta.base->offset, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &f->fd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ip, f->st->st_size, 0);
733 if (op->delta && (op->delta->format->flags & DELTAIO))
734 {
735 f->delta.op = DELTA_create;
736 paxdelta(ip, op, f, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_SIZE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
737 }
738 else f->delta.op = 0;
739 deltaout(ip, op, f);
740 }
741 else fileskip(ip, f);
742 break;
743 case DELTA_verify:
744 if (!f->delta.base || f->delta.base->mtime.tv_sec != f->st->st_mtime)
745 error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
746 pass:
747 if (validout(op, f) && selectfile(op, f))
748 {
749 f->delta.op = 0;
750 deltacopy(ip, op, f);
751 }
752 else fileskip(ip, f);
753 break;
754 default:
755 error(3, "%s: %s: not a delta archive (op=%d)", ip->name, f->name, f->delta.op);
756 break;
757 }
758 gettrailer(ip, f);
759 }
760 if (!getepilogue(ip))
761 break;
762 }
763 if (ip->delta && ip->delta->tab)
764 {
765 /*
766 * copy the non-empty untouched base hard links first
767 */
768
769 if (pos = hashscan(ip->delta->tab, 0))
770 {
771 message((-2, "copy non-empty untouched base hard links"));
772 while (hashnext(pos))
773 {
774 d = (Member_t*)pos->bucket->value;
775 if (!d->mark && d->info->linktype != HARDLINK && d->info->st->st_size > 0 && selectfile(op, d->info))
776 {
777 d->mark = 1;
778 deltacopy(ip, op, d->info);
779 }
780 }
781 hashdone(pos);
782 }
783
784 /*
785 * copy the remaining untouched base files and deletes
786 */
787
788 if (pos = hashscan(ip->delta->tab, 0))
789 {
790 message((-2, "copy remaining untouched base files"));
791 while (hashnext(pos))
792 {
793 d = (Member_t*)pos->bucket->value;
794 if (!d->mark && selectfile(op, d->info))
795 {
796 d->mark = 1;
797 if (d->info->linktype == HARDLINK)
798 {
799 if (!(h = (Member_t*)hashget(ip->delta->tab, d->info->linkpath)))
800 error(1, "%s: %s: %s: hard link not in base archive", ip->name, d->info->name, d->info->linkpath);
801 else if (!h->mark || h->info->delta.op == DELTA_delete)
802 {
803 h->info->name = d->info->name;
804 d = h;
805 }
806 }
807 deltacopy(ip, op, d->info);
808 }
809 }
810 hashdone(pos);
811 }
812 }
813 deltadelete(op);
814 putepilogue(op);
815 op->volume = 0;
816 op->selected = op->entries;
817 }
818
819 /*
820 * set delta info from pseudo file
821 */
822
823 void
deltaset(register Archive_t * ap,char * s)824 deltaset(register Archive_t* ap, char* s)
825 {
826 Format_t* dp;
827 char* t;
828 int type;
829
830 dp = 0;
831 if ((type = *++s) != TYPE_COMPRESS && type != TYPE_DELTA)
832 error(3, "type %c encoding not supported", *s);
833 if (*++s == INFO_SEP)
834 {
835 if (t = strchr(++s, INFO_SEP))
836 *t++ = 0;
837 if (*s)
838 {
839 if (isdigit(*s))
840 s = sfprints("delta%s", s);
841 dp = getformat(s, 1);
842 }
843
844 /*
845 * [<INFO_SEP>[<OP>]<VAL>]* may appear here
846 */
847
848 while ((s = t) && *s != INFO_SEP)
849 {
850 if (t = strchr(s, INFO_SEP))
851 *t++ = 0;
852 switch (*s++)
853 {
854 case INFO_ORDERED:
855 ap->ordered = 1;
856 break;
857 }
858 }
859 }
860 if (!dp)
861 dp = getformat(FMT_DELTA, 1);
862 initdelta(ap, dp);
863 ap->delta->compress = type == TYPE_COMPRESS;
864 ap->checkdelta = 0;
865 }
866
867 /*
868 * check for delta pseudo file
869 */
870
871 int
deltacheck(register Archive_t * ap,register File_t * f)872 deltacheck(register Archive_t* ap, register File_t* f)
873 {
874 register char* s;
875 register Archive_t* bp;
876 register char* t;
877 off_t size;
878 unsigned long checksum;
879
880 if (!f || !f->st->st_size && !f->st->st_dev && !f->st->st_ino && !(f->st->st_mode & (X_IRWXU|X_IRWXG|X_IRWXO)) && strmatch(f->name, INFO_MATCH))
881 {
882 if (ap->checkdelta)
883 {
884 ap->checkdelta = 0;
885 if (f)
886 {
887 s = f->name;
888 size = f->st->st_mtime;
889 checksum = (DELTA_LO(f->st->st_gid) << 16) | DELTA_LO(f->st->st_uid);
890 if (streq(s, "DELTA!!!"))
891 initdelta(ap, getformat("delta88", 1));
892 else if (*s++ == INFO_SEP)
893 {
894 if (strneq(s, ID, IDLEN) && (t = strchr(s, INFO_SEP)))
895 deltaset(ap, t);
896 else
897 {
898 if (t = strchr(s += 2, INFO_SEP))
899 *t = 0;
900 error(1, "unknown %s header ignored", s);
901 return 0;
902 }
903 }
904 }
905 else if (ap->delta)
906 {
907 size = ap->delta->size;
908 checksum = ap->delta->checksum;
909 }
910 if (ap->delta && ap->delta->format)
911 {
912 if (!ap->delta->compress && ap->parent)
913 error(3, "%s: %s: base archive cannot be a delta", ap->parent->name, ap->name);
914 if (bp = ap->delta->base)
915 {
916 if (ap->delta->format->variant == DELTA_88)
917 bp->checksum = bp->old.checksum;
918 message((-5, "checkdelta: %s size=%I*d:%I*d checksum=%08x:%08x", ap->delta->format->name, sizeof(size), size, sizeof(bp->size), bp->size, checksum, bp->checksum));
919 if (!ap->delta->compress)
920 {
921 if (!ap->ordered)
922 {
923 if (state.ordered)
924 error(3, "%s: delta archive not ordered", ap->name);
925 if (bp->size != size)
926 error(3, "%s: %s: base archive size mismatch -- expected %I*u, got %I*u", ap->name, bp->name, sizeof(size), size, sizeof(bp->size), bp->size);
927 }
928 if ((bp->checksum ^ checksum) & 0xffffffff)
929 error(1, "%s: %s: base archive checksum mismatch -- expected %08lx, got %08lx", ap->name, bp->name, checksum & 0xffffffff, bp->checksum & 0xffffffff);
930 }
931 }
932 else if (!ap->delta->compress)
933 {
934 error(state.list ? 1 : 3, "%s: base archive must be specified", ap->name);
935 deltabase(ap);
936 ap->delta->compress = 1;
937 }
938 if (ap->sum <= 0)
939 ap->sum++;
940 return 1;
941 }
942 if (f)
943 error(1, "%s: %s: unknown control header treated as regular file", ap->name, f->name);
944 }
945 else if (f && *f->name == INFO_SEP && strneq(f->name + 1, ID, IDLEN) && *(f->name + IDLEN + 1) == INFO_SEP)
946 {
947 getdeltaheader(ap, f);
948 setinfo(ap, f);
949 return 1;
950 }
951 }
952 if (f && ap->checkdelta && ap->delta)
953 ap->delta->format = getformat(FMT_PATCH, 1);
954 return 0;
955 }
956
957 #include <vdelta.h>
958
959 typedef struct
960 {
961 Vddisc_t vd;
962 Archive_t* ap;
963 off_t base;
964 Archive_t* bp;
965 off_t offset;
966 int* pfd;
967 int fd;
968 int op;
969 } Vdio_t;
970
971 #define Vdoff_t long
972
973 /*
974 * delta discipline read
975 */
976
977 static int
delread(void * buf,int n,Vdoff_t off,Vddisc_t * vd)978 delread(void* buf, int n, Vdoff_t off, Vddisc_t* vd)
979 {
980 register Vdio_t* dp = (Vdio_t*)vd;
981 register Vdoff_t diff;
982
983 message((-6, "delread: op=%o buf=%p n=%d off=%I*d nxt=%I*d", dp->op, buf, n, sizeof(off), off, sizeof(dp->offset), dp->offset));
984 if (diff = off - dp->offset)
985 {
986 dp->offset = off;
987 if (dp->op & DELTA_BIO)
988 {
989 if (bseek(dp->bp, diff, SEEK_CUR, 0) < 0)
990 error(PANIC, "BIO seek: have=%I*d need=%I*d", sizeof(dp->offset), dp->offset, sizeof(off), off);
991 }
992 else
993 {
994 off += dp->base;
995 if (lseek(dp->fd, off, SEEK_SET) != off)
996 {
997 message((-8, "delread: fd=%d n=%d off=%I*d: seek error", dp->fd, n, sizeof(off), off));
998 return -1;
999 }
1000 }
1001 }
1002 if (n > (dp->vd.size - dp->offset))
1003 n = dp->vd.size - dp->offset;
1004 if (n <= 0)
1005 {
1006 message((-8, "delread: fd=%d n=%d siz=%I*d off=%I*d: seek error", dp->fd, n, sizeof(dp->vd.size), dp->vd.size, sizeof(dp->offset), dp->offset));
1007 return 0;
1008 }
1009 n = (dp->op & DELTA_BIO) ? bread(dp->bp, buf, (off_t)0, (off_t)n, 1) : read(dp->fd, buf, n);
1010 if (n > 0)
1011 dp->offset += n;
1012 return n;
1013 }
1014
1015 /*
1016 * delta discipline write
1017 */
1018
1019 static int
delwrite(void * buf,int n,Vdoff_t off,Vddisc_t * vd)1020 delwrite(void* buf, int n, Vdoff_t off, Vddisc_t* vd)
1021 {
1022 register Vdio_t* dp = (Vdio_t*)vd;
1023 Buffer_t* bp;
1024 ssize_t k;
1025
1026 message((-6, "delwrite: op=%o buf=%p n=%d off=%I*d", dp->op, buf, n, sizeof(off), off));
1027 if (dp->op & DELTA_BIO)
1028 {
1029 bwrite(dp->bp, buf, n);
1030 return n;
1031 }
1032 if (dp->op & DELTA_HOLE)
1033 return holewrite(dp->fd, buf, n);
1034 if (bp = getbuffer(dp->fd))
1035 {
1036 if (bp->next + n < bp->past)
1037 {
1038 memcpy(bp->next, buf, n);
1039 bp->next += n;
1040 return n;
1041 }
1042 if ((dp->fd = open(state.tmp.file, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR)) < 0)
1043 error(3, "%s: cannot create delta temporary file", state.tmp.file);
1044 k = bp->next - bp->base;
1045 if (k > 0 && write(dp->fd, bp->base, k) != k)
1046 return -1;
1047 }
1048 return write(dp->fd, buf, n);
1049 }
1050
1051 /*
1052 * delta/update algorithm wrapper
1053 */
1054
1055 int
paxdelta(Archive_t * ip,Archive_t * ap,File_t * f,int op,...)1056 paxdelta(Archive_t* ip, Archive_t* ap, File_t* f, int op, ...)
1057 {
1058 register Vdio_t* dp;
1059 va_list vp;
1060 ssize_t n;
1061 int bufferclash = 0;
1062 int hole = 0;
1063 Format_t* fp;
1064 Buffer_t* bp;
1065 Sfio_t* mp = 0;
1066 Vdio_t* gen = 0;
1067 Vdio_t data[3];
1068
1069 #if DEBUG
1070 static const char* dataname[] = { "src", "tar", "del", "HUH" };
1071 #endif
1072
1073 va_start(vp, op);
1074 #if 0
1075 if (ap && ap->delta && !ap->delta->format)
1076 ap->delta->format = getformat(FMT_DELTA, 1);
1077 if (ip && ip->delta && !ip->delta->format)
1078 ip->delta->format = getformat(FMT_DELTA, 1);
1079 #else
1080 if (ap && ap->delta)
1081 {
1082 if (!ap->delta->format)
1083 ap->delta->format = getformat(FMT_DELTA, 1);
1084 fp = ap->delta->format;
1085 }
1086 if (ip && ip->delta)
1087 {
1088 if (!ip->delta->format)
1089 ip->delta->format = getformat(FMT_DELTA, 1);
1090 fp = ip->delta->format;
1091 }
1092 #endif
1093 #if DEBUG
1094 if (error_info.trace <= -5) mp = sfstropen();
1095 #endif
1096 memzero(data, sizeof(data));
1097 while (op)
1098 {
1099 dp = &data[op & DELTA_DATA];
1100 dp->ap = ap && ap->delta ? ap : ip;
1101 #if DEBUG
1102 if (mp) sfprintf(mp, " %s [", dataname[op & DELTA_DATA]);
1103 #endif
1104 if (op & DELTA_BIO)
1105 dp->bp = va_arg(vp, Archive_t*);
1106 else if (op & DELTA_FD)
1107 {
1108 if ((dp->fd = va_arg(vp, int)) == -1)
1109 {
1110 op &= ~(DELTA_FD|DELTA_FREE);
1111 op |= DELTA_BIO;
1112 dp->bp = ip ? ip : ap;
1113 }
1114 else if (bp = getbuffer(dp->fd))
1115 {
1116 op &= ~(DELTA_FD|DELTA_FREE);
1117 op |= DELTA_BUFFER;
1118 dp->vd.data = bp->base;
1119 bufferclash = 1;
1120 }
1121 #if DEBUG
1122 else if (mp) sfprintf(mp, " fd=%d", dp->fd);
1123 #endif
1124 }
1125 else if (op & DELTA_TEMP)
1126 {
1127 dp->pfd = va_arg(vp, int*);
1128 op |= DELTA_FD;
1129 op &= ~DELTA_FREE;
1130 #if DEBUG
1131 if (mp) sfprintf(mp, " TEMP");
1132 #endif
1133 }
1134 else if (op & DELTA_BUFFER)
1135 {
1136 dp->vd.data = va_arg(vp, char*);
1137 #if DEBUG
1138 if (mp) sfprintf(mp, " buffer=%p", dp->vd.data);
1139 #endif
1140 }
1141 if (op & DELTA_OFFSET)
1142 {
1143 dp->base = va_arg(vp, off_t);
1144 #if DEBUG
1145 if (mp) sfprintf(mp, " offset=%I*d", sizeof(dp->base), dp->base);
1146 #endif
1147 }
1148 if (op & DELTA_SIZE)
1149 {
1150 dp->vd.size = va_arg(vp, off_t);
1151 #if DEBUG
1152 if (mp) sfprintf(mp, " size=%I*d", sizeof(dp->vd.size), dp->vd.size);
1153 #endif
1154 }
1155 if ((op & (DELTA_BIO|DELTA_OUTPUT)) == DELTA_BIO && dp->vd.size > 0 && dp->vd.size <= state.buffersize && (dp->vd.data = bget(dp->bp, dp->vd.size, NiL)))
1156 {
1157 op &= ~(DELTA_BIO|DELTA_FREE);
1158 op |= DELTA_BUFFER;
1159 #if DEBUG
1160 if (mp) sfprintf(mp, " buffer=%p", dp->vd.data);
1161 #endif
1162 }
1163 if (op & (DELTA_BIO|DELTA_FD))
1164 {
1165 if (op & DELTA_OUTPUT)
1166 {
1167 dp->vd.writef = delwrite;
1168 if (!hole && (op & (DELTA_FD|DELTA_TEMP)) == DELTA_FD)
1169 {
1170 hole = 1;
1171 op |= DELTA_HOLE;
1172 holeinit(dp->fd);
1173 }
1174 }
1175 else dp->vd.readf = delread;
1176 if ((op & (DELTA_FD|DELTA_TEMP)) == DELTA_FD && dp->base && lseek(dp->fd, dp->base, SEEK_SET) != dp->base)
1177 error(3, "%s: cannot seek delta", f->name);
1178 #if DEBUG
1179 if (mp && (op & DELTA_BIO)) sfprintf(mp, " bio=%s", dp->bp->name);
1180 #endif
1181 }
1182 if (op & DELTA_OUTPUT)
1183 {
1184 if (gen) error(PANIC, "paxdelta(): more than one DELTA_OUTPUT");
1185 gen = dp;
1186 #if DEBUG
1187 if (mp) sfprintf(mp, " OUTPUT");
1188 #endif
1189 }
1190 #if DEBUG
1191 if (mp && (op & DELTA_COUNT)) sfprintf(mp, " COUNT");
1192 #endif
1193 #if DEBUG
1194 if (mp) sfprintf(mp, " ]");
1195 #endif
1196 dp->op = op;
1197 op = va_arg(vp, int);
1198 }
1199 va_end(vp);
1200 if (!gen)
1201 error(PANIC, "paxdelta(): no DELTA_OUTPUT");
1202 #if 0
1203 fp = (gen == &data[DELTA_DEL]) ? ap->delta->format : ip->delta->format;
1204 #endif
1205 if (gen->pfd)
1206 {
1207 if (!(state.test & 0000020) && fp->variant != DELTA_88 && (state.buffer[bufferclash ? (state.delta.bufferindex = !state.delta.bufferindex) : state.delta.bufferindex].base || (state.buffer[state.delta.bufferindex].base = newof(0, char, state.delta.buffersize, 0)) || (state.delta.buffersize >>= 1) && (state.buffer[state.delta.bufferindex].base = newof(0, char, state.delta.buffersize, 0))))
1208 {
1209 gen->fd = setbuffer(state.delta.bufferindex);
1210 bp = getbuffer(gen->fd);
1211 bp->next = bp->base;
1212 bp->past = bp->base + state.delta.buffersize;
1213 }
1214 else if ((gen->fd = open(state.tmp.file, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR)) < 0)
1215 error(3, "%s: cannot create delta temporary file", state.tmp.file);
1216 }
1217 switch (fp->variant)
1218 {
1219 case DELTA_88:
1220 case DELTA_PATCH:
1221 /*
1222 * force the new interface into the old
1223 * not the most efficient way but at least
1224 * the rest of the code is clean
1225 */
1226
1227 {
1228 static char* tmp;
1229
1230 if (gen == &data[DELTA_DEL])
1231 {
1232 if (!(data[DELTA_DEL].op & DELTA_FD))
1233 error(PANIC, "paxdelta: %s %s must be DELTA_TEMP or DELTA_FD", fp->name, dataname[DELTA_DEL]);
1234 for (op = 0; op < elementsof(data); op++)
1235 {
1236 if (op == DELTA_DEL) /*NOP*/;
1237 else if (!data[op].vd.size)
1238 {
1239 data[op].vd.data = state.tmp.buffer;
1240 data[op].op &= ~DELTA_FREE;
1241 }
1242 else switch (data[op].op & (DELTA_BIO|DELTA_FD|DELTA_OUTPUT))
1243 {
1244 case DELTA_BIO:
1245 if (!(data[op].vd.data = malloc(data[op].vd.size)))
1246 nospace();
1247 if (bread(data[op].bp, data[op].vd.data, data[op].vd.size, data[op].vd.size, 1) != data[op].vd.size)
1248 error(3, "%s: delta bread error", f->name);
1249 data[op].op &= ~DELTA_BIO;
1250 data[op].op |= DELTA_BUFFER|DELTA_FREE;
1251 break;
1252 case DELTA_FD:
1253 if (!(data[op].vd.data = malloc(data[op].vd.size)))
1254 nospace();
1255 if (data[op].base && lseek(data[op].fd, data[op].base, SEEK_SET) != data[op].base)
1256 error(3, "%s: delta seek error", f->name);
1257 if (read(data[op].fd, data[op].vd.data, data[op].vd.size) != data[op].vd.size)
1258 error(3, "%s: delta read error", f->name);
1259 if (data[op].op & DELTA_FREE)
1260 close(data[op].fd);
1261 data[op].op &= ~DELTA_FD;
1262 data[op].op |= DELTA_BUFFER|DELTA_FREE;
1263 break;
1264 }
1265 }
1266 switch (fp->variant)
1267 {
1268 case DELTA_88:
1269 n = delta(data[DELTA_SRC].vd.data, data[DELTA_SRC].vd.size, data[DELTA_TAR].vd.data, data[DELTA_TAR].vd.size, data[DELTA_DEL].fd) ? -1L : lseek(data[DELTA_DEL].fd, (off_t)0, SEEK_END);
1270 break;
1271 case DELTA_PATCH:
1272 error(1, "AHA %s %s/%s SRC=%d:%p TAR=%d:%p DEL=%d:%p", fp->name, ap->name, f->path, data[DELTA_SRC].vd.size, data[DELTA_SRC].vd.data, data[DELTA_TAR].vd.size, data[DELTA_TAR].vd.data, data[DELTA_DEL].vd.size, data[DELTA_DEL].vd.data);
1273 n = 0;
1274 break;
1275 }
1276 }
1277 else
1278 {
1279 if (!(data[DELTA_TAR].op & DELTA_FD))
1280 error(PANIC, "paxdelta: %s %s must be DELTA_TEMP or DELTA_FD", fp->name, dataname[DELTA_TAR]);
1281 for (op = 0; op < elementsof(data); op++)
1282 {
1283 if (op == DELTA_TAR) /*NOP*/;
1284 else if (!data[op].vd.size)
1285 {
1286 data[op].fd = 0;
1287 data[op].op &= ~DELTA_FREE;
1288 }
1289 else switch (data[op].op & (DELTA_BIO|DELTA_BUFFER|DELTA_OUTPUT))
1290 {
1291 case DELTA_BIO:
1292 if (!(data[op].vd.data = malloc(data[op].vd.size)))
1293 nospace();
1294 if (bread(data[op].bp, data[op].vd.data, data[op].vd.size, data[op].vd.size, 1) != data[op].vd.size)
1295 error(3, "%s: delta bread error", f->name);
1296 /*FALLTHROUGH*/
1297 case DELTA_BUFFER:
1298 if (!tmp) tmp = pathtemp(NiL, 0, NiL, error_info.id, NiL);
1299 if ((data[op].fd = open(tmp, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR)) < 0)
1300 error(3, "%s: cannot create delta temporary file", tmp);
1301 if (write(data[op].fd, data[op].vd.data, data[op].vd.size) != data[op].vd.size)
1302 error(ERROR_SYSTEM|3, "%s: delta write error", f->name);
1303 close(data[op].fd);
1304 if ((data[op].fd = open(tmp, O_RDONLY|O_BINARY)) < 0)
1305 error(ERROR_SYSTEM|3, "%s: cannot read delta temporary file", tmp);
1306 if (remove(tmp))
1307 error(ERROR_SYSTEM|1, "%s: cannot remove delta temporary file", tmp);
1308 if (data[op].op & DELTA_BUFFER)
1309 {
1310 if (data[op].op & DELTA_FREE)
1311 free(data[op].vd.data);
1312 data[op].vd.data = 0;
1313 }
1314 data[op].op &= ~(DELTA_BIO|DELTA_BUFFER);
1315 data[op].op |= DELTA_FD|DELTA_FREE;
1316 break;
1317 }
1318 }
1319 switch (fp->variant)
1320 {
1321 case DELTA_88:
1322 n = update(data[DELTA_SRC].fd, data[DELTA_SRC].base, data[DELTA_DEL].fd, data[DELTA_TAR].fd) ? -1L : lseek(data[DELTA_TAR].fd, (off_t)0, SEEK_END);
1323 break;
1324 case DELTA_PATCH:
1325 error(PANIC, "paxdelta: %s update not supported", fp->name);
1326 break;
1327 }
1328 }
1329 }
1330 break;
1331 default:
1332 if (gen != &data[DELTA_DEL] && !data[DELTA_SRC].vd.size && !data[DELTA_DEL].vd.size)
1333 n = 0;
1334 else if (gen == &data[DELTA_DEL])
1335 {
1336 n = vddelta((Vddisc_t*)&data[DELTA_SRC], (Vddisc_t*)&data[DELTA_TAR], (Vddisc_t*)&data[DELTA_DEL]);
1337 if (n == 15)
1338 f->delta.same = 1;
1339 }
1340 else
1341 n = vdupdate((Vddisc_t*)&data[DELTA_SRC], (Vddisc_t*)&data[DELTA_TAR], (Vddisc_t*)&data[DELTA_DEL]);
1342 break;
1343 }
1344 #if DEBUG
1345 if (mp)
1346 {
1347 message((-5, "%s %s: %s:%s return=%ld", gen == &data[DELTA_DEL] ? "delta" : "update", fp->name, f->name, sfstruse(mp), n));
1348 sfstrclose(mp);
1349 }
1350 #endif
1351 if (n < 0)
1352 {
1353 error(ERROR_SYSTEM|2, "%s: delta error", f->name);
1354 return -1;
1355 }
1356 f->uncompressed = f->st->st_size;
1357 f->st->st_size = n;
1358 for (op = 0; op < elementsof(data); op++)
1359 {
1360 if (data[op].op & DELTA_HOLE)
1361 holedone(data[op].fd);
1362 switch (data[op].op & (DELTA_BUFFER|DELTA_FD|DELTA_FREE))
1363 {
1364 case DELTA_BUFFER|DELTA_FREE:
1365 free(data[op].vd.data);
1366 break;
1367 case DELTA_FD|DELTA_FREE:
1368 if ((data[op].op & (DELTA_TEMP|DELTA_OUTPUT)) == DELTA_OUTPUT)
1369 closeout(ap, f, data[op].fd);
1370 else
1371 close(data[op].fd);
1372 if (data[op].vd.data)
1373 free(data[op].vd.data);
1374 break;
1375 }
1376 if (data[op].op & DELTA_COUNT)
1377 {
1378 ap->io->expand += n;
1379 if (data[op].op & DELTA_OUTPUT)
1380 setfile(ap, f);
1381 }
1382 if (data[op].op & DELTA_LIST)
1383 listentry(f);
1384 }
1385 if (gen->pfd)
1386 {
1387 if (bp = getbuffer(gen->fd))
1388 {
1389 *gen->pfd = gen->fd;
1390 bp->next = bp->base;
1391 }
1392 else
1393 {
1394 close(gen->fd);
1395 if ((*gen->pfd = open(state.tmp.file, O_RDONLY|O_BINARY)) < 0)
1396 error(ERROR_SYSTEM|3, "%s: cannot read delta temporary file", state.tmp.file);
1397 if (remove(state.tmp.file))
1398 error(ERROR_SYSTEM|1, "%s: cannot remove delta temporary file", state.tmp.file);
1399 }
1400 }
1401 return 0;
1402 }
1403