Implement -M flag: During a write or copy operation, treat the list of

files on standard input as an mtree(8) `specfile' specification, and
write or copy only those items in the specfile.

If the file exists in the underlying file system, its permissions and
modification time will be used unless specifically overridden by the
specfile. An error will be raised if the type of entry in the specfile
conflicts with that of an existing file.

Otherwise, it is necessary to specify at least the following parameters
in the specfile: type, mode, gname or gid, and uname or uid, device
(in the case of block or character devices), and link (in the case of
symbolic links). If time isn't provided, the current time will be used.
This commit is contained in:
lukem 2001-10-25 08:51:50 +00:00
parent ca2a1a8c3b
commit 55026d5454
7 changed files with 285 additions and 36 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.11 2001/10/25 05:33:32 lukem Exp $
# $NetBSD: Makefile,v 1.12 2001/10/25 08:51:50 lukem Exp $
# @(#)Makefile 8.1 (Berkeley) 5/31/93
# To install on versions prior to BSD 4.4 the following may have to be
@ -28,12 +28,24 @@
PROG= pax
SRCS= ar_io.c ar_subs.c buf_subs.c cpio.c file_subs.c ftree.c\
gen_subs.c getoldopt.c options.c pat_rep.c pax.c sel_subs.c tables.c\
tar.c tty_subs.c
tar.c tty_subs.c \
spec.c misc.c stat_flags.c pack_dev.c
# XXX not yet!
# MAN= pax.1 tar.1 cpio.1
# LINKS+= ${BINDIR}/pax ${BINDIR}/tar
# LINKS+= ${BINDIR}/pax ${BINDIR}/cpio
LDADD+= -lutil
DPADD+= ${LIBUTIL}
CPPFLAGS+= -I${.CURDIR}/../../usr.sbin/mtree \
-I${.CURDIR}/../../sbin/mknod \
-I${.CURDIR}/../../bin/ls
.PATH: ${.CURDIR}/../../usr.sbin/mtree \
${.CURDIR}/../../sbin/mknod \
${.CURDIR}/../../bin/ls
NOHTML=doc2html-error
.include <bsd.prog.mk>

View File

@ -1,4 +1,4 @@
/* $NetBSD: extern.h,v 1.26 2001/10/25 05:33:32 lukem Exp $ */
/* $NetBSD: extern.h,v 1.27 2001/10/25 08:51:50 lukem Exp $ */
/*-
* Copyright (c) 1992 Keith Muller.
@ -231,6 +231,7 @@ extern int zflag;
extern int Dflag;
extern int Hflag;
extern int Lflag;
extern int Mflag;
extern int Xflag;
extern int Yflag;
extern int Zflag;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ftree.c,v 1.11 2001/10/25 05:33:33 lukem Exp $ */
/* $NetBSD: ftree.c,v 1.12 2001/10/25 08:51:51 lukem Exp $ */
/*-
* Copyright (c) 1992 Keith Muller.
@ -37,12 +37,48 @@
* SUCH DAMAGE.
*/
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn of Wasabi Systems.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)ftree.c 8.2 (Berkeley) 4/18/94";
#else
__RCSID("$NetBSD: ftree.c,v 1.11 2001/10/25 05:33:33 lukem Exp $");
__RCSID("$NetBSD: ftree.c,v 1.12 2001/10/25 08:51:51 lukem Exp $");
#endif
#endif /* not lint */
@ -60,6 +96,7 @@ __RCSID("$NetBSD: ftree.c,v 1.11 2001/10/25 05:33:33 lukem Exp $");
#include "pax.h"
#include "ftree.h"
#include "extern.h"
#include "mtree.h"
/*
* routines to interface with the fts library function.
@ -83,6 +120,7 @@ static FTREE *fttail = NULL; /* tail of linked list of file args */
static FTREE *ftcur = NULL; /* current file arg being processed */
static FTSENT *ftent = NULL; /* current file tree entry */
static int ftree_skip; /* when set skip to next file arg */
static NODE *ftnode = NULL; /* mtree(8) specfile; used by -M */
static int ftree_arg(void);
@ -105,6 +143,28 @@ static int ftree_arg(void);
int
ftree_start(void)
{
/*
* 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);
}
/*
* 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
@ -214,13 +274,14 @@ ftree_sel(ARCHD *arcn)
/*
* if -n we are done with this arg, force a skip to the next arg when
* pax asks for the next file in next_file().
* if -M we don't use fts(3), so the rest of this function is moot.
* if -d we tell fts only to match the directory (if the arg is a dir)
* and not the entire file tree rooted at that point.
*/
if (nflag)
ftree_skip = 1;
if (!dflag || (arcn->type != PAX_DIR))
if (Mflag || !dflag || (arcn->type != PAX_DIR))
return;
if (ftent != NULL)
@ -344,9 +405,130 @@ ftree_arg(void)
int
next_file(ARCHD *arcn)
{
int cnt;
time_t atime;
time_t mtime;
static char curdir[PAXPATHLEN+2], curpath[PAXPATHLEN+2];
static int curdirlen;
struct stat statbuf;
FTSENT Mftent;
int cnt;
time_t atime, mtime;
char *curlink;
#define MFTENT_DUMMY_DEV UINT_MAX
curlink = NULL;
/*
* if parsing an mtree(8) specfile, build up `dummy' ftsent
* from specfile info, and jump below to complete setup of arcn.
*/
if (Mflag) {
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 %d: %s: %s",
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;
/* stat existing file */
if (lstat(Mftent.fts_path, &statbuf) == -1) {
/* fake up stat buffer */
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 %d: %s: %s not provided", \
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 ||
ftnode->flags & F_GNAME, "group");
NODETEST(ftnode->flags & F_UID ||
ftnode->flags & 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 %d: %s: type mismatch: specfile %s, tree %s",
ftnode->lineno, ftent->fts_path,
inotype(nodetoino(ftnode->type)),
inotype(statbuf.st_mode));
return(-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 (ftnode->flags & F_FLAGS)
statbuf.st_flags = ftnode->st_flags;
if (ftnode->flags & F_TIME)
statbuf.st_mtimespec = ftnode->st_mtimespec;
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 = l_strncpy(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);
}
if (ftnode->parent == ftnode)
ftnode = NULL;
else
ftnode = ftnode->parent;
if (ftnode != NULL) {
curdirlen -= strlen(ftnode->name) + 1;
curdir[curdirlen] = '\0';
}
}
} while (ftnode != NULL && ftnode->flags & F_VISIT);
goto got_ftent;
}
/*
* ftree_sel() might have set the ftree_skip flag if the user has the
@ -440,6 +622,7 @@ next_file(ARCHD *arcn)
continue;
}
got_ftent:
/*
* ok got a file tree node to process. copy info into arcn
* structure (initialize as required)
@ -491,10 +674,14 @@ next_file(ARCHD *arcn)
break;
case S_IFLNK:
arcn->type = PAX_SLK;
if (curlink != NULL) {
cnt = l_strncpy(arcn->ln_name, curlink,
sizeof(arcn->ln_name));
/*
* have to read the symlink path from the file
*/
if ((cnt = readlink(ftent->fts_path, arcn->ln_name,
} else if ((cnt =
readlink(ftent->fts_path, arcn->ln_name,
PAXPATHLEN)) < 0) {
syswarn(1, errno, "Unable to read symlink %s",
ftent->fts_path);

View File

@ -1,4 +1,4 @@
/* $NetBSD: options.c,v 1.33 2001/10/25 05:33:33 lukem Exp $ */
/* $NetBSD: options.c,v 1.34 2001/10/25 08:51:51 lukem Exp $ */
/*-
* Copyright (c) 1992 Keith Muller.
@ -42,7 +42,7 @@
#if 0
static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 4/18/94";
#else
__RCSID("$NetBSD: options.c,v 1.33 2001/10/25 05:33:33 lukem Exp $");
__RCSID("$NetBSD: options.c,v 1.34 2001/10/25 08:51:51 lukem Exp $");
#endif
#endif /* not lint */
@ -194,8 +194,8 @@ pax_options(int argc, char **argv)
/*
* process option flags
*/
while ((c=getopt(argc,argv,"ab:cdf:iklno:p:rs:tuvwx:zAB:DE:G:HLOPT:U:XYZ"))
!= -1) {
while ((c = getopt(argc, argv,
"ab:cdf:iklno:p:rs:tuvwx:zAB:DE:G:HLMOPT:U:XYZ")) != -1) {
switch (c) {
case 'a':
/*
@ -466,6 +466,14 @@ pax_options(int argc, char **argv)
Lflag = 1;
flg |= CLF;
break;
case 'M':
/*
* Treat list of filenames on stdin as an
* mtree(8) specfile. Non standard option.
*/
Mflag = 1;
flg |= CMF;
break;
case 'O':
/*
* Force one volume. Non standard option.
@ -1445,14 +1453,14 @@ pax_usage(void)
(void)fputs("[-U user] ... [-G group] ...\n ", stderr);
(void)fputs("[-T [from_date][,to_date]] ... ", stderr);
(void)fputs(" [pattern ...]\n", stderr);
(void)fputs(" pax -w [-dituvzHLPX] [-b blocksize] ", stderr);
(void)fputs(" pax -w [-dituvzHLMPX] [-b blocksize] ", stderr);
(void)fputs("[[-a] [-f archive]] [-x format] \n", stderr);
(void)fputs(" [-B bytes] [-o options] ... ", stderr);
(void)fputs("[-s replstr] ... [-U user] ...", stderr);
(void)fputs("\n [-G group] ... ", stderr);
(void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
(void)fputs("[file ...]\n", stderr);
(void)fputs(" pax -r -w [-diklntuvzDHLPXYZ] ", stderr);
(void)fputs(" pax -r -w [-diklntuvzDHLMPXYZ] ", stderr);
(void)fputs("[-p string] ... [-s replstr] ...", stderr);
(void)fputs("\n [-U user] ... [-G group] ... ", stderr);
(void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);

View File

@ -1,4 +1,4 @@
/* $NetBSD: options.h,v 1.6 1999/11/01 17:13:27 mrg Exp $ */
/* $NetBSD: options.h,v 1.7 2001/10/25 08:51:51 lukem Exp $ */
/*-
* Copyright (c) 1992 Keith Muller.
@ -82,18 +82,19 @@
#define CGF 0x00400000 /* nonstandard extension */
#define CHF 0x00800000 /* nonstandard extension */
#define CLF 0x01000000 /* nonstandard extension */
#define CPF 0x02000000 /* nonstandard extension */
#define CTF 0x04000000 /* nonstandard extension */
#define CUF 0x08000000 /* nonstandard extension */
#define CXF 0x10000000
#define CYF 0x20000000 /* nonstandard extension */
#define CZF 0x40000000 /* nonstandard extension */
#define CMF 0x02000000 /* nonstandard extension */
#define CPF 0x04000000 /* nonstandard extension */
#define CTF 0x08000000 /* nonstandard extension */
#define CUF 0x10000000 /* nonstandard extension */
#define CXF 0x20000000
#define CYF 0x40000000 /* nonstandard extension */
#define CZF 0x80000000 /* nonstandard extension */
/*
* ascii string indexed by bit position above (alter the above and you must
* alter this string) used to tell the user what flags caused us to complain
*/
#define FLGCH "abcdfiklnoprstuvwxABDEGHLPTUXYZ"
#define FLGCH "abcdfiklnoprstuvwxABDEGHLMPTUXYZ"
/*
* legal pax operation bit patterns
@ -110,7 +111,7 @@
* Illegal option flag subsets based on pax operation
*/
#define BDEXTR (AF|BF|LF|TF|WF|XF|CBF|CHF|CLF|CPF|CXF)
#define BDEXTR (AF|BF|LF|TF|WF|XF|CBF|CHF|CLF|CMF|CPF|CXF)
#define BDARCH (CF|KF|LF|NF|PF|RF|CDF|CEF|CYF|CZF)
#define BDCOPY (AF|BF|FF|OF|XF|CAF|CBF|CEF)
#define BDLIST (AF|BF|IF|KF|LF|OF|PF|RF|TF|UF|WF|XF|CBF|CDF|CHF|CLF|CPF|CXF|CYF|CZF)
#define BDLIST (AF|BF|IF|KF|LF|OF|PF|RF|TF|UF|WF|XF|CBF|CDF|CHF|CLF|CMF|CPF|CXF|CYF|CZF)

View File

@ -1,4 +1,4 @@
.\" $NetBSD: pax.1,v 1.25 2000/09/04 07:26:38 kleink Exp $
.\" $NetBSD: pax.1,v 1.26 2001/10/25 08:51:51 lukem Exp $
.\"
.\" Copyright (c) 1992 Keith Muller.
.\" Copyright (c) 1992, 1993
@ -37,7 +37,7 @@
.\"
.\" @(#)pax.1 8.4 (Berkeley) 4/18/94
.\"
.Dd March 30, 2000
.Dd October 25, 2001
.Dt PAX 1
.Os
.Sh NAME
@ -117,7 +117,7 @@
.Op Ar pattern ...\&
.Nm ""
.Fl w
.Op Fl dituvzAHLOPX
.Op Fl dituvzAHLMOPX
.Bk -words
.Op Fl b Ar blocksize
.Ek
@ -162,7 +162,7 @@
.Nm ""
.Fl r
.Fl w
.Op Fl diklntuvzADHLOPXYZ
.Op Fl diklntuvzADHLMOPXYZ
.Bk -words
.Op Fl p Ar string
.Ar ...\&
@ -868,6 +868,41 @@ Follow only command line symbolic links while performing a physical file
system traversal.
.It Fl L
Follow all symbolic links to perform a logical file system traversal.
.It Fl M
During a
.Em write
or
.Em copy
operation, treat the list of files on
.Dv standard input
as an
.Xr mtree 8
.Sq specfile
specification, and write or copy only those items in the specfile.
.Pp
If the file exists in the underlying file system, its permissions and
modification time will be used unless specifically overridden by the specfile.
An error will be raised if the type of entry in the specfile conflicts
with that of an existing file.
.Pp
Otherwise, it is necessary to specify at least the following parameters
in the specfile:
.Sy type ,
.Sy mode ,
.Sy gname
or
.Sy gid ,
and
.Sy uname
or
.Sy uid ,
.Sy device
(in the case of block or character devices), and
.Sy link
(in the case of symbolic links).
If
.Sy time
isn't provided, the current time will be used.
.It Fl O
Force the archive to be one volume. If a volume ends prematurely,
.Nm
@ -1136,9 +1171,10 @@ which are older (less recent inode change or file modification times) than
files with the same name found in the source file tree
.Pa home .
.Sh SEE ALSO
.Xr tar 1 ,
.Xr cpio 1 ,
.Xr symlink 7
.Xr tar 1 ,
.Xr symlink 7 ,
.Xr mtree 8
.Sh STANDARDS
The
.Nm
@ -1152,6 +1188,7 @@ The options
.Fl G ,
.Fl H ,
.Fl L ,
.Fl M ,
.Fl O ,
.Fl P ,
.Fl T ,
@ -1170,8 +1207,10 @@ and
operations are extensions to the
.Tn POSIX
standard.
.Sh AUTHOR
Keith Muller at the University of California, San Diego
.Sh AUTHORS
Keith Muller at the University of California, San Diego.
Luke Mewburn implemented
.Fl M .
.Sh ERRORS
.Nm
will exit with one of the following values:

View File

@ -1,4 +1,4 @@
/* $NetBSD: pax.c,v 1.14 2001/10/25 05:33:33 lukem Exp $ */
/* $NetBSD: pax.c,v 1.15 2001/10/25 08:51:51 lukem Exp $ */
/*-
* Copyright (c) 1992 Keith Muller.
@ -47,7 +47,7 @@ __COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\
#if 0
static char sccsid[] = "@(#)pax.c 8.2 (Berkeley) 4/18/94";
#else
__RCSID("$NetBSD: pax.c,v 1.14 2001/10/25 05:33:33 lukem Exp $");
__RCSID("$NetBSD: pax.c,v 1.15 2001/10/25 08:51:51 lukem Exp $");
#endif
#endif /* not lint */
@ -88,6 +88,7 @@ int Aflag; /* honor absolute path */
int Dflag; /* same as uflag except inode change time */
int Hflag; /* follow command line symlinks (write only) */
int Lflag; /* follow symlinks when writing */
int Mflag; /* treat stdin as an mtree(8) specfile */
int Xflag; /* archive files with same device id only */
int Yflag; /* same as Dflg except after name mode */
int Zflag; /* same as uflg except after name mode */