00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #ifndef lint
00035 #if 0
00036 static char sccsid[] = "@(#)pat_rep.c 8.2 (Berkeley) 4/18/94";
00037 #endif
00038 #endif
00039
00040 #include <sys/types.h>
00041 #include <sys/stat.h>
00042 #include <stdio.h>
00043 #include <string.h>
00044 #include <unistd.h>
00045 #include <stdlib.h>
00046 #include <errno.h>
00047 #ifdef NET2_REGEX
00048 #include <regexp.h>
00049 #else
00050 #include <regex.h>
00051 #endif
00052 #include "pax.h"
00053 #include "pat_rep.h"
00054 #include "extern.h"
00055
00056
00057
00058
00059
00060
00061
00062
00063 #define MAXSUBEXP 10
00064 static PATTERN *pathead = NULL;
00065 static PATTERN *pattail = NULL;
00066 static REPLACE *rephead = NULL;
00067 static REPLACE *reptail = NULL;
00068
00069 static int rep_name(char *, int *, int);
00070 static int tty_rename(ARCHD *);
00071 static int fix_path(char *, int *, char *, int);
00072 static int fn_match(char *, char *, char **);
00073 static char * range_match(char *, int);
00074 #ifdef NET2_REGEX
00075 static int resub(regexp *, char *, char *, char *);
00076 #else
00077 static int resub(regex_t *, regmatch_t *, char *, char *, char *);
00078 #endif
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 int
00097 rep_add(char *str)
00098 {
00099 char *pt1;
00100 char *pt2;
00101 REPLACE *rep;
00102 # ifndef NET2_REGEX
00103 int res;
00104 char rebuf[BUFSIZ];
00105 # endif
00106
00107
00108
00109
00110 if ((str == NULL) || (*str == '\0')) {
00111 paxwarn(1, "Empty replacement string");
00112 return(-1);
00113 }
00114
00115
00116
00117
00118
00119 if ((pt1 = strchr(str+1, *str)) == NULL) {
00120 paxwarn(1, "Invalid replacement string %s", str);
00121 return(-1);
00122 }
00123
00124
00125
00126
00127
00128 if ((rep = (REPLACE *)malloc(sizeof(REPLACE))) == NULL) {
00129 paxwarn(1, "Unable to allocate memory for replacement string");
00130 return(-1);
00131 }
00132
00133 *pt1 = '\0';
00134 # ifdef NET2_REGEX
00135 if ((rep->rcmp = regcomp(str+1)) == NULL) {
00136 # else
00137 if ((res = regcomp(&(rep->rcmp), str+1, 0)) != 0) {
00138 regerror(res, &(rep->rcmp), rebuf, sizeof(rebuf));
00139 paxwarn(1, "%s while compiling regular expression %s", rebuf, str);
00140 # endif
00141 (void)free((char *)rep);
00142 return(-1);
00143 }
00144
00145
00146
00147
00148
00149
00150 *pt1++ = *str;
00151 if ((pt2 = strchr(pt1, *str)) == NULL) {
00152 # ifdef NET2_REGEX
00153 (void)free((char *)rep->rcmp);
00154 # else
00155 regfree(&(rep->rcmp));
00156 # endif
00157 (void)free((char *)rep);
00158 paxwarn(1, "Invalid replacement string %s", str);
00159 return(-1);
00160 }
00161
00162 *pt2 = '\0';
00163 rep->nstr = pt1;
00164 pt1 = pt2++;
00165 rep->flgs = 0;
00166
00167
00168
00169
00170 while (*pt2 != '\0') {
00171 switch(*pt2) {
00172 case 'g':
00173 case 'G':
00174 rep->flgs |= GLOB;
00175 break;
00176 case 'p':
00177 case 'P':
00178 rep->flgs |= PRNT;
00179 break;
00180 default:
00181 # ifdef NET2_REGEX
00182 (void)free((char *)rep->rcmp);
00183 # else
00184 regfree(&(rep->rcmp));
00185 # endif
00186 (void)free((char *)rep);
00187 *pt1 = *str;
00188 paxwarn(1, "Invalid replacement string option %s", str);
00189 return(-1);
00190 }
00191 ++pt2;
00192 }
00193
00194
00195
00196
00197 rep->fow = NULL;
00198 if (rephead == NULL) {
00199 reptail = rephead = rep;
00200 return(0);
00201 }
00202 reptail->fow = rep;
00203 reptail = rep;
00204 return(0);
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 int
00219 pat_add(char *str, char *chdnam)
00220 {
00221 PATTERN *pt;
00222
00223
00224
00225
00226 if ((str == NULL) || (*str == '\0')) {
00227 paxwarn(1, "Empty pattern string");
00228 return(-1);
00229 }
00230
00231
00232
00233
00234
00235
00236 if ((pt = (PATTERN *)malloc(sizeof(PATTERN))) == NULL) {
00237 paxwarn(1, "Unable to allocate memory for pattern string");
00238 return(-1);
00239 }
00240
00241 pt->pstr = str;
00242 pt->pend = NULL;
00243 pt->plen = strlen(str);
00244 pt->fow = NULL;
00245 pt->flgs = 0;
00246 pt->chdname = chdnam;
00247
00248 if (pathead == NULL) {
00249 pattail = pathead = pt;
00250 return(0);
00251 }
00252 pattail->fow = pt;
00253 pattail = pt;
00254 return(0);
00255 }
00256
00257
00258
00259
00260
00261
00262
00263 void
00264 pat_chk(void)
00265 {
00266 PATTERN *pt;
00267 int wban = 0;
00268
00269
00270
00271
00272
00273 for (pt = pathead; pt != NULL; pt = pt->fow) {
00274 if (pt->flgs & MTCH)
00275 continue;
00276 if (!wban) {
00277 paxwarn(1, "WARNING! These patterns were not matched:");
00278 ++wban;
00279 }
00280 (void)fprintf(stderr, "%s\n", pt->pstr);
00281 }
00282 }
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 int
00301 pat_sel(ARCHD *arcn)
00302 {
00303 PATTERN *pt;
00304 PATTERN **ppt;
00305 int len;
00306
00307
00308
00309
00310 if ((pathead == NULL) || ((pt = arcn->pat) == NULL))
00311 return(0);
00312
00313
00314
00315
00316
00317 if (!nflag) {
00318 pt->flgs |= MTCH;
00319 return(0);
00320 }
00321
00322
00323
00324
00325
00326
00327
00328
00329 if (pt->flgs & DIR_MTCH)
00330 return(0);
00331
00332 if (!dflag && ((pt->pend != NULL) || (arcn->type == PAX_DIR))) {
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 if (pt->pend != NULL)
00347 *pt->pend = '\0';
00348
00349 if ((pt->pstr = strdup(arcn->name)) == NULL) {
00350 paxwarn(1, "Pattern select out of memory");
00351 if (pt->pend != NULL)
00352 *pt->pend = '/';
00353 pt->pend = NULL;
00354 return(-1);
00355 }
00356
00357
00358
00359
00360 if (pt->pend != NULL) {
00361 *pt->pend = '/';
00362 pt->pend = NULL;
00363 }
00364 pt->plen = strlen(pt->pstr);
00365
00366
00367
00368
00369 len = pt->plen - 1;
00370 if (*(pt->pstr + len) == '/') {
00371 *(pt->pstr + len) = '\0';
00372 pt->plen = len;
00373 }
00374 pt->flgs = DIR_MTCH | MTCH;
00375 arcn->pat = pt;
00376 return(0);
00377 }
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 pt = pathead;
00388 ppt = &pathead;
00389 while ((pt != NULL) && (pt != arcn->pat)) {
00390 ppt = &(pt->fow);
00391 pt = pt->fow;
00392 }
00393
00394 if (pt == NULL) {
00395
00396
00397
00398 paxwarn(1, "Pattern list inconsistant");
00399 return(-1);
00400 }
00401 *ppt = pt->fow;
00402 (void)free((char *)pt);
00403 arcn->pat = NULL;
00404 return(0);
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 int
00420 pat_match(ARCHD *arcn)
00421 {
00422 PATTERN *pt;
00423
00424 arcn->pat = NULL;
00425
00426
00427
00428
00429
00430 if (pathead == NULL) {
00431 if (nflag && !cflag)
00432 return(-1);
00433 return(0);
00434 }
00435
00436
00437
00438
00439 pt = pathead;
00440 while (pt != NULL) {
00441
00442
00443
00444
00445 if (pt->flgs & DIR_MTCH) {
00446
00447
00448
00449
00450
00451
00452 if ((arcn->name[pt->plen] == '/') &&
00453 (strncmp(pt->pstr, arcn->name, pt->plen) == 0))
00454 break;
00455 } else if (fn_match(pt->pstr, arcn->name, &pt->pend) == 0)
00456 break;
00457 pt = pt->fow;
00458 }
00459
00460
00461
00462
00463
00464 if (pt == NULL)
00465 return(cflag ? 0 : 1);
00466
00467
00468
00469
00470
00471
00472 arcn->pat = pt;
00473 if (!cflag)
00474 return(0);
00475
00476 if (pat_sel(arcn) < 0)
00477 return(-1);
00478 arcn->pat = NULL;
00479 return(1);
00480 }
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491 static int
00492 fn_match(char *pattern, char *string, char **pend)
00493 {
00494 char c;
00495 char test;
00496
00497 *pend = NULL;
00498 for (;;) {
00499 switch (c = *pattern++) {
00500 case '\0':
00501
00502
00503
00504 if (*string == '\0')
00505 return(0);
00506
00507
00508
00509
00510 if ((dflag == 1) || (*string != '/'))
00511 return(-1);
00512
00513
00514
00515
00516
00517 *pend = string;
00518 return(0);
00519 case '?':
00520 if ((test = *string++) == '\0')
00521 return (-1);
00522 break;
00523 case '*':
00524 c = *pattern;
00525
00526
00527
00528 while (c == '*')
00529 c = *++pattern;
00530
00531
00532
00533
00534 if (c == '\0')
00535 return (0);
00536
00537
00538
00539
00540 while ((test = *string) != '\0') {
00541 if (!fn_match(pattern, string, pend))
00542 return (0);
00543 ++string;
00544 }
00545 return (-1);
00546 case '[':
00547
00548
00549
00550 if (((test = *string++) == '\0') ||
00551 ((pattern = range_match(pattern, test)) == NULL))
00552 return (-1);
00553 break;
00554 case '\\':
00555 default:
00556 if (c != *string++)
00557 return (-1);
00558 break;
00559 }
00560 }
00561
00562 }
00563
00564 static char *
00565 range_match(char *pattern, int test)
00566 {
00567 char c;
00568 char c2;
00569 int negate;
00570 int ok = 0;
00571
00572 if ((negate = (*pattern == '!')) != 0)
00573 ++pattern;
00574
00575 while ((c = *pattern++) != ']') {
00576
00577
00578
00579 if (c == '\0')
00580 return (NULL);
00581
00582 if ((*pattern == '-') && ((c2 = pattern[1]) != '\0') &&
00583 (c2 != ']')) {
00584 if ((c <= test) && (test <= c2))
00585 ok = 1;
00586 pattern += 2;
00587 } else if (c == test)
00588 ok = 1;
00589 }
00590 return (ok == negate ? NULL : pattern);
00591 }
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607 int
00608 mod_name(ARCHD *arcn)
00609 {
00610 int res = 0;
00611
00612
00613
00614
00615
00616 if (rmleadslash && arcn->name[0] == '/') {
00617 if (arcn->name[1] == '\0') {
00618 arcn->name[0] = '.';
00619 } else {
00620 (void)memmove(arcn->name, &arcn->name[1],
00621 strlen(arcn->name));
00622 arcn->nlen--;
00623 }
00624 if (rmleadslash < 2) {
00625 rmleadslash = 2;
00626 paxwarn(0, "Removing leading / from absolute path names in the archive");
00627 }
00628 }
00629 if (rmleadslash && arcn->ln_name[0] == '/' &&
00630 (arcn->type == PAX_HLK || arcn->type == PAX_HRG)) {
00631 if (arcn->ln_name[1] == '\0') {
00632 arcn->ln_name[0] = '.';
00633 } else {
00634 (void)memmove(arcn->ln_name, &arcn->ln_name[1],
00635 strlen(arcn->ln_name));
00636 arcn->ln_nlen--;
00637 }
00638 if (rmleadslash < 2) {
00639 rmleadslash = 2;
00640 paxwarn(0, "Removing leading / from absolute path names in the archive");
00641 }
00642 }
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663 if (rephead != NULL) {
00664
00665
00666
00667
00668 if ((res = rep_name(arcn->name, &(arcn->nlen), 1)) != 0)
00669 return(res);
00670
00671 if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
00672 (arcn->type == PAX_HRG)) &&
00673 ((res = rep_name(arcn->ln_name, &(arcn->ln_nlen), 0)) != 0))
00674 return(res);
00675 }
00676
00677 if (iflag) {
00678
00679
00680
00681 if ((res = tty_rename(arcn)) != 0)
00682 return(res);
00683 if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
00684 (arcn->type == PAX_HRG))
00685 sub_name(arcn->ln_name, &(arcn->ln_nlen), sizeof(arcn->ln_name));
00686 }
00687 return(res);
00688 }
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700 static int
00701 tty_rename(ARCHD *arcn)
00702 {
00703 char tmpname[PAXPATHLEN+2];
00704 int res;
00705
00706
00707
00708
00709
00710
00711
00712 tty_prnt("\nATTENTION: %s interactive file rename operation.\n", argv0);
00713
00714 for (;;) {
00715 ls_tty(arcn);
00716 tty_prnt("Input new name, or a \".\" to keep the old name, ");
00717 tty_prnt("or a \"return\" to skip this file.\n");
00718 tty_prnt("Input > ");
00719 if (tty_read(tmpname, sizeof(tmpname)) < 0)
00720 return(-1);
00721 if (strcmp(tmpname, "..") == 0) {
00722 tty_prnt("Try again, illegal file name: ..\n");
00723 continue;
00724 }
00725 if (strlen(tmpname) > PAXPATHLEN) {
00726 tty_prnt("Try again, file name too long\n");
00727 continue;
00728 }
00729 break;
00730 }
00731
00732
00733
00734
00735 if (tmpname[0] == '\0') {
00736 tty_prnt("Skipping file.\n");
00737 return(1);
00738 }
00739 if ((tmpname[0] == '.') && (tmpname[1] == '\0')) {
00740 tty_prnt("Processing continues, name unchanged.\n");
00741 return(0);
00742 }
00743
00744
00745
00746
00747
00748
00749 tty_prnt("Processing continues, name changed to: %s\n", tmpname);
00750 res = add_name(arcn->name, arcn->nlen, tmpname);
00751 arcn->nlen = l_strncpy(arcn->name, tmpname, sizeof(arcn->name) - 1);
00752 arcn->name[arcn->nlen] = '\0';
00753 if (res < 0)
00754 return(-1);
00755 return(0);
00756 }
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766 int
00767 set_dest(ARCHD *arcn, char *dest_dir, int dir_len)
00768 {
00769 if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0)
00770 return(-1);
00771
00772
00773
00774
00775
00776
00777 if ((arcn->type != PAX_HLK) && (arcn->type != PAX_HRG))
00778 return(0);
00779
00780 if (fix_path(arcn->ln_name, &(arcn->ln_nlen), dest_dir, dir_len) < 0)
00781 return(-1);
00782 return(0);
00783 }
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793 static int
00794 fix_path( char *or_name, int *or_len, char *dir_name, int dir_len)
00795 {
00796 char *src;
00797 char *dest;
00798 char *start;
00799 int len;
00800
00801
00802
00803
00804
00805
00806
00807 start = or_name;
00808 src = start + *or_len;
00809 dest = src + dir_len;
00810 if (*start == '/') {
00811 ++start;
00812 --dest;
00813 }
00814 if ((len = dest - or_name) > PAXPATHLEN) {
00815 paxwarn(1, "File name %s/%s, too long", dir_name, start);
00816 return(-1);
00817 }
00818 *or_len = len;
00819
00820
00821
00822
00823 while (src >= start)
00824 *dest-- = *src--;
00825 src = dir_name + dir_len - 1;
00826
00827
00828
00829
00830 while (src >= dir_name)
00831 *dest-- = *src--;
00832
00833 *(or_name + len) = '\0';
00834 return(0);
00835 }
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856 static int
00857 rep_name(char *name, int *nlen, int prnt)
00858 {
00859 REPLACE *pt;
00860 char *inpt;
00861 char *outpt;
00862 char *endpt;
00863 char *rpt;
00864 int found = 0;
00865 int res;
00866 # ifndef NET2_REGEX
00867 regmatch_t pm[MAXSUBEXP];
00868 # endif
00869 char nname[PAXPATHLEN+1];
00870 char buf1[PAXPATHLEN+1];
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880 pt = rephead;
00881 (void)strcpy(buf1, name);
00882 inpt = buf1;
00883 outpt = nname;
00884 endpt = outpt + PAXPATHLEN;
00885
00886
00887
00888
00889 while (pt != NULL) {
00890 do {
00891
00892
00893
00894
00895 # ifdef NET2_REGEX
00896 if (regexec(pt->rcmp, inpt) == 0)
00897 # else
00898 if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0)
00899 # endif
00900 break;
00901
00902
00903
00904
00905
00906
00907
00908
00909 found = 1;
00910 # ifdef NET2_REGEX
00911 rpt = pt->rcmp->startp[0];
00912 # else
00913 rpt = inpt + pm[0].rm_so;
00914 # endif
00915
00916 while ((inpt < rpt) && (outpt < endpt))
00917 *outpt++ = *inpt++;
00918 if (outpt == endpt)
00919 break;
00920
00921
00922
00923
00924
00925
00926
00927 # ifdef NET2_REGEX
00928 if ((res = resub(pt->rcmp,pt->nstr,outpt,endpt)) < 0) {
00929 # else
00930 if ((res = resub(&(pt->rcmp),pm,pt->nstr,outpt,endpt))
00931 < 0) {
00932 # endif
00933 if (prnt)
00934 paxwarn(1, "Replacement name error %s",
00935 name);
00936 return(1);
00937 }
00938 outpt += res;
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950 # ifdef NET2_REGEX
00951 inpt = pt->rcmp->endp[0];
00952 # else
00953 inpt += pm[0].rm_eo - pm[0].rm_so;
00954 # endif
00955
00956 if ((outpt == endpt) || (*inpt == '\0'))
00957 break;
00958
00959
00960
00961
00962
00963 } while (pt->flgs & GLOB);
00964
00965 if (found)
00966 break;
00967
00968
00969
00970
00971 pt = pt->fow;
00972 }
00973
00974 if (found) {
00975
00976
00977
00978
00979 while ((outpt < endpt) && (*inpt != '\0'))
00980 *outpt++ = *inpt++;
00981
00982 *outpt = '\0';
00983 if ((outpt == endpt) && (*inpt != '\0')) {
00984 if (prnt)
00985 paxwarn(1,"Replacement name too long %s >> %s",
00986 name, nname);
00987 return(1);
00988 }
00989
00990
00991
00992
00993 if (prnt && (pt->flgs & PRNT)) {
00994 if (*nname == '\0')
00995 (void)fprintf(stderr,"%s >> <empty string>\n",
00996 name);
00997 else
00998 (void)fprintf(stderr,"%s >> %s\n", name, nname);
00999 }
01000
01001
01002
01003
01004
01005 if (*nname == '\0')
01006 return(1);
01007 *nlen = l_strncpy(name, nname, PAXPATHLEN + 1);
01008 name[PAXPATHLEN] = '\0';
01009 }
01010 return(0);
01011 }
01012
01013 #ifdef NET2_REGEX
01014
01015
01016
01017
01018
01019
01020
01021
01022 static int
01023 resub(regexp *prog, char *src, char *dest, char *destend)
01024 {
01025 char *spt;
01026 char *dpt;
01027 char c;
01028 int no;
01029 int len;
01030
01031 spt = src;
01032 dpt = dest;
01033 while ((dpt < destend) && ((c = *spt++) != '\0')) {
01034 if (c == '&')
01035 no = 0;
01036 else if ((c == '\\') && (*spt >= '0') && (*spt <= '9'))
01037 no = *spt++ - '0';
01038 else {
01039 if ((c == '\\') && ((*spt == '\\') || (*spt == '&')))
01040 c = *spt++;
01041 *dpt++ = c;
01042 continue;
01043 }
01044 if ((prog->startp[no] == NULL) || (prog->endp[no] == NULL) ||
01045 ((len = prog->endp[no] - prog->startp[no]) <= 0))
01046 continue;
01047
01048
01049
01050
01051
01052 if (len > (destend - dpt))
01053 len = destend - dpt;
01054 if (l_strncpy(dpt, prog->startp[no], len) != len)
01055 return(-1);
01056 dpt += len;
01057 }
01058 return(dpt - dest);
01059 }
01060
01061 #else
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071 static int
01072 resub(regex_t *rp, regmatch_t *pm, char *src, char *dest,
01073 char *destend)
01074 {
01075 char *spt;
01076 char *dpt;
01077 char c;
01078 regmatch_t *pmpt;
01079 int len;
01080 int subexcnt;
01081
01082 spt = src;
01083 dpt = dest;
01084 subexcnt = rp->re_nsub;
01085 while ((dpt < destend) && ((c = *spt++) != '\0')) {
01086
01087
01088
01089
01090 if (c == '&') {
01091 pmpt = pm;
01092 } else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) {
01093
01094
01095
01096 if ((len = *spt++ - '0') > subexcnt)
01097 return(-1);
01098 pmpt = pm + len;
01099 } else {
01100
01101
01102
01103 if ((c == '\\') && ((*spt == '\\') || (*spt == '&')))
01104 c = *spt++;
01105 *dpt++ = c;
01106 continue;
01107 }
01108
01109
01110
01111
01112 if ((pmpt->rm_so < 0) || (pmpt->rm_eo < 0) ||
01113 ((len = pmpt->rm_eo - pmpt->rm_so) <= 0))
01114 continue;
01115
01116
01117
01118
01119
01120 if (len > (destend - dpt))
01121 len = destend - dpt;
01122 if (l_strncpy(dpt, src + pmpt->rm_so, len) != len)
01123 return(-1);
01124 dpt += len;
01125 }
01126 return(dpt - dest);
01127 }
01128 #endif