Exemplo n.º 1
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_FILE_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(
#ifdef NET2_FTS
                               ftent->fts_statb.st_dev, ftent->fts_statb.st_ino,
#else
                               ftent->fts_statp->st_dev, ftent->fts_statp->st_ino,
#endif
                               &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';
#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;
            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
             * allways 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;
}
Exemplo n.º 2
0
int
ftree_start()
{

#ifndef SMALL
	/*
	 * if -M is given, the list of filenames on stdin is actually
	 * an mtree(8) specfile, so parse the specfile into a NODE *
	 * tree at ftnode, for use by next_file()
	 */
	if (Mflag) {
		if (fthead != NULL) {
			tty_warn(1,
	    "The -M flag is only supported when reading file list from stdin");
			return -1;
		}
		ftnode = spec(stdin);
		if (ftnode != NULL &&
		    (ftnode->type != F_DIR || strcmp(ftnode->name, ".") != 0)) {
			tty_warn(1,
			    "First node of specfile is not `.' directory");
			return -1;
		}
		return 0;
	}
#endif	/* SMALL */

	/*
	 * set up the operation mode of fts, open the first file arg. We must
	 * use FTS_NOCHDIR, as the user may have to open multiple archives and
	 * if fts did a chdir off into the boondocks, we may create an archive
	 * volume in an place where the user did not expect to.
	 */
	ftsopts = FTS_NOCHDIR;

	/*
	 * optional user flags that effect file traversal
	 * -H command line symlink follow only (half follow)
	 * -L follow sylinks (logical)
	 * -P do not follow sylinks (physical). This is the default.
	 * -X do not cross over mount points
	 * -t preserve access times on files read.
	 * -n select only the first member of a file tree when a match is found
	 * -d do not extract subtrees rooted at a directory arg.
	 */
	if (Lflag)
		ftsopts |= FTS_LOGICAL;
	else
		ftsopts |= FTS_PHYSICAL;
	if (Hflag)
#ifdef NET2_FTS
		tty_warn(0, "The -H flag is not supported on this version");
#else
		ftsopts |= FTS_COMFOLLOW;
#endif
	if (Xflag)
		ftsopts |= FTS_XDEV;

	if ((fthead == NULL) && ((farray[0] = malloc(PAXPATHLEN+2)) == NULL)) {
		tty_warn(1, "Unable to allocate memory for file name buffer");
		return -1;
	}

	if (ftree_arg() < 0)
		return -1;
	if (tflag && (atdir_start() < 0))
		return -1;
	return 0;
}
Exemplo n.º 3
0
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;
		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 = l_strncpy(arcn->name, ftent->fts_path, sizeof(arcn->name) - 1);
	arcn->name[arcn->nlen] = '\0';
	arcn->org_name = ftent->fts_path;
	return(0);
}