1*57266Smuller /*- 2*57266Smuller * Copyright (c) 1992 Keith Muller. 3*57266Smuller * Copyright (c) 1992 The Regents of the University of California. 4*57266Smuller * All rights reserved. 5*57266Smuller * 6*57266Smuller * This code is derived from software contributed to Berkeley by 7*57266Smuller * Keith Muller of the University of California, San Diego. 8*57266Smuller * 9*57266Smuller * %sccs.include.redist.c% 10*57266Smuller */ 11*57266Smuller 12*57266Smuller #ifndef lint 13*57266Smuller static char sccsid[] = "@(#)pat_rep.c 1.1 (Berkeley) 12/21/92"; 14*57266Smuller #endif /* not lint */ 15*57266Smuller 16*57266Smuller #include <sys/types.h> 17*57266Smuller #include <sys/time.h> 18*57266Smuller #include <sys/stat.h> 19*57266Smuller #include <sys/param.h> 20*57266Smuller #include <stdio.h> 21*57266Smuller #include <ctype.h> 22*57266Smuller #include <string.h> 23*57266Smuller #include <unistd.h> 24*57266Smuller #include <stdlib.h> 25*57266Smuller #include <fnmatch.h> 26*57266Smuller #ifdef NET2_REGEX 27*57266Smuller #include <regexp.h> 28*57266Smuller #else 29*57266Smuller #include <regex.h> 30*57266Smuller #endif 31*57266Smuller #include "pax.h" 32*57266Smuller #include "pat_rep.h" 33*57266Smuller #include "extern.h" 34*57266Smuller 35*57266Smuller /* 36*57266Smuller * routines to handle pattern matching, name modification (regular expression 37*57266Smuller * substitution and interactive renames), and destination name modification for 38*57266Smuller * copy (-rw). Both file name and link names are adjusted as required in these 39*57266Smuller * routines. 40*57266Smuller */ 41*57266Smuller 42*57266Smuller #define MAXSUBEXP 10 /* max subexpressions, DO NOT CHANGE */ 43*57266Smuller static PATTERN *pathead = NULL; /* file pattern match list head */ 44*57266Smuller static PATTERN *pattail = NULL; /* file pattern match list tail */ 45*57266Smuller static REPLACE *rephead = NULL; /* replacement string list head */ 46*57266Smuller static REPLACE *reptail = NULL; /* replacement string list tail */ 47*57266Smuller 48*57266Smuller static int rep_name __P((char *, int *, int)); 49*57266Smuller static int tty_rename __P((register ARCHD *)); 50*57266Smuller static int fix_path __P((char *, int *, char *, int)); 51*57266Smuller #ifdef NET2_REGEX 52*57266Smuller static int resub __P((regexp *, char *, char *, register char *)); 53*57266Smuller #else 54*57266Smuller static int resub __P((regex_t *, regmatch_t *, char *, char *, char *)); 55*57266Smuller #endif 56*57266Smuller 57*57266Smuller /* 58*57266Smuller * rep_add() 59*57266Smuller * parses the -s replacement string; compiles the regular expression 60*57266Smuller * and stores the compiled value and it's replacement string together in 61*57266Smuller * replacement string list. Input to this function is of the form: 62*57266Smuller * /old/new/pg 63*57266Smuller * The first char in the string specifies the delimiter used by this 64*57266Smuller * replacement string. "Old" is a regular expression in "ed" format which 65*57266Smuller * is compiled by regcomp() and is applied to filenames. "new" is the 66*57266Smuller * substitution string; p and g are options flags for printing and global 67*57266Smuller * replacement (over the single filename) 68*57266Smuller * Return: 69*57266Smuller * 0 if a proper replacement string and regular expression was added to 70*57266Smuller * the list of replacement patterns; -1 otherwise. 71*57266Smuller */ 72*57266Smuller 73*57266Smuller #if __STDC__ 74*57266Smuller int 75*57266Smuller rep_add(register char *str) 76*57266Smuller #else 77*57266Smuller int 78*57266Smuller rep_add(str) 79*57266Smuller register char *str; 80*57266Smuller #endif 81*57266Smuller { 82*57266Smuller register char *pt1; 83*57266Smuller register char *pt2; 84*57266Smuller register REPLACE *rep; 85*57266Smuller # ifndef NET2_REGEX 86*57266Smuller register int res; 87*57266Smuller char rebuf[BUFSIZ]; 88*57266Smuller # endif 89*57266Smuller 90*57266Smuller /* 91*57266Smuller * throw out the bad parameters 92*57266Smuller */ 93*57266Smuller if ((str == NULL) || (*str == '\0')) { 94*57266Smuller warn(1, "Empty replacement string"); 95*57266Smuller return(-1); 96*57266Smuller } 97*57266Smuller 98*57266Smuller /* 99*57266Smuller * first character in the string specifies what the delimiter is for 100*57266Smuller * this expression 101*57266Smuller */ 102*57266Smuller if ((pt1 = strchr(str+1, *str)) == NULL) { 103*57266Smuller warn(1, "Invalid replacement string %s", str); 104*57266Smuller return(-1); 105*57266Smuller } 106*57266Smuller 107*57266Smuller /* 108*57266Smuller * allocate space for the node that handles this replacement pattern 109*57266Smuller * and split out the regular expression and try to compile it 110*57266Smuller */ 111*57266Smuller if ((rep = (REPLACE *)malloc(sizeof(REPLACE))) == NULL) { 112*57266Smuller warn(1, "Unable to allocate memory for replacement string"); 113*57266Smuller return(-1); 114*57266Smuller } 115*57266Smuller 116*57266Smuller *pt1 = '\0'; 117*57266Smuller # ifdef NET2_REGEX 118*57266Smuller if ((rep->rcmp = regcomp(str+1)) == NULL) { 119*57266Smuller # else 120*57266Smuller if ((res = regcomp(&(rep->rcmp), str+1, 0)) != 0) { 121*57266Smuller regerror(res, &(rep->rcmp), rebuf, sizeof(rebuf)); 122*57266Smuller warn(1, "%s while compiling regular expression %s", rebuf, str); 123*57266Smuller # endif 124*57266Smuller (void)free((char *)rep); 125*57266Smuller return(-1); 126*57266Smuller } 127*57266Smuller 128*57266Smuller /* 129*57266Smuller * put the delimiter back in case we need an error message and 130*57266Smuller * locate the delimiter at the end of the replacement string 131*57266Smuller * we then point the node at the new substitution string 132*57266Smuller */ 133*57266Smuller *pt1++ = *str; 134*57266Smuller if ((pt2 = strchr(pt1, *str)) == NULL) { 135*57266Smuller # ifdef NET2_REGEX 136*57266Smuller (void)free((char *)rep->rcmp); 137*57266Smuller # else 138*57266Smuller regfree(&(rep->rcmp)); 139*57266Smuller # endif 140*57266Smuller (void)free((char *)rep); 141*57266Smuller warn(1, "Invalid replacement string %s", str); 142*57266Smuller return(-1); 143*57266Smuller } 144*57266Smuller 145*57266Smuller *pt2 = '\0'; 146*57266Smuller rep->nstr = pt1; 147*57266Smuller pt1 = pt2++; 148*57266Smuller rep->flgs = 0; 149*57266Smuller 150*57266Smuller /* 151*57266Smuller * set the options if any 152*57266Smuller */ 153*57266Smuller while (*pt2 != '\0') { 154*57266Smuller switch(*pt2) { 155*57266Smuller case 'g': 156*57266Smuller case 'G': 157*57266Smuller rep->flgs |= GLOB; 158*57266Smuller break; 159*57266Smuller case 'p': 160*57266Smuller case 'P': 161*57266Smuller rep->flgs |= PRNT; 162*57266Smuller break; 163*57266Smuller default: 164*57266Smuller # ifdef NET2_REGEX 165*57266Smuller (void)free((char *)rep->rcmp); 166*57266Smuller # else 167*57266Smuller regfree(&(rep->rcmp)); 168*57266Smuller # endif 169*57266Smuller (void)free((char *)rep); 170*57266Smuller *pt1 = *str; 171*57266Smuller warn(1, "Invalid replacement string option %s", str); 172*57266Smuller return(-1); 173*57266Smuller } 174*57266Smuller ++pt2; 175*57266Smuller } 176*57266Smuller 177*57266Smuller /* 178*57266Smuller * all done, link it in at the end 179*57266Smuller */ 180*57266Smuller rep->fow = NULL; 181*57266Smuller if (rephead == NULL) { 182*57266Smuller reptail = rephead = rep; 183*57266Smuller return(0); 184*57266Smuller } 185*57266Smuller reptail->fow = rep; 186*57266Smuller reptail = rep; 187*57266Smuller return(0); 188*57266Smuller } 189*57266Smuller 190*57266Smuller /* 191*57266Smuller * pat_add() 192*57266Smuller * add a pattern match to the pattern match list. Pattern matches are used 193*57266Smuller * to select which archive members are extracted. (They appear as 194*57266Smuller * arguments to pax in the list and read modes). If no patterns are 195*57266Smuller * supplied to pax, all members in the archive will be selected (and the 196*57266Smuller * pattern match list is empty). 197*57266Smuller * Return: 198*57266Smuller * 0 if the pattern was added to the list, -1 otherwise 199*57266Smuller */ 200*57266Smuller 201*57266Smuller #if __STDC__ 202*57266Smuller int 203*57266Smuller pat_add(char *str) 204*57266Smuller #else 205*57266Smuller int 206*57266Smuller pat_add(str) 207*57266Smuller char *str; 208*57266Smuller #endif 209*57266Smuller { 210*57266Smuller register PATTERN *pt; 211*57266Smuller 212*57266Smuller /* 213*57266Smuller * throw out the junk 214*57266Smuller */ 215*57266Smuller if ((str == NULL) || (*str == '\0')) { 216*57266Smuller warn(1, "Empty pattern string"); 217*57266Smuller return(-1); 218*57266Smuller } 219*57266Smuller 220*57266Smuller /* 221*57266Smuller * allocate space for the pattern and store the pattern. the pattern is 222*57266Smuller * part of argv so do not bother to copy it, just point at it. Add the 223*57266Smuller * node to the end of the pattern list 224*57266Smuller */ 225*57266Smuller if ((pt = (PATTERN *)malloc(sizeof(PATTERN))) == NULL) { 226*57266Smuller warn(1, "Unable to allocate memory for pattern string"); 227*57266Smuller return(-1); 228*57266Smuller } 229*57266Smuller 230*57266Smuller pt->pstr = str; 231*57266Smuller pt->plen = strlen(str); 232*57266Smuller pt->fow = NULL; 233*57266Smuller pt->flgs = 0; 234*57266Smuller if (pathead == NULL) { 235*57266Smuller pattail = pathead = pt; 236*57266Smuller return(0); 237*57266Smuller } 238*57266Smuller pattail->fow = pt; 239*57266Smuller pattail = pt; 240*57266Smuller return(0); 241*57266Smuller } 242*57266Smuller 243*57266Smuller /* 244*57266Smuller * pat_chk() 245*57266Smuller * complain if any the user supplied pattern did not result in a match to 246*57266Smuller * a selected archive member. 247*57266Smuller */ 248*57266Smuller 249*57266Smuller #if __STDC__ 250*57266Smuller void 251*57266Smuller pat_chk(void) 252*57266Smuller #else 253*57266Smuller void 254*57266Smuller pat_chk() 255*57266Smuller #endif 256*57266Smuller { 257*57266Smuller register PATTERN *pt; 258*57266Smuller register int wban = 0; 259*57266Smuller 260*57266Smuller /* 261*57266Smuller * walk down the list checking the flags to make sure MTCH was set, 262*57266Smuller * if not complain 263*57266Smuller */ 264*57266Smuller for (pt = pathead; pt != NULL; pt = pt->fow) { 265*57266Smuller if (pt->flgs & MTCH) 266*57266Smuller continue; 267*57266Smuller if (!wban) { 268*57266Smuller warn(1, "WARNING! These patterns were not matched:"); 269*57266Smuller ++wban; 270*57266Smuller } 271*57266Smuller (void)fprintf(stderr, "%s\n", pt->pstr); 272*57266Smuller } 273*57266Smuller } 274*57266Smuller 275*57266Smuller /* 276*57266Smuller * pat_sel() 277*57266Smuller * the archive member which matches a pattern was selected. Mark the 278*57266Smuller * pattern as having selected an archive member. arcn->pat points at the 279*57266Smuller * pattern that was matched. arcn->pat is set in pat_match() 280*57266Smuller * 281*57266Smuller * NOTE: When the -c option is used, we are called when there was no match 282*57266Smuller * by pat_match() (that means we did match before the inverted sense of 283*57266Smuller * the logic). Now this seems really strange at first, but with -c we 284*57266Smuller * need to keep track of those patterns that cause a archive member to NOT 285*57266Smuller * be selected (it found an archive member with a specified pattern) 286*57266Smuller * Return: 287*57266Smuller * 0 if the pattern pointed at by arcn->pat was tagged as creating a 288*57266Smuller * match, -1 otherwise. 289*57266Smuller */ 290*57266Smuller 291*57266Smuller #if __STDC__ 292*57266Smuller int 293*57266Smuller pat_sel(register ARCHD *arcn) 294*57266Smuller #else 295*57266Smuller int 296*57266Smuller pat_sel(arcn) 297*57266Smuller register ARCHD *arcn; 298*57266Smuller #endif 299*57266Smuller { 300*57266Smuller register PATTERN *pt; 301*57266Smuller register PATTERN **ppt; 302*57266Smuller register int len; 303*57266Smuller 304*57266Smuller /* 305*57266Smuller * if no patterns just return 306*57266Smuller */ 307*57266Smuller if ((pathead == NULL) || ((pt = arcn->pat) == NULL)) 308*57266Smuller return(0); 309*57266Smuller 310*57266Smuller /* 311*57266Smuller * when we are NOT limited to a single match per pattern mark the 312*57266Smuller * the pattern and return 313*57266Smuller */ 314*57266Smuller if (!nflag) { 315*57266Smuller pt->flgs |= MTCH; 316*57266Smuller if (dflag || (arcn->type != PAX_DIR)) 317*57266Smuller return(0); 318*57266Smuller /* 319*57266Smuller * ok we matched a directory and we are allowing 320*57266Smuller * subtree matches. We add this as a DIR_MTCH pattern 321*57266Smuller * so all its children will match. Note we know that 322*57266Smuller * when successful, pat_add() puts the pattern at the 323*57266Smuller * tail (yup a kludge). In the code below will make 324*57266Smuller * a dir match pattern 325*57266Smuller */ 326*57266Smuller if ((pat_add(arcn->name) < 0) || ((pt = pattail) == NULL)) 327*57266Smuller return(-1); 328*57266Smuller arcn->pat = pt; 329*57266Smuller } 330*57266Smuller 331*57266Smuller /* 332*57266Smuller * we reach this point only when we allow a single selected match per 333*57266Smuller * pattern, or we have to add a DIR_MATCH pattern. if the pattern 334*57266Smuller * matched a directory and we do not have -d * (dflag) we are done 335*57266Smuller * with this pattern. We may also be handed a file in the subtree of a 336*57266Smuller * directory. in that case when we are operating with -d, this pattern 337*57266Smuller * was already selected and we are done 338*57266Smuller */ 339*57266Smuller if (pt->flgs & DIR_MTCH) 340*57266Smuller return(0); 341*57266Smuller 342*57266Smuller if (!dflag && (arcn->type == PAX_DIR)) { 343*57266Smuller /* 344*57266Smuller * we are allowing subtree matches at directories, mark the 345*57266Smuller * node as a directory match so pat_match() will only match 346*57266Smuller * children of this directory (we replace the pattern with the 347*57266Smuller * directory name to enforce this subtree only match) 348*57266Smuller * pat_match() looks for DIR_MTCH to determine what comparison 349*57266Smuller * technique to use when it checks for a pattern match 350*57266Smuller */ 351*57266Smuller if ((pt->pstr = strdup(arcn->name)) == NULL) { 352*57266Smuller warn(1, "Pattern select out of memory"); 353*57266Smuller return(-1); 354*57266Smuller } 355*57266Smuller pt->plen = strlen(pt->pstr); 356*57266Smuller 357*57266Smuller /* 358*57266Smuller * strip off any trailing /, this should really never happen 359*57266Smuller */ 360*57266Smuller len = pt->plen - 1; 361*57266Smuller if (*(pt->pstr + len) == '/') { 362*57266Smuller *(pt->pstr + len) = '\0'; 363*57266Smuller pt->plen = len; 364*57266Smuller } 365*57266Smuller pt->flgs |= DIR_MTCH | MTCH; 366*57266Smuller return(0); 367*57266Smuller } 368*57266Smuller 369*57266Smuller /* 370*57266Smuller * it is not a directory, we are then done with this pattern, so we 371*57266Smuller * delete it from the list, as it can never be used for another match 372*57266Smuller * Seems kind of strange to do for a -c, but the pax spec is really 373*57266Smuller * vague on the interaction of -c -n and -d. We assume that when -c 374*57266Smuller * and the pattern rejects a member (i.e. it matched it) it is done. 375*57266Smuller * In effect we place the order of the flags as having -c last. 376*57266Smuller */ 377*57266Smuller pt = pathead; 378*57266Smuller ppt = &pathead; 379*57266Smuller while ((pt != NULL) && (pt != arcn->pat)) { 380*57266Smuller ppt = &(pt->fow); 381*57266Smuller pt = pt->fow; 382*57266Smuller } 383*57266Smuller 384*57266Smuller if (pt == NULL) { 385*57266Smuller /* 386*57266Smuller * should never happen.... 387*57266Smuller */ 388*57266Smuller warn(1, "Pattern list inconsistant"); 389*57266Smuller return(-1); 390*57266Smuller } 391*57266Smuller *ppt = pt->fow; 392*57266Smuller (void)free((char *)pt); 393*57266Smuller arcn->pat = NULL; 394*57266Smuller return(0); 395*57266Smuller } 396*57266Smuller 397*57266Smuller /* 398*57266Smuller * pat_match() 399*57266Smuller * see if this archive member matches any supplied pattern, if a match 400*57266Smuller * is found, arcn->pat is set to point at the potential pattern. Later if 401*57266Smuller * this archive member is "selected" we process and mark the pattern as 402*57266Smuller * one which matched a selected archive member (see pat_sel()) 403*57266Smuller * Return: 404*57266Smuller * 0 if this archive member should be processed, 1 if it should be 405*57266Smuller * skipped and -1 if we are done with all patterns (and pax should quit 406*57266Smuller * looking for more members) 407*57266Smuller */ 408*57266Smuller 409*57266Smuller #if __STDC__ 410*57266Smuller int 411*57266Smuller pat_match(register ARCHD *arcn) 412*57266Smuller #else 413*57266Smuller int 414*57266Smuller pat_match(arcn) 415*57266Smuller register ARCHD *arcn; 416*57266Smuller #endif 417*57266Smuller { 418*57266Smuller register PATTERN *pt; 419*57266Smuller 420*57266Smuller arcn->pat = NULL; 421*57266Smuller 422*57266Smuller /* 423*57266Smuller * if there are no more patterns and we have -n (and not -c) we are 424*57266Smuller * done. otherwise with no patterns to match, matches all 425*57266Smuller */ 426*57266Smuller if (pathead == NULL) { 427*57266Smuller if (nflag && !cflag) 428*57266Smuller return(-1); 429*57266Smuller return(0); 430*57266Smuller } 431*57266Smuller 432*57266Smuller /* 433*57266Smuller * have to search down the list one at a time looking for a match. 434*57266Smuller */ 435*57266Smuller pt = pathead; 436*57266Smuller while (pt != NULL) { 437*57266Smuller /* 438*57266Smuller * check for a file name match unless we have DIR_MTCH set in 439*57266Smuller * this pattern then we want a prefix match 440*57266Smuller */ 441*57266Smuller 442*57266Smuller if (pt->flgs & DIR_MTCH) { 443*57266Smuller /* 444*57266Smuller * this pattern was matched before to a directory 445*57266Smuller * as we must have -n set for this (but not -d). We can 446*57266Smuller * only match CHILDREN of that directory so we must use 447*57266Smuller * an exact prefix match 448*57266Smuller */ 449*57266Smuller if ((strncmp(pt->pstr, arcn->name, pt->plen) == 0) && 450*57266Smuller (arcn->name[pt->plen] == '/')) 451*57266Smuller break; 452*57266Smuller } else if (fnmatch(pt->pstr, arcn->name, 0) == 0) 453*57266Smuller break; 454*57266Smuller pt = pt->fow; 455*57266Smuller } 456*57266Smuller 457*57266Smuller /* 458*57266Smuller * return the result, remember that cflag (-c) inverts the sense of a 459*57266Smuller * match 460*57266Smuller */ 461*57266Smuller if (pt == NULL) 462*57266Smuller return(cflag ? 0 : 1); 463*57266Smuller 464*57266Smuller /* 465*57266Smuller * we had a match, now when we invert the sense (-c) we reject this 466*57266Smuller * member. However we have to tag the pattern a being successful, (in a 467*57266Smuller * match, not in selecting a archive member) so we call pat_sel() here. 468*57266Smuller */ 469*57266Smuller arcn->pat = pt; 470*57266Smuller if (!cflag) 471*57266Smuller return(0); 472*57266Smuller 473*57266Smuller if (pat_sel(arcn) < 0) 474*57266Smuller return(-1); 475*57266Smuller arcn->pat = NULL; 476*57266Smuller return(1); 477*57266Smuller } 478*57266Smuller 479*57266Smuller /* 480*57266Smuller * mod_name() 481*57266Smuller * modify a selected file name. first attempt to apply replacement string 482*57266Smuller * expressions, then apply interactive file rename. We apply replacement 483*57266Smuller * string expressions to both filenames and file links (if we didn't the 484*57266Smuller * links would point to the wrong place, and we could never be able to 485*57266Smuller * move an archive that has a file link in it). When we rename files 486*57266Smuller * interactively, we store that mapping (old name to user input name) so 487*57266Smuller * if we spot any file links to the old file name in the future, we will 488*57266Smuller * know exactly how to fix the file link. 489*57266Smuller * Return: 490*57266Smuller * 0 continue to process file, 1 skip this file, -1 pax is finished 491*57266Smuller */ 492*57266Smuller 493*57266Smuller #if __STDC__ 494*57266Smuller int 495*57266Smuller mod_name(register ARCHD *arcn) 496*57266Smuller #else 497*57266Smuller int 498*57266Smuller mod_name(arcn) 499*57266Smuller register ARCHD *arcn; 500*57266Smuller #endif 501*57266Smuller { 502*57266Smuller register int res = 0; 503*57266Smuller 504*57266Smuller /* 505*57266Smuller * IMPORTANT: We have a problem. what do we do with symlinks? 506*57266Smuller * Modifying a hard link name makes sense, as we know the file it 507*57266Smuller * points at should have been seen already in the archive (and if it 508*57266Smuller * wasn't seen because of a read error or a bad archive, we lose 509*57266Smuller * anyway). But there are no such requirements for symlinks. On one 510*57266Smuller * hand the symlink that refers to a file in the archive will have to 511*57266Smuller * be modified to so it will still work at its new location in the 512*57266Smuller * file system. On the other hand a symlink that points elsewhere (and 513*57266Smuller * should continue to do so) should not be modified. There is clearly 514*57266Smuller * no perfect solution here. So we handle them like hardlinks. Clearly 515*57266Smuller * a replacement made by the interactive rename mapping is very likely 516*57266Smuller * to be correct since it applies to a single file and is an exact 517*57266Smuller * match. The regular expression replacements are a little harder to 518*57266Smuller * justify though. We claim that the symlink name is only likely 519*57266Smuller * to be replaced when it points within the file tree being moved and 520*57266Smuller * in that case it should be modified. what we really need to do is to 521*57266Smuller * call an oracle here. :) 522*57266Smuller */ 523*57266Smuller if (rephead != NULL) { 524*57266Smuller /* 525*57266Smuller * we have replacement strings, modify the name and the link 526*57266Smuller * name if any. 527*57266Smuller */ 528*57266Smuller if ((res = rep_name(arcn->name, &(arcn->nlen), 1)) != 0) 529*57266Smuller return(res); 530*57266Smuller 531*57266Smuller if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || 532*57266Smuller (arcn->type == PAX_HRG)) && 533*57266Smuller ((res = rep_name(arcn->ln_name, &(arcn->ln_nlen), 0)) != 0)) 534*57266Smuller return(res); 535*57266Smuller } 536*57266Smuller 537*57266Smuller if (iflag) { 538*57266Smuller /* 539*57266Smuller * perform interactive file rename, then map the link if any 540*57266Smuller */ 541*57266Smuller if ((res = tty_rename(arcn)) != 0) 542*57266Smuller return(res); 543*57266Smuller if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || 544*57266Smuller (arcn->type == PAX_HRG)) 545*57266Smuller sub_name(arcn->ln_name, &(arcn->ln_nlen)); 546*57266Smuller } 547*57266Smuller return(res); 548*57266Smuller } 549*57266Smuller 550*57266Smuller /* 551*57266Smuller * tty_rename() 552*57266Smuller * Prompt the user for a replacement file name. A "." keeps the old name, 553*57266Smuller * a empty line skips the file, and an EOF on reading the tty, will cause 554*57266Smuller * pax to stop processing and exit. Otherwise the file name input, replaces 555*57266Smuller * the old one. 556*57266Smuller * Return: 557*57266Smuller * 0 process this file, 1 skip this file, -1 we need to exit pax 558*57266Smuller */ 559*57266Smuller 560*57266Smuller #if __STDC__ 561*57266Smuller static int 562*57266Smuller tty_rename(register ARCHD *arcn) 563*57266Smuller #else 564*57266Smuller static int 565*57266Smuller tty_rename(arcn) 566*57266Smuller register ARCHD *arcn; 567*57266Smuller #endif 568*57266Smuller { 569*57266Smuller char tmpname[PAXPATHLEN+2]; 570*57266Smuller int res; 571*57266Smuller 572*57266Smuller /* 573*57266Smuller * prompt user for the replacement name for a file, keep trying until 574*57266Smuller * we get some reasonable input. Archives may have more than one file 575*57266Smuller * on them with the same name (from updates etc). We print verbose info 576*57266Smuller * on the file so the user knows what is up. 577*57266Smuller */ 578*57266Smuller tty_prnt("\nATTENTION: Pax interactive file rename operation.\n"); 579*57266Smuller 580*57266Smuller for (;;) { 581*57266Smuller ls_tty(arcn); 582*57266Smuller tty_prnt("Input new name, or a \".\" to keep the old name, "); 583*57266Smuller tty_prnt("or a \"return\" to skip this file.\n"); 584*57266Smuller tty_prnt("Input > "); 585*57266Smuller if (tty_read(tmpname, sizeof(tmpname)) < 0) 586*57266Smuller return(-1); 587*57266Smuller if (strcmp(tmpname, "..") == 0) { 588*57266Smuller tty_prnt("Try again, illegal file name: ..\n"); 589*57266Smuller continue; 590*57266Smuller } 591*57266Smuller if (strlen(tmpname) > PAXPATHLEN) { 592*57266Smuller tty_prnt("Try again, file name too long\n"); 593*57266Smuller continue; 594*57266Smuller } 595*57266Smuller break; 596*57266Smuller } 597*57266Smuller 598*57266Smuller /* 599*57266Smuller * empty file name, skips this file. a "." leaves it alone 600*57266Smuller */ 601*57266Smuller if (tmpname[0] == '\0') { 602*57266Smuller tty_prnt("Skipping file.\n"); 603*57266Smuller return(1); 604*57266Smuller } 605*57266Smuller if ((tmpname[0] == '.') && (tmpname[1] == '\0')) { 606*57266Smuller tty_prnt("Processing continues, name unchanged.\n"); 607*57266Smuller return(0); 608*57266Smuller } 609*57266Smuller 610*57266Smuller /* 611*57266Smuller * ok the name changed. We may run into links that point at this 612*57266Smuller * file later. we have to remember where the user sent the file 613*57266Smuller * in order to repair any links. 614*57266Smuller */ 615*57266Smuller tty_prnt("Processing continues, name changed to: %s\n", tmpname); 616*57266Smuller res = add_name(arcn->name, arcn->nlen, tmpname); 617*57266Smuller arcn->nlen = l_strncpy(arcn->name, tmpname, PAXPATHLEN+1); 618*57266Smuller if (res < 0) 619*57266Smuller return(-1); 620*57266Smuller return(0); 621*57266Smuller } 622*57266Smuller 623*57266Smuller /* 624*57266Smuller * set_dest() 625*57266Smuller * fix up the file name and the link name (if any) so this file will land 626*57266Smuller * in the destination directory (used during copy() -rw). 627*57266Smuller * Return: 628*57266Smuller * 0 if ok, -1 if failure (name too long) 629*57266Smuller */ 630*57266Smuller 631*57266Smuller #if __STDC__ 632*57266Smuller int 633*57266Smuller set_dest(register ARCHD *arcn, char *dest_dir, int dir_len) 634*57266Smuller #else 635*57266Smuller int 636*57266Smuller set_dest(arcn, dest_dir, dir_len) 637*57266Smuller register ARCHD *arcn; 638*57266Smuller char *dest_dir; 639*57266Smuller int dir_len; 640*57266Smuller #endif 641*57266Smuller { 642*57266Smuller if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0) 643*57266Smuller return(-1); 644*57266Smuller 645*57266Smuller if ((arcn->type != PAX_HLK) && (arcn->type != PAX_HRG) && 646*57266Smuller (arcn->type != PAX_SLK)) 647*57266Smuller return(0); 648*57266Smuller 649*57266Smuller if (fix_path(arcn->ln_name, &(arcn->ln_nlen), dest_dir, dir_len) < 0) 650*57266Smuller return(-1); 651*57266Smuller return(0); 652*57266Smuller } 653*57266Smuller 654*57266Smuller /* 655*57266Smuller * fix_path 656*57266Smuller * concatenate dir_name and or_name and store the result in or_name (if 657*57266Smuller * it fits). This is one ugly function. 658*57266Smuller * Return: 659*57266Smuller * 0 if ok, -1 if the final name is too long 660*57266Smuller */ 661*57266Smuller 662*57266Smuller #if __STDC__ 663*57266Smuller static int 664*57266Smuller fix_path( char *or_name, int *or_len, char *dir_name, int dir_len) 665*57266Smuller #else 666*57266Smuller static int 667*57266Smuller fix_path(or_name, or_len, dir_name, dir_len) 668*57266Smuller char *or_name; 669*57266Smuller int *or_len; 670*57266Smuller char *dir_name; 671*57266Smuller int dir_len; 672*57266Smuller #endif 673*57266Smuller { 674*57266Smuller register char *src; 675*57266Smuller register char *dest; 676*57266Smuller register char *start; 677*57266Smuller int len; 678*57266Smuller 679*57266Smuller /* 680*57266Smuller * we shift the or_name to the right enough to tack in the dir_name 681*57266Smuller * at the front. We make sure we have enough space for it all before 682*57266Smuller * we start. since dest always ends in a slash, we skip of or_name 683*57266Smuller * if it also starts with one. 684*57266Smuller */ 685*57266Smuller start = or_name; 686*57266Smuller src = start + *or_len; 687*57266Smuller dest = src + dir_len; 688*57266Smuller if (*start == '/') { 689*57266Smuller ++start; 690*57266Smuller --dest; 691*57266Smuller } 692*57266Smuller if ((len = dest - or_name) > PAXPATHLEN) { 693*57266Smuller warn(1, "File name %s/%s, too long", dir_name, start); 694*57266Smuller return(-1); 695*57266Smuller } 696*57266Smuller *or_len = len; 697*57266Smuller 698*57266Smuller /* 699*57266Smuller * enough space, shift 700*57266Smuller */ 701*57266Smuller while (src >= start) 702*57266Smuller *dest-- = *src--; 703*57266Smuller src = dir_name + dir_len - 1; 704*57266Smuller 705*57266Smuller /* 706*57266Smuller * splice in the destination directory name 707*57266Smuller */ 708*57266Smuller while (src >= dir_name) 709*57266Smuller *dest-- = *src--; 710*57266Smuller 711*57266Smuller *(or_name + len) = '\0'; 712*57266Smuller return(0); 713*57266Smuller } 714*57266Smuller 715*57266Smuller /* 716*57266Smuller * rep_name() 717*57266Smuller * walk down the list of replacement strings applying each one in order. 718*57266Smuller * when we find one with a successful substitution, we modify the name 719*57266Smuller * as specified. if required, we print the results. if the resulting name 720*57266Smuller * is empty, we will skip this archive member. We use the regexp(3) 721*57266Smuller * routines (regexp() ought to win a prize as having the most cryptic 722*57266Smuller * library function manual page). 723*57266Smuller * --Parameters-- 724*57266Smuller * name is the file name we are going to apply the regular expressions to 725*57266Smuller * (and may be modified) 726*57266Smuller * nlen is the length of this name (and is modified to hold the length of 727*57266Smuller * the final string). 728*57266Smuller * prnt is a flag that says whether to print the final result. 729*57266Smuller * Return: 730*57266Smuller * 0 if substitution was successful, 1 if we are to skip the file (the name 731*57266Smuller * ended up empty) 732*57266Smuller */ 733*57266Smuller 734*57266Smuller #if __STDC__ 735*57266Smuller static int 736*57266Smuller rep_name(char *name, int *nlen, int prnt) 737*57266Smuller #else 738*57266Smuller static int 739*57266Smuller rep_name(name, nlen, prnt) 740*57266Smuller char *name; 741*57266Smuller int *nlen; 742*57266Smuller int prnt; 743*57266Smuller #endif 744*57266Smuller { 745*57266Smuller register REPLACE *pt; 746*57266Smuller register char *inpt; 747*57266Smuller register char *outpt; 748*57266Smuller register char *endpt; 749*57266Smuller register char *rpt; 750*57266Smuller register int found = 0; 751*57266Smuller register int res; 752*57266Smuller # ifndef NET2_REGEX 753*57266Smuller regmatch_t pm[MAXSUBEXP]; 754*57266Smuller # endif 755*57266Smuller char nname[PAXPATHLEN+1]; /* final result of all replacements */ 756*57266Smuller char buf1[PAXPATHLEN+1]; /* where we work on the name */ 757*57266Smuller 758*57266Smuller /* 759*57266Smuller * copy the name into buf1, where we will work on it. We need to keep 760*57266Smuller * the orig string around so we can print out the result of the final 761*57266Smuller * replacement. We build up the final result in nname. inpt points at 762*57266Smuller * the string we apply the regular expression to. prnt is used to 763*57266Smuller * suppress printing when we handle replacements on the link field 764*57266Smuller * (the user already saw that substitution go by) 765*57266Smuller */ 766*57266Smuller pt = rephead; 767*57266Smuller (void)strcpy(buf1, name); 768*57266Smuller inpt = buf1; 769*57266Smuller outpt = nname; 770*57266Smuller endpt = outpt + PAXPATHLEN; 771*57266Smuller 772*57266Smuller /* 773*57266Smuller * try each replacement string in order 774*57266Smuller */ 775*57266Smuller while (pt != NULL) { 776*57266Smuller do { 777*57266Smuller /* 778*57266Smuller * check for a successful substitution, if not go to 779*57266Smuller * the next pattern, or cleanup if we were global 780*57266Smuller */ 781*57266Smuller # ifdef NET2_REGEX 782*57266Smuller if (regexec(pt->rcmp, inpt) == 0) 783*57266Smuller # else 784*57266Smuller if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0) 785*57266Smuller # endif 786*57266Smuller break; 787*57266Smuller 788*57266Smuller /* 789*57266Smuller * ok we found one. We have three parts, the prefix 790*57266Smuller * which did not match, the section that did and the 791*57266Smuller * tail (that also did not match). Copy the prefix to 792*57266Smuller * the final output buffer (watching to make sure we 793*57266Smuller * do not create a string too long). 794*57266Smuller */ 795*57266Smuller found = 1; 796*57266Smuller # ifdef NET2_REGEX 797*57266Smuller rpt = pt->rcmp->startp[0]; 798*57266Smuller # else 799*57266Smuller rpt = inpt + pm[0].rm_so; 800*57266Smuller # endif 801*57266Smuller 802*57266Smuller while ((inpt < rpt) && (outpt < endpt)) 803*57266Smuller *outpt++ = *inpt++; 804*57266Smuller if (outpt == endpt) 805*57266Smuller break; 806*57266Smuller 807*57266Smuller /* 808*57266Smuller * for the second part (which matched the regular 809*57266Smuller * expression) apply the substitution using the 810*57266Smuller * replacement string and place it the prefix in the 811*57266Smuller * final output. If we have problems, skip it. 812*57266Smuller */ 813*57266Smuller # ifdef NET2_REGEX 814*57266Smuller if ((res = resub(pt->rcmp,pt->nstr,outpt,endpt)) < 0) { 815*57266Smuller # else 816*57266Smuller if ((res = resub(&(pt->rcmp),pm,pt->nstr,outpt,endpt)) 817*57266Smuller < 0) { 818*57266Smuller # endif 819*57266Smuller if (prnt) 820*57266Smuller warn(1, "Replacement name error %s", 821*57266Smuller name); 822*57266Smuller return(1); 823*57266Smuller } 824*57266Smuller outpt += res; 825*57266Smuller 826*57266Smuller /* 827*57266Smuller * we set up to look again starting at the first 828*57266Smuller * character in the tail (of the input string right 829*57266Smuller * after the last character matched by the regular 830*57266Smuller * expression (inpt always points at the first char in 831*57266Smuller * the string to process). If we are not doing a global 832*57266Smuller * substitution, we will use inpt to copy the tail to 833*57266Smuller * the final result. Make sure we do not overrun the 834*57266Smuller * output buffer 835*57266Smuller */ 836*57266Smuller # ifdef NET2_REGEX 837*57266Smuller inpt = pt->rcmp->endp[0]; 838*57266Smuller # else 839*57266Smuller inpt += pm[0].rm_eo; 840*57266Smuller # endif 841*57266Smuller 842*57266Smuller if ((outpt == endpt) || (*inpt == '\0')) 843*57266Smuller break; 844*57266Smuller 845*57266Smuller /* 846*57266Smuller * if the user wants global we keep trying to 847*57266Smuller * substitute until it fails, then we are done. 848*57266Smuller */ 849*57266Smuller } while (pt->flgs & GLOB); 850*57266Smuller 851*57266Smuller if (found) 852*57266Smuller break; 853*57266Smuller 854*57266Smuller /* 855*57266Smuller * a successful substitution did NOT occur, try the next one 856*57266Smuller */ 857*57266Smuller pt = pt->fow; 858*57266Smuller } 859*57266Smuller 860*57266Smuller if (found) { 861*57266Smuller /* 862*57266Smuller * we had a substitution, copy the last tail piece (if there is 863*57266Smuller * room) to the final result 864*57266Smuller */ 865*57266Smuller while ((outpt < endpt) && (*inpt != '\0')) 866*57266Smuller *outpt++ = *inpt++; 867*57266Smuller 868*57266Smuller *outpt = '\0'; 869*57266Smuller if ((outpt == endpt) && (*inpt != '\0')) { 870*57266Smuller if (prnt) 871*57266Smuller warn(1,"Replacement name too long %s >> %s", 872*57266Smuller name, nname); 873*57266Smuller return(1); 874*57266Smuller } 875*57266Smuller 876*57266Smuller /* 877*57266Smuller * inform the user of the result if wanted 878*57266Smuller */ 879*57266Smuller if (prnt && (pt->flgs & PRNT)) { 880*57266Smuller if (*nname == '\0') 881*57266Smuller (void)fprintf(stderr,"%s >> <empty string>\n", 882*57266Smuller name); 883*57266Smuller else 884*57266Smuller (void)fprintf(stderr,"%s >> %s\n", name, nname); 885*57266Smuller } 886*57266Smuller 887*57266Smuller /* 888*57266Smuller * if empty inform the caller this file is to be skipped 889*57266Smuller * otherwise copy the new name over the orig name and return 890*57266Smuller */ 891*57266Smuller if (*nname == '\0') 892*57266Smuller return(1); 893*57266Smuller *nlen = l_strncpy(name, nname, PAXPATHLEN + 1); 894*57266Smuller } 895*57266Smuller return(0); 896*57266Smuller } 897*57266Smuller 898*57266Smuller #ifdef NET2_REGEX 899*57266Smuller /* 900*57266Smuller * resub() 901*57266Smuller * apply the replacement to the matched expression. expand out the old 902*57266Smuller * style ed(1) subexpression expansion. 903*57266Smuller * Return: 904*57266Smuller * -1 if error, or the number of characters added to the destination. 905*57266Smuller */ 906*57266Smuller 907*57266Smuller #if __STDC__ 908*57266Smuller static int 909*57266Smuller resub(regexp *prog, char *src, char *dest, register char *destend) 910*57266Smuller #else 911*57266Smuller static int 912*57266Smuller resub(prog, src, dest, destend) 913*57266Smuller regexp *prog; 914*57266Smuller char *src; 915*57266Smuller char *dest; 916*57266Smuller register char *destend; 917*57266Smuller #endif 918*57266Smuller { 919*57266Smuller register char *spt; 920*57266Smuller register char *dpt; 921*57266Smuller register char c; 922*57266Smuller register int no; 923*57266Smuller register int len; 924*57266Smuller 925*57266Smuller spt = src; 926*57266Smuller dpt = dest; 927*57266Smuller while ((dpt < destend) && ((c = *spt++) != '\0')) { 928*57266Smuller if (c == '&') 929*57266Smuller no = 0; 930*57266Smuller else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) 931*57266Smuller no = *spt++ - '0'; 932*57266Smuller else { 933*57266Smuller if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) 934*57266Smuller c = *spt++; 935*57266Smuller *dpt++ = c; 936*57266Smuller continue; 937*57266Smuller } 938*57266Smuller if ((prog->startp[no] == NULL) || (prog->endp[no] == NULL) || 939*57266Smuller ((len = prog->endp[no] - prog->startp[no]) <= 0)) 940*57266Smuller continue; 941*57266Smuller 942*57266Smuller /* 943*57266Smuller * copy the subexpression to the destination. 944*57266Smuller * fail if we run out of space or the match string is damaged 945*57266Smuller */ 946*57266Smuller if (len > (destend - dpt)) 947*57266Smuller len = destend - dpt; 948*57266Smuller if (l_strncpy(dpt, prog->startp[no], len) != len) 949*57266Smuller return(-1); 950*57266Smuller dpt += len; 951*57266Smuller } 952*57266Smuller return(dpt - dest); 953*57266Smuller } 954*57266Smuller 955*57266Smuller #else 956*57266Smuller 957*57266Smuller /* 958*57266Smuller * resub() 959*57266Smuller * apply the replacement to the matched expression. expand out the old 960*57266Smuller * style ed(1) subexpression expansion. 961*57266Smuller * Return: 962*57266Smuller * -1 if error, or the number of characters added to the destination. 963*57266Smuller */ 964*57266Smuller 965*57266Smuller #if __STDC__ 966*57266Smuller static int 967*57266Smuller resub(regex_t *rp, register regmatch_t *pm, char *src, char *dest, 968*57266Smuller register char *destend) 969*57266Smuller #else 970*57266Smuller static int 971*57266Smuller resub(rp, pm, src, dest, destend) 972*57266Smuller regex_t *rp; 973*57266Smuller register regmatch_t *pm; 974*57266Smuller char *src; 975*57266Smuller char *dest; 976*57266Smuller register char *destend; 977*57266Smuller #endif 978*57266Smuller { 979*57266Smuller register char *spt; 980*57266Smuller register char *dpt; 981*57266Smuller register char c; 982*57266Smuller register regmatch_t *pmpt; 983*57266Smuller register int len; 984*57266Smuller int subexcnt; 985*57266Smuller 986*57266Smuller spt = src; 987*57266Smuller dpt = dest; 988*57266Smuller subexcnt = rp->re_nsub; 989*57266Smuller while ((dpt < destend) && ((c = *spt++) != '\0')) { 990*57266Smuller /* 991*57266Smuller * see if we just have an ordinary replacement character 992*57266Smuller * or we refer to a subexpression. 993*57266Smuller */ 994*57266Smuller if (c == '&') { 995*57266Smuller pmpt = pm; 996*57266Smuller } else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) { 997*57266Smuller /* 998*57266Smuller * make sure there is a subexpression as specified 999*57266Smuller */ 1000*57266Smuller if ((len = *spt++ - '0') > subexcnt) 1001*57266Smuller return(-1); 1002*57266Smuller pmpt = pm + len; 1003*57266Smuller } else { 1004*57266Smuller /* 1005*57266Smuller * Ordinary character, just copy it 1006*57266Smuller */ 1007*57266Smuller if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) 1008*57266Smuller c = *spt++; 1009*57266Smuller *dpt++ = c; 1010*57266Smuller continue; 1011*57266Smuller } 1012*57266Smuller 1013*57266Smuller /* 1014*57266Smuller * continue if the subexpression is bogus 1015*57266Smuller */ 1016*57266Smuller if ((pmpt->rm_so < 0) || (pmpt->rm_eo < 0) || 1017*57266Smuller ((len = pmpt->rm_eo - pmpt->rm_so) <= 0)) 1018*57266Smuller continue; 1019*57266Smuller 1020*57266Smuller /* 1021*57266Smuller * copy the subexpression to the destination. 1022*57266Smuller * fail if we run out of space or the match string is damaged 1023*57266Smuller */ 1024*57266Smuller if (len > (destend - dpt)) 1025*57266Smuller len = destend - dpt; 1026*57266Smuller if (l_strncpy(dpt, src + pmpt->rm_so, len) != len) 1027*57266Smuller return(-1); 1028*57266Smuller dpt += len; 1029*57266Smuller } 1030*57266Smuller return(dpt - dest); 1031*57266Smuller } 1032*57266Smuller #endif 1033