Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/pax/file.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 support
26
*/
27
28
#include "pax.h"
29
30
#include <tm.h>
31
32
/*
33
* "nocomment" is a hardwired "nocom"
34
* should be an sfio discipline
35
*/
36
37
#include "nocomment.c"
38
39
#if __STDC__
40
#define chmod(a,b) (error(-1,"%s#%d: chmod(%s,%05o)",__FILE__,__LINE__,a,b),chmod(a,b))
41
#endif
42
43
/*
44
* return read file descriptor for filtered current input file
45
*/
46
47
int
48
apply(register Archive_t* ap, register File_t* f, Filter_t* fp)
49
{
50
register int n;
51
char* arg;
52
int rfd;
53
int wfd;
54
55
if (state.filter.line <= 0)
56
arg = f->path;
57
else if (!*(arg = state.filter.command))
58
{
59
if ((rfd = open(f->st->st_size ? f->path : "/dev/null", O_RDONLY|O_BINARY)) < 0)
60
error(ERROR_SYSTEM|2, "%s: cannot read", f->path);
61
return rfd;
62
}
63
message((-4, "filter: %s %s", fp->command, f->path));
64
if ((wfd = open(state.tmp.file, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR)) < 0)
65
{
66
error(2, "%s: cannot create filter temporary %s", f->path, state.tmp.file);
67
return -1;
68
}
69
if ((rfd = open(state.tmp.file, O_RDONLY|O_BINARY)) < 0)
70
{
71
error(2, "%s: cannot open filter temporary %s", f->path, state.tmp.file);
72
close(wfd);
73
if (remove(state.tmp.file))
74
error(1, "%s: cannot remove filter temporary %s", f->path, state.tmp.file);
75
return -1;
76
}
77
if (remove(state.tmp.file))
78
error(1, "%s: cannot remove filter temporary %s", f->path, state.tmp.file);
79
if (ap->format->checksum)
80
f->checksum = 0;
81
f->st->st_size = 0;
82
if (streq(*fp->argv, "nocomment"))
83
{
84
int errors = error_info.errors;
85
off_t count;
86
Sfio_t* ip;
87
Sfio_t* op;
88
89
if ((ip = sfopen(NiL, f->path, "r")) && (op = sfnew(NiL, NiL, SF_UNBOUND, wfd, SF_WRITE)) && (count = nocomment(ip, op)) < 0)
90
error(2, "%s: %s: filter error", f->path, *fp->argv);
91
if (ip)
92
{
93
sfclose(ip);
94
if (op)
95
sfclose(op);
96
else
97
error(2, "%s: cannot redirect filter", f->path);
98
}
99
else
100
error(2, "%s: cannot read", f->path);
101
if (errors != error_info.errors)
102
{
103
close(rfd);
104
close(wfd);
105
return -1;
106
}
107
f->st->st_size = count;
108
}
109
else
110
{
111
Proc_t* proc;
112
113
*fp->patharg = arg;
114
if (!(proc = procopen(*fp->argv, fp->argv, NiL, NiL, PROC_READ)))
115
{
116
error(2, "%s: cannot execute filter %s", f->path, *fp->argv);
117
close(rfd);
118
close(wfd);
119
return -1;
120
}
121
holeinit(wfd);
122
while ((n = read(proc->rfd, state.tmp.buffer, state.buffersize)) > 0)
123
{
124
if (holewrite(wfd, state.tmp.buffer, n) != n)
125
{
126
error(2, "%s: filter write error", f->path);
127
break;
128
}
129
if (ap->format->checksum)
130
f->checksum = (*ap->format->checksum)(&state, ap, f, state.tmp.buffer, n, f->checksum);
131
f->st->st_size += n;
132
}
133
holedone(wfd);
134
if (n < 0)
135
error(ERROR_SYSTEM|2, "%s: %s filter read error", f->path, *fp->argv);
136
if (n = procclose(proc))
137
error(2, "%s: %s filter exit code %d", f->path, *fp->argv, n);
138
}
139
close(wfd);
140
message((-1, "%s: filter file size = %ld", f->path, f->st->st_size));
141
return rfd;
142
}
143
144
/*
145
* return read file descriptor for current input file
146
*/
147
148
int
149
openin(register Archive_t* ap, register File_t* f)
150
{
151
register int n;
152
Filter_t* fp;
153
int rfd;
154
155
if (f->type != X_IFREG)
156
rfd = -1;
157
else if (fp = filter(ap, f))
158
rfd = apply(ap, f, fp);
159
else if ((rfd = open(f->st->st_size ? f->path : "/dev/null", O_RDONLY|O_BINARY)) < 0)
160
error(ERROR_SYSTEM|2, "%s: cannot read", f->path);
161
else if (ap->format->checksum)
162
{
163
f->checksum = 0;
164
if (lseek(rfd, (off_t)0, SEEK_SET) != 0)
165
error(ERROR_SYSTEM|1, "%s: %s checksum seek error", f->path, ap->format->name);
166
else
167
{
168
while ((n = read(rfd, state.tmp.buffer, state.buffersize)) > 0)
169
f->checksum = (*ap->format->checksum)(&state, ap, f, state.tmp.buffer, n, f->checksum);
170
if (n < 0)
171
error(ERROR_SYSTEM|2, "%s: %s checksum read error", f->path, ap->format->name);
172
if (lseek(rfd, (off_t)0, SEEK_SET) != 0)
173
error(ERROR_SYSTEM|1, "%s: %s checksum seek error", f->path, ap->format->name);
174
}
175
}
176
if (rfd < 0)
177
f->st->st_size = 0;
178
return rfd;
179
}
180
181
/*
182
* create directory and all path name components leading to directory
183
*/
184
185
static int
186
missdir(register Archive_t* ap, register File_t* f)
187
{
188
register char* s;
189
register char* t;
190
long pp;
191
struct stat* st;
192
struct stat* sp;
193
struct stat st0;
194
struct stat st1;
195
196
s = f->name;
197
pathcanon(s, 0, 0);
198
if (t = strchr(*s == '/' ? s + 1 : s, '/'))
199
{
200
if (!state.mkdir)
201
{
202
if (!state.warnmkdir)
203
{
204
state.warnmkdir = 1;
205
error(1, "omit the --nomkdir option to create intermediate directories");
206
}
207
return -1;
208
}
209
st = 0;
210
sp = &st0;
211
do
212
{
213
*t = 0;
214
if (stat(s, sp))
215
{
216
*t = '/';
217
break;
218
}
219
*t = '/';
220
st = sp;
221
sp = (sp == &st0) ? &st1 : &st0;
222
} while (t = strchr(t + 1, '/'));
223
if (t)
224
{
225
if (!st && stat(".", st = &st0))
226
error(ERROR_SYSTEM|3, "%s: cannot stat .", s);
227
pp = f->perm;
228
f->perm = st->st_mode & state.modemask;
229
sp = f->st;
230
f->st = st;
231
do
232
{
233
*t = 0;
234
if (mkdir(s, f->perm))
235
{
236
error(ERROR_SYSTEM|2, "%s: cannot create directory", s);
237
*t = '/';
238
f->perm = pp;
239
f->st = sp;
240
return -1;
241
}
242
setfile(ap, f);
243
*t = '/';
244
} while (t = strchr(t + 1, '/'));
245
f->perm = pp;
246
f->st = sp;
247
}
248
}
249
return 0;
250
}
251
252
/*
253
* open file for writing, set all necessary info
254
*/
255
256
int
257
openout(register Archive_t* ap, register File_t* f)
258
{
259
register int fd;
260
int exists;
261
int perm;
262
int c;
263
Tv_t t1;
264
Tv_t t2;
265
size_t updated;
266
struct stat st;
267
268
pathcanon(f->name, 0, 0);
269
270
/*
271
* if not found and state.update then check down the view
272
*
273
* NOTE: VPATH in app code is ugly but the benefits of the
274
* combination with state.update win over beauty
275
*/
276
277
if (f->ro)
278
{
279
f->name = "PAX-INTERNAL-ERROR";
280
f->skip = 1;
281
exists = 0;
282
}
283
else if (exists = !(*state.statf)(f->name, &st))
284
{
285
if (!state.clobber && !S_ISDIR(st.st_mode))
286
{
287
error(1, "%s: already exists -- not overwritten", f->name);
288
return -1;
289
}
290
f->chmod = f->perm != (st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) &&
291
(state.chmod || state.update || S_ISDIR(st.st_mode));
292
st.st_mode = modex(st.st_mode);
293
}
294
else
295
{
296
typedef struct View
297
{
298
struct View* next;
299
char* root;
300
dev_t dev;
301
ino_t ino;
302
} View_t;
303
304
View_t* vp;
305
View_t* tp;
306
char* s;
307
char* e;
308
309
static View_t* view;
310
static char* offset;
311
312
if (state.update && !offset)
313
{
314
if (s = getenv("VPATH"))
315
{
316
if (!(s = strdup(s)))
317
nospace();
318
do
319
{
320
if (e = strchr(s, ':'))
321
*e++ = 0;
322
if (!(vp = newof(0, View_t, 1, 0)))
323
nospace();
324
vp->root = s;
325
if (stat(s, &st))
326
{
327
vp->dev = 0;
328
vp->ino = 0;
329
}
330
else
331
{
332
vp->dev = st.st_dev;
333
vp->ino = st.st_ino;
334
}
335
if (view)
336
tp = tp->next = vp;
337
else
338
view = tp = vp;
339
} while (s = e);
340
s = state.pwd;
341
e = 0;
342
for (;;)
343
{
344
if (stat(s, &st))
345
error(ERROR_SYSTEM|3, "%s: cannot stat pwd component", s);
346
for (vp = view; vp; vp = vp->next)
347
if (vp->ino == st.st_ino && vp->dev == st.st_dev)
348
{
349
offset = e ? e + 1 : ".";
350
tp = view;
351
view = vp->next;
352
while (tp && tp != view)
353
{
354
vp = tp;
355
tp = tp->next;
356
free(vp);
357
}
358
if (e)
359
*e = '/';
360
goto found;
361
}
362
if (e)
363
*e = '/';
364
else
365
e = s + strlen(s);
366
while (e > s && *--e != '/');
367
if (e <= s)
368
break;
369
*e = 0;
370
}
371
}
372
found:
373
if (!offset)
374
offset = ".";
375
}
376
st.st_mode = 0;
377
st.st_mtime = 0;
378
if (*f->name != '/')
379
for (vp = view; vp; vp = vp->next)
380
{
381
sfsprintf(state.tmp.buffer, state.tmp.buffersize - 1, "%s/%s/%s", vp->root, offset, f->name);
382
if (!stat(state.tmp.buffer, &st))
383
break;
384
}
385
f->chmod = state.chmod || state.update;
386
}
387
if (f->delta.op == DELTA_delete)
388
{
389
if (exists)
390
switch (X_ITYPE(st.st_mode))
391
{
392
case X_IFDIR:
393
if (!f->ro)
394
{
395
if (rmdir(f->name))
396
error(ERROR_SYSTEM|2, "%s: cannot remove directory", f->name);
397
else
398
listentry(f);
399
}
400
break;
401
default:
402
if (remove(f->name))
403
error(ERROR_SYSTEM|2, "%s: cannot remove file", f->name);
404
else
405
listentry(f);
406
break;
407
}
408
return -1;
409
}
410
if (state.operation == (IN|OUT))
411
{
412
if (exists && f->st->st_ino == st.st_ino && f->st->st_dev == st.st_dev)
413
{
414
error(2, "attempt to pass %s to self", f->name);
415
return -1;
416
}
417
if (state.linkf && f->type != X_IFDIR && (state.linkf == pathsetlink || f->st->st_dev == state.dev))
418
{
419
if (exists)
420
remove(f->name);
421
if ((*state.linkf)(f->path, f->name))
422
{
423
if (!exists && missdir(ap, f))
424
{
425
error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
426
return -1;
427
}
428
if (exists || (*state.linkf)(f->path, f->name))
429
{
430
error(ERROR_SYSTEM|2, "%s: cannot link to %s", f->path, f->name);
431
return -1;
432
}
433
}
434
setfile(ap, f);
435
return -2;
436
}
437
}
438
switch (f->type)
439
{
440
case X_IFDIR:
441
if (!(ap->format->flags & KEEPSIZE))
442
f->st->st_size = 0;
443
if (f->ro)
444
return -1;
445
if (exists && X_ITYPE(st.st_mode) != X_IFDIR)
446
{
447
if (remove(f->name))
448
{
449
error(ERROR_SYSTEM|2, "cannot remove current %s", f->name);
450
return -1;
451
}
452
exists = 0;
453
}
454
if (!exists && mkdir(f->name, f->perm) && (missdir(ap, f) || mkdir(f->name, f->perm)))
455
{
456
error(ERROR_SYSTEM|2, "%s: cannot create directory", f->name);
457
return -1;
458
}
459
updated = ap->updated;
460
setfile(ap, f);
461
if (!exists || f->chmod || state.update && ((c = tvcmp(tvmtime(&t1, f->st), tvmtime(&t2, &st))) > 0 || state.update == OPT_different && c))
462
{
463
listentry(f);
464
fd = -1;
465
}
466
else
467
{
468
ap->updated = updated;
469
if (state.update)
470
fd = -1;
471
else
472
fd = -2;
473
}
474
return fd;
475
case X_IFLNK:
476
if (exists && prune(ap, f, &st))
477
return -1;
478
if (!*f->linkpath)
479
return -2;
480
if (streq(f->name, f->linkpath))
481
{
482
error(1, "%s: symbolic link loops to self", f->name);
483
return -1;
484
}
485
if (exists && remove(f->name))
486
{
487
error(ERROR_SYSTEM|2, "cannot remove current %s", f->name);
488
return -1;
489
}
490
if (pathsetlink(f->linkpath, f->name))
491
{
492
if (!exists && missdir(ap, f))
493
{
494
error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
495
return -1;
496
}
497
if (exists || pathsetlink(f->linkpath, f->name))
498
{
499
error(ERROR_SYSTEM|2, "%s: cannot symlink to %s", f->name, f->linkpath);
500
return -1;
501
}
502
}
503
setfile(ap, f);
504
listentry(f);
505
return -1;
506
case X_IFSOCK:
507
IDEVICE(f->st, 0);
508
/*FALLTHROUGH*/
509
case X_IFBLK:
510
case X_IFCHR:
511
case X_IFIFO:
512
if (exists && (prune(ap, f, &st) || state.update && f->st->st_dev != st.st_dev))
513
return -1;
514
if (!(ap->format->flags & KEEPSIZE))
515
f->st->st_size = 0;
516
break;
517
case X_IFREG:
518
if (exists && prune(ap, f, &st))
519
return -1;
520
break;
521
}
522
if (!addlink(ap, f))
523
return -1;
524
switch (f->type)
525
{
526
case X_IFIFO:
527
if (exists && remove(f->name))
528
{
529
error(ERROR_SYSTEM|2, "cannot remove current %s", f->name);
530
return -1;
531
}
532
if (mkfifo(f->name, f->st->st_mode & S_IPERM))
533
{
534
if (errno == EPERM)
535
{
536
nofifo:
537
error(ERROR_SYSTEM|2, "%s: cannot create fifo file", f->name);
538
return -1;
539
}
540
if (!exists && missdir(ap, f))
541
{
542
error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
543
return -1;
544
}
545
if (exists || mkfifo(f->name, f->st->st_mode & S_IPERM))
546
goto nofifo;
547
}
548
setfile(ap, f);
549
return -2;
550
case X_IFSOCK:
551
IDEVICE(f->st, 0);
552
/*FALLTHROUGH*/
553
case X_IFBLK:
554
case X_IFCHR:
555
if (exists && remove(f->name))
556
{
557
error(ERROR_SYSTEM|2, "cannot remove current %s", f->name);
558
return -1;
559
}
560
if (mknod(f->name, f->st->st_mode, idevice(f->st)))
561
{
562
if (errno == EPERM)
563
{
564
nospecial:
565
error(ERROR_SYSTEM|2, "%s: cannot create %s special file", f->name, (f->type == X_IFBLK) ? "block" : "character");
566
return -1;
567
}
568
if (!exists && missdir(ap, f))
569
{
570
error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
571
return -1;
572
}
573
if (exists || mknod(f->name, f->st->st_mode, idevice(f->st)))
574
goto nospecial;
575
}
576
setfile(ap, f);
577
return -2;
578
default:
579
error(1, "%s: unknown file type 0%03o -- creating regular file", f->name, f->type >> 12);
580
/*FALLTHROUGH*/
581
case X_IFREG:
582
if (f->ro)
583
return dup(1);
584
if (state.intermediate)
585
{
586
char* d;
587
char* e;
588
int n;
589
int ifd;
590
591
/*
592
* copy to intermediate output file and rename
593
* to real file only on success - a handy
594
* backup option
595
*
596
* thanks to the amazing dr. ek
597
*/
598
599
if (missdir(ap, f))
600
{
601
error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
602
return -1;
603
}
604
d = (e = strrchr(f->name, '/')) ? f->name : ".";
605
for (n = 0;; n++)
606
{
607
if (e)
608
*e = 0;
609
f->intermediate = pathtemp(ap->path.temp, sizeof(ap->path.temp), d, error_info.id, &ifd);
610
if (e)
611
*e = '/';
612
message((-4, "%s: intermediate %s", f->name, f->intermediate));
613
if (f->intermediate)
614
{
615
ap->errors = error_info.errors;
616
return ifd;
617
}
618
if (n)
619
{
620
error(ERROR_SYSTEM|2, "%s: cannot create intermediate name", f->name);
621
return -1;
622
}
623
}
624
}
625
626
/*
627
* ok, the exists bits are only used right here
628
* you do the defines if its that important
629
*
630
* <chmod u+w><remove><missdir>
631
* 4 don't attempt
632
* 2 attempted and succeeded
633
* 1 attempted and failed
634
*/
635
636
if (!exists)
637
exists |= 0440;
638
else if (!state.linkf)
639
exists |= remove(f->name) ? 0010 : 0420;
640
else if (st.st_mode & S_IWUSR)
641
exists |= 0400;
642
if ((perm = f->perm) & (S_ISUID|S_ISGID|S_ISVTX))
643
perm &= ~(S_ISUID|S_ISGID|S_ISVTX);
644
while ((fd = open(f->name, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, perm)) < 0)
645
{
646
again:
647
if (!(exists & 0007))
648
{
649
if (missdir(ap, f))
650
{
651
error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
652
return -1;
653
}
654
exists |= 0002;
655
}
656
else if (!(exists & 0700))
657
{
658
if (chmod(f->name, perm | S_IWUSR))
659
{
660
exists |= 0100;
661
goto again;
662
}
663
exists |= 0200;
664
}
665
else if (!(exists & 0070))
666
{
667
if (remove(f->name))
668
{
669
exists |= 0010;
670
goto again;
671
}
672
exists ^= 0620;
673
}
674
else
675
{
676
error(ERROR_SYSTEM|2, "%s: cannot create%s%s", f->name, (exists & 0100) ? ERROR_translate(0, 0, 0, ", cannot enable user write") : "", (exists & 0010) ? ERROR_translate(0, 0, 0, ", cannot remove") : "");
677
return -1;
678
}
679
}
680
if (perm != f->perm)
681
f->chmod = 1;
682
else if ((exists & 0200) && chmod(f->name, f->perm))
683
error(ERROR_SYSTEM|1, "%s: cannot restore original mode %s", f->name, fmtperm(st.st_mode & S_IPERM));
684
return fd;
685
}
686
}
687
688
/*
689
* close an openin() fd, doing atime reset if necessary
690
*/
691
692
int
693
closein(register Archive_t* ap, register File_t* f, int fd)
694
{
695
int r;
696
697
r = 0;
698
if (close(fd))
699
r = -1;
700
if (state.resetacctime && f->type != X_IFLNK && !f->skip)
701
{
702
Tv_t av;
703
Tv_t mv;
704
705
tvgetatime(&av, f->st);
706
tvgetmtime(&mv, f->st);
707
settime(f->path, &av, &mv, NiL);
708
}
709
return r;
710
}
711
712
/*
713
* close an openout() fd, doing the intermediate rename if needed
714
*/
715
716
int
717
closeout(register Archive_t* ap, register File_t* f, int fd)
718
{
719
register char* s;
720
int r;
721
722
r = 0;
723
if (state.sync && fsync(fd))
724
r = -1;
725
if (close(fd))
726
r = -1;
727
if (s = f->intermediate)
728
{
729
f->intermediate = 0;
730
if (ap->errors != error_info.errors)
731
{
732
if (remove(s))
733
error(ERROR_SYSTEM|2, "%s: cannot remove intermediate file %s", f->name, s);
734
return -1;
735
}
736
if (rename(s, f->name) && (remove(f->name) || rename(s, f->name)))
737
{
738
error(ERROR_SYSTEM|2, "%s: cannot rename from intermediate file %s", f->name, s);
739
return -1;
740
}
741
if (chmod(f->name, f->perm))
742
{
743
error(ERROR_SYSTEM|1, "%s: cannot change mode to %s", f->name, fmtperm(f->perm));
744
return -1;
745
}
746
}
747
return r;
748
}
749
750
/*
751
* get file info for output
752
*/
753
754
int
755
getfile(register Archive_t* ap, register File_t* f, register Ftw_t* ftw)
756
{
757
register char* name;
758
register int n;
759
char* e;
760
761
name = ftw->path;
762
message((-4, "getfile(%s)", name));
763
switch (ftw->info)
764
{
765
case FTW_NS:
766
error(2, "%s: not found", name);
767
return 0;
768
case FTW_DNR:
769
if (state.files)
770
error(2, "%s: cannot read directory", name);
771
break;
772
case FTW_D:
773
case FTW_DNX:
774
case FTW_DP:
775
if (!state.descend)
776
ftw->status = FTW_SKIP;
777
else if (ftw->info == FTW_DNX)
778
{
779
error(2, "%s: cannot search directory", name);
780
ftw->status = FTW_SKIP;
781
}
782
else if (!state.files)
783
{
784
/*
785
* stdin files most likely come from tw/find with
786
* directory descendents already included; in posix
787
* omitting -d would result in duplicate output copies
788
* so we avoid the problem by peeking ahead and
789
* pruning all paths with this dir prefix
790
*/
791
792
n = ftw->pathlen;
793
name = stash(&ap->path.peek, name, n);
794
name[n] = '/';
795
if (!state.peekfile || !strncmp(state.peekfile, name, n))
796
while (state.peekfile = sfgetr(sfstdin, '\n', 1))
797
if (strncmp(state.peekfile, name, n))
798
{
799
state.peeklen = sfvalue(sfstdin) - 1;
800
break;
801
}
802
name[n] = 0;
803
}
804
break;
805
}
806
if (ap->delta)
807
ap->delta->hdr = ap->delta->hdrbuf;
808
name = stash(&ap->path.name, name, ftw->pathlen);
809
pathcanon(name, 0, 0);
810
f->path = stash(&ap->path.path, name, ftw->pathlen);
811
f->name = map(ap, name);
812
if (state.files && state.operation == (IN|OUT) && dirprefix(state.destination, name, 0))
813
return 0;
814
f->namesize = strlen(f->name) + 1;
815
ap->st = ftw->statb;
816
f->st = &ap->st;
817
f->perm = f->st->st_mode & S_IPERM;
818
f->st->st_mode = modex(f->st->st_mode);
819
f->uidname = 0;
820
f->gidname = 0;
821
f->link = 0;
822
if ((f->type = X_ITYPE(f->st->st_mode)) == X_IFLNK)
823
{
824
f->linkpathsize = f->st->st_size + 1;
825
f->linkpath = stash(&ap->stash.link, NiL, f->linkpathsize);
826
if (pathgetlink(f->path, f->linkpath, f->linkpathsize) != f->st->st_size)
827
{
828
error(2, "%s: cannot read symbolic link", f->path);
829
ftw->status = FTW_SKIP;
830
return 0;
831
}
832
f->linktype = SOFTLINK;
833
pathcanon(f->linkpath, 0, 0);
834
if (!(state.ftwflags & FTW_PHYSICAL))
835
f->linkpath = map(ap, f->linkpath);
836
if (streq(f->path, f->linkpath))
837
{
838
error(2, "%s: symbolic link loops to self", f->path);
839
ftw->status = FTW_SKIP;
840
return 0;
841
}
842
}
843
else
844
{
845
f->linktype = NOLINK;
846
f->linkpath = 0;
847
f->linkpathsize = 0;
848
}
849
f->ro = ropath(f->name);
850
if (!validout(ap, f))
851
return 0;
852
if (!(state.operation & IN) && f->type != X_IFDIR)
853
{
854
if (!addlink(ap, f) && !state.header.linkdata)
855
f->st->st_size = 0;
856
message((-4, "getfile(%s): dev'=%d ino'=%d", f->name, f->st->st_dev, f->st->st_ino));
857
}
858
ap->entries++;
859
f->delta.op = 0;
860
f->longname = 0;
861
f->longlink = 0;
862
f->skip = 0;
863
if (state.mode)
864
{
865
f->st->st_mode = strperm(state.mode, &e, f->st->st_mode);
866
if (*e)
867
error(2, "%s: invalid mode expression", state.mode);
868
}
869
if (state.mtime)
870
{
871
f->st->st_mtime = tmdate(state.mtime, &e, NiL);
872
if (*e)
873
error(2, "%s: invalid mtime", state.mtime);
874
}
875
message((-2, "getfile(): path=%s name=%s mode=%s size=%I*d mtime=%s", name, f->name, fmtmode(f->st->st_mode, 1), sizeof(f->st->st_size), f->st->st_size, fmttime("%K", f->st->st_mtime)));
876
return 1;
877
}
878
879
/*
880
* check that f is valid for archive output
881
*/
882
883
int
884
validout(register Archive_t* ap, register File_t* f)
885
{
886
if (f->ro)
887
return 0;
888
switch (f->type)
889
{
890
case X_IFBLK:
891
case X_IFCHR:
892
f->st->st_size = 0;
893
break;
894
case X_IFREG:
895
IDEVICE(f->st, 0);
896
break;
897
case X_IFDIR:
898
case X_IFIFO:
899
case X_IFLNK:
900
f->st->st_size = 0;
901
IDEVICE(f->st, 0);
902
break;
903
}
904
return ap->format->validate ? ((*ap->format->validate)(&state, ap, f) > 0) : 1;
905
}
906
907
/*
908
* add file which may be a link
909
* 0 returned if <dev,ino> already added
910
*/
911
912
int
913
addlink(register Archive_t* ap, register File_t* f)
914
{
915
register Link_t* p;
916
register char* s;
917
int n;
918
Fileid_t id;
919
unsigned short us;
920
921
id.dev = f->st->st_dev;
922
id.ino = f->st->st_ino;
923
if (!ap->delta)
924
switch (state.operation)
925
{
926
case IN:
927
us = id.dev;
928
if (us > state.devcnt)
929
{
930
state.devcnt = us;
931
state.inocnt = id.ino;
932
}
933
else if (us == state.devcnt)
934
{
935
us = id.ino;
936
if (us > state.inocnt)
937
state.inocnt = us;
938
}
939
break;
940
case IN|OUT:
941
if (!state.pass)
942
break;
943
/*FALLTHROUGH*/
944
case OUT:
945
if (!++state.inocnt)
946
{
947
if (!++state.devcnt)
948
goto toomany;
949
state.inocnt = 1;
950
}
951
f->st->st_dev = state.devcnt;
952
f->st->st_ino = state.inocnt;
953
break;
954
}
955
if (f->type == X_IFDIR)
956
return 0;
957
if (ap->format->flags & NOHARDLINKS)
958
{
959
if (state.operation == IN || f->st->st_nlink <= 1)
960
return 1;
961
}
962
else if ((ap->format->flags & LINKTYPE) && state.operation == IN)
963
{
964
if (f->linktype == NOLINK)
965
return 1;
966
f->linkpath = map(ap, f->linkpath);
967
goto linked;
968
}
969
else if (f->st->st_nlink <= 1)
970
return 1;
971
if (p = (Link_t*)hashget(state.linktab, (char*)&id))
972
{
973
if (ap->format->flags & NOHARDLINKS)
974
{
975
error(1, "%s: hard link information lost in %s format", f->name, ap->format->name);
976
return 1;
977
}
978
f->st->st_dev = p->id.dev;
979
f->st->st_ino = p->id.ino;
980
f->link = p;
981
f->linktype = HARDLINK;
982
f->linkpath = p->name;
983
if (state.pass && (state.operation & OUT) || !state.pass && state.operation == OUT)
984
return 0;
985
linked:
986
message((-1, "addlink(%s,%s)", f->name, f->linkpath));
987
if (ap->format->event && (ap->format->events & PAX_EVENT_BUG_19951031))
988
(*ap->format->event)(&state, ap, f, NiL, PAX_EVENT_BUG_19951031);
989
if (streq(f->name, f->linkpath))
990
{
991
error(2, "%s: hard link loops to self", f->name);
992
return 0;
993
}
994
if (!state.list)
995
{
996
s = f->linkpath;
997
if (access(s, F_OK))
998
{
999
f->skip = 1;
1000
error(2, "%s must exist for hard link %s", s, f->name);
1001
return 0;
1002
}
1003
remove(f->name);
1004
if (state.operation == IN && *s != '/')
1005
{
1006
strcpy(state.pwd + state.pwdlen, s);
1007
s = state.pwd;
1008
}
1009
if (link(s, f->name))
1010
{
1011
if (missdir(ap, f))
1012
{
1013
error(ERROR_SYSTEM|2, "%s: cannot create intermediate directories", f->name);
1014
return 0;
1015
}
1016
if (link(s, f->name))
1017
{
1018
error(ERROR_SYSTEM|2, "%s: cannot link to %s", f->linkpath, f->name);
1019
return -1;
1020
}
1021
}
1022
listentry(f);
1023
}
1024
return 0;
1025
}
1026
n = strlen(f->name) + 1;
1027
if (!(p = newof(0, Link_t, 1, n)))
1028
goto toomany;
1029
f->link = p;
1030
strcpy(p->name = (char*)p + sizeof(*p), f->name);
1031
p->namesize = n;
1032
p->id.dev = f->st->st_dev;
1033
p->id.ino = f->st->st_ino;
1034
hashput(state.linktab, NiL, p);
1035
return -1;
1036
toomany:
1037
if (!state.warnlinknum)
1038
{
1039
state.warnlinknum = 1;
1040
error(1, "too many hard links -- some links may become copies");
1041
}
1042
return -1;
1043
}
1044
1045
/*
1046
* get file uid and gid names given numbers
1047
*/
1048
1049
void
1050
getidnames(register File_t* f)
1051
{
1052
if (!f->uidname)
1053
f->uidname = fmtuid(f->st->st_uid);
1054
if (!f->gidname)
1055
f->gidname = fmtgid(f->st->st_gid);
1056
}
1057
1058
/*
1059
* set file uid and gid numbers given names
1060
*/
1061
1062
void
1063
setidnames(register File_t* f)
1064
{
1065
register int id;
1066
1067
if (f->uidname)
1068
{
1069
if ((id = struid(f->uidname)) < 0)
1070
{
1071
if (id == -1 && state.owner)
1072
error(1, "%s: invalid user name", f->uidname);
1073
f->uidname = 0;
1074
id = state.uid;
1075
}
1076
f->st->st_uid = id;
1077
}
1078
if (f->gidname)
1079
{
1080
if ((id = strgid(f->gidname)) < 0)
1081
{
1082
if (id == -1 && state.owner)
1083
error(1, "%s: invalid group name", f->gidname);
1084
f->gidname = 0;
1085
id = state.gid;
1086
}
1087
f->st->st_gid = id;
1088
}
1089
}
1090
1091
/*
1092
* allocate and initialize new archive pointer
1093
*/
1094
1095
Archive_t*
1096
initarchive(const char* name, int mode)
1097
{
1098
Archive_t* ap;
1099
1100
if (!(ap = newof(0, Archive_t, 1, 0)))
1101
nospace();
1102
initfile(ap, &ap->file, &ap->st, NiL, 0);
1103
ap->name = (char*)name;
1104
ap->expected = ap->format = 0;
1105
ap->section = 0;
1106
ap->sum = -1;
1107
ap->mio.mode = ap->tio.mode = mode;
1108
ap->io = &ap->mio;
1109
return ap;
1110
}
1111
1112
/*
1113
* return pointer to archive for op
1114
*/
1115
1116
Archive_t*
1117
getarchive(int op)
1118
{
1119
Archive_t** app;
1120
1121
app = (op & OUT) ? &state.out : &state.in;
1122
if (!*app)
1123
*app = initarchive(NiL, (op & OUT) ? (state.append ? (O_WRONLY|O_CREAT) : (O_WRONLY|O_CREAT|O_TRUNC)) : O_RDONLY);
1124
return *app;
1125
}
1126
1127
/*
1128
* initialize file info with name and mode
1129
*/
1130
1131
void
1132
initfile(register Archive_t* ap, register File_t* f, struct stat* st, register char* name, int mode)
1133
{
1134
memzero(f, sizeof(*f));
1135
f->st = st;
1136
memzero(f->st, sizeof(*f->st));
1137
if (name)
1138
{
1139
f->id = f->name = f->path = name;
1140
f->namesize = strlen(name) + 1;
1141
}
1142
f->st->st_mode = modex(mode);
1143
f->st->st_nlink = 1; /* system V needs this!!! */
1144
}
1145
1146
/*
1147
* set copied file info
1148
*/
1149
1150
void
1151
setfile(register Archive_t* ap, register File_t* f)
1152
{
1153
register Post_t* p;
1154
int updated;
1155
Post_t post;
1156
1157
if (f->skip || f->extended)
1158
return;
1159
switch (f->type)
1160
{
1161
case X_IFLNK:
1162
updated = 0;
1163
#if _lib_lchown
1164
if (state.owner)
1165
{
1166
if (state.flags & SETIDS)
1167
{
1168
post.uid = state.setuid;
1169
post.gid = state.setgid;
1170
}
1171
else
1172
{
1173
post.uid = f->st->st_uid;
1174
post.gid = f->st->st_gid;
1175
}
1176
if (lchown(f->name, post.uid, post.gid) < 0)
1177
error(1, "%s: cannot chown to (%d,%d)", f->name, post.uid, post.gid);
1178
}
1179
#endif
1180
#if _lib_lchmod
1181
if (f->chmod)
1182
{
1183
int m;
1184
struct stat st;
1185
1186
if (lstat(f->name, &st))
1187
error(1, "%s: not found", f->name);
1188
else if ((f->perm ^ st.st_mode) & state.modemask & (S_ISUID|S_ISGID|S_ISVTX|S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))
1189
{
1190
if (lchmod(f->name, f->perm & state.modemask))
1191
error(1, "%s: cannot chmod to %s", f->name, fmtmode(f->perm & state.modemask, 0) + 1);
1192
else if (m = f->perm & (S_ISUID|S_ISGID|S_ISVTX))
1193
{
1194
if (lstat(f->name, &st))
1195
error(1, "%s: not found", f->name);
1196
else if (m ^= (st.st_mode & (S_ISUID|S_ISGID|S_ISVTX)))
1197
error(1, "%s: mode %s not set", f->name, fmtmode(m, 0) + 1);
1198
}
1199
}
1200
}
1201
#endif
1202
ap->updated += updated;
1203
return;
1204
case X_IFDIR:
1205
if (f->chmod || state.acctime || state.modtime || state.owner || (f->perm & S_IRWXU) != S_IRWXU)
1206
{
1207
if (!(p = newof(0, Post_t, 1, 0)))
1208
error(3, "not enough space for file restoration info");
1209
tvgetatime(&p->atime, f->st);
1210
tvgetmtime(&p->mtime, f->st);
1211
p->uid = f->st->st_uid;
1212
p->gid = f->st->st_gid;
1213
p->mode = f->perm;
1214
if ((f->perm & S_IRWXU) != S_IRWXU)
1215
{
1216
p->chmod = 1;
1217
if (chmod(f->name, f->perm|S_IRWXU))
1218
error(1, "%s: cannot chmod to %s", f->name, fmtmode(f->st->st_mode|X_IRWXU, 1) + 1);
1219
}
1220
else
1221
p->chmod = f->chmod;
1222
hashput(state.restore, f->name, p);
1223
ap->updated++;
1224
return;
1225
}
1226
break;
1227
}
1228
ap->updated++;
1229
p = &post;
1230
if (state.acctime)
1231
tvgetatime(&p->atime, f->st);
1232
tvgetmtime(&p->mtime, f->st);
1233
p->uid = f->st->st_uid;
1234
p->gid = f->st->st_gid;
1235
p->mode = f->perm;
1236
p->chmod = f->chmod;
1237
restore(f->name, (char*)p, NiL);
1238
}
1239
1240
/*
1241
* set access and modification times of file
1242
*/
1243
1244
void
1245
settime(const char* name, Tv_t* ap, Tv_t* mp, Tv_t* cp)
1246
{
1247
if (*name && tvtouch(name, ap, mp, cp, 0) && errno != ENOENT && errno != ENOTDIR)
1248
error(1, "%s: cannot set times", name);
1249
}
1250
1251
/*
1252
* restore file status after processing
1253
*/
1254
1255
int
1256
restore(register const char* name, char* ap, void* handle)
1257
{
1258
register Post_t* p = (Post_t*)ap;
1259
int m;
1260
struct stat st;
1261
1262
NoP(handle);
1263
if (!*name)
1264
return 0;
1265
if (state.owner)
1266
{
1267
if (state.flags & SETIDS)
1268
{
1269
p->uid = state.setuid;
1270
p->gid = state.setgid;
1271
}
1272
if (chown(name, p->uid, p->gid) < 0)
1273
error(1, "%s: cannot chown to (%d,%d)", name, p->uid, p->gid);
1274
}
1275
if (p->chmod)
1276
{
1277
if (chmod(name, p->mode & state.modemask))
1278
error(1, "%s: cannot chmod to %s", name, fmtmode(p->mode & state.modemask, 0) + 1);
1279
else if (m = p->mode & (S_ISUID|S_ISGID|S_ISVTX))
1280
{
1281
if (stat(name, &st))
1282
error(1, "%s: not found", name);
1283
else if (m ^= (st.st_mode & (S_ISUID|S_ISGID|S_ISVTX)))
1284
error(1, "%s: mode %s not set", name, fmtmode(m, 0) + 1);
1285
}
1286
}
1287
if (state.modtime)
1288
settime(name, state.acctime ? &p->atime : 0, &p->mtime, NiL);
1289
return 0;
1290
}
1291
1292
/*
1293
* return 1 if f output can be pruned
1294
*/
1295
1296
int
1297
prune(register Archive_t* ap, register File_t* f, register struct stat* st)
1298
{
1299
Tv_t t1;
1300
Tv_t t2;
1301
struct stat so;
1302
int c;
1303
1304
if (state.operation != (IN|OUT) && state.update == OPT_update && !streq(f->name, f->path))
1305
{
1306
if ((*state.statf)(f->path, &so))
1307
return 0;
1308
st = &so;
1309
}
1310
if (st->st_mode == f->st->st_mode)
1311
{
1312
if (ap->delta && !tvcmp(tvmtime(&t1, f->st), tvmtime(&t2, st)))
1313
return 1;
1314
if (state.update && (!(c = tvcmp(tvmtime(&t1, f->st), tvmtime(&t2, st))) || state.update != OPT_different && c < 0))
1315
{
1316
if (state.exact)
1317
state.pattern->matched = 0;
1318
return 1;
1319
}
1320
}
1321
return 0;
1322
}
1323
1324
/*
1325
* write siz bytes of buf to fd checking for HOLE_MIN hole chunks
1326
* we assume siz is rounded nicely until the end
1327
*/
1328
1329
ssize_t
1330
holewrite(int fd, void* buf, size_t siz)
1331
{
1332
register char* t = (char*)buf;
1333
register char* e = t + siz;
1334
register char* b = 0;
1335
register char* s;
1336
ssize_t i;
1337
ssize_t n = 0;
1338
1339
static char hole[HOLE_MIN];
1340
1341
#if DEBUG
1342
if (state.test & 0000100)
1343
b = t;
1344
else
1345
#endif
1346
while (t < e)
1347
{
1348
s = t;
1349
if ((t += HOLE_MIN) > e)
1350
t = e;
1351
if (!*s && !*(t - 1) && !memcmp(s, hole, t - s))
1352
{
1353
if (b)
1354
{
1355
if (state.hole)
1356
{
1357
if (lseek(fd, state.hole, SEEK_CUR) < state.hole)
1358
return -1;
1359
state.hole = 0;
1360
}
1361
if ((i = write(fd, b, s - b)) != (s - b))
1362
return i;
1363
n += i;
1364
b = 0;
1365
}
1366
state.hole += t - s;
1367
n += t - s;
1368
}
1369
else if (!b)
1370
b = s;
1371
}
1372
if (b)
1373
{
1374
if (state.hole)
1375
{
1376
if (lseek(fd, state.hole, SEEK_CUR) < state.hole)
1377
return -1;
1378
state.hole = 0;
1379
}
1380
if ((i = write(fd, b, e - b)) != (e - b))
1381
return i;
1382
n += i;
1383
}
1384
return n;
1385
}
1386
1387
/*
1388
* make a seekable copy of ap->io input
1389
*/
1390
1391
void
1392
seekable(Archive_t* ap)
1393
{
1394
off_t m;
1395
off_t z;
1396
char* s;
1397
int rfd;
1398
int wfd;
1399
1400
if ((wfd = open(state.tmp.file, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR)) < 0)
1401
error(ERROR_SYSTEM|3, "%s: cannot create seekable temporary %s", ap->name, state.tmp.file);
1402
if ((rfd = open(state.tmp.file, O_RDONLY|O_BINARY)) < 0)
1403
error(ERROR_SYSTEM|3, "%s: cannot open seekable temporary %s", ap->name, state.tmp.file);
1404
if (remove(state.tmp.file))
1405
error(ERROR_SYSTEM|1, "%s: cannot remove seekable temporary %s", ap->name, state.tmp.file);
1406
ap->io->seekable = 1;
1407
z = 0;
1408
s = ap->io->buffer + ap->io->unread;
1409
m = ap->io->last - s;
1410
do
1411
{
1412
if (write(wfd, s, m) != m)
1413
error(ERROR_SYSTEM|3, "%s: seekable temporary %s write error", ap->name, state.tmp.file);
1414
z += m;
1415
} while ((m = read(ap->io->fd, s, state.buffersize)) > 0);
1416
close(wfd);
1417
close(ap->io->fd);
1418
ap->io->size = z;
1419
z = ap->io->count;
1420
ap->io->next = ap->io->last = s;
1421
ap->io->offset = ap->io->count = 0;
1422
if (ap->io->fd || (ap->io->fd = dup(rfd)) < 0)
1423
ap->io->fd = rfd;
1424
else
1425
close(rfd);
1426
bread(ap, NiL, z, z, 0);
1427
}
1428
1429