Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/pax/format.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 archive format support
26
*/
27
28
#include "format.h"
29
30
Format_t* formats = pax_first_format;
31
32
/*
33
* read archive prologue before files are copied
34
* compression and input archive formats are identified here
35
*/
36
37
int
38
getprologue(register Archive_t* ap)
39
{
40
register Format_t* fp;
41
register File_t* f = &ap->file;
42
off_t skipped;
43
int n;
44
unsigned char buf[MAXUNREAD];
45
unsigned char cvt[MAXUNREAD];
46
47
message((-6, "getprologue() volume=%d eof=%d", ap->volume, ap->io->eof));
48
if (ap->io->eof || state.volume && (ap->io->mode & O_ACCMODE) == O_WRONLY)
49
return 0;
50
state.volume[0] = 0;
51
ap->entry = 0;
52
ap->format = 0;
53
ap->swapio = 0;
54
ap->io->offset += ap->io->count;
55
ap->io->count = 0;
56
ap->section = SECTION_CONTROL;
57
convert(ap, SECTION_CONTROL, CC_NATIVE, CC_NATIVE);
58
ap->sum++;
59
f->name = 0;
60
f->record.format = 0;
61
f->skip = 0;
62
ap->checkdelta = !ap->delta || ap->delta->format && !(ap->delta->format->flags & PSEUDO);
63
f->delta.base = 0;
64
f->uncompressed = 0;
65
f->delta.checksum = 0;
66
f->delta.index = 0;
67
if (state.append || state.update)
68
bsave(ap);
69
70
/*
71
* first check if input is compressed
72
*/
73
74
if ((n = bread(ap, (char*)buf, (off_t)0, (off_t)sizeof(buf), 0)) <= MINID && !bcount(ap))
75
{
76
if (n && ap->volume <= 0)
77
goto unknown;
78
return 0;
79
}
80
bunread(ap, buf, n);
81
if (CC_NATIVE != CC_ASCII)
82
ccmapm(cvt, buf, sizeof(cvt), CC_ASCII, CC_NATIVE);
83
message((-2, "identify format"));
84
if (ap->volume <= 0 && !ap->compress)
85
{
86
fp = 0;
87
while (fp = nextformat(fp))
88
if ((fp->flags & COMPRESS) && (*fp->getprologue)(&state, fp, ap, f, buf, sizeof(buf)) > 0)
89
{
90
Compress_format_t* cp;
91
Proc_t* proc;
92
long ops[3];
93
char* cmd[3];
94
95
message((-1, "%s compression", fp->name));
96
ap->compress = fp;
97
cp = (Compress_format_t*)fp->data;
98
if (bseek(ap, (off_t)0, SEEK_SET, 1))
99
error(3, "%s: %s input must be seekable", ap->name, ap->compress->name);
100
undoable(ap, ap->compress);
101
if (state.meter.on && ap == state.in && ap->uncompressed)
102
state.meter.size = ap->uncompressed;
103
cmd[0] = cp->undo[0];
104
cmd[1] = cp->undo[1];
105
cmd[2] = 0;
106
ops[0] = PROC_FD_DUP(ap->io->fd, 0, PROC_FD_PARENT|PROC_FD_CHILD);
107
if (ap->parent && !state.ordered)
108
{
109
if ((n = open(state.tmp.file, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR)) < 0)
110
error(ERROR_SYSTEM|3, "%s: cannot create %s base temporary file %s", ap->name, cp->undo[0], state.tmp.file);
111
ops[1] = PROC_FD_DUP(n, 1, PROC_FD_PARENT|PROC_FD_CHILD);
112
ops[2] = 0;
113
proc = procopen(*cmd, cmd, NiL, ops, 0);
114
}
115
else
116
{
117
ops[1] = 0;
118
proc = procopen(*cmd, cmd, NiL, ops, PROC_READ);
119
}
120
if (!proc)
121
error(3, "%s: cannot execute %s filter", ap->name, cp->undo[0]);
122
if (ap->parent && !state.ordered)
123
{
124
if (n = procclose(proc))
125
error(3, "%s: %s filter exit code %d", ap->name, cp->undo[0], n);
126
if ((ap->io->fd = open(state.tmp.file, O_RDONLY|O_BINARY)) < 0)
127
error(ERROR_SYSTEM|3, "%s: cannot read %s base temporary file %s", ap->name, cp->undo[0], state.tmp.file);
128
if (remove(state.tmp.file))
129
error(ERROR_SYSTEM|1, "%s: cannot remove %s base temporary file %s", ap->name, cp->undo[0], state.tmp.file);
130
}
131
else
132
{
133
List_t* p;
134
135
ap->io->fd = proc->rfd;
136
if (!(p = newof(0, List_t, 1, 0)))
137
nospace();
138
p->item = (void*)proc;
139
p->next = state.proc;
140
state.proc = p;
141
}
142
if ((n = bread(ap, (char*)buf, (off_t)0, (off_t)sizeof(buf), 0)) <= MINID && !bcount(ap))
143
return 0;
144
bunread(ap, buf, n);
145
break;
146
}
147
}
148
149
/*
150
* now identify the format
151
*/
152
153
if (!(fp = ap->expected))
154
{
155
skipped = 0;
156
ap->entry = 1;
157
for (;;)
158
{
159
fp = 0;
160
while (fp = nextformat(fp))
161
if ((fp->flags & ARCHIVE) && fp->getprologue)
162
{
163
message((-2, "check %s", fp->name));
164
convert(ap, SECTION_CONTROL, (fp->flags & CONV) ? CC_NATIVE : CC_ASCII, CC_NATIVE);
165
if ((n = (*fp->getprologue)(&state, fp, ap, f, ((fp->flags & CONV) || CC_NATIVE == CC_ASCII) ? buf : cvt, sizeof(buf))) < 0)
166
return 0;
167
if (n > 0)
168
break;
169
if (ap->data)
170
{
171
error(ERROR_PANIC|4, "%s: data!=0 on failed getprologue()", fp->name);
172
ap->data = 0;
173
}
174
ap->checksum = ap->old.checksum = ap->memsum = ap->old.memsum = 0;
175
}
176
if (fp)
177
break;
178
convert(ap, SECTION_CONTROL, CC_NATIVE, CC_NATIVE);
179
if (!state.keepgoing || ap->io->eof || bread(ap, buf, (off_t)0, (off_t)1, 0) < 1)
180
{
181
unknown:
182
if (ap->expected)
183
error(3, "%s: unknown input format -- %s expected", ap->name, ap->expected->name);
184
if (ap->volume)
185
{
186
error(1, "%s: junk data after volume %d", ap->name, ap->volume);
187
return 0;
188
}
189
error(3, "%s: unknown input format", ap->name);
190
}
191
skipped++;
192
}
193
ap->entry = 0;
194
if (skipped)
195
error(1, "%s: %I*d byte%s skipped before identifying %s format archive", ap->name, sizeof(skipped), skipped, skipped == 1 ? "" : "s", fp->name);
196
}
197
else if (!(fp->flags & ARCHIVE) || !fp->getprologue || (*fp->getprologue)(&state, fp, ap, f, buf, sizeof(buf)) <= 0)
198
error(3, "%s: %s: archive format mismatch", ap->name, fp->name);
199
if (!ap->format)
200
ap->format = fp;
201
if (!ap->type)
202
ap->type = ap->format->name;
203
message((-1, "%s format", ap->type));
204
if ((state.operation & IN) && !state.list && !(ap->format->flags & IN))
205
error(3, "%s: %s read not implemented", ap->name, ap->type);
206
if ((state.operation & OUT) && !(ap->format->flags & OUT))
207
error(3, "%s: %s write not implemented", ap->name, ap->type);
208
ap->flags = state.operation | (ap->format->flags & ~(IN|OUT));
209
ap->sum--;
210
ap->volume++;
211
if (ap->peek && (ap->checkdelta || ap->delta) && deltacheck(ap, f))
212
ap->peek = 0;
213
if (state.summary && state.verbose && ap->volume > 0)
214
{
215
if (ap->io->blok)
216
sfprintf(sfstderr, "BLOK ");
217
if (ap->parent)
218
sfprintf(sfstderr, "%s base %s", ap->parent->name, ap->name);
219
else
220
{
221
sfprintf(sfstderr, "%s", ap->name);
222
if (ap->volume > 1)
223
sfprintf(sfstderr, " volume %d", ap->volume);
224
}
225
if (state.volume[0])
226
sfprintf(sfstderr, " label %s", state.volume);
227
sfprintf(sfstderr, " in");
228
if (ap->package)
229
sfprintf(sfstderr, " %s", ap->package);
230
if (ap->compress)
231
sfprintf(sfstderr, " %s", ap->compress->name);
232
if (ap->delta && ap->delta->format)
233
sfprintf(sfstderr, " %s", ap->delta->format->name);
234
sfprintf(sfstderr, " %s format", ap->type);
235
if (ap->swapio)
236
sfprintf(sfstderr, " %s swapped", "unix\0nuxi\0ixun\0xinu" + 5 * ap->swapio);
237
sfprintf(sfstderr, "\n");
238
}
239
if (ap->volume > 1)
240
{
241
if (ap->delta)
242
{
243
if (state.operation == (IN|OUT) || !(ap->delta->format->flags & DELTA))
244
error(3, "%s: %s archive cannot be multi-volume", ap->name, ap->parent ? "base" : "delta");
245
ap->delta = 0;
246
}
247
248
/*
249
* no hard links between volumes
250
*/
251
252
hashfree(state.linktab);
253
if (!(state.linktab = hashalloc(NiL, HASH_set, HASH_ALLOCATE, HASH_namesize, sizeof(Fileid_t), HASH_name, "links", 0)))
254
error(3, "cannot re-allocate hard link table");
255
}
256
return 1;
257
}
258
259
/*
260
* set pseudo file header+trailer info
261
*/
262
263
void
264
setinfo(register Archive_t* ap, register File_t* f)
265
{
266
long n;
267
268
if (ap->delta && ap->delta->format)
269
{
270
if (ap->delta->format->variant != DELTA_IGNORE && ap->entry > 1 && f->st->st_mtime)
271
{
272
if ((n = f->st->st_mtime - ap->delta->index) < 0)
273
error(3, "%s: corrupt archive: %d extra file%s", ap->name, -n, n == -1 ? "" : "s");
274
else if (n > 0)
275
error(3, "%s: corrupt archive: %d missing file%s", ap->name, n, n == 1 ? "" : "s");
276
}
277
ap->delta->epilogue = 1;
278
}
279
}
280
281
/*
282
* output pseudo file header+trailer
283
*/
284
285
void
286
putinfo(register Archive_t* ap, char* file, unsigned long mtime, unsigned long checksum)
287
{
288
register File_t* f = &ap->file;
289
Sfio_t* np = 0;
290
Delta_format_t* dp;
291
292
if (!file)
293
{
294
if (!(np = sfstropen()))
295
nospace();
296
if (!ap->delta || ap->delta->format->variant == DELTA_88)
297
sfprintf(np, "DELTA");
298
else
299
{
300
sfprintf(np, "%c%s%c%c%c%s", INFO_SEP, ID, INFO_SEP, ap->delta->compress ? TYPE_COMPRESS : TYPE_DELTA, INFO_SEP, (dp = (Delta_format_t*)ap->delta->format->data) ? dp->variant : "");
301
if (state.ordered)
302
sfprintf(np, "%c%c", INFO_SEP, INFO_ORDERED);
303
}
304
sfprintf(np, "%c%c%c", INFO_SEP, INFO_SEP, INFO_SEP);
305
if (!(file = sfstruse(np)))
306
nospace();
307
}
308
initfile(ap, f, f->st, file, X_IFREG);
309
f->skip = 1;
310
f->st->st_mtime = mtime;
311
f->st->st_uid = DELTA_LO(checksum);
312
f->st->st_gid = DELTA_HI(checksum);
313
if (putheader(ap, f))
314
puttrailer(ap, f);
315
if (np)
316
sfstrclose(np);
317
}
318
319
/*
320
* write archive prologue before files are copied
321
*/
322
323
void
324
putprologue(register Archive_t* ap, int append)
325
{
326
message((-6, "putprologue()"));
327
ap->section = SECTION_CONTROL;
328
if (ap->delta && ap->delta->format->variant == DELTA_88)
329
ap->checksum = ap->old.checksum;
330
if (!(ap->format->flags & CONV))
331
{
332
convert(ap, SECTION_CONTROL, CC_NATIVE, CC_ASCII);
333
if (!ap->convert[0].on)
334
convert(ap, SECTION_DATA, CC_NATIVE, CC_NATIVE);
335
}
336
if ((!ap->format->putprologue || (*ap->format->putprologue)(&state, ap, append) >= 0) && !(ap->format->flags & DELTAINFO) && ap->delta && !(ap->delta->format->flags & PSEUDO))
337
{
338
if (ap->delta->base)
339
putinfo(ap, NiL, ap->delta->base->size, ap->delta->base->checksum);
340
else
341
putinfo(ap, NiL, 0, 0);
342
}
343
}
344
345
/*
346
* read archive epilogue after all files have been copied
347
*/
348
349
int
350
getepilogue(register Archive_t* ap)
351
{
352
register char* s;
353
register off_t n;
354
register int i;
355
unsigned int z;
356
int x;
357
char buf[BLOCKSIZE];
358
359
message((-6, "getepilogue()"));
360
ap->section = SECTION_CONTROL;
361
state.updated = ap->updated;
362
if (ap->delta && ap->delta->epilogue < 0)
363
error(3, "%s: corrupt archive: missing epilogue", ap->name);
364
if (state.append || state.update && (ap->io->mode & O_RDWR))
365
{
366
backup(ap);
367
return 0;
368
}
369
if (!ap->format->getepilogue || !(*ap->format->getepilogue)(&state, ap))
370
{
371
/*
372
* check for more volumes
373
* volumes begin on BLOCKSIZE boundaries
374
* separated by null byte filler
375
*/
376
377
if (ap->io->keep)
378
{
379
bskip(ap);
380
if (ap->io->eof)
381
ap->io->keep = 0;
382
else if (ap->io->keep > 0)
383
ap->io->keep--;
384
goto done;
385
}
386
x = 0;
387
z = 0;
388
i = 0;
389
if (!(n = roundof(ap->io->count, BLOCKSIZE) - ap->io->count) || bread(ap, buf, (off_t)0, (off_t)n, 0) > 0)
390
do
391
{
392
for (s = buf; s < buf + n && !*s; s++);
393
z += s - buf;
394
if (z >= BLOCKSIZE)
395
x = 1;
396
if (s < buf + n)
397
{
398
if (n == BLOCKSIZE)
399
{
400
if (!x && ap->format->event && (ap->format->events & PAX_EVENT_SKIP_JUNK))
401
{
402
if ((*ap->format->event)(&state, ap, NiL, buf, PAX_EVENT_SKIP_JUNK) > 0)
403
continue;
404
if (i)
405
error(1, "%s: %d junk block%s after volume %d", ap->name, i, i == 1 ? "" : "s", ap->volume);
406
}
407
bunread(ap, buf, BLOCKSIZE);
408
goto done;
409
}
410
if (ap->volume > 1)
411
error(1, "junk data after volume %d", ap->volume);
412
break;
413
}
414
n = BLOCKSIZE;
415
i++;
416
} while (bread(ap, buf, (off_t)0, n, 0) > 0);
417
bflushin(ap, 0);
418
}
419
done:
420
if (ap->format->done)
421
(*ap->format->done)(&state, ap);
422
ap->swapio = 0;
423
return 1;
424
}
425
426
/*
427
* write archive epilogue after files have been copied
428
*/
429
430
void
431
putepilogue(register Archive_t* ap)
432
{
433
register ssize_t n;
434
register off_t boundary;
435
436
message((-6, "putepilogue()"));
437
if (state.install.path)
438
{
439
if (sfclose(state.install.sp))
440
error(ERROR_SYSTEM|2, "%s: install temporary write error", state.install.path);
441
state.filter.line = 2;
442
state.filter.name = state.install.name;
443
state.filter.command = "";
444
ftwalk(state.install.path, copyout, state.ftwflags, NiL);
445
state.filter.line = 0;
446
}
447
if (state.checksum.path)
448
{
449
if (sfclose(state.checksum.sp))
450
error(ERROR_SYSTEM|2, "%s: checksum temporary write error", state.checksum.path);
451
sumclose(state.checksum.sum);
452
state.checksum.sum = 0;
453
state.filter.line = 2;
454
state.filter.name = state.checksum.name;
455
state.filter.command = "";
456
ftwalk(state.checksum.path, copyout, state.ftwflags, NiL);
457
state.filter.line = 0;
458
}
459
ap->section = SECTION_CONTROL;
460
if (ap->selected > state.selected)
461
{
462
state.selected = ap->selected;
463
if (ap->delta && (ap->delta->format->flags & DELTA))
464
{
465
if (ap->format->event && (ap->format->events & PAX_EVENT_DELTA_EXTEND))
466
(*ap->format->event)(&state, ap, NiL, NiL, PAX_EVENT_DELTA_EXTEND);
467
else
468
putinfo(ap, NiL, ap->delta->index + 1, 0);
469
}
470
if (!ap->format->putepilogue || (boundary = (*ap->format->putepilogue)(&state, ap)) <= 0)
471
boundary = ap->io->count;
472
if (n = ((ap->io->count > boundary) ? roundof(ap->io->count, boundary) : boundary) - ap->io->count)
473
{
474
memzero(state.tmp.buffer, n);
475
bwrite(ap, state.tmp.buffer, n);
476
}
477
bflushout(ap);
478
ap->volume++;
479
}
480
else
481
{
482
ap->io->count = ap->io->offset = 0;
483
ap->io->next = ap->io->buffer + ap->io->unread;
484
}
485
if (ap->format->done)
486
(*ap->format->done)(&state, ap);
487
}
488
489
/*
490
* get key [ug]id value
491
*/
492
493
static void
494
getkeyid(Archive_t* ap, File_t* f, int index, uid_t* ip, int d)
495
{
496
register Option_t* op;
497
498
op = &options[index];
499
if (op->level < 7)
500
{
501
if (op->entry == ap->entry)
502
*ip = op->temp.number;
503
else if (op->level > 0 && op->perm.string)
504
*ip = op->perm.number;
505
}
506
else if (op->level >= 8)
507
*ip = d;
508
}
509
510
/*
511
* get key name value
512
*/
513
514
static void
515
getkeyname(Archive_t* ap, File_t* f, int index, char** sp, uid_t* ip, int d)
516
{
517
register Option_t* op;
518
519
op = &options[index];
520
if (op->level < 7)
521
{
522
if (op->entry == ap->entry)
523
*sp = op->temp.string;
524
else if (op->level > 0 && op->perm.string)
525
*sp = op->perm.string;
526
}
527
else if (ip && op->level >= 8)
528
{
529
*sp = 0;
530
*ip = d;
531
}
532
}
533
534
/*
535
* get key size value
536
*/
537
538
static void
539
getkeysize(Archive_t* ap, File_t* f, int index, off_t* zp)
540
{
541
register Option_t* op;
542
543
NoP(f);
544
op = &options[index];
545
if (op->level < 7)
546
{
547
if (op->entry == ap->entry)
548
{
549
if (op->temp.string)
550
*zp = strtoll(op->temp.string, NiL, 10);
551
}
552
else if (op->level > 0)
553
{
554
if (op->perm.string)
555
*zp = strtoll(op->perm.string, NiL, 10);
556
}
557
}
558
}
559
560
/*
561
* get key time value
562
*/
563
564
static void
565
getkeytime(Archive_t* ap, File_t* f, int index)
566
{
567
register Option_t* op;
568
register Value_t* vp;
569
Tv_t tv;
570
571
NoP(f);
572
op = &options[index];
573
message((-5, "getkeytime %s level=%d entry=%d:%d", op->name, op->level, op->entry, ap->entry));
574
if (op->level < 7)
575
{
576
if (op->entry == ap->entry)
577
vp = &op->temp;
578
else if (op->level > 0)
579
vp = &op->perm;
580
else
581
return;
582
tv.tv_sec = vp->number;
583
tv.tv_nsec = vp->fraction;
584
if (!tv.tv_sec && !tv.tv_nsec && index != OPT_mtime)
585
tvgetmtime(&tv, f->st);
586
switch (index)
587
{
588
case OPT_atime:
589
tvsetatime(&tv, f->st);
590
break;
591
case OPT_mtime:
592
tvsetmtime(&tv, f->st);
593
break;
594
case OPT_ctime:
595
tvsetctime(&tv, f->st);
596
break;
597
}
598
}
599
else if (op->level >= 8)
600
{
601
tvgettime(&tv);
602
vp = &op->perm;
603
vp->number = tv.tv_sec;
604
vp->fraction = tv.tv_nsec;
605
}
606
}
607
608
/*
609
* read next archive entry header
610
*/
611
612
int
613
getheader(register Archive_t* ap, register File_t* f)
614
{
615
register char* s;
616
long i;
617
618
message((-6, "getheader()"));
619
ap->section = SECTION_CONTROL;
620
ap->sum++;
621
ap->entry++;
622
if (state.append || state.update)
623
bsave(ap);
624
if (!ap->peek)
625
{
626
f->delta.base = 0;
627
f->delta.checksum = 0;
628
f->delta.index = 0;
629
f->uncompressed = 0;
630
}
631
do
632
{
633
if (ap->peek)
634
ap->peek = 0;
635
else
636
{
637
f->name = 0;
638
f->record.format = 0;
639
f->skip = 0;
640
i = f->st->st_ino;
641
memset(f->st, 0, sizeof(*f->st));
642
f->st->st_ino = i;
643
f->st->st_nlink = 1;
644
if ((*ap->format->getheader)(&state, ap, f) <= 0)
645
{
646
ap->entry--;
647
return 0;
648
}
649
}
650
if (!f->name)
651
error(3, "%s: %s format entry %d.%d name not set", ap->name, ap->type, ap->volume, ap->entry);
652
} while ((ap->checkdelta || ap->delta) && deltacheck(ap, f));
653
ap->entries++;
654
getkeysize(ap, f, OPT_size, &f->st->st_size);
655
getkeytime(ap, f, OPT_mtime);
656
getkeytime(ap, f, OPT_atime);
657
getkeytime(ap, f, OPT_ctime);
658
getkeyid(ap, f, OPT_gid, &f->st->st_gid, state.gid);
659
getkeyname(ap, f, OPT_gname, &f->gidname, &f->st->st_gid, state.gid);
660
getkeyname(ap, f, OPT_path, &f->name, NiL, 0);
661
getkeyname(ap, f, OPT_linkpath, &f->linkpath, NiL, 0);
662
getkeyid(ap, f, OPT_uid, &f->st->st_uid, state.uid);
663
getkeyname(ap, f, OPT_uname, &f->uidname, &f->st->st_uid, state.uid);
664
if (!state.list)
665
setidnames(f);
666
if (f->name != ap->stash.head.string)
667
f->name = stash(&ap->stash.head, f->name, 0);
668
if (ap->flags & DOS)
669
undos(f);
670
f->type = X_ITYPE(f->st->st_mode);
671
s = pathcanon(f->name, 0, 0);
672
if (s > f->name + 1 && *--s == '/')
673
{
674
*s = 0;
675
if ((ap->format->flags & SLASHDIR) && f->type == X_IFREG)
676
{
677
f->st->st_mode &= ~X_IFREG;
678
f->st->st_mode |= (f->type = X_IFDIR);
679
f->datasize = f->st->st_size;
680
}
681
}
682
f->path = stash(&ap->path.name, f->name, 0);
683
f->name = map(ap, f->name);
684
f->namesize = strlen(f->name) + 1;
685
if (f->linkpath)
686
{
687
pathcanon(f->linkpath, 0, 0);
688
if (!(state.ftwflags & FTW_PHYSICAL))
689
f->linkpath = map(ap, f->linkpath);
690
f->linkpathsize = strlen(f->linkpath) + 1;
691
}
692
else
693
f->linkpathsize = 0;
694
f->perm = modei(f->st->st_mode);
695
f->ro = ropath(f->name);
696
getdeltaheader(ap, f);
697
#if DEBUG
698
if (error_info.trace)
699
{
700
s = &state.tmp.buffer[0];
701
if (f->record.format)
702
sfsprintf(s, state.tmp.buffersize, " [%c,%d,%d]", f->record.format, state.blocksize, state.record.size);
703
else
704
*s = 0;
705
message((-1, "archive=%s path=%s name=%s entry=%d.%d size=%I*u uncompressed=%I*u delta=%c%s", ap->name, f->path, f->name, ap->volume, ap->entry, sizeof(f->st->st_size), f->st->st_size, sizeof(f->uncompressed), f->uncompressed, f->delta.op ? f->delta.op : DELTA_nop, s));
706
}
707
#endif
708
if (ap->sum > 0)
709
{
710
if (ap->format->flags & SUM)
711
ap->memsum = FNV_INIT;
712
else if (!ap->delta || !ap->delta->trailer)
713
ap->memsum = 0;
714
ap->old.memsum = 0;
715
}
716
ap->section = SECTION_DATA;
717
ap->convert[ap->section].on = ap->convert[ap->section].f2t != 0;
718
return 1;
719
}
720
721
/*
722
* write next archive entry header
723
*/
724
725
int
726
putheader(register Archive_t* ap, register File_t* f)
727
{
728
register int n;
729
730
message((-6, "putheader()"));
731
if (!f->extended)
732
{
733
setdeltaheader(ap, f);
734
ap->entry++;
735
ap->entries++;
736
}
737
ap->section = SECTION_CONTROL;
738
if ((n = (*ap->format->putheader)(&state, ap, f)) < 0)
739
return -1;
740
if (!n)
741
{
742
if (!ap->incomplete)
743
return 0;
744
ap->incomplete = 0;
745
if ((ap->io->count + f->st->st_size) > state.maxout)
746
{
747
error(2, "%s: too large to fit in one volume", f->name);
748
return -1;
749
}
750
state.complete = 0;
751
putepilogue(ap);
752
newio(ap, 0, 0);
753
putprologue(ap, 0);
754
state.complete = 1;
755
if ((n = (*ap->format->putheader)(&state, ap, f)) <= 0)
756
return n;
757
}
758
putdeltaheader(ap, f);
759
if (state.checksum.sum)
760
suminit(state.checksum.sum);
761
ap->section = SECTION_DATA;
762
ap->convert[ap->section].on = ap->convert[ap->section].f2t != 0;
763
if (state.install.sp && !f->extended)
764
{
765
n = 0;
766
if (f->st->st_gid != state.gid && ((f->st->st_mode & S_ISGID) || (f->st->st_mode & S_IRGRP) && !(f->st->st_mode & S_IROTH) || (f->st->st_mode & S_IXGRP) && !(f->st->st_mode & S_IXOTH)))
767
{
768
sfprintf(state.install.sp, "chgrp %s %s\n", fmtgid(f->st->st_gid), f->name);
769
n = 1;
770
}
771
if (f->st->st_uid != state.uid && ((f->st->st_mode & S_ISUID) || (f->st->st_mode & S_IRUSR) && !(f->st->st_mode & (S_IRGRP|S_IROTH)) || (f->st->st_mode & S_IXUSR) && !(f->st->st_mode & (S_IXGRP|S_IXOTH))))
772
{
773
sfprintf(state.install.sp, "chown %s %s\n", fmtuid(f->st->st_uid), f->name);
774
n = 1;
775
}
776
if (n || (f->st->st_mode & (S_ISUID|S_ISGID)))
777
sfprintf(state.install.sp, "chmod %04o %s\n", modex(f->st->st_mode & S_IPERM), f->name);
778
}
779
return 1;
780
}
781
782
/*
783
* read entry trailer
784
*/
785
786
void
787
gettrailer(register Archive_t* ap, File_t* f)
788
{
789
register off_t n;
790
791
message((-6, "gettrailer()"));
792
NoP(f);
793
ap->section = SECTION_CONTROL;
794
if (ap->sum-- > 0)
795
{
796
ap->checksum ^= ap->memsum;
797
ap->old.checksum ^= ap->old.memsum;
798
}
799
if (ap->format->gettrailer)
800
(*ap->format->gettrailer)(&state, ap, f);
801
getdeltatrailer(ap, f);
802
if ((n = ap->format->align) && (n = roundof(ap->io->count, n) - ap->io->count))
803
bread(ap, state.tmp.buffer, (off_t)0, n, 1);
804
if (!(ap->format->flags & SUM) && ap->sum >= 0)
805
{
806
ap->memsum = 0;
807
ap->old.memsum = 0;
808
}
809
}
810
811
/*
812
* write entry trailer
813
*/
814
815
void
816
puttrailer(register Archive_t* ap, register File_t* f)
817
{
818
register int n;
819
char* s;
820
821
message((-6, "puttrailer()"));
822
if (state.checksum.sum && !f->extended)
823
{
824
sumdone(state.checksum.sum);
825
if (f->link)
826
{
827
if (!f->link->checksum)
828
{
829
sumprint(state.checksum.sum, state.tmp.str, 0, 0);
830
if (!(s = sfstruse(state.tmp.str)) || !(f->link->checksum = strdup(s)))
831
nospace();
832
}
833
sfputr(state.checksum.sp, f->link->checksum, -1);
834
}
835
else
836
sumprint(state.checksum.sum, state.checksum.sp, 0, 0);
837
sfprintf(state.checksum.sp, " %04o %s %s %s\n"
838
, modex(f->st->st_mode & S_IPERM)
839
, (f->st->st_uid != state.uid && ((f->st->st_mode & S_ISUID) || (f->st->st_mode & S_IRUSR) && !(f->st->st_mode & (S_IRGRP|S_IROTH)) || (f->st->st_mode & S_IXUSR) && !(f->st->st_mode & (S_IXGRP|S_IXOTH)))) ? fmtuid(f->st->st_uid) : "-"
840
, (f->st->st_gid != state.gid && ((f->st->st_mode & S_ISGID) || (f->st->st_mode & S_IRGRP) && !(f->st->st_mode & S_IROTH) || (f->st->st_mode & S_IXGRP) && !(f->st->st_mode & S_IXOTH))) ? fmtgid(f->st->st_gid) : "-"
841
, f->name
842
);
843
}
844
ap->section = SECTION_CONTROL;
845
putdeltatrailer(ap, f);
846
if (ap->format->puttrailer)
847
(*ap->format->puttrailer)(&state, ap, f);
848
if ((n = ap->format->align) && (n = roundof(ap->io->count, n) - ap->io->count))
849
{
850
memzero(state.tmp.buffer, n);
851
bwrite(ap, state.tmp.buffer, n);
852
}
853
listentry(f);
854
}
855
856