157266Smuller /*- 257266Smuller * Copyright (c) 1992 Keith Muller. 3*60676Sbostic * Copyright (c) 1992, 1993 4*60676Sbostic * The Regents of the University of California. All rights reserved. 557266Smuller * 657266Smuller * This code is derived from software contributed to Berkeley by 757266Smuller * Keith Muller of the University of California, San Diego. 857266Smuller * 957266Smuller * %sccs.include.redist.c% 1057266Smuller */ 1157266Smuller 1257266Smuller #ifndef lint 13*60676Sbostic static char sccsid[] = "@(#)pat_rep.c 8.1 (Berkeley) 05/31/93"; 1457266Smuller #endif /* not lint */ 1557266Smuller 1657266Smuller #include <sys/types.h> 1757266Smuller #include <sys/time.h> 1857266Smuller #include <sys/stat.h> 1957266Smuller #include <sys/param.h> 2057266Smuller #include <stdio.h> 2157266Smuller #include <ctype.h> 2257266Smuller #include <string.h> 2357266Smuller #include <unistd.h> 2457266Smuller #include <stdlib.h> 2557266Smuller #include <fnmatch.h> 2657266Smuller #ifdef NET2_REGEX 2757266Smuller #include <regexp.h> 2857266Smuller #else 2957266Smuller #include <regex.h> 3057266Smuller #endif 3157266Smuller #include "pax.h" 3257266Smuller #include "pat_rep.h" 3357266Smuller #include "extern.h" 3457266Smuller 3557266Smuller /* 3657266Smuller * routines to handle pattern matching, name modification (regular expression 3757266Smuller * substitution and interactive renames), and destination name modification for 3857266Smuller * copy (-rw). Both file name and link names are adjusted as required in these 3957266Smuller * routines. 4057266Smuller */ 4157266Smuller 4257266Smuller #define MAXSUBEXP 10 /* max subexpressions, DO NOT CHANGE */ 4357266Smuller static PATTERN *pathead = NULL; /* file pattern match list head */ 4457266Smuller static PATTERN *pattail = NULL; /* file pattern match list tail */ 4557266Smuller static REPLACE *rephead = NULL; /* replacement string list head */ 4657266Smuller static REPLACE *reptail = NULL; /* replacement string list tail */ 4757266Smuller 4857266Smuller static int rep_name __P((char *, int *, int)); 4957266Smuller static int tty_rename __P((register ARCHD *)); 5057266Smuller static int fix_path __P((char *, int *, char *, int)); 5157266Smuller #ifdef NET2_REGEX 5257266Smuller static int resub __P((regexp *, char *, char *, register char *)); 5357266Smuller #else 5457266Smuller static int resub __P((regex_t *, regmatch_t *, char *, char *, char *)); 5557266Smuller #endif 5657266Smuller 5757266Smuller /* 5857266Smuller * rep_add() 5957266Smuller * parses the -s replacement string; compiles the regular expression 6057266Smuller * and stores the compiled value and it's replacement string together in 6157266Smuller * replacement string list. Input to this function is of the form: 6257266Smuller * /old/new/pg 6357266Smuller * The first char in the string specifies the delimiter used by this 6457266Smuller * replacement string. "Old" is a regular expression in "ed" format which 6557266Smuller * is compiled by regcomp() and is applied to filenames. "new" is the 6657266Smuller * substitution string; p and g are options flags for printing and global 6757266Smuller * replacement (over the single filename) 6857266Smuller * Return: 6957266Smuller * 0 if a proper replacement string and regular expression was added to 7057266Smuller * the list of replacement patterns; -1 otherwise. 7157266Smuller */ 7257266Smuller 7357266Smuller #if __STDC__ 7457266Smuller int 7557266Smuller rep_add(register char *str) 7657266Smuller #else 7757266Smuller int 7857266Smuller rep_add(str) 7957266Smuller register char *str; 8057266Smuller #endif 8157266Smuller { 8257266Smuller register char *pt1; 8357266Smuller register char *pt2; 8457266Smuller register REPLACE *rep; 8557266Smuller # ifndef NET2_REGEX 8657266Smuller register int res; 8757266Smuller char rebuf[BUFSIZ]; 8857266Smuller # endif 8957266Smuller 9057266Smuller /* 9157266Smuller * throw out the bad parameters 9257266Smuller */ 9357266Smuller if ((str == NULL) || (*str == '\0')) { 9457266Smuller warn(1, "Empty replacement string"); 9557266Smuller return(-1); 9657266Smuller } 9757266Smuller 9857266Smuller /* 9957266Smuller * first character in the string specifies what the delimiter is for 10057266Smuller * this expression 10157266Smuller */ 10257266Smuller if ((pt1 = strchr(str+1, *str)) == NULL) { 10357266Smuller warn(1, "Invalid replacement string %s", str); 10457266Smuller return(-1); 10557266Smuller } 10657266Smuller 10757266Smuller /* 10857266Smuller * allocate space for the node that handles this replacement pattern 10957266Smuller * and split out the regular expression and try to compile it 11057266Smuller */ 11157266Smuller if ((rep = (REPLACE *)malloc(sizeof(REPLACE))) == NULL) { 11257266Smuller warn(1, "Unable to allocate memory for replacement string"); 11357266Smuller return(-1); 11457266Smuller } 11557266Smuller 11657266Smuller *pt1 = '\0'; 11757266Smuller # ifdef NET2_REGEX 11857266Smuller if ((rep->rcmp = regcomp(str+1)) == NULL) { 11957266Smuller # else 12057266Smuller if ((res = regcomp(&(rep->rcmp), str+1, 0)) != 0) { 12157266Smuller regerror(res, &(rep->rcmp), rebuf, sizeof(rebuf)); 12257266Smuller warn(1, "%s while compiling regular expression %s", rebuf, str); 12357266Smuller # endif 12457266Smuller (void)free((char *)rep); 12557266Smuller return(-1); 12657266Smuller } 12757266Smuller 12857266Smuller /* 12957266Smuller * put the delimiter back in case we need an error message and 13057266Smuller * locate the delimiter at the end of the replacement string 13157266Smuller * we then point the node at the new substitution string 13257266Smuller */ 13357266Smuller *pt1++ = *str; 13457266Smuller if ((pt2 = strchr(pt1, *str)) == NULL) { 13557266Smuller # ifdef NET2_REGEX 13657266Smuller (void)free((char *)rep->rcmp); 13757266Smuller # else 13857266Smuller regfree(&(rep->rcmp)); 13957266Smuller # endif 14057266Smuller (void)free((char *)rep); 14157266Smuller warn(1, "Invalid replacement string %s", str); 14257266Smuller return(-1); 14357266Smuller } 14457266Smuller 14557266Smuller *pt2 = '\0'; 14657266Smuller rep->nstr = pt1; 14757266Smuller pt1 = pt2++; 14857266Smuller rep->flgs = 0; 14957266Smuller 15057266Smuller /* 15157266Smuller * set the options if any 15257266Smuller */ 15357266Smuller while (*pt2 != '\0') { 15457266Smuller switch(*pt2) { 15557266Smuller case 'g': 15657266Smuller case 'G': 15757266Smuller rep->flgs |= GLOB; 15857266Smuller break; 15957266Smuller case 'p': 16057266Smuller case 'P': 16157266Smuller rep->flgs |= PRNT; 16257266Smuller break; 16357266Smuller default: 16457266Smuller # ifdef NET2_REGEX 16557266Smuller (void)free((char *)rep->rcmp); 16657266Smuller # else 16757266Smuller regfree(&(rep->rcmp)); 16857266Smuller # endif 16957266Smuller (void)free((char *)rep); 17057266Smuller *pt1 = *str; 17157266Smuller warn(1, "Invalid replacement string option %s", str); 17257266Smuller return(-1); 17357266Smuller } 17457266Smuller ++pt2; 17557266Smuller } 17657266Smuller 17757266Smuller /* 17857266Smuller * all done, link it in at the end 17957266Smuller */ 18057266Smuller rep->fow = NULL; 18157266Smuller if (rephead == NULL) { 18257266Smuller reptail = rephead = rep; 18357266Smuller return(0); 18457266Smuller } 18557266Smuller reptail->fow = rep; 18657266Smuller reptail = rep; 18757266Smuller return(0); 18857266Smuller } 18957266Smuller 19057266Smuller /* 19157266Smuller * pat_add() 19257266Smuller * add a pattern match to the pattern match list. Pattern matches are used 19357266Smuller * to select which archive members are extracted. (They appear as 19457266Smuller * arguments to pax in the list and read modes). If no patterns are 19557266Smuller * supplied to pax, all members in the archive will be selected (and the 19657266Smuller * pattern match list is empty). 19757266Smuller * Return: 19857266Smuller * 0 if the pattern was added to the list, -1 otherwise 19957266Smuller */ 20057266Smuller 20157266Smuller #if __STDC__ 20257266Smuller int 20357266Smuller pat_add(char *str) 20457266Smuller #else 20557266Smuller int 20657266Smuller pat_add(str) 20757266Smuller char *str; 20857266Smuller #endif 20957266Smuller { 21057266Smuller register PATTERN *pt; 21157266Smuller 21257266Smuller /* 21357266Smuller * throw out the junk 21457266Smuller */ 21557266Smuller if ((str == NULL) || (*str == '\0')) { 21657266Smuller warn(1, "Empty pattern string"); 21757266Smuller return(-1); 21857266Smuller } 21957266Smuller 22057266Smuller /* 22157266Smuller * allocate space for the pattern and store the pattern. the pattern is 22257266Smuller * part of argv so do not bother to copy it, just point at it. Add the 22357266Smuller * node to the end of the pattern list 22457266Smuller */ 22557266Smuller if ((pt = (PATTERN *)malloc(sizeof(PATTERN))) == NULL) { 22657266Smuller warn(1, "Unable to allocate memory for pattern string"); 22757266Smuller return(-1); 22857266Smuller } 22957266Smuller 23057266Smuller pt->pstr = str; 23157266Smuller pt->plen = strlen(str); 23257266Smuller pt->fow = NULL; 23357266Smuller pt->flgs = 0; 23457266Smuller if (pathead == NULL) { 23557266Smuller pattail = pathead = pt; 23657266Smuller return(0); 23757266Smuller } 23857266Smuller pattail->fow = pt; 23957266Smuller pattail = pt; 24057266Smuller return(0); 24157266Smuller } 24257266Smuller 24357266Smuller /* 24457266Smuller * pat_chk() 24557266Smuller * complain if any the user supplied pattern did not result in a match to 24657266Smuller * a selected archive member. 24757266Smuller */ 24857266Smuller 24957266Smuller #if __STDC__ 25057266Smuller void 25157266Smuller pat_chk(void) 25257266Smuller #else 25357266Smuller void 25457266Smuller pat_chk() 25557266Smuller #endif 25657266Smuller { 25757266Smuller register PATTERN *pt; 25857266Smuller register int wban = 0; 25957266Smuller 26057266Smuller /* 26157266Smuller * walk down the list checking the flags to make sure MTCH was set, 26257266Smuller * if not complain 26357266Smuller */ 26457266Smuller for (pt = pathead; pt != NULL; pt = pt->fow) { 26557266Smuller if (pt->flgs & MTCH) 26657266Smuller continue; 26757266Smuller if (!wban) { 26857266Smuller warn(1, "WARNING! These patterns were not matched:"); 26957266Smuller ++wban; 27057266Smuller } 27157266Smuller (void)fprintf(stderr, "%s\n", pt->pstr); 27257266Smuller } 27357266Smuller } 27457266Smuller 27557266Smuller /* 27657266Smuller * pat_sel() 27757266Smuller * the archive member which matches a pattern was selected. Mark the 27857266Smuller * pattern as having selected an archive member. arcn->pat points at the 27957266Smuller * pattern that was matched. arcn->pat is set in pat_match() 28057266Smuller * 28157266Smuller * NOTE: When the -c option is used, we are called when there was no match 28257266Smuller * by pat_match() (that means we did match before the inverted sense of 28357266Smuller * the logic). Now this seems really strange at first, but with -c we 28457266Smuller * need to keep track of those patterns that cause a archive member to NOT 28557266Smuller * be selected (it found an archive member with a specified pattern) 28657266Smuller * Return: 28757266Smuller * 0 if the pattern pointed at by arcn->pat was tagged as creating a 28857266Smuller * match, -1 otherwise. 28957266Smuller */ 29057266Smuller 29157266Smuller #if __STDC__ 29257266Smuller int 29357266Smuller pat_sel(register ARCHD *arcn) 29457266Smuller #else 29557266Smuller int 29657266Smuller pat_sel(arcn) 29757266Smuller register ARCHD *arcn; 29857266Smuller #endif 29957266Smuller { 30057266Smuller register PATTERN *pt; 30157266Smuller register PATTERN **ppt; 30257266Smuller register int len; 30357266Smuller 30457266Smuller /* 30557266Smuller * if no patterns just return 30657266Smuller */ 30757266Smuller if ((pathead == NULL) || ((pt = arcn->pat) == NULL)) 30857266Smuller return(0); 30957266Smuller 31057266Smuller /* 31157266Smuller * when we are NOT limited to a single match per pattern mark the 31257266Smuller * the pattern and return 31357266Smuller */ 31457266Smuller if (!nflag) { 31557266Smuller pt->flgs |= MTCH; 31657266Smuller if (dflag || (arcn->type != PAX_DIR)) 31757266Smuller return(0); 31857266Smuller /* 31957266Smuller * ok we matched a directory and we are allowing 32057266Smuller * subtree matches. We add this as a DIR_MTCH pattern 32157266Smuller * so all its children will match. Note we know that 32257266Smuller * when successful, pat_add() puts the pattern at the 32357266Smuller * tail (yup a kludge). In the code below will make 32457266Smuller * a dir match pattern 32557266Smuller */ 32657266Smuller if ((pat_add(arcn->name) < 0) || ((pt = pattail) == NULL)) 32757266Smuller return(-1); 32857266Smuller arcn->pat = pt; 32957266Smuller } 33057266Smuller 33157266Smuller /* 33257266Smuller * we reach this point only when we allow a single selected match per 33357266Smuller * pattern, or we have to add a DIR_MATCH pattern. if the pattern 33457266Smuller * matched a directory and we do not have -d * (dflag) we are done 33557266Smuller * with this pattern. We may also be handed a file in the subtree of a 33657266Smuller * directory. in that case when we are operating with -d, this pattern 33757266Smuller * was already selected and we are done 33857266Smuller */ 33957266Smuller if (pt->flgs & DIR_MTCH) 34057266Smuller return(0); 34157266Smuller 34257266Smuller if (!dflag && (arcn->type == PAX_DIR)) { 34357266Smuller /* 34457266Smuller * we are allowing subtree matches at directories, mark the 34557266Smuller * node as a directory match so pat_match() will only match 34657266Smuller * children of this directory (we replace the pattern with the 34757266Smuller * directory name to enforce this subtree only match) 34857266Smuller * pat_match() looks for DIR_MTCH to determine what comparison 34957266Smuller * technique to use when it checks for a pattern match 35057266Smuller */ 35157266Smuller if ((pt->pstr = strdup(arcn->name)) == NULL) { 35257266Smuller warn(1, "Pattern select out of memory"); 35357266Smuller return(-1); 35457266Smuller } 35557266Smuller pt->plen = strlen(pt->pstr); 35657266Smuller 35757266Smuller /* 35857266Smuller * strip off any trailing /, this should really never happen 35957266Smuller */ 36057266Smuller len = pt->plen - 1; 36157266Smuller if (*(pt->pstr + len) == '/') { 36257266Smuller *(pt->pstr + len) = '\0'; 36357266Smuller pt->plen = len; 36457266Smuller } 36557266Smuller pt->flgs |= DIR_MTCH | MTCH; 36657266Smuller return(0); 36757266Smuller } 36857266Smuller 36957266Smuller /* 37057266Smuller * it is not a directory, we are then done with this pattern, so we 37157266Smuller * delete it from the list, as it can never be used for another match 37257266Smuller * Seems kind of strange to do for a -c, but the pax spec is really 37357266Smuller * vague on the interaction of -c -n and -d. We assume that when -c 37457266Smuller * and the pattern rejects a member (i.e. it matched it) it is done. 37557266Smuller * In effect we place the order of the flags as having -c last. 37657266Smuller */ 37757266Smuller pt = pathead; 37857266Smuller ppt = &pathead; 37957266Smuller while ((pt != NULL) && (pt != arcn->pat)) { 38057266Smuller ppt = &(pt->fow); 38157266Smuller pt = pt->fow; 38257266Smuller } 38357266Smuller 38457266Smuller if (pt == NULL) { 38557266Smuller /* 38657266Smuller * should never happen.... 38757266Smuller */ 38857266Smuller warn(1, "Pattern list inconsistant"); 38957266Smuller return(-1); 39057266Smuller } 39157266Smuller *ppt = pt->fow; 39257266Smuller (void)free((char *)pt); 39357266Smuller arcn->pat = NULL; 39457266Smuller return(0); 39557266Smuller } 39657266Smuller 39757266Smuller /* 39857266Smuller * pat_match() 39957266Smuller * see if this archive member matches any supplied pattern, if a match 40057266Smuller * is found, arcn->pat is set to point at the potential pattern. Later if 40157266Smuller * this archive member is "selected" we process and mark the pattern as 40257266Smuller * one which matched a selected archive member (see pat_sel()) 40357266Smuller * Return: 40457266Smuller * 0 if this archive member should be processed, 1 if it should be 40557266Smuller * skipped and -1 if we are done with all patterns (and pax should quit 40657266Smuller * looking for more members) 40757266Smuller */ 40857266Smuller 40957266Smuller #if __STDC__ 41057266Smuller int 41157266Smuller pat_match(register ARCHD *arcn) 41257266Smuller #else 41357266Smuller int 41457266Smuller pat_match(arcn) 41557266Smuller register ARCHD *arcn; 41657266Smuller #endif 41757266Smuller { 41857266Smuller register PATTERN *pt; 41957266Smuller 42057266Smuller arcn->pat = NULL; 42157266Smuller 42257266Smuller /* 42357266Smuller * if there are no more patterns and we have -n (and not -c) we are 42457266Smuller * done. otherwise with no patterns to match, matches all 42557266Smuller */ 42657266Smuller if (pathead == NULL) { 42757266Smuller if (nflag && !cflag) 42857266Smuller return(-1); 42957266Smuller return(0); 43057266Smuller } 43157266Smuller 43257266Smuller /* 43357266Smuller * have to search down the list one at a time looking for a match. 43457266Smuller */ 43557266Smuller pt = pathead; 43657266Smuller while (pt != NULL) { 43757266Smuller /* 43857266Smuller * check for a file name match unless we have DIR_MTCH set in 43957266Smuller * this pattern then we want a prefix match 44057266Smuller */ 44157266Smuller 44257266Smuller if (pt->flgs & DIR_MTCH) { 44357266Smuller /* 44457266Smuller * this pattern was matched before to a directory 44557266Smuller * as we must have -n set for this (but not -d). We can 44657266Smuller * only match CHILDREN of that directory so we must use 44757266Smuller * an exact prefix match 44857266Smuller */ 44957266Smuller if ((strncmp(pt->pstr, arcn->name, pt->plen) == 0) && 45057266Smuller (arcn->name[pt->plen] == '/')) 45157266Smuller break; 45257266Smuller } else if (fnmatch(pt->pstr, arcn->name, 0) == 0) 45357266Smuller break; 45457266Smuller pt = pt->fow; 45557266Smuller } 45657266Smuller 45757266Smuller /* 45857266Smuller * return the result, remember that cflag (-c) inverts the sense of a 45957266Smuller * match 46057266Smuller */ 46157266Smuller if (pt == NULL) 46257266Smuller return(cflag ? 0 : 1); 46357266Smuller 46457266Smuller /* 46557266Smuller * we had a match, now when we invert the sense (-c) we reject this 46657266Smuller * member. However we have to tag the pattern a being successful, (in a 46757266Smuller * match, not in selecting a archive member) so we call pat_sel() here. 46857266Smuller */ 46957266Smuller arcn->pat = pt; 47057266Smuller if (!cflag) 47157266Smuller return(0); 47257266Smuller 47357266Smuller if (pat_sel(arcn) < 0) 47457266Smuller return(-1); 47557266Smuller arcn->pat = NULL; 47657266Smuller return(1); 47757266Smuller } 47857266Smuller 47957266Smuller /* 48057266Smuller * mod_name() 48157266Smuller * modify a selected file name. first attempt to apply replacement string 48257266Smuller * expressions, then apply interactive file rename. We apply replacement 48357266Smuller * string expressions to both filenames and file links (if we didn't the 48457266Smuller * links would point to the wrong place, and we could never be able to 48557266Smuller * move an archive that has a file link in it). When we rename files 48657266Smuller * interactively, we store that mapping (old name to user input name) so 48757266Smuller * if we spot any file links to the old file name in the future, we will 48857266Smuller * know exactly how to fix the file link. 48957266Smuller * Return: 49057266Smuller * 0 continue to process file, 1 skip this file, -1 pax is finished 49157266Smuller */ 49257266Smuller 49357266Smuller #if __STDC__ 49457266Smuller int 49557266Smuller mod_name(register ARCHD *arcn) 49657266Smuller #else 49757266Smuller int 49857266Smuller mod_name(arcn) 49957266Smuller register ARCHD *arcn; 50057266Smuller #endif 50157266Smuller { 50257266Smuller register int res = 0; 50357266Smuller 50457266Smuller /* 50557266Smuller * IMPORTANT: We have a problem. what do we do with symlinks? 50657266Smuller * Modifying a hard link name makes sense, as we know the file it 50757266Smuller * points at should have been seen already in the archive (and if it 50857266Smuller * wasn't seen because of a read error or a bad archive, we lose 50957266Smuller * anyway). But there are no such requirements for symlinks. On one 51057266Smuller * hand the symlink that refers to a file in the archive will have to 51157266Smuller * be modified to so it will still work at its new location in the 51257266Smuller * file system. On the other hand a symlink that points elsewhere (and 51357266Smuller * should continue to do so) should not be modified. There is clearly 51457266Smuller * no perfect solution here. So we handle them like hardlinks. Clearly 51557266Smuller * a replacement made by the interactive rename mapping is very likely 51657266Smuller * to be correct since it applies to a single file and is an exact 51757266Smuller * match. The regular expression replacements are a little harder to 51857266Smuller * justify though. We claim that the symlink name is only likely 51957266Smuller * to be replaced when it points within the file tree being moved and 52057266Smuller * in that case it should be modified. what we really need to do is to 52157266Smuller * call an oracle here. :) 52257266Smuller */ 52357266Smuller if (rephead != NULL) { 52457266Smuller /* 52557266Smuller * we have replacement strings, modify the name and the link 52657266Smuller * name if any. 52757266Smuller */ 52857266Smuller if ((res = rep_name(arcn->name, &(arcn->nlen), 1)) != 0) 52957266Smuller return(res); 53057266Smuller 53157266Smuller if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || 53257266Smuller (arcn->type == PAX_HRG)) && 53357266Smuller ((res = rep_name(arcn->ln_name, &(arcn->ln_nlen), 0)) != 0)) 53457266Smuller return(res); 53557266Smuller } 53657266Smuller 53757266Smuller if (iflag) { 53857266Smuller /* 53957266Smuller * perform interactive file rename, then map the link if any 54057266Smuller */ 54157266Smuller if ((res = tty_rename(arcn)) != 0) 54257266Smuller return(res); 54357266Smuller if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || 54457266Smuller (arcn->type == PAX_HRG)) 54557266Smuller sub_name(arcn->ln_name, &(arcn->ln_nlen)); 54657266Smuller } 54757266Smuller return(res); 54857266Smuller } 54957266Smuller 55057266Smuller /* 55157266Smuller * tty_rename() 55257266Smuller * Prompt the user for a replacement file name. A "." keeps the old name, 55357266Smuller * a empty line skips the file, and an EOF on reading the tty, will cause 55457266Smuller * pax to stop processing and exit. Otherwise the file name input, replaces 55557266Smuller * the old one. 55657266Smuller * Return: 55757266Smuller * 0 process this file, 1 skip this file, -1 we need to exit pax 55857266Smuller */ 55957266Smuller 56057266Smuller #if __STDC__ 56157266Smuller static int 56257266Smuller tty_rename(register ARCHD *arcn) 56357266Smuller #else 56457266Smuller static int 56557266Smuller tty_rename(arcn) 56657266Smuller register ARCHD *arcn; 56757266Smuller #endif 56857266Smuller { 56957266Smuller char tmpname[PAXPATHLEN+2]; 57057266Smuller int res; 57157266Smuller 57257266Smuller /* 57357266Smuller * prompt user for the replacement name for a file, keep trying until 57457266Smuller * we get some reasonable input. Archives may have more than one file 57557266Smuller * on them with the same name (from updates etc). We print verbose info 57657266Smuller * on the file so the user knows what is up. 57757266Smuller */ 57857266Smuller tty_prnt("\nATTENTION: Pax interactive file rename operation.\n"); 57957266Smuller 58057266Smuller for (;;) { 58157266Smuller ls_tty(arcn); 58257266Smuller tty_prnt("Input new name, or a \".\" to keep the old name, "); 58357266Smuller tty_prnt("or a \"return\" to skip this file.\n"); 58457266Smuller tty_prnt("Input > "); 58557266Smuller if (tty_read(tmpname, sizeof(tmpname)) < 0) 58657266Smuller return(-1); 58757266Smuller if (strcmp(tmpname, "..") == 0) { 58857266Smuller tty_prnt("Try again, illegal file name: ..\n"); 58957266Smuller continue; 59057266Smuller } 59157266Smuller if (strlen(tmpname) > PAXPATHLEN) { 59257266Smuller tty_prnt("Try again, file name too long\n"); 59357266Smuller continue; 59457266Smuller } 59557266Smuller break; 59657266Smuller } 59757266Smuller 59857266Smuller /* 59957266Smuller * empty file name, skips this file. a "." leaves it alone 60057266Smuller */ 60157266Smuller if (tmpname[0] == '\0') { 60257266Smuller tty_prnt("Skipping file.\n"); 60357266Smuller return(1); 60457266Smuller } 60557266Smuller if ((tmpname[0] == '.') && (tmpname[1] == '\0')) { 60657266Smuller tty_prnt("Processing continues, name unchanged.\n"); 60757266Smuller return(0); 60857266Smuller } 60957266Smuller 61057266Smuller /* 61157266Smuller * ok the name changed. We may run into links that point at this 61257266Smuller * file later. we have to remember where the user sent the file 61357266Smuller * in order to repair any links. 61457266Smuller */ 61557266Smuller tty_prnt("Processing continues, name changed to: %s\n", tmpname); 61657266Smuller res = add_name(arcn->name, arcn->nlen, tmpname); 61757266Smuller arcn->nlen = l_strncpy(arcn->name, tmpname, PAXPATHLEN+1); 61857266Smuller if (res < 0) 61957266Smuller return(-1); 62057266Smuller return(0); 62157266Smuller } 62257266Smuller 62357266Smuller /* 62457266Smuller * set_dest() 62557266Smuller * fix up the file name and the link name (if any) so this file will land 62657266Smuller * in the destination directory (used during copy() -rw). 62757266Smuller * Return: 62857266Smuller * 0 if ok, -1 if failure (name too long) 62957266Smuller */ 63057266Smuller 63157266Smuller #if __STDC__ 63257266Smuller int 63357266Smuller set_dest(register ARCHD *arcn, char *dest_dir, int dir_len) 63457266Smuller #else 63557266Smuller int 63657266Smuller set_dest(arcn, dest_dir, dir_len) 63757266Smuller register ARCHD *arcn; 63857266Smuller char *dest_dir; 63957266Smuller int dir_len; 64057266Smuller #endif 64157266Smuller { 64257266Smuller if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0) 64357266Smuller return(-1); 64457266Smuller 64557600Smuller /* 64657600Smuller * It is really hard to deal with symlinks here, we cannot be sure 64757600Smuller * if the name they point was moved (or will be moved). It is best to 64857600Smuller * leave them alone. 64957600Smuller */ 65057600Smuller if ((arcn->type != PAX_HLK) && (arcn->type != PAX_HRG)) 65157266Smuller return(0); 65257266Smuller 65357266Smuller if (fix_path(arcn->ln_name, &(arcn->ln_nlen), dest_dir, dir_len) < 0) 65457266Smuller return(-1); 65557266Smuller return(0); 65657266Smuller } 65757266Smuller 65857266Smuller /* 65957266Smuller * fix_path 66057266Smuller * concatenate dir_name and or_name and store the result in or_name (if 66157266Smuller * it fits). This is one ugly function. 66257266Smuller * Return: 66357266Smuller * 0 if ok, -1 if the final name is too long 66457266Smuller */ 66557266Smuller 66657266Smuller #if __STDC__ 66757266Smuller static int 66857266Smuller fix_path( char *or_name, int *or_len, char *dir_name, int dir_len) 66957266Smuller #else 67057266Smuller static int 67157266Smuller fix_path(or_name, or_len, dir_name, dir_len) 67257266Smuller char *or_name; 67357266Smuller int *or_len; 67457266Smuller char *dir_name; 67557266Smuller int dir_len; 67657266Smuller #endif 67757266Smuller { 67857266Smuller register char *src; 67957266Smuller register char *dest; 68057266Smuller register char *start; 68157266Smuller int len; 68257266Smuller 68357266Smuller /* 68457266Smuller * we shift the or_name to the right enough to tack in the dir_name 68557266Smuller * at the front. We make sure we have enough space for it all before 68657266Smuller * we start. since dest always ends in a slash, we skip of or_name 68757266Smuller * if it also starts with one. 68857266Smuller */ 68957266Smuller start = or_name; 69057266Smuller src = start + *or_len; 69157266Smuller dest = src + dir_len; 69257266Smuller if (*start == '/') { 69357266Smuller ++start; 69457266Smuller --dest; 69557266Smuller } 69657266Smuller if ((len = dest - or_name) > PAXPATHLEN) { 69757266Smuller warn(1, "File name %s/%s, too long", dir_name, start); 69857266Smuller return(-1); 69957266Smuller } 70057266Smuller *or_len = len; 70157266Smuller 70257266Smuller /* 70357266Smuller * enough space, shift 70457266Smuller */ 70557266Smuller while (src >= start) 70657266Smuller *dest-- = *src--; 70757266Smuller src = dir_name + dir_len - 1; 70857266Smuller 70957266Smuller /* 71057266Smuller * splice in the destination directory name 71157266Smuller */ 71257266Smuller while (src >= dir_name) 71357266Smuller *dest-- = *src--; 71457266Smuller 71557266Smuller *(or_name + len) = '\0'; 71657266Smuller return(0); 71757266Smuller } 71857266Smuller 71957266Smuller /* 72057266Smuller * rep_name() 72157266Smuller * walk down the list of replacement strings applying each one in order. 72257266Smuller * when we find one with a successful substitution, we modify the name 72357266Smuller * as specified. if required, we print the results. if the resulting name 72457266Smuller * is empty, we will skip this archive member. We use the regexp(3) 72557266Smuller * routines (regexp() ought to win a prize as having the most cryptic 72657266Smuller * library function manual page). 72757266Smuller * --Parameters-- 72857266Smuller * name is the file name we are going to apply the regular expressions to 72957266Smuller * (and may be modified) 73057266Smuller * nlen is the length of this name (and is modified to hold the length of 73157266Smuller * the final string). 73257266Smuller * prnt is a flag that says whether to print the final result. 73357266Smuller * Return: 73457266Smuller * 0 if substitution was successful, 1 if we are to skip the file (the name 73557266Smuller * ended up empty) 73657266Smuller */ 73757266Smuller 73857266Smuller #if __STDC__ 73957266Smuller static int 74057266Smuller rep_name(char *name, int *nlen, int prnt) 74157266Smuller #else 74257266Smuller static int 74357266Smuller rep_name(name, nlen, prnt) 74457266Smuller char *name; 74557266Smuller int *nlen; 74657266Smuller int prnt; 74757266Smuller #endif 74857266Smuller { 74957266Smuller register REPLACE *pt; 75057266Smuller register char *inpt; 75157266Smuller register char *outpt; 75257266Smuller register char *endpt; 75357266Smuller register char *rpt; 75457266Smuller register int found = 0; 75557266Smuller register int res; 75657266Smuller # ifndef NET2_REGEX 75757266Smuller regmatch_t pm[MAXSUBEXP]; 75857266Smuller # endif 75957266Smuller char nname[PAXPATHLEN+1]; /* final result of all replacements */ 76057266Smuller char buf1[PAXPATHLEN+1]; /* where we work on the name */ 76157266Smuller 76257266Smuller /* 76357266Smuller * copy the name into buf1, where we will work on it. We need to keep 76457266Smuller * the orig string around so we can print out the result of the final 76557266Smuller * replacement. We build up the final result in nname. inpt points at 76657266Smuller * the string we apply the regular expression to. prnt is used to 76757266Smuller * suppress printing when we handle replacements on the link field 76857266Smuller * (the user already saw that substitution go by) 76957266Smuller */ 77057266Smuller pt = rephead; 77157266Smuller (void)strcpy(buf1, name); 77257266Smuller inpt = buf1; 77357266Smuller outpt = nname; 77457266Smuller endpt = outpt + PAXPATHLEN; 77557266Smuller 77657266Smuller /* 77757266Smuller * try each replacement string in order 77857266Smuller */ 77957266Smuller while (pt != NULL) { 78057266Smuller do { 78157266Smuller /* 78257266Smuller * check for a successful substitution, if not go to 78357266Smuller * the next pattern, or cleanup if we were global 78457266Smuller */ 78557266Smuller # ifdef NET2_REGEX 78657266Smuller if (regexec(pt->rcmp, inpt) == 0) 78757266Smuller # else 78857266Smuller if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0) 78957266Smuller # endif 79057266Smuller break; 79157266Smuller 79257266Smuller /* 79357266Smuller * ok we found one. We have three parts, the prefix 79457266Smuller * which did not match, the section that did and the 79557266Smuller * tail (that also did not match). Copy the prefix to 79657266Smuller * the final output buffer (watching to make sure we 79757266Smuller * do not create a string too long). 79857266Smuller */ 79957266Smuller found = 1; 80057266Smuller # ifdef NET2_REGEX 80157266Smuller rpt = pt->rcmp->startp[0]; 80257266Smuller # else 80357266Smuller rpt = inpt + pm[0].rm_so; 80457266Smuller # endif 80557266Smuller 80657266Smuller while ((inpt < rpt) && (outpt < endpt)) 80757266Smuller *outpt++ = *inpt++; 80857266Smuller if (outpt == endpt) 80957266Smuller break; 81057266Smuller 81157266Smuller /* 81257266Smuller * for the second part (which matched the regular 81357266Smuller * expression) apply the substitution using the 81457266Smuller * replacement string and place it the prefix in the 81557266Smuller * final output. If we have problems, skip it. 81657266Smuller */ 81757266Smuller # ifdef NET2_REGEX 81857266Smuller if ((res = resub(pt->rcmp,pt->nstr,outpt,endpt)) < 0) { 81957266Smuller # else 82057266Smuller if ((res = resub(&(pt->rcmp),pm,pt->nstr,outpt,endpt)) 82157266Smuller < 0) { 82257266Smuller # endif 82357266Smuller if (prnt) 82457266Smuller warn(1, "Replacement name error %s", 82557266Smuller name); 82657266Smuller return(1); 82757266Smuller } 82857266Smuller outpt += res; 82957266Smuller 83057266Smuller /* 83157266Smuller * we set up to look again starting at the first 83257266Smuller * character in the tail (of the input string right 83357266Smuller * after the last character matched by the regular 83457266Smuller * expression (inpt always points at the first char in 83557266Smuller * the string to process). If we are not doing a global 83657266Smuller * substitution, we will use inpt to copy the tail to 83757266Smuller * the final result. Make sure we do not overrun the 83857266Smuller * output buffer 83957266Smuller */ 84057266Smuller # ifdef NET2_REGEX 84157266Smuller inpt = pt->rcmp->endp[0]; 84257266Smuller # else 84357266Smuller inpt += pm[0].rm_eo; 84457266Smuller # endif 84557266Smuller 84657266Smuller if ((outpt == endpt) || (*inpt == '\0')) 84757266Smuller break; 84857266Smuller 84957266Smuller /* 85057266Smuller * if the user wants global we keep trying to 85157266Smuller * substitute until it fails, then we are done. 85257266Smuller */ 85357266Smuller } while (pt->flgs & GLOB); 85457266Smuller 85557266Smuller if (found) 85657266Smuller break; 85757266Smuller 85857266Smuller /* 85957266Smuller * a successful substitution did NOT occur, try the next one 86057266Smuller */ 86157266Smuller pt = pt->fow; 86257266Smuller } 86357266Smuller 86457266Smuller if (found) { 86557266Smuller /* 86657266Smuller * we had a substitution, copy the last tail piece (if there is 86757266Smuller * room) to the final result 86857266Smuller */ 86957266Smuller while ((outpt < endpt) && (*inpt != '\0')) 87057266Smuller *outpt++ = *inpt++; 87157266Smuller 87257266Smuller *outpt = '\0'; 87357266Smuller if ((outpt == endpt) && (*inpt != '\0')) { 87457266Smuller if (prnt) 87557266Smuller warn(1,"Replacement name too long %s >> %s", 87657266Smuller name, nname); 87757266Smuller return(1); 87857266Smuller } 87957266Smuller 88057266Smuller /* 88157266Smuller * inform the user of the result if wanted 88257266Smuller */ 88357266Smuller if (prnt && (pt->flgs & PRNT)) { 88457266Smuller if (*nname == '\0') 88557266Smuller (void)fprintf(stderr,"%s >> <empty string>\n", 88657266Smuller name); 88757266Smuller else 88857266Smuller (void)fprintf(stderr,"%s >> %s\n", name, nname); 88957266Smuller } 89057266Smuller 89157266Smuller /* 89257266Smuller * if empty inform the caller this file is to be skipped 89357266Smuller * otherwise copy the new name over the orig name and return 89457266Smuller */ 89557266Smuller if (*nname == '\0') 89657266Smuller return(1); 89757266Smuller *nlen = l_strncpy(name, nname, PAXPATHLEN + 1); 89857266Smuller } 89957266Smuller return(0); 90057266Smuller } 90157266Smuller 90257266Smuller #ifdef NET2_REGEX 90357266Smuller /* 90457266Smuller * resub() 90557266Smuller * apply the replacement to the matched expression. expand out the old 90657266Smuller * style ed(1) subexpression expansion. 90757266Smuller * Return: 90857266Smuller * -1 if error, or the number of characters added to the destination. 90957266Smuller */ 91057266Smuller 91157266Smuller #if __STDC__ 91257266Smuller static int 91357266Smuller resub(regexp *prog, char *src, char *dest, register char *destend) 91457266Smuller #else 91557266Smuller static int 91657266Smuller resub(prog, src, dest, destend) 91757266Smuller regexp *prog; 91857266Smuller char *src; 91957266Smuller char *dest; 92057266Smuller register char *destend; 92157266Smuller #endif 92257266Smuller { 92357266Smuller register char *spt; 92457266Smuller register char *dpt; 92557266Smuller register char c; 92657266Smuller register int no; 92757266Smuller register int len; 92857266Smuller 92957266Smuller spt = src; 93057266Smuller dpt = dest; 93157266Smuller while ((dpt < destend) && ((c = *spt++) != '\0')) { 93257266Smuller if (c == '&') 93357266Smuller no = 0; 93457266Smuller else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) 93557266Smuller no = *spt++ - '0'; 93657266Smuller else { 93757266Smuller if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) 93857266Smuller c = *spt++; 93957266Smuller *dpt++ = c; 94057266Smuller continue; 94157266Smuller } 94257266Smuller if ((prog->startp[no] == NULL) || (prog->endp[no] == NULL) || 94357266Smuller ((len = prog->endp[no] - prog->startp[no]) <= 0)) 94457266Smuller continue; 94557266Smuller 94657266Smuller /* 94757266Smuller * copy the subexpression to the destination. 94857266Smuller * fail if we run out of space or the match string is damaged 94957266Smuller */ 95057266Smuller if (len > (destend - dpt)) 95157266Smuller len = destend - dpt; 95257266Smuller if (l_strncpy(dpt, prog->startp[no], len) != len) 95357266Smuller return(-1); 95457266Smuller dpt += len; 95557266Smuller } 95657266Smuller return(dpt - dest); 95757266Smuller } 95857266Smuller 95957266Smuller #else 96057266Smuller 96157266Smuller /* 96257266Smuller * resub() 96357266Smuller * apply the replacement to the matched expression. expand out the old 96457266Smuller * style ed(1) subexpression expansion. 96557266Smuller * Return: 96657266Smuller * -1 if error, or the number of characters added to the destination. 96757266Smuller */ 96857266Smuller 96957266Smuller #if __STDC__ 97057266Smuller static int 97157266Smuller resub(regex_t *rp, register regmatch_t *pm, char *src, char *dest, 97257266Smuller register char *destend) 97357266Smuller #else 97457266Smuller static int 97557266Smuller resub(rp, pm, src, dest, destend) 97657266Smuller regex_t *rp; 97757266Smuller register regmatch_t *pm; 97857266Smuller char *src; 97957266Smuller char *dest; 98057266Smuller register char *destend; 98157266Smuller #endif 98257266Smuller { 98357266Smuller register char *spt; 98457266Smuller register char *dpt; 98557266Smuller register char c; 98657266Smuller register regmatch_t *pmpt; 98757266Smuller register int len; 98857266Smuller int subexcnt; 98957266Smuller 99057266Smuller spt = src; 99157266Smuller dpt = dest; 99257266Smuller subexcnt = rp->re_nsub; 99357266Smuller while ((dpt < destend) && ((c = *spt++) != '\0')) { 99457266Smuller /* 99557266Smuller * see if we just have an ordinary replacement character 99657266Smuller * or we refer to a subexpression. 99757266Smuller */ 99857266Smuller if (c == '&') { 99957266Smuller pmpt = pm; 100057266Smuller } else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) { 100157266Smuller /* 100257266Smuller * make sure there is a subexpression as specified 100357266Smuller */ 100457266Smuller if ((len = *spt++ - '0') > subexcnt) 100557266Smuller return(-1); 100657266Smuller pmpt = pm + len; 100757266Smuller } else { 100857266Smuller /* 100957266Smuller * Ordinary character, just copy it 101057266Smuller */ 101157266Smuller if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) 101257266Smuller c = *spt++; 101357266Smuller *dpt++ = c; 101457266Smuller continue; 101557266Smuller } 101657266Smuller 101757266Smuller /* 101857266Smuller * continue if the subexpression is bogus 101957266Smuller */ 102057266Smuller if ((pmpt->rm_so < 0) || (pmpt->rm_eo < 0) || 102157266Smuller ((len = pmpt->rm_eo - pmpt->rm_so) <= 0)) 102257266Smuller continue; 102357266Smuller 102457266Smuller /* 102557266Smuller * copy the subexpression to the destination. 102657266Smuller * fail if we run out of space or the match string is damaged 102757266Smuller */ 102857266Smuller if (len > (destend - dpt)) 102957266Smuller len = destend - dpt; 103057266Smuller if (l_strncpy(dpt, src + pmpt->rm_so, len) != len) 103157266Smuller return(-1); 103257266Smuller dpt += len; 103357266Smuller } 103457266Smuller return(dpt - dest); 103557266Smuller } 103657266Smuller #endif 1037