📄 pat_rep.c
字号:
/* NOTREACHED */}#ifdef __STDC__static char *range_match(register char *pattern, register int test)#elsestatic char *range_match(pattern, test) register char *pattern; register int test;#endif{ register char c; register char c2; int negate; int ok = 0; if (negate = (*pattern == '!')) ++pattern; while ((c = *pattern++) != ']') { /* * Illegal pattern */ if (c == '\0') return (NULL); if ((*pattern == '-') && ((c2 = pattern[1]) != '\0') && (c2 != ']')) { if ((c <= test) && (test <= c2)) ok = 1; pattern += 2; } else if (c == test) ok = 1; } return (ok == negate ? NULL : pattern);}/* * mod_name() * modify a selected file name. first attempt to apply replacement string * expressions, then apply interactive file rename. We apply replacement * string expressions to both filenames and file links (if we didn't the * links would point to the wrong place, and we could never be able to * move an archive that has a file link in it). When we rename files * interactively, we store that mapping (old name to user input name) so * if we spot any file links to the old file name in the future, we will * know exactly how to fix the file link. * Return: * 0 continue to process file, 1 skip this file, -1 pax is finished */#if __STDC__intmod_name(register ARCHD *arcn)#elseintmod_name(arcn) register ARCHD *arcn;#endif{ register int res = 0; /* * IMPORTANT: We have a problem. what do we do with symlinks? * Modifying a hard link name makes sense, as we know the file it * points at should have been seen already in the archive (and if it * wasn't seen because of a read error or a bad archive, we lose * anyway). But there are no such requirements for symlinks. On one * hand the symlink that refers to a file in the archive will have to * be modified to so it will still work at its new location in the * file system. On the other hand a symlink that points elsewhere (and * should continue to do so) should not be modified. There is clearly * no perfect solution here. So we handle them like hardlinks. Clearly * a replacement made by the interactive rename mapping is very likely * to be correct since it applies to a single file and is an exact * match. The regular expression replacements are a little harder to * justify though. We claim that the symlink name is only likely * to be replaced when it points within the file tree being moved and * in that case it should be modified. what we really need to do is to * call an oracle here. :) */ if (rephead != NULL) { /* * we have replacement strings, modify the name and the link * name if any. */ if ((res = rep_name(arcn->name, &(arcn->nlen), 1)) != 0) return(res); if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) && ((res = rep_name(arcn->ln_name, &(arcn->ln_nlen), 0)) != 0)) return(res); } if (iflag) { /* * perform interactive file rename, then map the link if any */ if ((res = tty_rename(arcn)) != 0) return(res); if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) sub_name(arcn->ln_name, &(arcn->ln_nlen)); } return(res);}/* * tty_rename() * Prompt the user for a replacement file name. A "." keeps the old name, * a empty line skips the file, and an EOF on reading the tty, will cause * pax to stop processing and exit. Otherwise the file name input, replaces * the old one. * Return: * 0 process this file, 1 skip this file, -1 we need to exit pax */#if __STDC__static inttty_rename(register ARCHD *arcn)#elsestatic inttty_rename(arcn) register ARCHD *arcn;#endif{ char tmpname[PAXPATHLEN+2]; int res; /* * prompt user for the replacement name for a file, keep trying until * we get some reasonable input. Archives may have more than one file * on them with the same name (from updates etc). We print verbose info * on the file so the user knows what is up. */ tty_prnt("\nATTENTION: %s interactive file rename operation.\n", argv0); for (;;) { ls_tty(arcn); tty_prnt("Input new name, or a \".\" to keep the old name, "); tty_prnt("or a \"return\" to skip this file.\n"); tty_prnt("Input > "); if (tty_read(tmpname, sizeof(tmpname)) < 0) return(-1); if (strcmp(tmpname, "..") == 0) { tty_prnt("Try again, illegal file name: ..\n"); continue; } if (strlen(tmpname) > PAXPATHLEN) { tty_prnt("Try again, file name too long\n"); continue; } break; } /* * empty file name, skips this file. a "." leaves it alone */ if (tmpname[0] == '\0') { tty_prnt("Skipping file.\n"); return(1); } if ((tmpname[0] == '.') && (tmpname[1] == '\0')) { tty_prnt("Processing continues, name unchanged.\n"); return(0); } /* * ok the name changed. We may run into links that point at this * file later. we have to remember where the user sent the file * in order to repair any links. */ tty_prnt("Processing continues, name changed to: %s\n", tmpname); res = add_name(arcn->name, arcn->nlen, tmpname); arcn->nlen = l_strncpy(arcn->name, tmpname, PAXPATHLEN+1); if (res < 0) return(-1); return(0);}/* * set_dest() * fix up the file name and the link name (if any) so this file will land * in the destination directory (used during copy() -rw). * Return: * 0 if ok, -1 if failure (name too long) */#if __STDC__intset_dest(register ARCHD *arcn, char *dest_dir, int dir_len)#elseintset_dest(arcn, dest_dir, dir_len) register ARCHD *arcn; char *dest_dir; int dir_len;#endif{ if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0) return(-1); /* * It is really hard to deal with symlinks here, we cannot be sure * if the name they point was moved (or will be moved). It is best to * leave them alone. */ if ((arcn->type != PAX_HLK) && (arcn->type != PAX_HRG)) return(0); if (fix_path(arcn->ln_name, &(arcn->ln_nlen), dest_dir, dir_len) < 0) return(-1); return(0);}/* * fix_path * concatenate dir_name and or_name and store the result in or_name (if * it fits). This is one ugly function. * Return: * 0 if ok, -1 if the final name is too long */#if __STDC__static intfix_path( char *or_name, int *or_len, char *dir_name, int dir_len)#elsestatic intfix_path(or_name, or_len, dir_name, dir_len) char *or_name; int *or_len; char *dir_name; int dir_len;#endif{ register char *src; register char *dest; register char *start; int len; /* * we shift the or_name to the right enough to tack in the dir_name * at the front. We make sure we have enough space for it all before * we start. since dest always ends in a slash, we skip of or_name * if it also starts with one. */ start = or_name; src = start + *or_len; dest = src + dir_len; if (*start == '/') { ++start; --dest; } if ((len = dest - or_name) > PAXPATHLEN) { warn(1, "File name %s/%s, too long", dir_name, start); return(-1); } *or_len = len; /* * enough space, shift */ while (src >= start) *dest-- = *src--; src = dir_name + dir_len - 1; /* * splice in the destination directory name */ while (src >= dir_name) *dest-- = *src--; *(or_name + len) = '\0'; return(0);}/* * rep_name() * walk down the list of replacement strings applying each one in order. * when we find one with a successful substitution, we modify the name * as specified. if required, we print the results. if the resulting name * is empty, we will skip this archive member. We use the regexp(3) * routines (regexp() ought to win a prize as having the most cryptic * library function manual page). * --Parameters-- * name is the file name we are going to apply the regular expressions to * (and may be modified) * nlen is the length of this name (and is modified to hold the length of * the final string). * prnt is a flag that says whether to print the final result. * Return: * 0 if substitution was successful, 1 if we are to skip the file (the name * ended up empty) */#if __STDC__static intrep_name(char *name, int *nlen, int prnt)#elsestatic intrep_name(name, nlen, prnt) char *name; int *nlen; int prnt;#endif{ register REPLACE *pt; register char *inpt; register char *outpt; register char *endpt; register char *rpt; register int found = 0; register int res;# ifndef NET2_REGEX regmatch_t pm[MAXSUBEXP];# endif char nname[PAXPATHLEN+1]; /* final result of all replacements */ char buf1[PAXPATHLEN+1]; /* where we work on the name */ /* * copy the name into buf1, where we will work on it. We need to keep * the orig string around so we can print out the result of the final * replacement. We build up the final result in nname. inpt points at * the string we apply the regular expression to. prnt is used to * suppress printing when we handle replacements on the link field * (the user already saw that substitution go by) */ pt = rephead; (void)strcpy(buf1, name); inpt = buf1; outpt = nname; endpt = outpt + PAXPATHLEN; /* * try each replacement string in order */ while (pt != NULL) { do { /* * check for a successful substitution, if not go to * the next pattern, or cleanup if we were global */# ifdef NET2_REGEX if (regexec(pt->rcmp, inpt) == 0)# else if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0)# endif break; /* * ok we found one. We have three parts, the prefix * which did not match, the section that did and the * tail (that also did not match). Copy the prefix to * the final output buffer (watching to make sure we * do not create a string too long). */ found = 1;# ifdef NET2_REGEX rpt = pt->rcmp->startp[0];# else rpt = inpt + pm[0].rm_so;# endif while ((inpt < rpt) && (outpt < endpt)) *outpt++ = *inpt++; if (outpt == endpt) break; /* * for the second part (which matched the regular * expression) apply the substitution using the * replacement string and place it the prefix in the * final output. If we have problems, skip it. */# ifdef NET2_REGEX if ((res = resub(pt->rcmp,pt->nstr,outpt,endpt)) < 0) {# else if ((res = resub(&(pt->rcmp),pm,pt->nstr,outpt,endpt)) < 0) {# endif if (prnt) warn(1, "Replacement name error %s", name); return(1); } outpt += res; /* * we set up to look again starting at the first * character in the tail (of the input string right * after the last character matched by the regular * expression (inpt always points at the first char in * the string to process). If we are not doing a global * substitution, we will use inpt to copy the tail to * the final result. Make sure we do not overrun the * output buffer */# ifdef NET2_REGEX inpt = pt->rcmp->endp[0];# else inpt += pm[0].rm_eo;# endif if ((outpt == endpt) || (*inpt == '\0')) break; /* * if the user wants global we keep trying to * substitute until it fails, then we are done. */ } while (pt->flgs & GLOB); if (found) break; /* * a successful substitution did NOT occur, try the next one */ pt = pt->fow; } if (found) { /* * we had a substitution, copy the last tail piece (if there is * room) to the final result */ while ((outpt < endpt) && (*inpt != '\0')) *outpt++ = *inpt++; *outpt = '\0'; if ((outpt == endpt) && (*inpt != '\0')) { if (prnt) warn(1,"Replacement name too long %s >> %s", name, nname); return(1); } /* * inform the user of the result if wanted */ if (prnt && (pt->flgs & PRNT)) { if (*nname == '\0') (void)fprintf(stderr,"%s >> <empty string>\n", name); else (void)fprintf(stderr,"%s >> %s\n", name, nname); } /* * if empty inform the caller this file is to be skipped * otherwise copy the new name over the orig name and return */ if (*nname == '\0') return(1); *nlen = l_strncpy(name, nname, PAXPATHLEN + 1); } return(0);}#ifdef NET2_REGEX/* * resub() * apply the replacement to the matched expression. expand out the old * style ed(1) subexpression expansion. * Return: * -1 if error, or the number of characters added to the destination. */#if __STDC__static intresub(regexp *prog, char *src, char *dest, register char *destend)#elsestatic intresub(prog, src, dest, destend) regexp *prog; char *src; char *dest; register char *destend;#endif{ register char *spt; register char *dpt; register char c; register int no; register int len; spt = src; dpt = dest; while ((dpt < destend) && ((c = *spt++) != '\0')) { if (c == '&') no = 0; else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) no = *spt++ - '0'; else { if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) c = *spt++; *dpt++ = c; continue; } if ((prog->startp[no] == NULL) || (prog->endp[no] == NULL) || ((len = prog->endp[no] - prog->startp[no]) <= 0)) continue; /* * copy the subexpression to the destination. * fail if we run out of space or the match string is damaged */ if (len > (destend - dpt)) len = destend - dpt; if (l_strncpy(dpt, prog->startp[no], len) != len) return(-1); dpt += len; } return(dpt - dest);}#else/* * resub() * apply the replacement to the matched expression. expand out the old * style ed(1) subexpression expansion. * Return: * -1 if error, or the number of characters added to the destination. */#if __STDC__static intresub(regex_t *rp, register regmatch_t *pm, char *src, char *dest, register char *destend)#elsestatic intresub(rp, pm, src, dest, destend) regex_t *rp; register regmatch_t *pm; char *src; char *dest; register char *destend;#endif{ register char *spt; register char *dpt; register char c; register regmatch_t *pmpt; register int len; int subexcnt; spt = src; dpt = dest; subexcnt = rp->re_nsub; while ((dpt < destend) && ((c = *spt++) != '\0')) { /* * see if we just have an ordinary replacement character * or we refer to a subexpression. */ if (c == '&') { pmpt = pm; } else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) { /* * make sure there is a subexpression as specified */ if ((len = *spt++ - '0') > subexcnt) return(-1); pmpt = pm + len; } else { /* * Ordinary character, just copy it */ if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) c = *spt++; *dpt++ = c; continue; } /* * continue if the subexpression is bogus */ if ((pmpt->rm_so < 0) || (pmpt->rm_eo < 0) || ((len = pmpt->rm_eo - pmpt->rm_so) <= 0)) continue; /* * copy the subexpression to the destination. * fail if we run out of space or the match string is damaged */ if (len > (destend - dpt)) len = destend - dpt; if (l_strncpy(dpt, src + pmpt->rm_so, len) != len) return(-1); dpt += len; } return(dpt - dest);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -