Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/pax/copy.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1987-2012 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 file copy support
26
*/
27
28
#include "pax.h"
29
30
/*
31
* copy files in from archive
32
*/
33
34
void
35
copyin(register Archive_t* ap)
36
{
37
register File_t* f = &ap->file;
38
39
deltabase(ap);
40
while (getprologue(ap))
41
{
42
while (getheader(ap, f))
43
{
44
if (selectfile(ap, f))
45
filein(ap, f);
46
else
47
fileskip(ap, f);
48
if (ap->info)
49
ap->info->checksum = ap->memsum;
50
gettrailer(ap, f);
51
}
52
if (!getepilogue(ap))
53
break;
54
}
55
deltaverify(ap);
56
}
57
58
/*
59
* copy a single file out to the archive
60
* called by ftwalk()
61
*/
62
63
int
64
copyout(register Ftw_t* ftw)
65
{
66
register Archive_t* ap = state.out;
67
register File_t* f = &ap->file;
68
69
if (getfile(ap, f, ftw))
70
{
71
if (selectfile(ap, f))
72
{
73
f->fd = openin(ap, f);
74
deltaout(NiL, ap, f);
75
}
76
else
77
ftw->status = FTW_SKIP;
78
}
79
return 0;
80
}
81
82
/*
83
* low level for copyout()
84
* if rfd<0 && st_size>0 then input from bread()
85
*/
86
87
void
88
fileout(register Archive_t* ap, register File_t* f)
89
{
90
register size_t m;
91
register ssize_t n;
92
register off_t c;
93
int err;
94
Buffer_t* bp;
95
96
if (f->delta.op == DELTA_verify)
97
ap->selected--;
98
else if (putheader(ap, f))
99
{
100
if (!ap->format->putdata || !(*ap->format->putdata)(&state, ap, f, f->fd))
101
{
102
err = 0;
103
c = f->st->st_size;
104
while (c > 0)
105
{
106
n = m = c > state.buffersize ? state.buffersize : c;
107
if (!err)
108
{
109
if (f->fd >= 0)
110
{
111
if ((n = read(f->fd, ap->io->next, m)) < 0 && errno == EIO)
112
{
113
static char* buf;
114
115
if (!buf)
116
{
117
n = 1024 * 8;
118
error(1, "EIO read error -- falling back to aligned reads");
119
if (!(buf = malloc(state.buffersize + n)))
120
nospace();
121
buf += n - (((ssize_t)buf) & (n - 1));
122
}
123
if ((n = read(f->fd, buf, m)) > 0)
124
memcpy(ap->io->next, buf, n);
125
}
126
}
127
else if (bp = getbuffer(f->fd))
128
{
129
memcpy(ap->io->next, bp->next, m);
130
if (f->extended && ap->convert[SECTION_CONTROL].f2a)
131
ccmapstr(ap->convert[SECTION_CONTROL].f2a, ap->io->next, m);
132
bp->next += m;
133
}
134
else if (bread(f->ap, ap->io->next, (off_t)0, (off_t)n, 1) <= 0)
135
n = -1;
136
}
137
if (n <= 0)
138
{
139
if (n)
140
error(ERROR_SYSTEM|2, "%s: read error", f->path);
141
else
142
error(2, "%s: file size changed", f->path);
143
memzero(ap->io->next, state.buffersize);
144
err = 1;
145
}
146
else
147
{
148
c -= n;
149
bput(ap, n);
150
}
151
}
152
}
153
puttrailer(ap, f);
154
}
155
if (f->fd >= 0)
156
closein(ap, f, f->fd);
157
}
158
159
/*
160
* low level for copyin()
161
*/
162
163
void
164
filein(register Archive_t* ap, register File_t* f)
165
{
166
register off_t c;
167
register int n;
168
register char* s;
169
int dfd;
170
int wfd;
171
long checksum;
172
Filter_t* fp;
173
Proc_t* pp;
174
Tv_t t1;
175
Tv_t t2;
176
struct stat st;
177
178
if (f->skip)
179
goto skip;
180
else if (state.list)
181
{
182
if (fp = filter(ap, f))
183
{
184
for (n = 0; s = fp->argv[n]; n++)
185
{
186
while (*s)
187
if (*s++ == '%' && *s == '(')
188
break;
189
if (*s)
190
{
191
s = fp->argv[n];
192
listprintf(state.tmp.str, ap, f, s);
193
if (!(fp->argv[n] = sfstruse(state.tmp.str)))
194
nospace();
195
break;
196
}
197
}
198
pp = procopen(*fp->argv, fp->argv, NiL, NiL, PROC_WRITE);
199
if (s)
200
fp->argv[n] = s;
201
if (!pp)
202
{
203
error(2, "%s: %s: cannot execute filter %s", ap->name, f->path, *fp->argv);
204
goto skip;
205
}
206
if (!ap->format->getdata || !(*ap->format->getdata)(&state, ap, f, pp->wfd))
207
{
208
checksum = 0;
209
for (c = f->st->st_size; c > 0; c -= n)
210
{
211
n = (c > state.buffersize) ? state.buffersize : c;
212
if (!(s = bget(ap, n, NiL)))
213
{
214
error(ERROR_SYSTEM|2, "%s: read error", f->name);
215
break;
216
}
217
if (write(pp->wfd, s, n) != n)
218
{
219
error(ERROR_SYSTEM|2, "%s: write error", f->name);
220
break;
221
}
222
if (ap->format->checksum)
223
checksum = (*ap->format->checksum)(&state, ap, f, s, n, checksum);
224
}
225
}
226
if (ap->format->checksum && checksum != f->checksum)
227
error(1, "%s: %s checksum error (0x%08x != 0x%08x)", f->name, ap->format->name, checksum, f->checksum);
228
/*
229
* explicitly ignore exit status
230
*/
231
232
procclose(pp);
233
return;
234
}
235
listentry(f);
236
goto skip;
237
}
238
else switch (f->delta.op)
239
{
240
case DELTA_create:
241
if (f->delta.base)
242
error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
243
if (ap->delta->format->flags & PSEUDO)
244
goto regular;
245
if ((wfd = openout(ap, f)) < 0)
246
goto skip;
247
else
248
paxdelta(NiL, ap, f, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, f->st->st_size, 0);
249
break;
250
case DELTA_update:
251
if (!f->delta.base || (unsigned long)f->delta.base->mtime.tv_sec >= (unsigned long)f->st->st_mtime)
252
error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
253
c = f->st->st_size;
254
if ((wfd = openout(ap, f)) < 0)
255
goto skip;
256
if (state.ordered)
257
{
258
if (!f->delta.base->uncompressed)
259
paxdelta(NiL, ap, f, DELTA_SRC|DELTA_BIO|DELTA_SIZE, ap->delta->base, f->delta.base->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0);
260
else if (!paxdelta(NiL, ap, f, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap->delta->base, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &dfd, 0))
261
paxdelta(NiL, ap, f, DELTA_SRC|DELTA_FD|DELTA_SIZE|DELTA_FREE, dfd, f->delta.base->uncompressed, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0);
262
}
263
else if (!f->delta.base->uncompressed)
264
paxdelta(NiL, ap, f, DELTA_SRC|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ap->delta->base->io->fd, f->delta.base->offset, f->delta.base->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0);
265
else if (!paxdelta(NiL, ap, f, DELTA_DEL|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ap->delta->base->io->fd, f->delta.base->offset, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &dfd, 0))
266
paxdelta(NiL, ap, f, DELTA_SRC|DELTA_FD|DELTA_SIZE|DELTA_FREE, dfd, f->delta.base->uncompressed, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0);
267
break;
268
case DELTA_verify:
269
if (!f->delta.base || f->delta.base->mtime.tv_sec != f->st->st_mtime)
270
error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
271
if ((*state.statf)(f->name, &st))
272
error(2, "%s: not copied from base archive", f->name);
273
else if (st.st_size != f->delta.base->size || state.modtime && tvcmp(tvmtime(&t1, &st), tvmtime(&t2, f->st)))
274
error(1, "%s: changed from base archive", f->name);
275
break;
276
case DELTA_delete:
277
if (!f->delta.base)
278
error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__);
279
/*FALLTHROUGH*/
280
default:
281
regular:
282
wfd = openout(ap, f);
283
if (wfd >= 0)
284
{
285
holeinit(wfd);
286
if (!ap->format->getdata || !(*ap->format->getdata)(&state, ap, f, wfd))
287
{
288
checksum = 0;
289
for (c = f->st->st_size; c > 0; c -= n)
290
{
291
n = (c > state.buffersize) ? state.buffersize : c;
292
if (!(s = bget(ap, n, NiL)))
293
{
294
error(ERROR_SYSTEM|2, "%s: read error", f->name);
295
break;
296
}
297
if (holewrite(wfd, s, n) != n)
298
{
299
error(ERROR_SYSTEM|2, "%s: write error", f->name);
300
break;
301
}
302
if (ap->format->checksum)
303
checksum = (*ap->format->checksum)(&state, ap, f, s, n, checksum);
304
}
305
}
306
holedone(wfd);
307
closeout(ap, f, wfd);
308
setfile(ap, f);
309
if (ap->format->checksum && checksum != f->checksum)
310
error(1, "%s: %s checksum error (0x%08x != 0x%08x)", f->name, ap->format->name, checksum, f->checksum);
311
}
312
else if (ap->format->getdata)
313
(*ap->format->getdata)(&state, ap, f, wfd);
314
else
315
{
316
if (wfd < -1)
317
listentry(f);
318
goto skip;
319
}
320
break;
321
}
322
listentry(f);
323
return;
324
skip:
325
fileskip(ap, f);
326
}
327
328
/*
329
* skip over archive member f file data
330
*/
331
332
void
333
fileskip(register Archive_t* ap, register File_t* f)
334
{
335
Member_t* d;
336
off_t n;
337
338
if (ap->delta && (d = (Member_t*)hashget(ap->delta->tab, f->name)))
339
d->info->delta.op = DELTA_delete;
340
if ((!ap->format->getdata || !(*ap->format->getdata)(&state, ap, f, -1)) && ((n = f->st->st_size) > 0 && f->type == X_IFREG || (n = f->datasize)) && bread(ap, NiL, (off_t)0, n, 1) < 0)
341
error(ERROR_SYSTEM|2, "%s: skip error", f->name);
342
}
343
344
/*
345
* single file copyin() and copyout() smashed together
346
* called by ftwalk()
347
*/
348
349
int
350
copyinout(Ftw_t* ftw)
351
{
352
register File_t* f = &state.out->file;
353
register char* s;
354
register off_t c;
355
register ssize_t n;
356
register int rfd;
357
register int wfd;
358
359
if (getfile(state.out, f, ftw) && selectfile(state.out, f))
360
{
361
s = f->name;
362
f->name = stash(&state.out->path.copy, NiL, state.pwdlen + f->namesize);
363
strcpy(strcopy(f->name, state.pwd), s + (*s == '/'));
364
if ((wfd = openout(state.out, f)) >= 0)
365
{
366
if ((rfd = openin(state.out, f)) >= 0)
367
{
368
#if defined(SEEK_DATA) && defined(SEEK_HOLE)
369
off_t data;
370
off_t hole;
371
int more;
372
373
data = 0;
374
more = 1;
375
while (more)
376
{
377
if ((hole = lseek(rfd, data, SEEK_HOLE)) < data)
378
{
379
hole = lseek(rfd, 0, SEEK_END);
380
more = 0;
381
}
382
while ((c = hole - data) > 0)
383
{
384
if (c > state.buffersize)
385
c = state.buffersize;
386
if (lseek(rfd, data, SEEK_SET) != data || (n = read(rfd, state.tmp.buffer, (size_t)c)) <= 0)
387
{
388
error(ERROR_SYSTEM|2, "%s: read error", f->name);
389
more = 0;
390
break;
391
}
392
if (lseek(wfd, data, SEEK_SET) != data || write(wfd, state.tmp.buffer, n) != n)
393
{
394
error(ERROR_SYSTEM|2, "%s: write error", f->name);
395
more = 0;
396
break;
397
}
398
state.out->io->count += n;
399
data += n;
400
}
401
if (!more)
402
break;
403
if ((data = lseek(rfd, hole, SEEK_DATA)) < hole)
404
{
405
if ((data = lseek(rfd, -1, SEEK_END)) < 0 || lseek(wfd, data, SEEK_SET) != data || write(wfd, "", 1) != 1)
406
error(ERROR_SYSTEM|2, "%s: write error", f->name);
407
state.out->io->count += 1;
408
break;
409
}
410
}
411
#else
412
holeinit(wfd);
413
for (c = f->st->st_size; c > 0; c -= n)
414
{
415
if ((n = read(rfd, state.tmp.buffer, (size_t)((c > state.buffersize) ? state.buffersize : c))) <= 0)
416
{
417
error(ERROR_SYSTEM|2, "%s: read error", f->name);
418
break;
419
}
420
if (holewrite(wfd, state.tmp.buffer, n) != n)
421
{
422
error(ERROR_SYSTEM|2, "%s: write error", f->name);
423
break;
424
}
425
state.out->io->count += n;
426
}
427
holedone(wfd);
428
#endif
429
closeout(state.out, f, wfd);
430
closein(state.out, f, rfd);
431
setfile(state.out, f);
432
listentry(f);
433
}
434
else
435
closeout(state.out, f, wfd);
436
}
437
else if (wfd != -1)
438
listentry(f);
439
}
440
return 0;
441
}
442
443
/*
444
* compare ft1 and ft2 for ftwalk() sort
445
*/
446
447
int
448
cmpftw(Ftw_t* ft1, Ftw_t* ft2)
449
{
450
return strcoll(ft1->name, ft2->name);
451
}
452
453
/*
454
* skip to the next unquoted occurrence of d in s
455
*/
456
457
static char*
458
skip(register char* s, register int d)
459
{
460
register int c;
461
register int q;
462
463
q = 0;
464
while (c = *s++)
465
if (c == q)
466
q = 0;
467
else if (c == '\\')
468
{
469
if (*s)
470
s++;
471
}
472
else if (!q)
473
{
474
if (c == d)
475
return s - 1;
476
else if (c == '"' || c == '\'')
477
q = c;
478
}
479
return 0;
480
}
481
482
/*
483
* copy files out using copyfile
484
*/
485
486
typedef int (*Ftw_cmp_t)(Ftw_t*, Ftw_t*);
487
488
void
489
copy(register Archive_t* ap, register int (*copyfile)(Ftw_t*))
490
{
491
register char* s;
492
register char* t;
493
register char* v;
494
register int c;
495
unsigned long flags;
496
char* mode;
497
char* mtime;
498
499
if (ap)
500
{
501
deltabase(ap);
502
if (ap->delta && ap->delta->format != ap->expected && ap->expected)
503
error(3, "%s: archive format %s does not match requested format %s", ap->name, ap->delta->format->name, ap->expected->name);
504
if (state.append || state.update)
505
{
506
ap->format = ap->delta->format;
507
if (!(ap->format->flags & APPEND))
508
error(3, "%s: archive format %s does support append/update", ap->name, ap->format->name);
509
if (state.update)
510
ap->update = ap->delta->tab;
511
ap->delta = 0;
512
ap->parent = 0;
513
ap->volume--;
514
}
515
putprologue(ap, state.append || state.update);
516
}
517
if (state.files)
518
ftwalk((char*)state.files, copyfile, state.ftwflags|FTW_MULTIPLE, state.exact ? (Ftw_cmp_t)0 : cmpftw);
519
else
520
{
521
sfopen(sfstdin, NiL, "rt");
522
sfset(sfstdin, SF_SHARE, 0);
523
mode = state.mode;
524
mtime = state.mtime;
525
for (;;)
526
{
527
if (s = state.peekfile)
528
{
529
state.peekfile = 0;
530
c = state.peeklen;
531
}
532
else if (!(s = sfgetr(sfstdin, '\n', 1)))
533
break;
534
else
535
c = sfvalue(sfstdin) - 1;
536
sfwrite(state.tmp.lst, s, c);
537
if (!(s = sfstruse(state.tmp.lst)))
538
nospace();
539
flags = state.ftwflags;
540
if (state.filter.line)
541
{
542
if (!(c = *s++))
543
continue;
544
state.filter.options = s;
545
if (!(s = skip(s, c)))
546
continue;
547
*s++ = 0;
548
state.filter.command = s;
549
if (!(s = skip(s, c)))
550
continue;
551
*s++ = 0;
552
state.filter.path = s;
553
if (!(s = skip(s, c)))
554
state.filter.name = state.filter.path;
555
else
556
{
557
*s++ = 0;
558
state.filter.name = s;
559
if (s = skip(s, c))
560
*s = 0;
561
}
562
s = state.filter.options;
563
for (;;)
564
{
565
if (t = strchr(s, ','))
566
*t = 0;
567
if (v = strchr(s, '='))
568
{
569
*v++ = 0;
570
c = strtol(v, NiL, 0);
571
}
572
else
573
c = 1;
574
if (s[0] == 'n' && s[1] == 'o')
575
{
576
s += 2;
577
c = !c;
578
}
579
if (streq(s, "logical") || streq(s, "physical"))
580
{
581
if (s[0] == 'p')
582
c = !c;
583
if (c)
584
flags &= ~(FTW_META|FTW_PHYSICAL);
585
else
586
{
587
flags &= ~(FTW_META);
588
flags |= FTW_PHYSICAL;
589
}
590
}
591
else if (streq(s, "mode"))
592
state.mode = v;
593
else if (streq(s, "mtime"))
594
state.mtime = v;
595
if (!t)
596
break;
597
s = t + 1;
598
}
599
s = state.filter.path;
600
state.filter.line = *state.filter.name ? 2 : 1;
601
}
602
c = *s ? ftwalk(s, copyfile, flags, NiL) : 0;
603
state.mode = mode;
604
state.mtime = mtime;
605
if (c)
606
{
607
error(2, "%s: not completely copied", s);
608
break;
609
}
610
}
611
}
612
if (ap)
613
{
614
deltadelete(ap);
615
putepilogue(ap);
616
}
617
}
618
619