예제 #1
0
static int
tty_rename(ARCHD *arcn)
{
	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, sizeof(arcn->name) - 1);
	arcn->name[arcn->nlen] = '\0';
	if (res < 0)
		return(-1);
	return(0);
}
예제 #2
0
static int
resub(regex_t *rp, regmatch_t *pm, char *src, char *dest,
	char *destend)
{
	char *spt;
	char *dpt;
	char c;
	regmatch_t *pmpt;
	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);
}
예제 #3
0
void
sub_name(char *oname, int *onamelen, size_t onamesize)
{
	NAMT *pt;
	u_int indx;

	if (ntab == NULL)
		return;
	/*
	 * look the name up in the hash table
	 */
	indx = st_hash(oname, *onamelen, N_TAB_SZ);
	if ((pt = ntab[indx]) == NULL)
		return;

	while (pt != NULL) {
		/*
		 * walk down the hash chain looking for a match
		 */
		if (strcmp(oname, pt->oname) == 0) {
			/*
			 * found it, replace it with the new name
			 * and return (we know that oname has enough space)
			 */
			*onamelen = l_strncpy(oname, pt->nname, onamesize - 1);
			oname[*onamelen] = '\0';
			return;
		}
		pt = pt->fow;
	}

	/*
	 * no match, just return
	 */
	return;
}
예제 #4
0
int
chk_lnk(ARCHD *arcn)
{
	HRDLNK *pt;
	HRDLNK **ppt;
	u_int indx;

	if (ltab == NULL)
		return(-1);
	/*
	 * ignore those nodes that cannot have hard links
	 */
	if ((arcn->type == PAX_DIR) || (arcn->sb.st_nlink <= 1))
		return(0);

	/*
	 * hash inode number and look for this file
	 */
	indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ;
	if ((pt = ltab[indx]) != NULL) {
		/*
		 * it's hash chain in not empty, walk down looking for it
		 */
		ppt = &(ltab[indx]);
		while (pt != NULL) {
			if ((pt->ino == arcn->sb.st_ino) &&
			    (pt->dev == arcn->sb.st_dev))
				break;
			ppt = &(pt->fow);
			pt = pt->fow;
		}

		if (pt != NULL) {
			/*
			 * found a link. set the node type and copy in the
			 * name of the file it is to link to. we need to
			 * handle hardlinks to regular files differently than
			 * other links.
			 */
			arcn->ln_nlen = l_strncpy(arcn->ln_name, pt->name,
				sizeof(arcn->ln_name) - 1);
			arcn->ln_name[arcn->ln_nlen] = '\0';
			if (arcn->type == PAX_REG)
				arcn->type = PAX_HRG;
			else
				arcn->type = PAX_HLK;

			/*
			 * if we have found all the links to this file, remove
			 * it from the database
			 */
			if (--pt->nlink <= 1) {
				*ppt = pt->fow;
				free((char *)pt->name);
				free((char *)pt);
			}
			return(1);
		}
	}

	/*
	 * we never saw this file before. It has links so we add it to the
	 * front of this hash chain
	 */
	if ((pt = (HRDLNK *)malloc(sizeof(HRDLNK))) != NULL) {
		if ((pt->name = strdup(arcn->name)) != NULL) {
			pt->dev = arcn->sb.st_dev;
			pt->ino = arcn->sb.st_ino;
			pt->nlink = arcn->sb.st_nlink;
			pt->fow = ltab[indx];
			ltab[indx] = pt;
			return(0);
		}
		free((char *)pt);
	}

	paxwarn(1, "Hard link table out of memory");
	return(-1);
}
예제 #5
0
static int
rep_name(char *name, int *nlen, int prnt)
{
	REPLACE *pt;
	char *inpt;
	char *outpt;
	char *endpt;
	char *rpt;
	int found = 0;
	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)
					paxwarn(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 - pm[0].rm_so;
#			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)
				paxwarn(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);
		name[PAXPATHLEN] = '\0';
	}
	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.
 */

static int
resub(regexp *prog, char *src, char *dest, char *destend)
{
	char *spt;
	char *dpt;
	char c;
	int no;
	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);
}
예제 #6
0
파일: ftree.c 프로젝트: quickgold192/oslab1
int
next_file(ARCHD *arcn)
{
    int cnt;
    time_t atime;
    time_t mtime;

    /*
     * ftree_sel() might have set the ftree_skip flag if the user has the
     * -n option and a file was selected from this file arg tree. (-n says
     * only one member is matched for each pattern) ftree_skip being 1
     * forces us to go to the next arg now.
     */
    if (ftree_skip) {
        /*
         * clear and go to next arg
         */
        ftree_skip = 0;
        if (ftree_arg() < 0)
            return(-1);
    }

    /*
     * loop until we get a valid file to process
     */
    for(;;) {
        if ((ftent = fts_read(ftsp)) == NULL) {
            /*
             * out of files in this tree, go to next arg, if none
             * we are done
             */
            if (ftree_arg() < 0)
                return(-1);
            continue;
        }

        /*
         * handle each type of fts_read() flag
         */
        switch(ftent->fts_info) {
        case FTS_D:
        case FTS_DEFAULT:
        case FTS_F:
        case FTS_SL:
        case FTS_SLNONE:
            /*
             * these are all ok
             */
            break;
        case FTS_DP:
            /*
             * already saw this directory. If the user wants file
             * access times reset, we use this to restore the
             * access time for this directory since this is the
             * last time we will see it in this file subtree
             * remember to force the time (this is -t on a read
             * directory, not a created directory).
             */
#			ifdef NET2_FTS
            if (!tflag || (get_atdir(ftent->fts_statb.st_dev,
                                     ftent->fts_statb.st_ino, &mtime, &atime) < 0))
#			else
            if (!tflag || (get_atdir(ftent->fts_statp->st_dev,
                                     ftent->fts_statp->st_ino, &mtime, &atime) < 0))
#			endif
                continue;
            set_ftime(ftent->fts_path, mtime, atime, 1);
            continue;
        case FTS_DC:
            /*
             * fts claims a file system cycle
             */
            paxwarn(1,"File system cycle found at %s",ftent->fts_path);
            continue;
        case FTS_DNR:
#			ifdef NET2_FTS
            syswarn(1, errno,
#			else
            syswarn(1, ftent->fts_errno,
#			endif
                    "Unable to read directory %s", ftent->fts_path);
            continue;
        case FTS_ERR:
#			ifdef NET2_FTS
            syswarn(1, errno,
#			else
            syswarn(1, ftent->fts_errno,
#			endif
                    "File system traversal error");
            continue;
        case FTS_NS:
        case FTS_NSOK:
#			ifdef NET2_FTS
            syswarn(1, errno,
#			else
            syswarn(1, ftent->fts_errno,
#			endif
                    "Unable to access %s", ftent->fts_path);
            continue;
        }

        /*
         * ok got a file tree node to process. copy info into arcn
         * structure (initialize as required)
         */
        arcn->skip = 0;
        arcn->pad = 0;
        arcn->ln_nlen = 0;
        arcn->ln_name[0] = '\0';
#		ifdef NET2_FTS
        arcn->sb = ftent->fts_statb;
#		else
        arcn->sb = *(ftent->fts_statp);
#		endif

        /*
         * file type based set up and copy into the arcn struct
         * SIDE NOTE:
         * we try to reset the access time on all files and directories
         * we may read when the -t flag is specified. files are reset
         * when we close them after copying. we reset the directories
         * when we are done with their file tree (we also clean up at
         * end in case we cut short a file tree traversal). However
         * there is no way to reset access times on symlinks.
         */
        switch(S_IFMT & arcn->sb.st_mode) {
        case S_IFDIR:
            arcn->type = PAX_DIR;
            if (!tflag)
                break;
            add_atdir(ftent->fts_path, arcn->sb.st_dev,
                      arcn->sb.st_ino, arcn->sb.st_mtime,
                      arcn->sb.st_atime);
            break;
        case S_IFCHR:
            arcn->type = PAX_CHR;
            break;
        case S_IFBLK:
            arcn->type = PAX_BLK;
            break;
        case S_IFREG:
            /*
             * only regular files with have data to store on the
             * archive. all others will store a zero length skip.
             * the skip field is used by pax for actual data it has
             * to read (or skip over).
             */
            arcn->type = PAX_REG;
            arcn->skip = arcn->sb.st_size;
            break;
        case S_IFLNK:
            arcn->type = PAX_SLK;
            /*
             * have to read the symlink path from the file
             */
            if ((cnt = readlink(ftent->fts_path, arcn->ln_name,
                                PAXPATHLEN - 1)) < 0) {
                syswarn(1, errno, "Unable to read symlink %s",
                        ftent->fts_path);
                continue;
            }
            /*
             * set link name length, watch out readlink does not
             * always NUL terminate the link path
             */
            arcn->ln_name[cnt] = '\0';
            arcn->ln_nlen = cnt;
            break;
#if 0
        case S_IFSOCK:
            /*
             * under BSD storing a socket is senseless but we will
             * let the format specific write function make the
             * decision of what to do with it.
             */
            arcn->type = PAX_SCK;
            break;
#endif
        case S_IFIFO:
            arcn->type = PAX_FIF;
            break;
        }
        break;
    }

    /*
     * copy file name, set file name length
     */
    arcn->nlen = l_strncpy(arcn->name, ftent->fts_path, sizeof(arcn->name) - 1);
    arcn->name[arcn->nlen] = '\0';
    arcn->org_name = ftent->fts_path;
    return(0);
}
예제 #7
0
void
copy(void)
{
	ARCHD *arcn;
	int res;
	int fddest;
	char *dest_pt;
	int dlen;
	int drem;
	int fdsrc = -1;
	struct stat sb;
	ARCHD archd;
	char dirbuf[PAXPATHLEN+1];

	arcn = &archd;
	/*
	 * set up the destination dir path and make sure it is a directory. We
	 * make sure we have a trailing / on the destination
	 */
	dlen = l_strncpy(dirbuf, dirptr, sizeof(dirbuf) - 1);
	dest_pt = dirbuf + dlen;
	if (*(dest_pt-1) != '/') {
		*dest_pt++ = '/';
		++dlen;
	}
	*dest_pt = '\0';
	drem = PAXPATHLEN - dlen;

	if (stat(dirptr, &sb) < 0) {
		syswarn(1, errno, "Cannot access destination directory %s",
			dirptr);
		return;
	}
	if (!S_ISDIR(sb.st_mode)) {
		paxwarn(1, "Destination is not a directory %s", dirptr);
		return;
	}

	/*
	 * start up the hard link table; file traversal routines and the
	 * modification time and access mode database
	 */
	if ((lnk_start() < 0) || (ftree_start() < 0) || (dir_start() < 0))
		return;

	/*
	 * When we are doing interactive rename, we store the mapping of names
	 * so we can fix up hard links files later in the archive.
	 */
	if (iflag && (name_start() < 0))
		return;

	/*
	 * set up to cp file trees
	 */
	cp_start();

	/*
	 * while there are files to archive, process them
	 */
	while (next_file(arcn) == 0) {
		fdsrc = -1;

		/*
		 * check if this file meets user specified options
		 */
		if (sel_chk(arcn) != 0)
			continue;

		/*
		 * if there is already a file in the destination directory with
		 * the same name and it is newer, skip the one stored on the
		 * archive.
		 * NOTE: this test is done BEFORE name modifications as
		 * specified by pax. this can be confusing to the user who
		 * might expect the test to be done on an existing file AFTER
		 * the name mod. In honesty the pax spec is probably flawed in
		 * this respect
		 */
		if (uflag || Dflag) {
			/*
			 * create the destination name
			 */
			if (*(arcn->name) == '/')
				res = 1;
			else
				res = 0;
			if ((arcn->nlen - res) > drem) {
				paxwarn(1, "Destination pathname too long %s",
					arcn->name);
				continue;
			}
			strncpy(dest_pt, arcn->name + res, drem);
			dirbuf[PAXPATHLEN] = '\0';

			/*
			 * if existing file is same age or newer skip
			 */
			res = lstat(dirbuf, &sb);
			*dest_pt = '\0';

		    	if (res == 0) {
				if (uflag && Dflag) {
					if ((arcn->sb.st_mtime<=sb.st_mtime) &&
			    		    (arcn->sb.st_ctime<=sb.st_ctime))
						continue;
				} else if (Dflag) {
					if (arcn->sb.st_ctime <= sb.st_ctime)
						continue;
				} else if (arcn->sb.st_mtime <= sb.st_mtime)
					continue;
			}
		}

		/*
		 * this file is considered selected. See if this is a hard link
		 * to a previous file; modify the name as requested by the
		 * user; set the final destination.
		 */
		ftree_sel(arcn);
		if ((chk_lnk(arcn) < 0) || ((res = mod_name(arcn)) < 0))
			break;
		if ((res > 0) || (set_dest(arcn, dirbuf, dlen) < 0)) {
			/*
			 * skip file, purge from link table
			 */
			purg_lnk(arcn);
			continue;
		}

		/*
		 * Non standard -Y and -Z flag. When the existing file is
		 * same age or newer skip
		 */
		if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) {
			if (Yflag && Zflag) {
				if ((arcn->sb.st_mtime <= sb.st_mtime) &&
				    (arcn->sb.st_ctime <= sb.st_ctime))
					continue;
			} else if (Yflag) {
				if (arcn->sb.st_ctime <= sb.st_ctime)
					continue;
			} else if (arcn->sb.st_mtime <= sb.st_mtime)
				continue;
		}

		if (vflag) {
			fputs(arcn->name, listf);
			vfpart = 1;
		}
		++flcnt;

		/*
		 * try to create a hard link to the src file if requested
		 * but make sure we are not trying to overwrite ourselves.
		 */
		if (lflag)
			res = cross_lnk(arcn);
		else
			res = chk_same(arcn);
		if (res <= 0) {
			if (vflag && vfpart) {
				putc('\n', listf);
				vfpart = 0;
			}
			continue;
		}

		/*
		 * have to create a new file
		 */
		if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) {
			/*
			 * create a link or special file
			 */
			if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
				res = lnk_creat(arcn);
			else
				res = node_creat(arcn);
			if (res < 0)
				purg_lnk(arcn);
			if (vflag && vfpart) {
				putc('\n', listf);
				vfpart = 0;
			}
			continue;
		}

		/*
		 * have to copy a regular file to the destination directory.
		 * first open source file and then create the destination file
		 */
		if ((fdsrc = open(arcn->org_name, O_RDONLY, 0)) < 0) {
			syswarn(1, errno, "Unable to open %s to read",
			    arcn->org_name);
			purg_lnk(arcn);
			continue;
		}
		if ((fddest = file_creat(arcn)) < 0) {
			rdfile_close(arcn, &fdsrc);
			purg_lnk(arcn);
			continue;
		}

		/*
		 * copy source file data to the destination file
		 */
		cp_file(arcn, fdsrc, fddest);
		file_close(arcn, fddest);
		rdfile_close(arcn, &fdsrc);

		if (vflag && vfpart) {
			putc('\n', listf);
			vfpart = 0;
		}
	}

	/*
	 * restore directory modes and times as required; make sure all
	 * patterns were selected block off signals to avoid chance for
	 * multiple entry into the cleanup code.
	 */
	sigprocmask(SIG_BLOCK, &s_mask, NULL);
	ar_close();
	proc_dir();
	ftree_chk();
}
예제 #8
0
static int
rep_name(char *name, int *nlen, int prnt)
{
	REPLACE *pt;
	char *inpt;
	char *outpt;
	char *endpt;
	char *rpt;
	int found = 0;
	int res;
	regmatch_t pm[MAXSUBEXP];
	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;
	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
			 */
			if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0)
				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;
			rpt = inpt + pm[0].rm_so;

			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.
			 */
			if ((res = resub(&(pt->rcmp),pm,pt->nstr,outpt,endpt))
			    < 0) {
				if (prnt)
					paxwarn(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
			 */
			inpt += pm[0].rm_eo - pm[0].rm_so;

			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)
				paxwarn(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')
				fprintf(stderr,"%s >> <empty string>\n",
				    name);
			else
				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);
		name[PAXPATHLEN] = '\0';
	}
	return(0);
}