Example #1
0
File: ftree.c Project: Mobbe/bitrig
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) {
			if (errno)
				syswarn(1, errno, "next_file");
			/*
			 * 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).
			 */
			if (!tflag || (get_atdir(ftent->fts_statp->st_dev,
			    ftent->fts_statp->st_ino, &mtime, &atime) < 0))
				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:
			syswarn(1, ftent->fts_errno,
			    "Unable to read directory %s", ftent->fts_path);
			continue;
		case FTS_ERR:
			syswarn(1, ftent->fts_errno,
			    "File system traversal error");
			continue;
		case FTS_NS:
		case FTS_NSOK:
			syswarn(1, ftent->fts_errno,
			    "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';
		memcpy(&arcn->sb, ftent->fts_statp, sizeof(arcn->sb));

		/*
		 * 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)) < 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;
		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;
		case S_IFIFO:
			arcn->type = PAX_FIF;
			break;
		}
		break;
	}

	/*
	 * copy file name, set file name length
	 */
	arcn->nlen = strlcpy(arcn->name, ftent->fts_path, sizeof(arcn->name));
	if (arcn->nlen >= sizeof(arcn->name))
		arcn->nlen = sizeof(arcn->name) - 1; /* XXX truncate? */
	arcn->org_name = ftent->fts_path;
	return(0);
}
Example #2
0
int
next_file(ARCHD *arcn)
{
#ifndef SMALL
	static	char	curdir[PAXPATHLEN+2], curpath[PAXPATHLEN+2];
	static	int	curdirlen;

	struct stat	statbuf;
	FTSENT		Mftent;
#endif	/* SMALL */
	int		cnt;
	time_t		atime, mtime;
	char		*curlink;
#define MFTENT_DUMMY_DEV	UINT_MAX

	curlink = NULL;
#ifndef SMALL
	/*
	 * if parsing an mtree(8) specfile, build up `dummy' ftsent
	 * from specfile info, and jump below to complete setup of arcn.
	 */
	if (Mflag) {
		int	skipoptional;

 next_ftnode:
		skipoptional = 0;
		if (ftnode == NULL)		/* tree is empty */
			return (-1);

						/* get current name */
		if (snprintf(curpath, sizeof(curpath), "%s%s%s",
		    curdir, curdirlen ? "/" : "", ftnode->name)
		    >= sizeof(curpath)) {
			tty_warn(1, "line %lu: %s: %s", (u_long)ftnode->lineno,
			    curdir, strerror(ENAMETOOLONG));
			return (-1);
		}
		ftnode->flags |= F_VISIT;	/* mark node visited */

						/* construct dummy FTSENT */
		Mftent.fts_path = curpath;
		Mftent.fts_statp = &statbuf;
		Mftent.fts_pointer = ftnode;
		ftent = &Mftent;
						/* look for existing file */
		if (lstat(Mftent.fts_path, &statbuf) == -1) {
			if (ftnode->flags & F_OPT)
				skipoptional = 1;

						/* missing: fake up stat info */
			memset(&statbuf, 0, sizeof(statbuf));
			statbuf.st_dev = MFTENT_DUMMY_DEV;
			statbuf.st_ino = ftnode->lineno;
			statbuf.st_size = 0;
#define NODETEST(t, m)							\
			if (!(t)) {					\
				tty_warn(1, "line %lu: %s: %s not specified", \
				    (u_long)ftnode->lineno,		\
				    ftent->fts_path, m);		\
				return -1;				\
			}
			statbuf.st_mode = nodetoino(ftnode->type);
			NODETEST(ftnode->flags & F_TYPE, "type");
			NODETEST(ftnode->flags & F_MODE, "mode");
			if (!(ftnode->flags & F_TIME))
				statbuf.st_mtime = starttime;
			NODETEST(ftnode->flags & (F_GID | F_GNAME), "group");
			NODETEST(ftnode->flags & (F_UID | F_UNAME), "user");
			if (ftnode->type == F_BLOCK || ftnode->type == F_CHAR)
				NODETEST(ftnode->flags & F_DEV,
				    "device number");
			if (ftnode->type == F_LINK)
				NODETEST(ftnode->flags & F_SLINK, "symlink");
			/* don't require F_FLAGS or F_SIZE */
#undef NODETEST
		} else {
			if (ftnode->flags & F_TYPE && nodetoino(ftnode->type)
			    != (statbuf.st_mode & S_IFMT)) {
				tty_warn(1,
			    "line %lu: %s: type mismatch: specfile %s, tree %s",
				    (u_long)ftnode->lineno, ftent->fts_path,
				    inotype(nodetoino(ftnode->type)),
				    inotype(statbuf.st_mode));
				return -1;
			}
			if (ftnode->type == F_DIR && (ftnode->flags & F_OPT))
				skipoptional = 1;
		}
		/*
		 * override settings with those from specfile
		 */
		if (ftnode->flags & F_MODE) {
			statbuf.st_mode &= ~ALLPERMS; 
			statbuf.st_mode |= (ftnode->st_mode & ALLPERMS);
		}
		if (ftnode->flags & (F_GID | F_GNAME))
			statbuf.st_gid = ftnode->st_gid;
		if (ftnode->flags & (F_UID | F_UNAME))
			statbuf.st_uid = ftnode->st_uid;
#if HAVE_STRUCT_STAT_ST_FLAGS
		if (ftnode->flags & F_FLAGS)
			statbuf.st_flags = ftnode->st_flags;
#endif
		if (ftnode->flags & F_TIME)
#if BSD4_4 && !HAVE_NBTOOL_CONFIG_H
			statbuf.st_mtimespec = ftnode->st_mtimespec;
#else
			statbuf.st_mtime = ftnode->st_mtimespec.tv_sec;
#endif
		if (ftnode->flags & F_DEV)
			statbuf.st_rdev = ftnode->st_rdev;
		if (ftnode->flags & F_SLINK)
			curlink = ftnode->slink;
				/* ignore F_SIZE */

		/*
		 * find next node
		 */
		if (ftnode->type == F_DIR && ftnode->child != NULL) {
					/* directory with unseen child */
			ftnode = ftnode->child;
			curdirlen = strlcpy(curdir, curpath, sizeof(curdir));
		} else do {
			if (ftnode->next != NULL) {
					/* next node at current level */
				ftnode = ftnode->next;
			} else {	/* move back to parent */
					/* reset time only on first cd.. */
				if (Mftent.fts_pointer == ftnode && tflag &&
				    (get_atdir(MFTENT_DUMMY_DEV, ftnode->lineno,
				    &mtime, &atime) == 0)) {
					set_ftime(ftent->fts_path,
					    mtime, atime, 1, 0);
				}
				ftnode = ftnode->parent;
				if (ftnode->parent == ftnode)
					ftnode = NULL;
				else {
					curdirlen -= strlen(ftnode->name) + 1;
					curdir[curdirlen] = '\0';
				}
			}
		} while (ftnode != NULL && ftnode->flags & F_VISIT);
		if (skipoptional)	/* skip optional entries */
			goto next_ftnode;
		goto got_ftent;
	}
#endif	/* SMALL */

	/*
	 * 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;
	}

	if (ftsp == NULL)
		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).
			 */
			if (!tflag || (get_atdir(
			    ftent->fts_statp->st_dev, ftent->fts_statp->st_ino,
			    &mtime, &atime) < 0))
				continue;
			set_ftime(ftent->fts_path, mtime, atime, 1, 0);
			continue;
		case FTS_DC:
			/*
			 * fts claims a file system cycle
			 */
			tty_warn(1,"File system cycle found at %s",
			    ftent->fts_path);
			continue;
		case FTS_DNR:
			syswarn(1, FTS_ERRNO(ftent),
			    "Unable to read directory %s", ftent->fts_path);
			continue;
		case FTS_ERR:
			syswarn(1, FTS_ERRNO(ftent),
			    "File system traversal error");
			continue;
		case FTS_NS:
		case FTS_NSOK:
			syswarn(1, FTS_ERRNO(ftent),
			    "Unable to access %s", ftent->fts_path);
			continue;
		}

#ifndef SMALL
 got_ftent:
#endif	/* SMALL */
		/*
		 * 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';
		arcn->sb = *(ftent->fts_statp);

		/*
		 * 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;
			if (curlink != NULL) {
				cnt = strlcpy(arcn->ln_name, curlink,
				    sizeof(arcn->ln_name));
			/*
			 * have to read the symlink path from the file
			 */
			} else if ((cnt =
			    readlink(ftent->fts_path, arcn->ln_name,
			    sizeof(arcn->ln_name) - 1)) < 0) {
				syswarn(1, errno, "Unable to read symlink %s",
				    ftent->fts_path);
				continue;
			}
			/*
			 * set link name length, watch out readlink does not
			 * always null terminate the link path
			 */
			arcn->ln_name[cnt] = '\0';
			arcn->ln_nlen = cnt;
			break;
#ifdef S_IFSOCK
		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 = strlcpy(arcn->name, ftent->fts_path, sizeof(arcn->name));
	arcn->org_name = arcn->fts_name;
	strlcpy(arcn->fts_name, ftent->fts_path, sizeof arcn->fts_name);
	if (strcmp(NM_CPIO, argv0) == 0) {
		/*
		 * cpio does *not* descend directories listed in the
		 * arguments, unlike pax/tar, so needs special handling
		 * here.  failure to do so results in massive amounts
		 * of duplicated files in the output. We kill fts after
		 * the first name is extracted, what a waste.
		 */
		ftcur->refcnt = 1;
		(void)ftree_arg();
	}
	return 0;
}