Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / cmd / pax / misc.c
1 /* $XConsortium: misc.c /main/3 1995/11/01 17:01:03 rswiston $ */
2 /***************************************************************
3 *                                                              *
4 *                      AT&T - PROPRIETARY                      *
5 *                                                              *
6 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
7 *                          AT&T CORP.                          *
8 *                                                              *
9 *                Copyright (c) 1995 AT&T Corp.                 *
10 *                     All Rights Reserved                      *
11 *                                                              *
12 *           This software is licensed by AT&T Corp.            *
13 *       under the terms and conditions of the license in       *
14 *       http://www.research.att.com/orgs/ssr/book/reuse        *
15 *                                                              *
16 *               This software was created by the               *
17 *           Software Engineering Research Department           *
18 *                    AT&T Bell Laboratories                    *
19 *                                                              *
20 *               For further information contact                *
21 *                     gsf@research.att.com                     *
22 *                                                              *
23 ***************************************************************/
24
25 /* : : generated by proto : : */
26
27 #if !defined(__PROTO__)
28 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
29 #if defined(__cplusplus)
30 #define __MANGLE__      "C"
31 #else
32 #define __MANGLE__
33 #endif
34 #define __STDARG__
35 #define __PROTO__(x)    x
36 #define __OTORP__(x)
37 #define __PARAM__(n,o)  n
38 #if !defined(__STDC__) && !defined(__cplusplus)
39 #if !defined(c_plusplus)
40 #define const
41 #endif
42 #define signed
43 #define void            int
44 #define volatile
45 #define __V_            char
46 #else
47 #define __V_            void
48 #endif
49 #else
50 #define __PROTO__(x)    ()
51 #define __OTORP__(x)    x
52 #define __PARAM__(n,o)  o
53 #define __MANGLE__
54 #define __V_            char
55 #define const
56 #define signed
57 #define void            int
58 #define volatile
59 #endif
60 #if defined(__cplusplus) || defined(c_plusplus)
61 #define __VARARG__      ...
62 #else
63 #define __VARARG__
64 #endif
65 #if defined(__STDARG__)
66 #define __VA_START__(p,a)       va_start(p,a)
67 #else
68 #define __VA_START__(p,a)       va_start(p)
69 #endif
70 #endif
71 #include "pax.h"
72 #include "options.h"
73
74 #include <sfdisc.h>
75
76 /*
77  * return format index given format name
78  */
79
80 int
81 getformat __PARAM__((register char* name), (name)) __OTORP__(register char* name;){
82         register int    i;
83
84         strlower(name);
85         for (i = 0; format[i].name; i++)
86                 if (streq(name, format[i].name))
87                         break;
88         return(format[i].name ? i : streq(name, "-") || streq(name, "pax") ? OUT_DEFAULT : -1);
89 }
90
91 /*
92  * path name strcmp()
93  */
94
95 static int
96 pathcmp __PARAM__((register const char* s, register const char* t), (s, t)) __OTORP__(register const char* s; register const char* t;){
97         register int    sc;
98         register int    tc;
99
100         for (;;)
101         {
102                 tc = *t++;
103                 if (!(sc = *s++))
104                         return(tc ? -1 : 0);
105                 if (sc != tc)
106                 {
107                         if (tc == 0 || tc == '/')
108                                 return(1);
109                         if (sc == '/')
110                                 return(-1);
111                         return(strcoll(s - 1, t - 1));
112                 }
113         }
114 }
115
116 /*
117  * check base archive ordering
118  */
119
120 static void
121 ordered __PARAM__((Archive_t* ap, const char* prv, const char* cur), (ap, prv, cur)) __OTORP__(Archive_t* ap; const char* prv; const char* cur;){
122         if (pathcmp(prv, cur) > 0)
123                 error(3, "%s: %s: archive member must appear before %s", ap->name, prv, cur);
124 }
125
126 /*
127  * check f with patterns given on cmd line
128  */
129
130 int
131 selectfile __PARAM__((register Archive_t* ap, register File_t* f), (ap, f)) __OTORP__(register Archive_t* ap; register File_t* f;){
132         register Archive_t*     bp;
133         register Member_t*      d;
134         int                     linked = 0;
135
136         if (f->skip || f->namesize <= 1)
137                 return(0);
138         if (state.ordered)
139         {
140                 ordered(ap, ap->path.prev, f->name);
141                 strcpy(ap->path.prev, f->name);
142         }
143         if (f->record.format && state.record.pattern)
144         {
145                 static char     fmt[2];
146
147                 fmt[0] = f->record.format;
148                 if (!strmatch(fmt, state.record.pattern))
149                         return(0);
150         }
151         if (state.append || ap->parent)
152         {
153                 linked = 1;
154                 addlink(ap, f);
155                 if (!ap->parent)
156                         return(0);
157                 if (!(d = newof(0, Member_t, 1, 0)))
158                         error(3, "%s: out of space", f->name);
159                 d->dev = f->st->st_dev;
160                 d->ino = f->st->st_ino;
161                 d->mtime = f->st->st_mtime;
162                 d->offset = ap->io.offset + ap->io.count;
163                 d->size = f->st->st_size;
164                 d->expand = f->delta.size;
165                 if (!(d->info = (File_t*)memdup(f, sizeof(File_t))) || !(d->info->st = (struct stat*)memdup(f->st, sizeof(struct stat))))
166                         error(3, "%s: out of space", f->name);
167                 d->info->name = d->info->path = hashput(ap->parent->delta->tab, f->name, d);
168                 if (d->info->uidname) d->info->uidname = strdup(d->info->uidname);
169                 if (d->info->gidname) d->info->gidname = strdup(d->info->gidname);
170                 d->info->delta.base = d;
171                 if (!state.ordered)
172                         return(0);
173         }
174         if (!match(f->name) || state.verify && f->type != X_IFDIR && !verify(ap, f))
175                 return(0);
176         ap->selected++;
177         if (state.list && !linked)
178                 addlink(ap, f);
179         if (state.ordered && ap->delta && ap->delta->format != COMPRESS && (bp = ap->delta->base))
180         {
181                 register int    n;
182                 register int    m;
183
184                 for (;;)
185                 {
186                         if (bp->peek) bp->peek = 0;
187                         else
188                         {
189                                 if (bp->skip && bp->skip == bp->io.offset + bp->io.count)
190                                         fileskip(bp, &bp->file);
191                                 if (!getheader(bp, &bp->file)) break;
192                                 bp->skip = bp->io.offset + bp->io.count;
193                         }
194                         ordered(bp, bp->path.prev, bp->file.name);
195                         if ((m = pathcmp(bp->file.name, f->name)) > 0)
196                         {
197                                 bp->peek = 1;
198                                 break;
199                         }
200                         n = selectfile(bp, &bp->file);
201                         if (!m) break;
202                         if (n && !state.list)
203                         {
204                                 if (ap->io.mode)
205                                 {
206                                         File_t  tmp;
207
208                                         initfile(ap, &tmp, bp->file.name, X_IFREG);
209                                         tmp.delta.op = DELTA_delete;
210                                         putheader(ap, &tmp);
211                                         puttrailer(ap, &tmp);
212                                 }
213                                 else
214                                 {
215                                         struct stat     st;
216
217                                         if (!(*state.statf)(f->name, &st))
218                                         {
219                                                 if (S_ISDIR(st.st_mode))
220                                                 {
221                                                         if (!streq(f->name, ".") && !streq(f->name, ".."))
222                                                         {
223                                                                 if (rmdir(f->name)) error(ERROR_SYSTEM|2, "%s: cannot remove directory", f->name);
224                                                                 else listentry(f);
225                                                         }
226                                                 }
227                                                 else if (remove(f->name)) error(ERROR_SYSTEM|2, "%s: cannot remove file", f->name);
228                                                 else listentry(f);
229                                         }
230                                 }
231                         }
232                 }
233         }
234         return(1);
235 }
236
237 /*
238  * verify action on file
239  *
240  *      EOF     exit
241  *      NULL    skip file
242  *      .       keep file
243  *      <else>  rename file
244  */
245
246 int
247 verify __PARAM__((Archive_t* ap, register File_t* f), (ap, f)) __OTORP__(Archive_t* ap; register File_t* f;){
248         register char*  prompt;
249         register char*  name;
250
251         NoP(ap);
252         if (state.yesno) switch (state.operation)
253         {
254         case IN:
255                 prompt = "Read";
256                 break;
257         case OUT:
258                 prompt = "Write";
259                 break;
260         default:
261                 prompt = "Pass";
262                 break;
263         }
264         else prompt = "Rename";
265         sfprintf(state.wtty, "%s %s: " , prompt, f->name);
266         if (!(name = sfgetr(state.rtty, '\n', 1)))
267         {
268                 sfputc(state.wtty, '\n');
269                 finish(2);
270         }
271         if (state.yesno)
272                 return(*name == 'y');
273         switch (*name)
274         {
275         case 0:
276                 return(0);
277         case '.':
278                 if (!*(name + 1)) break;
279                 /*FALLTHROUGH*/
280         default:
281                 f->namesize = pathcanon(f->name = name, 0) - name + 1;
282                 break;
283         }
284         return(1);
285 }
286
287 /*
288  * check for file name mapping
289  * static data possibly returned
290  * two simultaneous calls supported
291  */
292
293 char*
294 map __PARAM__((register char* name), (name)) __OTORP__(register char* name;){
295         register Map_t* mp;
296         char*           to;
297         char*           from;
298
299         static char     filebuffer[4][PATH_MAX];
300         static int      filename = 0;
301
302         filename ^= 2;
303         from = to = name;
304         for (mp = state.maps; mp; mp = mp->next)
305                 if (reexec(mp->re, from))
306                 {
307                         filename ^= 1;
308                         to = filebuffer[filename];
309                         resub(mp->re, from, mp->into, to, mp->flags);
310                         if (mp->flags & RE_VERBOSE) sfprintf(sfstderr, "%s >> %s\n", from, to);
311                         if (mp->flags & RE_STOP) break;
312                         from = to;
313                 }
314         return(to);
315 }
316
317 typedef struct
318 {
319         Archive_t*      archive;
320         File_t*         file;
321 } List_handle_t;
322
323 /*
324  * sfkeyprintf() lookup
325  */
326
327 static int
328 listlookup __PARAM__((__V_* handle, register const char* name, const char* arg, int cc, char** ps, long* pn), (handle, name, arg, cc, ps, pn)) __OTORP__(__V_* handle; register const char* name; const char* arg; int cc; char** ps; long* pn;){
329         List_handle_t*          gp = (List_handle_t*)handle;
330         register File_t*        f = gp->file;
331         register struct stat*   st = f->st;
332         register char*          s = 0;
333         register long           n = 0;
334         Option_t*               op;
335
336         static Sfio_t*          mp;
337         static const char       fmt_time[] = "time=%?%l";
338         static const char       fmt_mode[] = "mode";
339
340         static char             buf[PATH_MAX];
341         static char             huh[8];
342
343         if (!(op = (Option_t*)hashget(state.options, name)))
344         {
345                 if (*name != '$')
346                         return(0);
347                 if (!(op = newof(0, Option_t, 1, 0)))
348                         error(3, "out of space [option]");
349                 op->name = hashput(state.options, 0, op);
350                 op->macro = getenv(name + 1);
351                 op->index = OPT_environ;
352                 op->flags |= OPT_DISABLE;
353         }
354         if (op->macro && !(op->flags & OPT_DISABLE))
355         {
356                 op->flags |= OPT_DISABLE;
357                 if (!mp && !(mp = sfstropen()))
358                         error(3, "out of space [macro]");
359                 sfkeyprintf(mp, handle, op->macro, listlookup, NiL);
360                 s = sfstruse(mp);
361                 op->flags &= ~OPT_DISABLE;
362         }
363         else switch (op->index)
364         {
365         case OPT_atime:
366                 n = st->st_atime;
367                 if (!arg)
368                         arg = fmt_time;
369                 break;
370         case OPT_charset:
371                 s = "ASCII";
372                 break;
373         case OPT_chksum:
374         case OPT_magic:
375         case OPT_typeflag:
376         case OPT_version:
377                 if (!gp->archive || gp->archive->format != PAX && gp->archive->format != TAR && gp->archive->format != USTAR)
378                         return(0);
379                 switch (op->index)
380                 {
381                 case OPT_chksum:
382                         s = tar_header.chksum;
383                         break;
384                 case OPT_magic:
385                         s = tar_header.magic;
386                         break;
387                 case OPT_typeflag:
388                         n = tar_header.typeflag;
389                         break;
390                 case OPT_version:
391                         s = tar_header.version;
392                         break;
393                 }
394                 break;
395         case OPT_ctime:
396                 n = st->st_ctime;
397                 if (!arg)
398                         arg = fmt_time;
399                 break;
400         case OPT_delta:
401                 switch (f->delta.op)
402                 {
403                 case 0:
404                 case DELTA_pass:
405                         return(0);
406                 case DELTA_create:
407                         s = "create";
408                         break;
409                 case DELTA_delete:
410                         s = "delete";
411                         break;
412                 case DELTA_update:
413                         s = "update";
414                         break;
415                 case DELTA_verify:
416                         s = "verify";
417                         break;
418                 default:
419                         sfsprintf(s = huh, sizeof(huh), "[op=%c]", f->delta.op);
420                         break;
421                 }
422                 break;
423         case OPT_device:
424                 if (f->type == X_IFBLK || f->type == X_IFCHR)
425                         s = fmtdev(st);
426                 else return(0);
427                 break;
428         case OPT_devmajor:
429                 n = major(st->st_dev);
430                 break;
431         case OPT_devminor:
432                 n = minor(st->st_dev);
433                 break;
434         case OPT_environ:
435                 if (!(s = op->macro))
436                         return(0);
437                 break;
438         case OPT_gname:
439                 if (f->gidname)
440                 {
441                         if (cc == 's') s = f->gidname;
442                         else n = strgid(f->gidname);
443                 }
444                 else if (cc == 's') s = fmtgid(st->st_gid);
445                 else n = st->st_gid;
446                 break;
447         case OPT_ino:
448                 n = st->st_ino;
449                 break;
450         case OPT_linkop:
451                 switch (f->linktype)
452                 {
453                 case HARDLINK:
454                         s = "==";
455                         break;
456                 case SOFTLINK:
457                         s = "->";
458                         break;
459                 default:
460                         return(0);
461                 }
462                 break;
463         case OPT_linkpath:
464                 if (f->linktype == NOLINK)
465                         return(0);
466                 s = f->linkname;
467                 break;
468         case OPT_mark:
469                 if (f->linktype == HARDLINK)
470                         s = "=";
471                 else if (f->linktype == SOFTLINK)
472                         s = "@";
473                 else if (f->type == X_IFDIR)
474                         s = "/";
475                 else if (f->type == X_IFIFO || f->type == X_IFSOCK)
476                         s = "|";
477                 else if (f->type == X_IFBLK || f->type == X_IFCHR)
478                         s = "$";
479                 else if (st->st_mode & (X_IXUSR|X_IXGRP|X_IXOTH))
480                         s = "*";
481                 else return(0);
482                 break;
483         case OPT_mode:
484                 n = st->st_mode;
485                 if (!arg)
486                         arg = fmt_mode;
487                 break;
488         case OPT_mtime:
489                 n = st->st_mtime;
490                 if (!arg)
491                         arg = fmt_time;
492                 break;
493         case OPT_name:
494                 if (s = strrchr(f->name, '/')) s++;
495                 else s = f->name;
496                 break;
497         case OPT_nlink:
498                 n = st->st_nlink;
499                 break;
500         case OPT_path:
501                 s = f->name;
502                 break;
503         case OPT_sequence:
504                 sfsprintf(s = buf, sizeof(buf), "%d-%d", gp->archive->volume, gp->archive->entry);
505                 break;
506         case OPT_size:
507                 if (f->linktype == SOFTLINK) n = f->linknamesize - 1;
508                 else if (f->delta.size != -1) n = f->delta.size;
509                 else n = st->st_size;
510                 break;
511         case OPT_uname:
512                 if (f->uidname)
513                 {
514                         if (cc == 's') s = f->uidname;
515                         else n = strgid(f->uidname);
516                 }
517                 else if (cc == 's') s = fmtuid(st->st_uid);
518                 else n = st->st_uid;
519                 break;
520         default:
521                 return(0);
522         }
523         if (s) *ps = s;
524         else if (cc == 's' && arg)
525         {
526                 if (strneq(arg, fmt_mode, 4))
527                         *ps = fmtmode(n, 1);
528                 else if (strneq(arg, fmt_time, 4))
529                         *ps = fmttime((*(arg + 4) == '=' ? arg : fmt_time) + 5, n);
530         }
531         else *pn = n;
532         return(1);
533 }
534
535 /*
536  * set up lookup() handle and call sfkeyprintf()
537  */
538
539 int
540 listprintf __PARAM__((Sfio_t* sp, Archive_t* ap, File_t* f, const char* format), (sp, ap, f, format)) __OTORP__(Sfio_t* sp; Archive_t* ap; File_t* f; const char* format;){
541         List_handle_t   list;
542
543         NoP(ap);
544         list.archive = state.in;
545         list.file = f;
546         return(sfkeyprintf(sp, &list, format, listlookup, NiL));
547 }
548
549 /*
550  * list entry information based on state.drop, state.list and state.verbose
551  */
552
553 void
554 listentry __PARAM__((register File_t* f), (f)) __OTORP__(register File_t* f;){
555         if (!f->extended && !f->skip && (state.drop || state.list || state.verbose))
556         {
557                 if (state.drop)
558                 {
559                         if (++state.dropcount >= 50)
560                         {
561                                 state.dropcount = 0;
562                                 sfprintf(sfstderr, ".\n");
563                         }
564                         else
565                         {
566                                 sfprintf(sfstderr, ".");
567                                 sfsync(sfstderr);
568                         }
569                 }
570                 else listprintf(state.list ? sfstdout : sfstderr, state.in, f, state.listformat);
571         }
572 }
573
574 /*
575  * prepare patterns for match()
576  */
577
578 char**
579 initmatch __PARAM__((char** p), (p)) __OTORP__(char** p;){
580         register char** a;
581
582         a = p;
583         while (*a)
584                 pathcanon(*a++, 0);
585         return(p);
586 }
587
588 /*
589  * determine if file s matches input patterns
590  */
591
592 int
593 match __PARAM__((register char* s), (s)) __OTORP__(register char* s;){
594         register char** p;
595         register char*  t;
596         int             n;
597
598         if (!(p = state.patterns)) return(state.matchsense);
599         if (state.exact)
600         {
601                 n = 0;
602                 while (t = *p++)
603                         if (*t)
604                         {
605                                 if (streq(s, t))
606                                 {
607                                         *--p = "";
608                                         return(1);
609                                 }
610                                 n = 1;
611                         }
612                 if (!n) finish(0);
613         }
614         else while (t = *p++)
615         {
616                 if (state.descend && dirprefix(t, s) || strmatch(s, t))
617                         return(state.matchsense);
618         }
619         return(!state.matchsense);
620 }
621
622 /*
623  * return 1 if p is a directory prefix of s
624  */
625
626 int
627 dirprefix __PARAM__((register char* p, register char* s), (p, s)) __OTORP__(register char* p; register char* s;){
628         if (*p == '.' && !*(p + 1) && *s != '/' && (*s != '.' || *(s + 1) != '.' || *(s + 2) && *(s + 2) != '/'))
629                 return(1);
630         if (*p == '/' && !*(p + 1))
631                 return(*s == '/');
632         while (*p)
633                 if (*p++ != *s++)
634                         return(0);
635         return(!*s || *s == '/');
636 }
637
638 /*
639  * return 1 if s is a portable string
640  */
641
642 int
643 portable __PARAM__((const char* s), (s)) __OTORP__(const char* s;){
644         register unsigned char* u = (unsigned char*)s;
645         register int            c;
646
647         while (c = *s++)
648                 if (c > 0177)
649                         return(0);
650         return(1);
651 }