14b88c807SRodney W. Grimes /*-
2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro F. Giffuni *
44b88c807SRodney W. Grimes * Copyright (c) 1992 Keith Muller.
54b88c807SRodney W. Grimes * Copyright (c) 1992, 1993
64b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved.
74b88c807SRodney W. Grimes *
84b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by
94b88c807SRodney W. Grimes * Keith Muller of the University of California, San Diego.
104b88c807SRodney W. Grimes *
114b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
124b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions
134b88c807SRodney W. Grimes * are met:
144b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
154b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
164b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
174b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
184b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution.
19fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
204b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software
214b88c807SRodney W. Grimes * without specific prior written permission.
224b88c807SRodney W. Grimes *
234b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
244b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
254b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
264b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
274b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
284b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
294b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
304b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
314b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
324b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
334b88c807SRodney W. Grimes * SUCH DAMAGE.
344b88c807SRodney W. Grimes */
354b88c807SRodney W. Grimes
364b88c807SRodney W. Grimes #include <sys/types.h>
374b88c807SRodney W. Grimes #include <sys/stat.h>
384b88c807SRodney W. Grimes #include <stdio.h>
394b88c807SRodney W. Grimes #include <string.h>
404b88c807SRodney W. Grimes #include <stdlib.h>
414b88c807SRodney W. Grimes #include <regex.h>
424b88c807SRodney W. Grimes #include "pax.h"
434b88c807SRodney W. Grimes #include "pat_rep.h"
444b88c807SRodney W. Grimes #include "extern.h"
454b88c807SRodney W. Grimes
464b88c807SRodney W. Grimes /*
474b88c807SRodney W. Grimes * routines to handle pattern matching, name modification (regular expression
484b88c807SRodney W. Grimes * substitution and interactive renames), and destination name modification for
494b88c807SRodney W. Grimes * copy (-rw). Both file name and link names are adjusted as required in these
504b88c807SRodney W. Grimes * routines.
514b88c807SRodney W. Grimes */
524b88c807SRodney W. Grimes
534b88c807SRodney W. Grimes #define MAXSUBEXP 10 /* max subexpressions, DO NOT CHANGE */
544b88c807SRodney W. Grimes static PATTERN *pathead = NULL; /* file pattern match list head */
554b88c807SRodney W. Grimes static PATTERN *pattail = NULL; /* file pattern match list tail */
564b88c807SRodney W. Grimes static REPLACE *rephead = NULL; /* replacement string list head */
574b88c807SRodney W. Grimes static REPLACE *reptail = NULL; /* replacement string list tail */
584b88c807SRodney W. Grimes
5946251ddeSWarner Losh static int rep_name(char *, int *, int);
60f789b261SWarner Losh static int tty_rename(ARCHD *);
6146251ddeSWarner Losh static int fix_path(char *, int *, char *, int);
62f789b261SWarner Losh static int fn_match(char *, char *, char **);
63f789b261SWarner Losh static char * range_match(char *, int);
64c9022a35SUlrich Spörlein static int resub(regex_t *, regmatch_t *, char *, char *, char *, char *);
654b88c807SRodney W. Grimes
664b88c807SRodney W. Grimes /*
674b88c807SRodney W. Grimes * rep_add()
684b88c807SRodney W. Grimes * parses the -s replacement string; compiles the regular expression
694b88c807SRodney W. Grimes * and stores the compiled value and it's replacement string together in
704b88c807SRodney W. Grimes * replacement string list. Input to this function is of the form:
714b88c807SRodney W. Grimes * /old/new/pg
724b88c807SRodney W. Grimes * The first char in the string specifies the delimiter used by this
734b88c807SRodney W. Grimes * replacement string. "Old" is a regular expression in "ed" format which
744b88c807SRodney W. Grimes * is compiled by regcomp() and is applied to filenames. "new" is the
754b88c807SRodney W. Grimes * substitution string; p and g are options flags for printing and global
764b88c807SRodney W. Grimes * replacement (over the single filename)
774b88c807SRodney W. Grimes * Return:
784b88c807SRodney W. Grimes * 0 if a proper replacement string and regular expression was added to
794b88c807SRodney W. Grimes * the list of replacement patterns; -1 otherwise.
804b88c807SRodney W. Grimes */
814b88c807SRodney W. Grimes
824b88c807SRodney W. Grimes int
rep_add(char * str)83f789b261SWarner Losh rep_add(char *str)
844b88c807SRodney W. Grimes {
85f789b261SWarner Losh char *pt1;
86f789b261SWarner Losh char *pt2;
87f789b261SWarner Losh REPLACE *rep;
88f789b261SWarner Losh int res;
894b88c807SRodney W. Grimes char rebuf[BUFSIZ];
904b88c807SRodney W. Grimes
914b88c807SRodney W. Grimes /*
924b88c807SRodney W. Grimes * throw out the bad parameters
934b88c807SRodney W. Grimes */
944b88c807SRodney W. Grimes if ((str == NULL) || (*str == '\0')) {
95778766feSKris Kennaway paxwarn(1, "Empty replacement string");
964b88c807SRodney W. Grimes return(-1);
974b88c807SRodney W. Grimes }
984b88c807SRodney W. Grimes
994b88c807SRodney W. Grimes /*
1004b88c807SRodney W. Grimes * first character in the string specifies what the delimiter is for
1014b88c807SRodney W. Grimes * this expression
1024b88c807SRodney W. Grimes */
1034b88c807SRodney W. Grimes if ((pt1 = strchr(str+1, *str)) == NULL) {
104778766feSKris Kennaway paxwarn(1, "Invalid replacement string %s", str);
1054b88c807SRodney W. Grimes return(-1);
1064b88c807SRodney W. Grimes }
1074b88c807SRodney W. Grimes
1084b88c807SRodney W. Grimes /*
1094b88c807SRodney W. Grimes * allocate space for the node that handles this replacement pattern
1104b88c807SRodney W. Grimes * and split out the regular expression and try to compile it
1114b88c807SRodney W. Grimes */
1124b88c807SRodney W. Grimes if ((rep = (REPLACE *)malloc(sizeof(REPLACE))) == NULL) {
113778766feSKris Kennaway paxwarn(1, "Unable to allocate memory for replacement string");
1144b88c807SRodney W. Grimes return(-1);
1154b88c807SRodney W. Grimes }
1164b88c807SRodney W. Grimes
1174b88c807SRodney W. Grimes *pt1 = '\0';
1184b88c807SRodney W. Grimes if ((res = regcomp(&(rep->rcmp), str+1, 0)) != 0) {
1194b88c807SRodney W. Grimes regerror(res, &(rep->rcmp), rebuf, sizeof(rebuf));
120778766feSKris Kennaway paxwarn(1, "%s while compiling regular expression %s", rebuf, str);
121367787a3SBrian Somers free(rep);
1224b88c807SRodney W. Grimes return(-1);
1234b88c807SRodney W. Grimes }
1244b88c807SRodney W. Grimes
1254b88c807SRodney W. Grimes /*
1264b88c807SRodney W. Grimes * put the delimiter back in case we need an error message and
1274b88c807SRodney W. Grimes * locate the delimiter at the end of the replacement string
1284b88c807SRodney W. Grimes * we then point the node at the new substitution string
1294b88c807SRodney W. Grimes */
1304b88c807SRodney W. Grimes *pt1++ = *str;
1314b88c807SRodney W. Grimes if ((pt2 = strchr(pt1, *str)) == NULL) {
132367787a3SBrian Somers regfree(&rep->rcmp);
133367787a3SBrian Somers free(rep);
134778766feSKris Kennaway paxwarn(1, "Invalid replacement string %s", str);
1354b88c807SRodney W. Grimes return(-1);
1364b88c807SRodney W. Grimes }
1374b88c807SRodney W. Grimes
1384b88c807SRodney W. Grimes *pt2 = '\0';
1394b88c807SRodney W. Grimes rep->nstr = pt1;
1404b88c807SRodney W. Grimes pt1 = pt2++;
1414b88c807SRodney W. Grimes rep->flgs = 0;
1424b88c807SRodney W. Grimes
1434b88c807SRodney W. Grimes /*
1444b88c807SRodney W. Grimes * set the options if any
1454b88c807SRodney W. Grimes */
1464b88c807SRodney W. Grimes while (*pt2 != '\0') {
1474b88c807SRodney W. Grimes switch(*pt2) {
1484b88c807SRodney W. Grimes case 'g':
1494b88c807SRodney W. Grimes case 'G':
1504b88c807SRodney W. Grimes rep->flgs |= GLOB;
1514b88c807SRodney W. Grimes break;
1524b88c807SRodney W. Grimes case 'p':
1534b88c807SRodney W. Grimes case 'P':
1544b88c807SRodney W. Grimes rep->flgs |= PRNT;
1554b88c807SRodney W. Grimes break;
1564b88c807SRodney W. Grimes default:
157367787a3SBrian Somers regfree(&rep->rcmp);
158367787a3SBrian Somers free(rep);
1594b88c807SRodney W. Grimes *pt1 = *str;
160778766feSKris Kennaway paxwarn(1, "Invalid replacement string option %s", str);
1614b88c807SRodney W. Grimes return(-1);
1624b88c807SRodney W. Grimes }
1634b88c807SRodney W. Grimes ++pt2;
1644b88c807SRodney W. Grimes }
1654b88c807SRodney W. Grimes
1664b88c807SRodney W. Grimes /*
1674b88c807SRodney W. Grimes * all done, link it in at the end
1684b88c807SRodney W. Grimes */
1694b88c807SRodney W. Grimes rep->fow = NULL;
1704b88c807SRodney W. Grimes if (rephead == NULL) {
1714b88c807SRodney W. Grimes reptail = rephead = rep;
1724b88c807SRodney W. Grimes return(0);
1734b88c807SRodney W. Grimes }
1744b88c807SRodney W. Grimes reptail->fow = rep;
1754b88c807SRodney W. Grimes reptail = rep;
1764b88c807SRodney W. Grimes return(0);
1774b88c807SRodney W. Grimes }
1784b88c807SRodney W. Grimes
1794b88c807SRodney W. Grimes /*
1804b88c807SRodney W. Grimes * pat_add()
1814b88c807SRodney W. Grimes * add a pattern match to the pattern match list. Pattern matches are used
1824b88c807SRodney W. Grimes * to select which archive members are extracted. (They appear as
1834b88c807SRodney W. Grimes * arguments to pax in the list and read modes). If no patterns are
1844b88c807SRodney W. Grimes * supplied to pax, all members in the archive will be selected (and the
1854b88c807SRodney W. Grimes * pattern match list is empty).
1864b88c807SRodney W. Grimes * Return:
1874b88c807SRodney W. Grimes * 0 if the pattern was added to the list, -1 otherwise
1884b88c807SRodney W. Grimes */
1894b88c807SRodney W. Grimes
1904b88c807SRodney W. Grimes int
pat_add(char * str,char * chdnam)19140feca3aSMark Murray pat_add(char *str, char *chdnam)
1924b88c807SRodney W. Grimes {
193f789b261SWarner Losh PATTERN *pt;
1944b88c807SRodney W. Grimes
1954b88c807SRodney W. Grimes /*
1964b88c807SRodney W. Grimes * throw out the junk
1974b88c807SRodney W. Grimes */
1984b88c807SRodney W. Grimes if ((str == NULL) || (*str == '\0')) {
199778766feSKris Kennaway paxwarn(1, "Empty pattern string");
2004b88c807SRodney W. Grimes return(-1);
2014b88c807SRodney W. Grimes }
2024b88c807SRodney W. Grimes
2034b88c807SRodney W. Grimes /*
2044b88c807SRodney W. Grimes * allocate space for the pattern and store the pattern. the pattern is
2054b88c807SRodney W. Grimes * part of argv so do not bother to copy it, just point at it. Add the
2064b88c807SRodney W. Grimes * node to the end of the pattern list
2074b88c807SRodney W. Grimes */
2084b88c807SRodney W. Grimes if ((pt = (PATTERN *)malloc(sizeof(PATTERN))) == NULL) {
209778766feSKris Kennaway paxwarn(1, "Unable to allocate memory for pattern string");
2104b88c807SRodney W. Grimes return(-1);
2114b88c807SRodney W. Grimes }
2124b88c807SRodney W. Grimes
2134b88c807SRodney W. Grimes pt->pstr = str;
2144b88c807SRodney W. Grimes pt->pend = NULL;
2154b88c807SRodney W. Grimes pt->plen = strlen(str);
2164b88c807SRodney W. Grimes pt->fow = NULL;
2174b88c807SRodney W. Grimes pt->flgs = 0;
21840feca3aSMark Murray pt->chdname = chdnam;
219b1787decSKris Kennaway
2204b88c807SRodney W. Grimes if (pathead == NULL) {
2214b88c807SRodney W. Grimes pattail = pathead = pt;
2224b88c807SRodney W. Grimes return(0);
2234b88c807SRodney W. Grimes }
2244b88c807SRodney W. Grimes pattail->fow = pt;
2254b88c807SRodney W. Grimes pattail = pt;
2264b88c807SRodney W. Grimes return(0);
2274b88c807SRodney W. Grimes }
2284b88c807SRodney W. Grimes
2294b88c807SRodney W. Grimes /*
2304b88c807SRodney W. Grimes * pat_chk()
2314b88c807SRodney W. Grimes * complain if any the user supplied pattern did not result in a match to
2324b88c807SRodney W. Grimes * a selected archive member.
2334b88c807SRodney W. Grimes */
2344b88c807SRodney W. Grimes
2354b88c807SRodney W. Grimes void
pat_chk(void)2364b88c807SRodney W. Grimes pat_chk(void)
2374b88c807SRodney W. Grimes {
238f789b261SWarner Losh PATTERN *pt;
239f789b261SWarner Losh int wban = 0;
2404b88c807SRodney W. Grimes
2414b88c807SRodney W. Grimes /*
2424b88c807SRodney W. Grimes * walk down the list checking the flags to make sure MTCH was set,
2434b88c807SRodney W. Grimes * if not complain
2444b88c807SRodney W. Grimes */
2454b88c807SRodney W. Grimes for (pt = pathead; pt != NULL; pt = pt->fow) {
2464b88c807SRodney W. Grimes if (pt->flgs & MTCH)
2474b88c807SRodney W. Grimes continue;
2484b88c807SRodney W. Grimes if (!wban) {
249778766feSKris Kennaway paxwarn(1, "WARNING! These patterns were not matched:");
2504b88c807SRodney W. Grimes ++wban;
2514b88c807SRodney W. Grimes }
2524b88c807SRodney W. Grimes (void)fprintf(stderr, "%s\n", pt->pstr);
2534b88c807SRodney W. Grimes }
2544b88c807SRodney W. Grimes }
2554b88c807SRodney W. Grimes
2564b88c807SRodney W. Grimes /*
2574b88c807SRodney W. Grimes * pat_sel()
2584b88c807SRodney W. Grimes * the archive member which matches a pattern was selected. Mark the
2594b88c807SRodney W. Grimes * pattern as having selected an archive member. arcn->pat points at the
2604b88c807SRodney W. Grimes * pattern that was matched. arcn->pat is set in pat_match()
2614b88c807SRodney W. Grimes *
2624b88c807SRodney W. Grimes * NOTE: When the -c option is used, we are called when there was no match
2634b88c807SRodney W. Grimes * by pat_match() (that means we did match before the inverted sense of
2644b88c807SRodney W. Grimes * the logic). Now this seems really strange at first, but with -c we
2659d5abbddSJens Schweikhardt * need to keep track of those patterns that cause an archive member to NOT
2664b88c807SRodney W. Grimes * be selected (it found an archive member with a specified pattern)
2674b88c807SRodney W. Grimes * Return:
2684b88c807SRodney W. Grimes * 0 if the pattern pointed at by arcn->pat was tagged as creating a
2694b88c807SRodney W. Grimes * match, -1 otherwise.
2704b88c807SRodney W. Grimes */
2714b88c807SRodney W. Grimes
2724b88c807SRodney W. Grimes int
pat_sel(ARCHD * arcn)273f789b261SWarner Losh pat_sel(ARCHD *arcn)
2744b88c807SRodney W. Grimes {
275f789b261SWarner Losh PATTERN *pt;
276f789b261SWarner Losh PATTERN **ppt;
277f789b261SWarner Losh int len;
2784b88c807SRodney W. Grimes
2794b88c807SRodney W. Grimes /*
2804b88c807SRodney W. Grimes * if no patterns just return
2814b88c807SRodney W. Grimes */
2824b88c807SRodney W. Grimes if ((pathead == NULL) || ((pt = arcn->pat) == NULL))
2834b88c807SRodney W. Grimes return(0);
2844b88c807SRodney W. Grimes
2854b88c807SRodney W. Grimes /*
2864b88c807SRodney W. Grimes * when we are NOT limited to a single match per pattern mark the
2874b88c807SRodney W. Grimes * pattern and return
2884b88c807SRodney W. Grimes */
2894b88c807SRodney W. Grimes if (!nflag) {
2904b88c807SRodney W. Grimes pt->flgs |= MTCH;
2914b88c807SRodney W. Grimes return(0);
2924b88c807SRodney W. Grimes }
2934b88c807SRodney W. Grimes
2944b88c807SRodney W. Grimes /*
2954b88c807SRodney W. Grimes * we reach this point only when we allow a single selected match per
2964b88c807SRodney W. Grimes * pattern, if the pattern matches a directory and we do not have -d
2974b88c807SRodney W. Grimes * (dflag) we are done with this pattern. We may also be handed a file
2984b88c807SRodney W. Grimes * in the subtree of a directory. in that case when we are operating
2994b88c807SRodney W. Grimes * with -d, this pattern was already selected and we are done
3004b88c807SRodney W. Grimes */
3014b88c807SRodney W. Grimes if (pt->flgs & DIR_MTCH)
3024b88c807SRodney W. Grimes return(0);
3034b88c807SRodney W. Grimes
3044b88c807SRodney W. Grimes if (!dflag && ((pt->pend != NULL) || (arcn->type == PAX_DIR))) {
3054b88c807SRodney W. Grimes /*
3064b88c807SRodney W. Grimes * ok we matched a directory and we are allowing
3074b88c807SRodney W. Grimes * subtree matches but because of the -n only its children will
3084b88c807SRodney W. Grimes * match. This is tagged as a DIR_MTCH type.
3094b88c807SRodney W. Grimes * WATCH IT, the code assumes that pt->pend points
3104b88c807SRodney W. Grimes * into arcn->name and arcn->name has not been modified.
3114b88c807SRodney W. Grimes * If not we will have a big mess. Yup this is another kludge
3124b88c807SRodney W. Grimes */
3134b88c807SRodney W. Grimes
3144b88c807SRodney W. Grimes /*
3154b88c807SRodney W. Grimes * if this was a prefix match, remove trailing part of path
3164b88c807SRodney W. Grimes * so we can copy it. Future matches will be exact prefix match
3174b88c807SRodney W. Grimes */
3184b88c807SRodney W. Grimes if (pt->pend != NULL)
3194b88c807SRodney W. Grimes *pt->pend = '\0';
3204b88c807SRodney W. Grimes
3214b88c807SRodney W. Grimes if ((pt->pstr = strdup(arcn->name)) == NULL) {
322778766feSKris Kennaway paxwarn(1, "Pattern select out of memory");
3234b88c807SRodney W. Grimes if (pt->pend != NULL)
3244b88c807SRodney W. Grimes *pt->pend = '/';
3254b88c807SRodney W. Grimes pt->pend = NULL;
3264b88c807SRodney W. Grimes return(-1);
3274b88c807SRodney W. Grimes }
3284b88c807SRodney W. Grimes
3294b88c807SRodney W. Grimes /*
3304b88c807SRodney W. Grimes * put the trailing / back in the source string
3314b88c807SRodney W. Grimes */
3324b88c807SRodney W. Grimes if (pt->pend != NULL) {
3334b88c807SRodney W. Grimes *pt->pend = '/';
3344b88c807SRodney W. Grimes pt->pend = NULL;
3354b88c807SRodney W. Grimes }
3364b88c807SRodney W. Grimes pt->plen = strlen(pt->pstr);
3374b88c807SRodney W. Grimes
3384b88c807SRodney W. Grimes /*
3394b88c807SRodney W. Grimes * strip off any trailing /, this should really never happen
3404b88c807SRodney W. Grimes */
3414b88c807SRodney W. Grimes len = pt->plen - 1;
3424b88c807SRodney W. Grimes if (*(pt->pstr + len) == '/') {
3434b88c807SRodney W. Grimes *(pt->pstr + len) = '\0';
3444b88c807SRodney W. Grimes pt->plen = len;
3454b88c807SRodney W. Grimes }
3464b88c807SRodney W. Grimes pt->flgs = DIR_MTCH | MTCH;
3474b88c807SRodney W. Grimes arcn->pat = pt;
3484b88c807SRodney W. Grimes return(0);
3494b88c807SRodney W. Grimes }
3504b88c807SRodney W. Grimes
3514b88c807SRodney W. Grimes /*
3524b88c807SRodney W. Grimes * we are then done with this pattern, so we delete it from the list
3534b88c807SRodney W. Grimes * because it can never be used for another match.
3544b88c807SRodney W. Grimes * Seems kind of strange to do for a -c, but the pax spec is really
3554b88c807SRodney W. Grimes * vague on the interaction of -c -n and -d. We assume that when -c
3564b88c807SRodney W. Grimes * and the pattern rejects a member (i.e. it matched it) it is done.
3574b88c807SRodney W. Grimes * In effect we place the order of the flags as having -c last.
3584b88c807SRodney W. Grimes */
3594b88c807SRodney W. Grimes pt = pathead;
3604b88c807SRodney W. Grimes ppt = &pathead;
3614b88c807SRodney W. Grimes while ((pt != NULL) && (pt != arcn->pat)) {
3624b88c807SRodney W. Grimes ppt = &(pt->fow);
3634b88c807SRodney W. Grimes pt = pt->fow;
3644b88c807SRodney W. Grimes }
3654b88c807SRodney W. Grimes
3664b88c807SRodney W. Grimes if (pt == NULL) {
3674b88c807SRodney W. Grimes /*
3684b88c807SRodney W. Grimes * should never happen....
3694b88c807SRodney W. Grimes */
37001c99176SUlrich Spörlein paxwarn(1, "Pattern list inconsistent");
3714b88c807SRodney W. Grimes return(-1);
3724b88c807SRodney W. Grimes }
3734b88c807SRodney W. Grimes *ppt = pt->fow;
374367787a3SBrian Somers free(pt);
3754b88c807SRodney W. Grimes arcn->pat = NULL;
3764b88c807SRodney W. Grimes return(0);
3774b88c807SRodney W. Grimes }
3784b88c807SRodney W. Grimes
3794b88c807SRodney W. Grimes /*
3804b88c807SRodney W. Grimes * pat_match()
3814b88c807SRodney W. Grimes * see if this archive member matches any supplied pattern, if a match
3824b88c807SRodney W. Grimes * is found, arcn->pat is set to point at the potential pattern. Later if
3834b88c807SRodney W. Grimes * this archive member is "selected" we process and mark the pattern as
3844b88c807SRodney W. Grimes * one which matched a selected archive member (see pat_sel())
3854b88c807SRodney W. Grimes * Return:
3864b88c807SRodney W. Grimes * 0 if this archive member should be processed, 1 if it should be
3874b88c807SRodney W. Grimes * skipped and -1 if we are done with all patterns (and pax should quit
3884b88c807SRodney W. Grimes * looking for more members)
3894b88c807SRodney W. Grimes */
3904b88c807SRodney W. Grimes
3914b88c807SRodney W. Grimes int
pat_match(ARCHD * arcn)392f789b261SWarner Losh pat_match(ARCHD *arcn)
3934b88c807SRodney W. Grimes {
394f789b261SWarner Losh PATTERN *pt;
3954b88c807SRodney W. Grimes
3964b88c807SRodney W. Grimes arcn->pat = NULL;
3974b88c807SRodney W. Grimes
3984b88c807SRodney W. Grimes /*
3994b88c807SRodney W. Grimes * if there are no more patterns and we have -n (and not -c) we are
4004b88c807SRodney W. Grimes * done. otherwise with no patterns to match, matches all
4014b88c807SRodney W. Grimes */
4024b88c807SRodney W. Grimes if (pathead == NULL) {
4034b88c807SRodney W. Grimes if (nflag && !cflag)
4044b88c807SRodney W. Grimes return(-1);
4054b88c807SRodney W. Grimes return(0);
4064b88c807SRodney W. Grimes }
4074b88c807SRodney W. Grimes
4084b88c807SRodney W. Grimes /*
4094b88c807SRodney W. Grimes * have to search down the list one at a time looking for a match.
4104b88c807SRodney W. Grimes */
4114b88c807SRodney W. Grimes pt = pathead;
4124b88c807SRodney W. Grimes while (pt != NULL) {
4134b88c807SRodney W. Grimes /*
4144b88c807SRodney W. Grimes * check for a file name match unless we have DIR_MTCH set in
4154b88c807SRodney W. Grimes * this pattern then we want a prefix match
4164b88c807SRodney W. Grimes */
4174b88c807SRodney W. Grimes if (pt->flgs & DIR_MTCH) {
4184b88c807SRodney W. Grimes /*
4194b88c807SRodney W. Grimes * this pattern was matched before to a directory
4204b88c807SRodney W. Grimes * as we must have -n set for this (but not -d). We can
4214b88c807SRodney W. Grimes * only match CHILDREN of that directory so we must use
4224b88c807SRodney W. Grimes * an exact prefix match (no wildcards).
4234b88c807SRodney W. Grimes */
4244b88c807SRodney W. Grimes if ((arcn->name[pt->plen] == '/') &&
4254b88c807SRodney W. Grimes (strncmp(pt->pstr, arcn->name, pt->plen) == 0))
4264b88c807SRodney W. Grimes break;
4274b88c807SRodney W. Grimes } else if (fn_match(pt->pstr, arcn->name, &pt->pend) == 0)
4284b88c807SRodney W. Grimes break;
4294b88c807SRodney W. Grimes pt = pt->fow;
4304b88c807SRodney W. Grimes }
4314b88c807SRodney W. Grimes
4324b88c807SRodney W. Grimes /*
4334b88c807SRodney W. Grimes * return the result, remember that cflag (-c) inverts the sense of a
4344b88c807SRodney W. Grimes * match
4354b88c807SRodney W. Grimes */
4364b88c807SRodney W. Grimes if (pt == NULL)
4374b88c807SRodney W. Grimes return(cflag ? 0 : 1);
4384b88c807SRodney W. Grimes
4394b88c807SRodney W. Grimes /*
4409d5abbddSJens Schweikhardt * We had a match, now when we invert the sense (-c) we reject this
4414b88c807SRodney W. Grimes * member. However we have to tag the pattern a being successful, (in a
4429d5abbddSJens Schweikhardt * match, not in selecting an archive member) so we call pat_sel() here.
4434b88c807SRodney W. Grimes */
4444b88c807SRodney W. Grimes arcn->pat = pt;
4454b88c807SRodney W. Grimes if (!cflag)
4464b88c807SRodney W. Grimes return(0);
4474b88c807SRodney W. Grimes
4484b88c807SRodney W. Grimes if (pat_sel(arcn) < 0)
4494b88c807SRodney W. Grimes return(-1);
4504b88c807SRodney W. Grimes arcn->pat = NULL;
4514b88c807SRodney W. Grimes return(1);
4524b88c807SRodney W. Grimes }
4534b88c807SRodney W. Grimes
4544b88c807SRodney W. Grimes /*
4554b88c807SRodney W. Grimes * fn_match()
4564b88c807SRodney W. Grimes * Return:
4574b88c807SRodney W. Grimes * 0 if this archive member should be processed, 1 if it should be
4584b88c807SRodney W. Grimes * skipped and -1 if we are done with all patterns (and pax should quit
4594b88c807SRodney W. Grimes * looking for more members)
4604b88c807SRodney W. Grimes * Note: *pend may be changed to show where the prefix ends.
4614b88c807SRodney W. Grimes */
4624b88c807SRodney W. Grimes
4634b88c807SRodney W. Grimes static int
fn_match(char * pattern,char * string,char ** pend)464f789b261SWarner Losh fn_match(char *pattern, char *string, char **pend)
4654b88c807SRodney W. Grimes {
466f789b261SWarner Losh char c;
4674b88c807SRodney W. Grimes char test;
4684b88c807SRodney W. Grimes
4694b88c807SRodney W. Grimes *pend = NULL;
4704b88c807SRodney W. Grimes for (;;) {
4714b88c807SRodney W. Grimes switch (c = *pattern++) {
4724b88c807SRodney W. Grimes case '\0':
4734b88c807SRodney W. Grimes /*
4744b88c807SRodney W. Grimes * Ok we found an exact match
4754b88c807SRodney W. Grimes */
4764b88c807SRodney W. Grimes if (*string == '\0')
4774b88c807SRodney W. Grimes return(0);
4784b88c807SRodney W. Grimes
4794b88c807SRodney W. Grimes /*
4804b88c807SRodney W. Grimes * Check if it is a prefix match
4814b88c807SRodney W. Grimes */
4824b88c807SRodney W. Grimes if ((dflag == 1) || (*string != '/'))
4834b88c807SRodney W. Grimes return(-1);
4844b88c807SRodney W. Grimes
4854b88c807SRodney W. Grimes /*
4864b88c807SRodney W. Grimes * It is a prefix match, remember where the trailing
4874b88c807SRodney W. Grimes * / is located
4884b88c807SRodney W. Grimes */
4894b88c807SRodney W. Grimes *pend = string;
4904b88c807SRodney W. Grimes return(0);
4914b88c807SRodney W. Grimes case '?':
4924b88c807SRodney W. Grimes if ((test = *string++) == '\0')
4934b88c807SRodney W. Grimes return (-1);
4944b88c807SRodney W. Grimes break;
4954b88c807SRodney W. Grimes case '*':
4964b88c807SRodney W. Grimes c = *pattern;
4974b88c807SRodney W. Grimes /*
4984b88c807SRodney W. Grimes * Collapse multiple *'s.
4994b88c807SRodney W. Grimes */
5004b88c807SRodney W. Grimes while (c == '*')
5014b88c807SRodney W. Grimes c = *++pattern;
5024b88c807SRodney W. Grimes
5034b88c807SRodney W. Grimes /*
5044b88c807SRodney W. Grimes * Optimized hack for pattern with a * at the end
5054b88c807SRodney W. Grimes */
5064b88c807SRodney W. Grimes if (c == '\0')
5074b88c807SRodney W. Grimes return (0);
5084b88c807SRodney W. Grimes
5094b88c807SRodney W. Grimes /*
5104b88c807SRodney W. Grimes * General case, use recursion.
5114b88c807SRodney W. Grimes */
5124b88c807SRodney W. Grimes while ((test = *string) != '\0') {
5134b88c807SRodney W. Grimes if (!fn_match(pattern, string, pend))
5144b88c807SRodney W. Grimes return (0);
5154b88c807SRodney W. Grimes ++string;
5164b88c807SRodney W. Grimes }
5174b88c807SRodney W. Grimes return (-1);
5184b88c807SRodney W. Grimes case '[':
5194b88c807SRodney W. Grimes /*
5204b88c807SRodney W. Grimes * range match
5214b88c807SRodney W. Grimes */
5224b88c807SRodney W. Grimes if (((test = *string++) == '\0') ||
5234b88c807SRodney W. Grimes ((pattern = range_match(pattern, test)) == NULL))
5244b88c807SRodney W. Grimes return (-1);
5254b88c807SRodney W. Grimes break;
5264b88c807SRodney W. Grimes case '\\':
5274b88c807SRodney W. Grimes default:
5284b88c807SRodney W. Grimes if (c != *string++)
5294b88c807SRodney W. Grimes return (-1);
5304b88c807SRodney W. Grimes break;
5314b88c807SRodney W. Grimes }
5324b88c807SRodney W. Grimes }
5334b88c807SRodney W. Grimes /* NOTREACHED */
5344b88c807SRodney W. Grimes }
5354b88c807SRodney W. Grimes
5364b88c807SRodney W. Grimes static char *
range_match(char * pattern,int test)537f789b261SWarner Losh range_match(char *pattern, int test)
5384b88c807SRodney W. Grimes {
539f789b261SWarner Losh char c;
540f789b261SWarner Losh char c2;
5414b88c807SRodney W. Grimes int negate;
5424b88c807SRodney W. Grimes int ok = 0;
5434b88c807SRodney W. Grimes
544b1787decSKris Kennaway if ((negate = (*pattern == '!')) != 0)
5454b88c807SRodney W. Grimes ++pattern;
5464b88c807SRodney W. Grimes
5474b88c807SRodney W. Grimes while ((c = *pattern++) != ']') {
5484b88c807SRodney W. Grimes /*
5494b88c807SRodney W. Grimes * Illegal pattern
5504b88c807SRodney W. Grimes */
5514b88c807SRodney W. Grimes if (c == '\0')
5524b88c807SRodney W. Grimes return (NULL);
5534b88c807SRodney W. Grimes
5544b88c807SRodney W. Grimes if ((*pattern == '-') && ((c2 = pattern[1]) != '\0') &&
5554b88c807SRodney W. Grimes (c2 != ']')) {
5564b88c807SRodney W. Grimes if ((c <= test) && (test <= c2))
5574b88c807SRodney W. Grimes ok = 1;
5584b88c807SRodney W. Grimes pattern += 2;
5594b88c807SRodney W. Grimes } else if (c == test)
5604b88c807SRodney W. Grimes ok = 1;
5614b88c807SRodney W. Grimes }
5624b88c807SRodney W. Grimes return (ok == negate ? NULL : pattern);
5634b88c807SRodney W. Grimes }
5644b88c807SRodney W. Grimes
5654b88c807SRodney W. Grimes /*
5664b88c807SRodney W. Grimes * mod_name()
5674b88c807SRodney W. Grimes * modify a selected file name. first attempt to apply replacement string
5684b88c807SRodney W. Grimes * expressions, then apply interactive file rename. We apply replacement
5694b88c807SRodney W. Grimes * string expressions to both filenames and file links (if we didn't the
5704b88c807SRodney W. Grimes * links would point to the wrong place, and we could never be able to
5714b88c807SRodney W. Grimes * move an archive that has a file link in it). When we rename files
5724b88c807SRodney W. Grimes * interactively, we store that mapping (old name to user input name) so
5734b88c807SRodney W. Grimes * if we spot any file links to the old file name in the future, we will
5744b88c807SRodney W. Grimes * know exactly how to fix the file link.
5754b88c807SRodney W. Grimes * Return:
5764b88c807SRodney W. Grimes * 0 continue to process file, 1 skip this file, -1 pax is finished
5774b88c807SRodney W. Grimes */
5784b88c807SRodney W. Grimes
5794b88c807SRodney W. Grimes int
mod_name(ARCHD * arcn)580f789b261SWarner Losh mod_name(ARCHD *arcn)
5814b88c807SRodney W. Grimes {
582f789b261SWarner Losh int res = 0;
5834b88c807SRodney W. Grimes
5844b88c807SRodney W. Grimes /*
585b1787decSKris Kennaway * Strip off leading '/' if appropriate.
586b1787decSKris Kennaway * Currently, this option is only set for the tar format.
587b1787decSKris Kennaway */
588b1787decSKris Kennaway if (rmleadslash && arcn->name[0] == '/') {
589b1787decSKris Kennaway if (arcn->name[1] == '\0') {
590b1787decSKris Kennaway arcn->name[0] = '.';
591b1787decSKris Kennaway } else {
592b1787decSKris Kennaway (void)memmove(arcn->name, &arcn->name[1],
593b1787decSKris Kennaway strlen(arcn->name));
594b1787decSKris Kennaway arcn->nlen--;
595b1787decSKris Kennaway }
596b1787decSKris Kennaway if (rmleadslash < 2) {
597b1787decSKris Kennaway rmleadslash = 2;
598b1787decSKris Kennaway paxwarn(0, "Removing leading / from absolute path names in the archive");
599b1787decSKris Kennaway }
600b1787decSKris Kennaway }
601b1787decSKris Kennaway if (rmleadslash && arcn->ln_name[0] == '/' &&
602b1787decSKris Kennaway (arcn->type == PAX_HLK || arcn->type == PAX_HRG)) {
603b1787decSKris Kennaway if (arcn->ln_name[1] == '\0') {
604b1787decSKris Kennaway arcn->ln_name[0] = '.';
605b1787decSKris Kennaway } else {
606b1787decSKris Kennaway (void)memmove(arcn->ln_name, &arcn->ln_name[1],
607b1787decSKris Kennaway strlen(arcn->ln_name));
608b1787decSKris Kennaway arcn->ln_nlen--;
609b1787decSKris Kennaway }
610b1787decSKris Kennaway if (rmleadslash < 2) {
611b1787decSKris Kennaway rmleadslash = 2;
612b1787decSKris Kennaway paxwarn(0, "Removing leading / from absolute path names in the archive");
613b1787decSKris Kennaway }
614b1787decSKris Kennaway }
615b1787decSKris Kennaway
616b1787decSKris Kennaway /*
6174b88c807SRodney W. Grimes * IMPORTANT: We have a problem. what do we do with symlinks?
6184b88c807SRodney W. Grimes * Modifying a hard link name makes sense, as we know the file it
6194b88c807SRodney W. Grimes * points at should have been seen already in the archive (and if it
6204b88c807SRodney W. Grimes * wasn't seen because of a read error or a bad archive, we lose
6214b88c807SRodney W. Grimes * anyway). But there are no such requirements for symlinks. On one
6224b88c807SRodney W. Grimes * hand the symlink that refers to a file in the archive will have to
6234b88c807SRodney W. Grimes * be modified to so it will still work at its new location in the
6244b88c807SRodney W. Grimes * file system. On the other hand a symlink that points elsewhere (and
6254b88c807SRodney W. Grimes * should continue to do so) should not be modified. There is clearly
6264b88c807SRodney W. Grimes * no perfect solution here. So we handle them like hardlinks. Clearly
6274b88c807SRodney W. Grimes * a replacement made by the interactive rename mapping is very likely
6284b88c807SRodney W. Grimes * to be correct since it applies to a single file and is an exact
6294b88c807SRodney W. Grimes * match. The regular expression replacements are a little harder to
6304b88c807SRodney W. Grimes * justify though. We claim that the symlink name is only likely
6314b88c807SRodney W. Grimes * to be replaced when it points within the file tree being moved and
6324b88c807SRodney W. Grimes * in that case it should be modified. what we really need to do is to
6334b88c807SRodney W. Grimes * call an oracle here. :)
6344b88c807SRodney W. Grimes */
6354b88c807SRodney W. Grimes if (rephead != NULL) {
6364b88c807SRodney W. Grimes /*
6374b88c807SRodney W. Grimes * we have replacement strings, modify the name and the link
6384b88c807SRodney W. Grimes * name if any.
6394b88c807SRodney W. Grimes */
6404b88c807SRodney W. Grimes if ((res = rep_name(arcn->name, &(arcn->nlen), 1)) != 0)
6414b88c807SRodney W. Grimes return(res);
6424b88c807SRodney W. Grimes
6434b88c807SRodney W. Grimes if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
6444b88c807SRodney W. Grimes (arcn->type == PAX_HRG)) &&
6454b88c807SRodney W. Grimes ((res = rep_name(arcn->ln_name, &(arcn->ln_nlen), 0)) != 0))
6464b88c807SRodney W. Grimes return(res);
6474b88c807SRodney W. Grimes }
6484b88c807SRodney W. Grimes
6494b88c807SRodney W. Grimes if (iflag) {
6504b88c807SRodney W. Grimes /*
6514b88c807SRodney W. Grimes * perform interactive file rename, then map the link if any
6524b88c807SRodney W. Grimes */
6534b88c807SRodney W. Grimes if ((res = tty_rename(arcn)) != 0)
6544b88c807SRodney W. Grimes return(res);
6554b88c807SRodney W. Grimes if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
6564b88c807SRodney W. Grimes (arcn->type == PAX_HRG))
657b1787decSKris Kennaway sub_name(arcn->ln_name, &(arcn->ln_nlen), sizeof(arcn->ln_name));
6584b88c807SRodney W. Grimes }
6594b88c807SRodney W. Grimes return(res);
6604b88c807SRodney W. Grimes }
6614b88c807SRodney W. Grimes
6624b88c807SRodney W. Grimes /*
6634b88c807SRodney W. Grimes * tty_rename()
6644b88c807SRodney W. Grimes * Prompt the user for a replacement file name. A "." keeps the old name,
6654b88c807SRodney W. Grimes * a empty line skips the file, and an EOF on reading the tty, will cause
6664b88c807SRodney W. Grimes * pax to stop processing and exit. Otherwise the file name input, replaces
6674b88c807SRodney W. Grimes * the old one.
6684b88c807SRodney W. Grimes * Return:
6694b88c807SRodney W. Grimes * 0 process this file, 1 skip this file, -1 we need to exit pax
6704b88c807SRodney W. Grimes */
6714b88c807SRodney W. Grimes
6724b88c807SRodney W. Grimes static int
tty_rename(ARCHD * arcn)673f789b261SWarner Losh tty_rename(ARCHD *arcn)
6744b88c807SRodney W. Grimes {
6754b88c807SRodney W. Grimes char tmpname[PAXPATHLEN+2];
6764b88c807SRodney W. Grimes int res;
6774b88c807SRodney W. Grimes
6784b88c807SRodney W. Grimes /*
6794b88c807SRodney W. Grimes * prompt user for the replacement name for a file, keep trying until
6804b88c807SRodney W. Grimes * we get some reasonable input. Archives may have more than one file
6814b88c807SRodney W. Grimes * on them with the same name (from updates etc). We print verbose info
6824b88c807SRodney W. Grimes * on the file so the user knows what is up.
6834b88c807SRodney W. Grimes */
6844b88c807SRodney W. Grimes tty_prnt("\nATTENTION: %s interactive file rename operation.\n", argv0);
6854b88c807SRodney W. Grimes
6864b88c807SRodney W. Grimes for (;;) {
6874b88c807SRodney W. Grimes ls_tty(arcn);
6884b88c807SRodney W. Grimes tty_prnt("Input new name, or a \".\" to keep the old name, ");
6894b88c807SRodney W. Grimes tty_prnt("or a \"return\" to skip this file.\n");
6904b88c807SRodney W. Grimes tty_prnt("Input > ");
6914b88c807SRodney W. Grimes if (tty_read(tmpname, sizeof(tmpname)) < 0)
6924b88c807SRodney W. Grimes return(-1);
6934b88c807SRodney W. Grimes if (strcmp(tmpname, "..") == 0) {
6944b88c807SRodney W. Grimes tty_prnt("Try again, illegal file name: ..\n");
6954b88c807SRodney W. Grimes continue;
6964b88c807SRodney W. Grimes }
6974b88c807SRodney W. Grimes if (strlen(tmpname) > PAXPATHLEN) {
6984b88c807SRodney W. Grimes tty_prnt("Try again, file name too long\n");
6994b88c807SRodney W. Grimes continue;
7004b88c807SRodney W. Grimes }
7014b88c807SRodney W. Grimes break;
7024b88c807SRodney W. Grimes }
7034b88c807SRodney W. Grimes
7044b88c807SRodney W. Grimes /*
7054b88c807SRodney W. Grimes * empty file name, skips this file. a "." leaves it alone
7064b88c807SRodney W. Grimes */
7074b88c807SRodney W. Grimes if (tmpname[0] == '\0') {
7084b88c807SRodney W. Grimes tty_prnt("Skipping file.\n");
7094b88c807SRodney W. Grimes return(1);
7104b88c807SRodney W. Grimes }
7114b88c807SRodney W. Grimes if ((tmpname[0] == '.') && (tmpname[1] == '\0')) {
7124b88c807SRodney W. Grimes tty_prnt("Processing continues, name unchanged.\n");
7134b88c807SRodney W. Grimes return(0);
7144b88c807SRodney W. Grimes }
7154b88c807SRodney W. Grimes
7164b88c807SRodney W. Grimes /*
7174b88c807SRodney W. Grimes * ok the name changed. We may run into links that point at this
7184b88c807SRodney W. Grimes * file later. we have to remember where the user sent the file
7194b88c807SRodney W. Grimes * in order to repair any links.
7204b88c807SRodney W. Grimes */
7214b88c807SRodney W. Grimes tty_prnt("Processing continues, name changed to: %s\n", tmpname);
7224b88c807SRodney W. Grimes res = add_name(arcn->name, arcn->nlen, tmpname);
723b1787decSKris Kennaway arcn->nlen = l_strncpy(arcn->name, tmpname, sizeof(arcn->name) - 1);
724b1787decSKris Kennaway arcn->name[arcn->nlen] = '\0';
7254b88c807SRodney W. Grimes if (res < 0)
7264b88c807SRodney W. Grimes return(-1);
7274b88c807SRodney W. Grimes return(0);
7284b88c807SRodney W. Grimes }
7294b88c807SRodney W. Grimes
7304b88c807SRodney W. Grimes /*
7314b88c807SRodney W. Grimes * set_dest()
7324b88c807SRodney W. Grimes * fix up the file name and the link name (if any) so this file will land
7334b88c807SRodney W. Grimes * in the destination directory (used during copy() -rw).
7344b88c807SRodney W. Grimes * Return:
7354b88c807SRodney W. Grimes * 0 if ok, -1 if failure (name too long)
7364b88c807SRodney W. Grimes */
7374b88c807SRodney W. Grimes
7384b88c807SRodney W. Grimes int
set_dest(ARCHD * arcn,char * dest_dir,int dir_len)739f789b261SWarner Losh set_dest(ARCHD *arcn, char *dest_dir, int dir_len)
7404b88c807SRodney W. Grimes {
7414b88c807SRodney W. Grimes if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0)
7424b88c807SRodney W. Grimes return(-1);
7434b88c807SRodney W. Grimes
7444b88c807SRodney W. Grimes /*
7454b88c807SRodney W. Grimes * It is really hard to deal with symlinks here, we cannot be sure
7464b88c807SRodney W. Grimes * if the name they point was moved (or will be moved). It is best to
7474b88c807SRodney W. Grimes * leave them alone.
7484b88c807SRodney W. Grimes */
7494b88c807SRodney W. Grimes if ((arcn->type != PAX_HLK) && (arcn->type != PAX_HRG))
7504b88c807SRodney W. Grimes return(0);
7514b88c807SRodney W. Grimes
7524b88c807SRodney W. Grimes if (fix_path(arcn->ln_name, &(arcn->ln_nlen), dest_dir, dir_len) < 0)
7534b88c807SRodney W. Grimes return(-1);
7544b88c807SRodney W. Grimes return(0);
7554b88c807SRodney W. Grimes }
7564b88c807SRodney W. Grimes
7574b88c807SRodney W. Grimes /*
7584b88c807SRodney W. Grimes * fix_path
7594b88c807SRodney W. Grimes * concatenate dir_name and or_name and store the result in or_name (if
7604b88c807SRodney W. Grimes * it fits). This is one ugly function.
7614b88c807SRodney W. Grimes * Return:
7624b88c807SRodney W. Grimes * 0 if ok, -1 if the final name is too long
7634b88c807SRodney W. Grimes */
7644b88c807SRodney W. Grimes
7654b88c807SRodney W. Grimes static int
fix_path(char * or_name,int * or_len,char * dir_name,int dir_len)7664b88c807SRodney W. Grimes fix_path( char *or_name, int *or_len, char *dir_name, int dir_len)
7674b88c807SRodney W. Grimes {
768f789b261SWarner Losh char *src;
769f789b261SWarner Losh char *dest;
770f789b261SWarner Losh char *start;
7714b88c807SRodney W. Grimes int len;
7724b88c807SRodney W. Grimes
7734b88c807SRodney W. Grimes /*
7744b88c807SRodney W. Grimes * we shift the or_name to the right enough to tack in the dir_name
7754b88c807SRodney W. Grimes * at the front. We make sure we have enough space for it all before
7764b88c807SRodney W. Grimes * we start. since dest always ends in a slash, we skip of or_name
7774b88c807SRodney W. Grimes * if it also starts with one.
7784b88c807SRodney W. Grimes */
7794b88c807SRodney W. Grimes start = or_name;
7804b88c807SRodney W. Grimes src = start + *or_len;
7814b88c807SRodney W. Grimes dest = src + dir_len;
7824b88c807SRodney W. Grimes if (*start == '/') {
7834b88c807SRodney W. Grimes ++start;
7844b88c807SRodney W. Grimes --dest;
7854b88c807SRodney W. Grimes }
7864b88c807SRodney W. Grimes if ((len = dest - or_name) > PAXPATHLEN) {
787778766feSKris Kennaway paxwarn(1, "File name %s/%s, too long", dir_name, start);
7884b88c807SRodney W. Grimes return(-1);
7894b88c807SRodney W. Grimes }
7904b88c807SRodney W. Grimes *or_len = len;
7914b88c807SRodney W. Grimes
7924b88c807SRodney W. Grimes /*
7934b88c807SRodney W. Grimes * enough space, shift
7944b88c807SRodney W. Grimes */
7954b88c807SRodney W. Grimes while (src >= start)
7964b88c807SRodney W. Grimes *dest-- = *src--;
7974b88c807SRodney W. Grimes src = dir_name + dir_len - 1;
7984b88c807SRodney W. Grimes
7994b88c807SRodney W. Grimes /*
8004b88c807SRodney W. Grimes * splice in the destination directory name
8014b88c807SRodney W. Grimes */
8024b88c807SRodney W. Grimes while (src >= dir_name)
8034b88c807SRodney W. Grimes *dest-- = *src--;
8044b88c807SRodney W. Grimes
8054b88c807SRodney W. Grimes *(or_name + len) = '\0';
8064b88c807SRodney W. Grimes return(0);
8074b88c807SRodney W. Grimes }
8084b88c807SRodney W. Grimes
8094b88c807SRodney W. Grimes /*
8104b88c807SRodney W. Grimes * rep_name()
8114b88c807SRodney W. Grimes * walk down the list of replacement strings applying each one in order.
8124b88c807SRodney W. Grimes * when we find one with a successful substitution, we modify the name
8134b88c807SRodney W. Grimes * as specified. if required, we print the results. if the resulting name
8144b88c807SRodney W. Grimes * is empty, we will skip this archive member. We use the regexp(3)
8154b88c807SRodney W. Grimes * routines (regexp() ought to win a prize as having the most cryptic
8164b88c807SRodney W. Grimes * library function manual page).
8174b88c807SRodney W. Grimes * --Parameters--
8184b88c807SRodney W. Grimes * name is the file name we are going to apply the regular expressions to
8194b88c807SRodney W. Grimes * (and may be modified)
8204b88c807SRodney W. Grimes * nlen is the length of this name (and is modified to hold the length of
8214b88c807SRodney W. Grimes * the final string).
8224b88c807SRodney W. Grimes * prnt is a flag that says whether to print the final result.
8234b88c807SRodney W. Grimes * Return:
8244b88c807SRodney W. Grimes * 0 if substitution was successful, 1 if we are to skip the file (the name
8254b88c807SRodney W. Grimes * ended up empty)
8264b88c807SRodney W. Grimes */
8274b88c807SRodney W. Grimes
8284b88c807SRodney W. Grimes static int
rep_name(char * name,int * nlen,int prnt)8294b88c807SRodney W. Grimes rep_name(char *name, int *nlen, int prnt)
8304b88c807SRodney W. Grimes {
831f789b261SWarner Losh REPLACE *pt;
832f789b261SWarner Losh char *inpt;
833f789b261SWarner Losh char *outpt;
834f789b261SWarner Losh char *endpt;
835f789b261SWarner Losh char *rpt;
836f789b261SWarner Losh int found = 0;
837f789b261SWarner Losh int res;
8384b88c807SRodney W. Grimes regmatch_t pm[MAXSUBEXP];
8394b88c807SRodney W. Grimes char nname[PAXPATHLEN+1]; /* final result of all replacements */
8404b88c807SRodney W. Grimes char buf1[PAXPATHLEN+1]; /* where we work on the name */
8414b88c807SRodney W. Grimes
8424b88c807SRodney W. Grimes /*
8434b88c807SRodney W. Grimes * copy the name into buf1, where we will work on it. We need to keep
8444b88c807SRodney W. Grimes * the orig string around so we can print out the result of the final
8454b88c807SRodney W. Grimes * replacement. We build up the final result in nname. inpt points at
8464b88c807SRodney W. Grimes * the string we apply the regular expression to. prnt is used to
8474b88c807SRodney W. Grimes * suppress printing when we handle replacements on the link field
8484b88c807SRodney W. Grimes * (the user already saw that substitution go by)
8494b88c807SRodney W. Grimes */
8504b88c807SRodney W. Grimes pt = rephead;
8511e00885aSPedro F. Giffuni (void)strlcpy(buf1, name, sizeof(buf1));
8524b88c807SRodney W. Grimes inpt = buf1;
8534b88c807SRodney W. Grimes outpt = nname;
8544b88c807SRodney W. Grimes endpt = outpt + PAXPATHLEN;
8554b88c807SRodney W. Grimes
8564b88c807SRodney W. Grimes /*
8574b88c807SRodney W. Grimes * try each replacement string in order
8584b88c807SRodney W. Grimes */
8594b88c807SRodney W. Grimes while (pt != NULL) {
8604b88c807SRodney W. Grimes do {
8614b88c807SRodney W. Grimes /*
8624b88c807SRodney W. Grimes * check for a successful substitution, if not go to
8634b88c807SRodney W. Grimes * the next pattern, or cleanup if we were global
8644b88c807SRodney W. Grimes */
8654b88c807SRodney W. Grimes if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0)
8664b88c807SRodney W. Grimes break;
8674b88c807SRodney W. Grimes
8684b88c807SRodney W. Grimes /*
8694b88c807SRodney W. Grimes * ok we found one. We have three parts, the prefix
8704b88c807SRodney W. Grimes * which did not match, the section that did and the
8714b88c807SRodney W. Grimes * tail (that also did not match). Copy the prefix to
8724b88c807SRodney W. Grimes * the final output buffer (watching to make sure we
8734b88c807SRodney W. Grimes * do not create a string too long).
8744b88c807SRodney W. Grimes */
8754b88c807SRodney W. Grimes found = 1;
8764b88c807SRodney W. Grimes rpt = inpt + pm[0].rm_so;
8774b88c807SRodney W. Grimes
8784b88c807SRodney W. Grimes while ((inpt < rpt) && (outpt < endpt))
8794b88c807SRodney W. Grimes *outpt++ = *inpt++;
8804b88c807SRodney W. Grimes if (outpt == endpt)
8814b88c807SRodney W. Grimes break;
8824b88c807SRodney W. Grimes
8834b88c807SRodney W. Grimes /*
8844b88c807SRodney W. Grimes * for the second part (which matched the regular
8854b88c807SRodney W. Grimes * expression) apply the substitution using the
8864b88c807SRodney W. Grimes * replacement string and place it the prefix in the
8874b88c807SRodney W. Grimes * final output. If we have problems, skip it.
8884b88c807SRodney W. Grimes */
889c9022a35SUlrich Spörlein if ((res = resub(&(pt->rcmp),pm,inpt,pt->nstr,outpt,endpt))
8904b88c807SRodney W. Grimes < 0) {
8914b88c807SRodney W. Grimes if (prnt)
892778766feSKris Kennaway paxwarn(1, "Replacement name error %s",
8934b88c807SRodney W. Grimes name);
8944b88c807SRodney W. Grimes return(1);
8954b88c807SRodney W. Grimes }
8964b88c807SRodney W. Grimes outpt += res;
8974b88c807SRodney W. Grimes
8984b88c807SRodney W. Grimes /*
8994b88c807SRodney W. Grimes * we set up to look again starting at the first
9004b88c807SRodney W. Grimes * character in the tail (of the input string right
9014b88c807SRodney W. Grimes * after the last character matched by the regular
9024b88c807SRodney W. Grimes * expression (inpt always points at the first char in
9034b88c807SRodney W. Grimes * the string to process). If we are not doing a global
9044b88c807SRodney W. Grimes * substitution, we will use inpt to copy the tail to
9054b88c807SRodney W. Grimes * the final result. Make sure we do not overrun the
9064b88c807SRodney W. Grimes * output buffer
9074b88c807SRodney W. Grimes */
908f08c1d5eSDavid E. O'Brien inpt += pm[0].rm_eo - pm[0].rm_so;
9094b88c807SRodney W. Grimes
9104b88c807SRodney W. Grimes if ((outpt == endpt) || (*inpt == '\0'))
9114b88c807SRodney W. Grimes break;
9124b88c807SRodney W. Grimes
9134b88c807SRodney W. Grimes /*
9144b88c807SRodney W. Grimes * if the user wants global we keep trying to
9154b88c807SRodney W. Grimes * substitute until it fails, then we are done.
9164b88c807SRodney W. Grimes */
9174b88c807SRodney W. Grimes } while (pt->flgs & GLOB);
9184b88c807SRodney W. Grimes
9194b88c807SRodney W. Grimes if (found)
9204b88c807SRodney W. Grimes break;
9214b88c807SRodney W. Grimes
9224b88c807SRodney W. Grimes /*
9234b88c807SRodney W. Grimes * a successful substitution did NOT occur, try the next one
9244b88c807SRodney W. Grimes */
9254b88c807SRodney W. Grimes pt = pt->fow;
9264b88c807SRodney W. Grimes }
9274b88c807SRodney W. Grimes
9284b88c807SRodney W. Grimes if (found) {
9294b88c807SRodney W. Grimes /*
9304b88c807SRodney W. Grimes * we had a substitution, copy the last tail piece (if there is
9314b88c807SRodney W. Grimes * room) to the final result
9324b88c807SRodney W. Grimes */
9334b88c807SRodney W. Grimes while ((outpt < endpt) && (*inpt != '\0'))
9344b88c807SRodney W. Grimes *outpt++ = *inpt++;
9354b88c807SRodney W. Grimes
9364b88c807SRodney W. Grimes *outpt = '\0';
9374b88c807SRodney W. Grimes if ((outpt == endpt) && (*inpt != '\0')) {
9384b88c807SRodney W. Grimes if (prnt)
939778766feSKris Kennaway paxwarn(1,"Replacement name too long %s >> %s",
9404b88c807SRodney W. Grimes name, nname);
9414b88c807SRodney W. Grimes return(1);
9424b88c807SRodney W. Grimes }
9434b88c807SRodney W. Grimes
9444b88c807SRodney W. Grimes /*
9454b88c807SRodney W. Grimes * inform the user of the result if wanted
9464b88c807SRodney W. Grimes */
9474b88c807SRodney W. Grimes if (prnt && (pt->flgs & PRNT)) {
9484b88c807SRodney W. Grimes if (*nname == '\0')
9494b88c807SRodney W. Grimes (void)fprintf(stderr,"%s >> <empty string>\n",
9504b88c807SRodney W. Grimes name);
9514b88c807SRodney W. Grimes else
9524b88c807SRodney W. Grimes (void)fprintf(stderr,"%s >> %s\n", name, nname);
9534b88c807SRodney W. Grimes }
9544b88c807SRodney W. Grimes
9554b88c807SRodney W. Grimes /*
9564b88c807SRodney W. Grimes * if empty inform the caller this file is to be skipped
9574b88c807SRodney W. Grimes * otherwise copy the new name over the orig name and return
9584b88c807SRodney W. Grimes */
9594b88c807SRodney W. Grimes if (*nname == '\0')
9604b88c807SRodney W. Grimes return(1);
9614b88c807SRodney W. Grimes *nlen = l_strncpy(name, nname, PAXPATHLEN + 1);
962877155d0SPhilippe Charnier name[PAXPATHLEN] = '\0';
9634b88c807SRodney W. Grimes }
9644b88c807SRodney W. Grimes return(0);
9654b88c807SRodney W. Grimes }
9664b88c807SRodney W. Grimes
9674b88c807SRodney W. Grimes
9684b88c807SRodney W. Grimes /*
9694b88c807SRodney W. Grimes * resub()
9704b88c807SRodney W. Grimes * apply the replacement to the matched expression. expand out the old
9714b88c807SRodney W. Grimes * style ed(1) subexpression expansion.
9724b88c807SRodney W. Grimes * Return:
9734b88c807SRodney W. Grimes * -1 if error, or the number of characters added to the destination.
9744b88c807SRodney W. Grimes */
9754b88c807SRodney W. Grimes
9764b88c807SRodney W. Grimes static int
resub(regex_t * rp,regmatch_t * pm,char * orig,char * src,char * dest,char * destend)977c9022a35SUlrich Spörlein resub(regex_t *rp, regmatch_t *pm, char *orig, char *src, char *dest,
978f789b261SWarner Losh char *destend)
9794b88c807SRodney W. Grimes {
980f789b261SWarner Losh char *spt;
981f789b261SWarner Losh char *dpt;
982f789b261SWarner Losh char c;
983f789b261SWarner Losh regmatch_t *pmpt;
984f789b261SWarner Losh int len;
9854b88c807SRodney W. Grimes int subexcnt;
9864b88c807SRodney W. Grimes
9874b88c807SRodney W. Grimes spt = src;
9884b88c807SRodney W. Grimes dpt = dest;
9894b88c807SRodney W. Grimes subexcnt = rp->re_nsub;
9904b88c807SRodney W. Grimes while ((dpt < destend) && ((c = *spt++) != '\0')) {
9914b88c807SRodney W. Grimes /*
9924b88c807SRodney W. Grimes * see if we just have an ordinary replacement character
9934b88c807SRodney W. Grimes * or we refer to a subexpression.
9944b88c807SRodney W. Grimes */
9954b88c807SRodney W. Grimes if (c == '&') {
9964b88c807SRodney W. Grimes pmpt = pm;
9974b88c807SRodney W. Grimes } else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) {
9984b88c807SRodney W. Grimes /*
9994b88c807SRodney W. Grimes * make sure there is a subexpression as specified
10004b88c807SRodney W. Grimes */
10014b88c807SRodney W. Grimes if ((len = *spt++ - '0') > subexcnt)
10024b88c807SRodney W. Grimes return(-1);
10034b88c807SRodney W. Grimes pmpt = pm + len;
10044b88c807SRodney W. Grimes } else {
10054b88c807SRodney W. Grimes /*
10064b88c807SRodney W. Grimes * Ordinary character, just copy it
10074b88c807SRodney W. Grimes */
10084b88c807SRodney W. Grimes if ((c == '\\') && ((*spt == '\\') || (*spt == '&')))
10094b88c807SRodney W. Grimes c = *spt++;
10104b88c807SRodney W. Grimes *dpt++ = c;
10114b88c807SRodney W. Grimes continue;
10124b88c807SRodney W. Grimes }
10134b88c807SRodney W. Grimes
10144b88c807SRodney W. Grimes /*
10154b88c807SRodney W. Grimes * continue if the subexpression is bogus
10164b88c807SRodney W. Grimes */
10174b88c807SRodney W. Grimes if ((pmpt->rm_so < 0) || (pmpt->rm_eo < 0) ||
10184b88c807SRodney W. Grimes ((len = pmpt->rm_eo - pmpt->rm_so) <= 0))
10194b88c807SRodney W. Grimes continue;
10204b88c807SRodney W. Grimes
10214b88c807SRodney W. Grimes /*
10224b88c807SRodney W. Grimes * copy the subexpression to the destination.
10234b88c807SRodney W. Grimes * fail if we run out of space or the match string is damaged
10244b88c807SRodney W. Grimes */
10254b88c807SRodney W. Grimes if (len > (destend - dpt))
10264b88c807SRodney W. Grimes len = destend - dpt;
1027c9022a35SUlrich Spörlein if (l_strncpy(dpt, orig + pmpt->rm_so, len) != len)
10284b88c807SRodney W. Grimes return(-1);
10294b88c807SRodney W. Grimes dpt += len;
10304b88c807SRodney W. Grimes }
10314b88c807SRodney W. Grimes return(dpt - dest);
10324b88c807SRodney W. Grimes }
1033