Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/pax/delta.c
1808 views
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 <[email protected]> *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1404