Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/pax/misc.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 miscellaneous support
26
*/
27
28
#include "pax.h"
29
30
#include <dlldefs.h>
31
#include <sfdisc.h>
32
#include <tmx.h>
33
34
static Format_t*
35
scan(void)
36
{
37
register Format_t* fp;
38
Format_t* lp;
39
Format_t* rp;
40
Dllscan_t* dls;
41
Dllent_t* dle;
42
void* dll;
43
Paxlib_f init;
44
45
for (fp = formats; fp->next; fp = fp->next);
46
rp = fp;
47
if (dls = dllsopen(state.id, NiL, NiL))
48
{
49
while (dle = dllsread(dls))
50
if (dll = dlopen(dle->path, RTLD_LAZY))
51
{
52
if (dllcheck(dll, dle->path, PAX_PLUGIN_VERSION, NiL) &&
53
(init = (Paxlib_f)dlllook(dll, "pax_lib")) &&
54
(lp = (*init)(&state)))
55
fp = fp->next = lp;
56
else
57
dlclose(dll);
58
}
59
else
60
message((-1, "%s: %s", dle->path, dlerror()));
61
dllsclose(dls);
62
}
63
return rp->next;
64
}
65
66
/*
67
* format list iterator
68
* fp=0 for first element
69
* dll format scan kicked in when static formats exhausted
70
*/
71
72
Format_t*
73
nextformat(Format_t* fp)
74
{
75
if (!fp)
76
return formats;
77
if (!(fp = fp->next) && !state.scanned)
78
{
79
state.scanned = 1;
80
fp = scan();
81
}
82
return fp;
83
}
84
85
/*
86
* return format given name
87
*/
88
89
Format_t*
90
getformat(register char* name, int must)
91
{
92
register Format_t* fp;
93
94
if (!name || !*name || streq(name, "-"))
95
name = FMT_DEFAULT;
96
fp = 0;
97
while (fp = nextformat(fp))
98
if (!strcasecmp(name, fp->name) || fp->match && strgrpmatch(name, fp->match, NiL, 0, STR_ICASE|STR_LEFT|STR_RIGHT))
99
return fp;
100
if (must)
101
error(3, "%s: unknown format", name);
102
return 0;
103
}
104
105
/*
106
* path name strcmp()
107
*/
108
109
static int
110
pathcmp(register const char* s, register const char* t)
111
{
112
register int sc;
113
register int tc;
114
115
for (;;)
116
{
117
tc = *t++;
118
if (!(sc = *s++))
119
return tc ? -1 : 0;
120
if (sc != tc)
121
{
122
if (tc == 0 || tc == '/')
123
return 1;
124
if (sc == '/')
125
return -1;
126
return strcoll(s - 1, t - 1);
127
}
128
}
129
}
130
131
/*
132
* check base archive ordering
133
*/
134
135
static void
136
ordered(Archive_t* ap, const char* prv, const char* cur)
137
{
138
if (pathcmp(prv, cur) > 0)
139
error(3, "%s: %s: archive member must appear before %s", ap->name, prv, cur);
140
}
141
142
/*
143
* check f with patterns given on cmd line
144
*/
145
146
int
147
selectfile(register Archive_t* ap, register File_t* f)
148
{
149
register Archive_t* bp;
150
register Member_t* d;
151
int linked = 0;
152
int c;
153
Tv_t t;
154
155
ap->info = 0;
156
if (f->skip || f->namesize <= 1 || f->linkpath && !*f->linkpath)
157
return 0;
158
if (state.ordered)
159
{
160
ordered(ap, ap->path.prev.string, f->name);
161
stash(&ap->path.prev, f->name, 0); /*HERE*/
162
}
163
if (f->record.format && state.record.pattern)
164
{
165
static char fmt[2];
166
167
fmt[0] = f->record.format;
168
if (!strmatch(fmt, state.record.pattern))
169
return 0;
170
}
171
if (ap->parent)
172
{
173
linked = 1;
174
addlink(ap, f);
175
if (!ap->parent)
176
return 0;
177
if (!(d = newof(0, Member_t, 1, 0)))
178
nospace();
179
d->dev = f->st->st_dev;
180
d->ino = f->st->st_ino;
181
d->mode = f->st->st_mode;
182
tvgetatime(&d->atime, f->st);
183
tvgetmtime(&d->mtime, f->st);
184
d->offset = ap->io->offset + ap->io->count;
185
d->size = f->st->st_size;
186
d->uncompressed = f->uncompressed;
187
if (!(d->info = (File_t*)memdup(f, sizeof(File_t))) || !(d->info->st = (struct stat*)memdup(f->st, sizeof(struct stat))))
188
nospace();
189
d->info->name = d->info->path = hashput(ap->parent->delta->tab, f->name, d);
190
if (d->info->linktype != NOLINK)
191
d->info->linkpath = strdup(d->info->linkpath);
192
if (d->info->uidname)
193
d->info->uidname = strdup(d->info->uidname);
194
if (d->info->gidname)
195
d->info->gidname = strdup(d->info->gidname);
196
d->info->delta.base = d;
197
ap->info = d->info;
198
if (!state.ordered)
199
return 0;
200
}
201
if (!match(f->path))
202
return 0;
203
if (f->type != X_IFDIR && ap->update && (d = (Member_t*)hashget(ap->update, f->name)))
204
{
205
if (f->type != X_IFREG && d->dev != f->st->st_dev)
206
/* keep */;
207
else if (!(c = tvcmp(&d->mtime, tvmtime(&t, f->st))))
208
return 0;
209
else if (state.update != OPT_different && c > 0)
210
return 0;
211
else
212
return 0;
213
}
214
if (state.verify && !verify(ap, f, NiL))
215
return 0;
216
ap->selected++;
217
if (!linked)
218
{
219
if (state.list)
220
addlink(ap, f);
221
if (ap->tab)
222
{
223
if (!(d = newof(0, Member_t, 1, 0)))
224
nospace();
225
d->dev = f->st->st_dev;
226
d->ino = f->st->st_ino;
227
d->mode = f->st->st_mode;
228
tvgetatime(&d->atime, f->st);
229
tvgetmtime(&d->mtime, f->st);
230
d->offset = ap->io->offset + ap->io->count;
231
d->size = f->st->st_size;
232
d->uncompressed = f->uncompressed;
233
hashput(ap->tab, f->path, d);
234
}
235
}
236
if (state.ordered && ap->delta && !(ap->delta->format->flags & COMPRESS) && (bp = ap->delta->base))
237
{
238
register int n;
239
register int m;
240
241
for (;;)
242
{
243
if (bp->peek)
244
bp->peek = 0;
245
else
246
{
247
if (bp->skip && bp->skip == bp->io->offset + bp->io->count)
248
fileskip(bp, &bp->file);
249
if (!getheader(bp, &bp->file))
250
break;
251
bp->skip = bp->io->offset + bp->io->count;
252
}
253
ordered(bp, bp->path.prev.string, bp->file.name);
254
if ((m = pathcmp(bp->file.name, f->name)) > 0)
255
{
256
bp->peek = 1;
257
break;
258
}
259
n = selectfile(bp, &bp->file);
260
if (!m)
261
break;
262
if (n && !state.list)
263
{
264
if (ap->io->mode != O_RDONLY)
265
{
266
File_t tmp;
267
struct stat st;
268
269
initfile(ap, &tmp, &st, bp->file.name, X_IFREG);
270
tmp.delta.op = DELTA_delete;
271
putheader(ap, &tmp);
272
puttrailer(ap, &tmp);
273
}
274
else
275
{
276
struct stat st;
277
278
if (!(*state.statf)(f->name, &st))
279
{
280
if (S_ISDIR(st.st_mode))
281
{
282
if (!streq(f->name, ".") && !streq(f->name, ".."))
283
{
284
if (rmdir(f->name))
285
error(ERROR_SYSTEM|2, "%s: cannot remove directory", f->name);
286
else
287
listentry(f);
288
}
289
}
290
else if (remove(f->name))
291
error(ERROR_SYSTEM|2, "%s: cannot remove file", f->name);
292
else
293
listentry(f);
294
}
295
}
296
}
297
}
298
}
299
return 1;
300
}
301
302
/*
303
* verify action on file
304
*
305
* EOF exit
306
* NULL skip file
307
* . keep file
308
* <else> rename file
309
*/
310
311
int
312
verify(Archive_t* ap, register File_t* f, register char* prompt)
313
{
314
register char* name;
315
316
NoP(ap);
317
if (!prompt)
318
{
319
if (state.yesno < 0)
320
return 0;
321
else if (state.yesno)
322
switch (state.operation)
323
{
324
case IN:
325
prompt = "Read";
326
break;
327
case OUT:
328
prompt = "Write";
329
break;
330
default:
331
prompt = "Pass";
332
break;
333
}
334
else
335
prompt = "Rename";
336
}
337
sfprintf(state.wtty, "%s %s: " , prompt, f->name);
338
if (!(name = sfgetr(state.rtty, '\n', 1)))
339
{
340
sfputc(state.wtty, '\n');
341
finish(2);
342
}
343
if (state.yesno)
344
{
345
if (*name == 'q' || *name == 'Q' || *name == '-')
346
{
347
state.yesno = -1;
348
return 0;
349
}
350
return *name == 'y' || *name == 'Y' || *name == '1';
351
}
352
switch (*name)
353
{
354
case 0:
355
return 0;
356
case '.':
357
if (!*(name + 1))
358
break;
359
/*FALLTHROUGH*/
360
default:
361
f->namesize = pathcanon(f->name = name, 0, 0) - name + 1;
362
break;
363
}
364
return 1;
365
}
366
367
/*
368
* no dos in our pathnames
369
*/
370
371
void
372
undos(File_t* f)
373
{
374
register char* s;
375
376
if (strchr(f->name, '\\'))
377
{
378
s = f->name;
379
if (s[1] == ':' && isalpha(s[0]))
380
{
381
if (*(s += 2) == '\\' || *s == '/')
382
s++;
383
f->name = s;
384
}
385
for (; *s; s++)
386
if (*s == '\\')
387
*s = '/';
388
}
389
}
390
391
/*
392
* check for file name mapping
393
* static data possibly returned
394
* two simultaneous calls supported
395
*/
396
397
char*
398
map(Archive_t* ap, register char* name)
399
{
400
register Map_t* mp;
401
char* to;
402
char* from;
403
File_t f;
404
int n;
405
regmatch_t match[10];
406
407
if (state.filter.line > 1)
408
{
409
state.filter.line = 1;
410
name = state.filter.name;
411
}
412
from = to = name;
413
for (mp = state.maps; mp; mp = mp->next)
414
if (!(n = regexec(&mp->re, from, elementsof(match), match, 0)))
415
{
416
if (n = regsubexec(&mp->re, from, elementsof(match), match))
417
regfatal(&mp->re, 3, n);
418
n = strlen(mp->re.re_sub->re_buf) + 1;
419
if (!(to = fmtbuf(n + ((mp->flags & MAP_INDEX) ? 10 : 0))))
420
nospace();
421
memcpy(to, mp->re.re_sub->re_buf, n);
422
if (mp->flags & MAP_INDEX)
423
sfsprintf(to + n - 1, 10, ".%04d", ap->entry);
424
if (mp->re.re_sub->re_flags & REG_SUB_PRINT)
425
sfprintf(sfstderr, "%s >> %s\n", from, to);
426
if (mp->re.re_sub->re_flags & REG_SUB_STOP)
427
break;
428
from = to;
429
}
430
else if (n != REG_NOMATCH)
431
regfatal(&mp->re, 3, n);
432
if (state.local && (*to == '/' || *to == '.' && *(to + 1) == '.' && (!*(to + 2) || *(to + 2) == '/')))
433
{
434
if (state.verify)
435
{
436
f.name = to;
437
if (verify(NiL, &f, "Retain non-local file"))
438
return f.name;
439
}
440
error(1, "%s: non-local path rejected", to);
441
to = "";
442
}
443
return to;
444
}
445
446
typedef struct
447
{
448
Archive_t* archive;
449
File_t* file;
450
} List_handle_t;
451
452
#define TYPE_mode 1
453
#define TYPE_time 2
454
455
/*
456
* sfkeyprintf() lookup
457
*/
458
459
static int
460
listlookup(void* handle, register Sffmt_t* fmt, const char* arg, char** ps, Sflong_t* pn)
461
{
462
List_handle_t* gp = (List_handle_t*)handle;
463
register File_t* f = gp->file;
464
register struct stat* st = f->st;
465
char* s = 0;
466
Sflong_t n = 0;
467
Time_t t = TMX_NOTIME;
468
int type = 0;
469
int k;
470
char* e;
471
Option_t* op;
472
473
static const char fmt_time[] = "time=%?%l";
474
static const char fmt_mode[] = "mode";
475
476
if (fmt->t_str)
477
{
478
if (!(op = (Option_t*)hashget(state.options, fmt->t_str)))
479
{
480
if (*fmt->t_str != '$')
481
return 0;
482
if (!(op = newof(0, Option_t, 1, 0)))
483
nospace();
484
op->name = hashput(state.options, 0, op);
485
op->macro = getenv(fmt->t_str + 1);
486
op->index = OPT_environ;
487
op->flags |= OPT_DISABLE;
488
}
489
if (op->macro && !(op->flags & OPT_DISABLE))
490
{
491
op->flags |= OPT_DISABLE;
492
if (!(state.tmp.mac && !(state.tmp.mac = sfstropen())))
493
nospace();
494
sfkeyprintf(state.tmp.mac, handle, op->macro, listlookup, NiL);
495
if (!(s = sfstruse(state.tmp.mac)))
496
nospace();
497
op->flags &= ~OPT_DISABLE;
498
}
499
else
500
switch (op->index)
501
{
502
case OPT_atime:
503
n = st->st_atime;
504
t = tmxgetatime(st);
505
type = TYPE_time;
506
break;
507
case OPT_charset:
508
s = "ASCII";
509
break;
510
case OPT_ctime:
511
n = st->st_ctime;
512
t = tmxgetctime(st);
513
type = TYPE_time;
514
break;
515
case OPT_delta_op:
516
if (f->uncompressed && (k = (st->st_size * 100) / f->uncompressed) < 100)
517
sfsprintf(s = fmtbuf(32), 32, "%c%02d.%1d%%", f->delta.op ? f->delta.op : 'c', k, (int)((st->st_size * 1000) / f->uncompressed) % 10);
518
else
519
switch (f->delta.op)
520
{
521
case 0:
522
case DELTA_pass:
523
return 0;
524
case DELTA_create:
525
s = "create";
526
break;
527
case DELTA_delete:
528
s = "delete";
529
break;
530
case DELTA_update:
531
s = "update";
532
break;
533
case DELTA_verify:
534
s = "verify";
535
break;
536
default:
537
sfsprintf(s = fmtbuf(8), 8, "[op=%c]", f->delta.op);
538
break;
539
}
540
break;
541
case OPT_device:
542
if (f->type == X_IFBLK || f->type == X_IFCHR)
543
s = fmtdev(st);
544
else
545
return 0;
546
break;
547
case OPT_devmajor:
548
n = major(st->st_dev);
549
break;
550
case OPT_devminor:
551
n = minor(st->st_dev);
552
break;
553
case OPT_dir:
554
if (s = strrchr(f->name, '/'))
555
{
556
sfwrite(state.tmp.fmt, f->name, s - f->name);
557
if (!(s = sfstruse(state.tmp.fmt)))
558
nospace();
559
}
560
else
561
s = ".";
562
break;
563
case OPT_entry:
564
n = gp->archive->entry;
565
break;
566
case OPT_environ:
567
if (!(s = op->macro))
568
return 0;
569
break;
570
case OPT_gname:
571
if (f->gidname)
572
{
573
if (fmt->fmt == 's')
574
s = f->gidname;
575
else
576
n = strgid(f->gidname);
577
break;
578
}
579
/*FALLTHROUGH*/
580
case OPT_gid:
581
if (fmt->fmt == 's')
582
s = fmtgid(st->st_gid);
583
else
584
n = st->st_gid;
585
break;
586
case OPT_ino:
587
n = st->st_ino;
588
break;
589
case OPT_linkop:
590
switch (f->linktype)
591
{
592
case HARDLINK:
593
s = "==";
594
break;
595
case SOFTLINK:
596
s = "->";
597
break;
598
default:
599
return 0;
600
}
601
break;
602
case OPT_linkpath:
603
if (f->linktype == NOLINK)
604
return 0;
605
s = f->linkpath;
606
break;
607
case OPT_mark:
608
if (f->linktype == HARDLINK)
609
s = "=";
610
else if (f->linktype == SOFTLINK)
611
s = "@";
612
else if (f->type == X_IFDIR)
613
s = "/";
614
else if (f->type == X_IFIFO)
615
s = "|";
616
else if (f->type == X_IFSOCK)
617
s = "=";
618
else if (f->type == X_IFBLK || f->type == X_IFCHR)
619
s = "$";
620
else if (st->st_mode & (X_IXUSR|X_IXGRP|X_IXOTH))
621
s = "*";
622
else
623
return 0;
624
break;
625
case OPT_mode:
626
n = st->st_mode;
627
type = TYPE_mode;
628
break;
629
case OPT_mtime:
630
n = st->st_mtime;
631
t = tmxgetmtime(st);
632
type = TYPE_time;
633
break;
634
case OPT_name:
635
if (s = strrchr(f->name, '/'))
636
s++;
637
else
638
s = f->name;
639
break;
640
case OPT_nlink:
641
n = st->st_nlink;
642
break;
643
case OPT_path:
644
s = f->name;
645
break;
646
case OPT_pid:
647
n = state.pid;
648
break;
649
case OPT_release:
650
s = release();
651
break;
652
case OPT_sequence:
653
if (gp->archive->volume)
654
sfsprintf(s = fmtbuf(32), 32, "%d-%d", gp->archive->volume, gp->archive->entry);
655
else
656
n = gp->archive->entry;
657
break;
658
case OPT_size:
659
if (f->linktype == SOFTLINK)
660
n = f->linkpathsize - 1;
661
else if (f->uncompressed)
662
n = f->uncompressed;
663
else
664
n = (Sfulong_t)st->st_size;
665
break;
666
case OPT_tmp:
667
if (s = strrchr(state.tmp.file, '/'))
668
{
669
sfwrite(state.tmp.fmt, state.tmp.file, s - state.tmp.file);
670
if (!(s = sfstruse(state.tmp.fmt)))
671
nospace();
672
}
673
else
674
s = ".";
675
break;
676
case OPT_uname:
677
if (f->uidname)
678
{
679
if (fmt->fmt == 's')
680
s = f->uidname;
681
else
682
n = struid(f->uidname);
683
break;
684
}
685
/*FALLTHROUGH*/
686
case OPT_uid:
687
if (fmt->fmt == 's')
688
s = fmtuid(st->st_uid);
689
else
690
n = st->st_uid;
691
break;
692
default:
693
if (gp->archive && gp->archive->format->lookup)
694
{
695
if ((k = (*gp->archive->format->lookup)(&state, gp->archive, f, op->index, &s, &n)) < 0)
696
return 0;
697
else if (k > 0)
698
break;
699
}
700
if (!(op->flags & OPT_SET) || !(s = op->perm.string))
701
return 0;
702
break;
703
}
704
}
705
else
706
{
707
op = 0;
708
switch (fmt->fmt)
709
{
710
case 'd':
711
if (!op)
712
s = f->name;
713
if (e = strrchr(s, '/'))
714
{
715
sfwrite(state.tmp.fmt, s, e - s);
716
if (!(s = sfstruse(state.tmp.fmt)))
717
nospace();
718
}
719
else
720
s = ".";
721
*ps = s;
722
fmt->fmt = 's';
723
return 1;
724
case 'f':
725
fmt->fmt = 'F';
726
break;
727
case 'n':
728
*pn = f->ap->entry;
729
fmt->fmt = 'u';
730
return 1;
731
case 'p':
732
*pn = state.pid;
733
fmt->fmt = 'u';
734
return 1;
735
}
736
}
737
switch (fmt->fmt)
738
{
739
case 'D':
740
if (f->type == X_IFBLK || f->type == X_IFCHR)
741
s = fmtdev(st);
742
else if (!op)
743
s = " ";
744
else
745
{
746
*pn = n;
747
fmt->fmt = 'u';
748
return 1;
749
}
750
break;
751
case 'L':
752
if (f->linktype != NOLINK)
753
{
754
if (!op)
755
s = f->name;
756
sfprintf(state.tmp.fmt, "%s %s %s", s, f->linktype == HARDLINK ? "==" : "->", f->linkpath);
757
if (!(s = sfstruse(state.tmp.fmt)))
758
nospace();
759
break;
760
}
761
/*FALLTHROUGH*/
762
case 'F':
763
if (!op)
764
s = f->name;
765
if (e = strrchr(s, '/'))
766
s = e + 1;
767
break;
768
case 'M':
769
if (!op)
770
n = st->st_mode;
771
s = fmtmode(n, 1);
772
break;
773
case 'T':
774
if (!arg)
775
arg = "%b %e %H:%M %Y";
776
if (!op)
777
{
778
n = st->st_mtime;
779
t = tmxgetmtime(st);
780
}
781
if ((unsigned long)n >= state.testdate)
782
{
783
n = state.testdate;
784
t = TMX_NOTIME;
785
}
786
s = t == TMX_NOTIME ? fmttime(arg, n) : fmttmx(arg, t);
787
break;
788
default:
789
if (s)
790
*ps = s;
791
else if (fmt->fmt == 's' && (arg || type))
792
{
793
if (type == TYPE_mode || arg && *pn == ':' && strneq(arg, fmt_mode, 4))
794
*ps = fmtmode(n, 1);
795
else if ((k = arg && *pn == ':' && strneq(arg, fmt_time, 4)) || type == TYPE_time)
796
{
797
if (k && *(arg + 4) == '=')
798
arg += 5;
799
if (!arg || !*arg)
800
arg = fmt_time + 5;
801
if ((unsigned long)n >= state.testdate)
802
{
803
n = state.testdate;
804
t = TMX_NOTIME;
805
}
806
*ps = t == TMX_NOTIME ? fmttime(arg, (time_t)n) : fmttmx(arg, t);
807
}
808
}
809
else
810
*pn = n;
811
return 1;
812
}
813
*ps = s;
814
fmt->fmt = 's';
815
return 1;
816
}
817
818
/*
819
* set up lookup() handle and call sfkeyprintf()
820
*/
821
822
int
823
listprintf(Sfio_t* sp, Archive_t* ap, File_t* f, const char* format)
824
{
825
List_handle_t list;
826
827
list.archive = ap;
828
list.file = f;
829
return sfkeyprintf(sp, &list, format, listlookup, NiL);
830
}
831
832
/*
833
* list entry information based on state.drop, state.list and state.verbose
834
*/
835
836
void
837
listentry(register File_t* f)
838
{
839
int n;
840
int p;
841
int i;
842
int j;
843
int k;
844
char* s;
845
char* e;
846
char bar[METER_parts + 1];
847
848
if (!f->extended && !f->skip && (state.drop || state.list || state.meter.on || state.verbose))
849
{
850
if (state.meter.on)
851
{
852
for (s = f->name; *s; s++)
853
if (s[0] == ' ' && s[1] == '-' && s[2] == '-' && s[3] == ' ')
854
break;
855
if (*s)
856
{
857
if (state.meter.last)
858
{
859
sfprintf(sfstderr, "%*s", state.meter.last, "\r");
860
state.meter.last = 0;
861
}
862
sfprintf(sfstderr, "\n");
863
listprintf(sfstderr, state.in, f, state.listformat);
864
sfprintf(sfstderr, "\n\n");
865
return;
866
}
867
n = state.in->io->count > 1024 ? 10 : 0;
868
if ((p = ((state.in->io->count >> n) * 100) / (state.meter.size >> n)) >= 100)
869
p = 99;
870
n = listprintf(state.meter.tmp, state.in, f, state.listformat);
871
if (!(s = sfstruse(state.meter.tmp)))
872
nospace();
873
if (state.meter.fancy)
874
{
875
if (n > (state.meter.width - METER_width))
876
{
877
e = "*";
878
s += n - (state.meter.width - METER_width) + 1;
879
n = state.meter.width - METER_width;
880
}
881
else
882
e = "";
883
j = n + METER_width;
884
if (!state.meter.last)
885
state.meter.last = j;
886
if ((k = state.meter.last - j) < 0)
887
k = 0;
888
if ((i = (p / (100 / METER_parts))) >= sizeof(bar))
889
i = sizeof(bar) - 1;
890
n = 0;
891
while (n < i)
892
bar[n++] = '*';
893
while (n < elementsof(bar) - 1)
894
bar[n++] = ' ';
895
bar[n] = 0;
896
state.meter.last = sfprintf(sfstderr, "%02d%% |%s| %s%s%*s\r", p, bar, e, s, k, "") - k - 1;
897
}
898
else
899
sfprintf(sfstderr, "%02d%% %s\n", p, s);
900
sfsync(sfstderr);
901
if (state.test & 0000200)
902
sleep(1);
903
}
904
else if (state.drop)
905
{
906
if (++state.dropcount >= 50)
907
{
908
state.dropcount = 0;
909
sfprintf(sfstderr, ".\n");
910
}
911
else
912
{
913
sfprintf(sfstderr, ".");
914
sfsync(sfstderr);
915
}
916
}
917
else
918
listprintf(state.list ? sfstdout : sfstderr, state.in, f, state.listformat);
919
}
920
}
921
922
/*
923
* prepare patterns for match()
924
*/
925
926
void
927
initmatch(char** v)
928
{
929
register char* s;
930
register char** a;
931
Pattern_t* p;
932
size_t n;
933
size_t m;
934
935
m = 0;
936
a = v;
937
while (*a)
938
m += strlen(*a++) + 1;
939
n = a - v + 1;
940
if (!(p = newof(0, Pattern_t, n, m)))
941
nospace();
942
state.pattern = state.patterns = p;
943
s = (char*)(p + n);
944
for (a = v; *a; a++, p++)
945
{
946
s = strcopy(p->pattern = s, *a) + 1;
947
pathcanon(p->pattern, s - p->pattern, 0);
948
}
949
}
950
951
/*
952
* determine if file s matches input patterns
953
*/
954
955
int
956
match(register char* s)
957
{
958
register Pattern_t* p;
959
int n;
960
961
if (!(p = state.pattern))
962
return state.matchsense;
963
if (state.exact)
964
{
965
for (n = 0; p->pattern; p++)
966
if (!p->matched || p->directory)
967
{
968
if (state.descend && dirprefix(p->pattern, s, p->directory))
969
{
970
state.pattern = p;
971
p->directory = p->matched = 1;
972
return 1;
973
}
974
else if (p->directory)
975
p->directory = 0;
976
else if (strmatch(s, p->pattern))
977
{
978
state.pattern = p;
979
p->matched = 1;
980
return 1;
981
}
982
else
983
n = 1;
984
}
985
if (!n)
986
finish(0);
987
}
988
else
989
for (; p->pattern; p++)
990
if (state.descend && dirprefix(p->pattern, s, 0) || strmatch(s, p->pattern))
991
return state.matchsense;
992
return !state.matchsense;
993
}
994
995
/*
996
* return 1 if p is a directory prefix of s
997
*/
998
999
int
1000
dirprefix(register char* p, register char* s, int proper)
1001
{
1002
if (*p == '.' && !*(p + 1) && *s != '/' && (*s != '.' || *(s + 1) != '.' || *(s + 2) && *(s + 2) != '/'))
1003
return !proper;
1004
if (*p == '/' && !*(p + 1))
1005
return *s == '/';
1006
while (*p)
1007
if (*p++ != *s++)
1008
return 0;
1009
return *s == '/' || !proper && !*s;
1010
}
1011
1012
/*
1013
* allocate and copy a tmp string
1014
* a!=0 for lifetime of a
1015
* f!=0 for lifetime of f
1016
*/
1017
1018
char*
1019
stash(register Value_t* v, const char* s, size_t z)
1020
{
1021
if (!z)
1022
{
1023
if (!s)
1024
return 0;
1025
z = strlen(s);
1026
}
1027
z++;
1028
if (z > v->size)
1029
{
1030
v->size = roundof(z, 256);
1031
if (!(v->string = newof(v->string, char, v->size, 0)))
1032
nospace();
1033
}
1034
if (s)
1035
{
1036
memcpy(v->string, s, z - 1);
1037
v->string[z - 1] = 0;
1038
}
1039
return v->string;
1040
}
1041
1042
/*
1043
* out of space panic
1044
*/
1045
1046
void
1047
nospace(void)
1048
{
1049
error(ERROR_SYSTEM|3, "out of space");
1050
}
1051
1052
/*
1053
* if current file cannot fit completely in current archive
1054
* then bump it to another volume
1055
*/
1056
1057
void
1058
complete(Archive_t* ap, register File_t* f, size_t header)
1059
{
1060
off_t n;
1061
1062
n = header + f->st->st_size;
1063
if (ap->io->count + n > state.maxout)
1064
{
1065
if (n > state.maxout)
1066
error(1, "%s: too large to fit in one volume", f->name);
1067
else
1068
{
1069
state.complete = 0;
1070
putepilogue(ap);
1071
newio(ap, 0, 0);
1072
putprologue(ap, 0);
1073
state.complete = 1;
1074
}
1075
}
1076
}
1077
1078
/*
1079
* verify that compress undo command exists
1080
* alternate undotoo checked if undo not found
1081
*/
1082
1083
void
1084
undoable(Archive_t* ap, Format_t* fp)
1085
{
1086
register Compress_format_t* cp = (Compress_format_t*)fp->data;
1087
char buf[PATH_MAX];
1088
1089
if (!pathpath(cp->undo[0], NiL, PATH_EXECUTE, buf, sizeof(buf)))
1090
{
1091
if (!cp->undotoo[0] || !pathpath(cp->undotoo[0], NiL, PATH_EXECUTE, buf, sizeof(buf)))
1092
error(3, "%s: %s: command required to read compressed archive", ap->name, cp->undo[0]);
1093
cp->undo[0] = cp->undotoo[0];
1094
cp->undotoo[0] = 0;
1095
cp->undo[1] = cp->undotoo[1];
1096
}
1097
}
1098
1099