]> git.wh0rd.org - dump.git/commitdiff
dump -m implementation.
authorStelian Pop <stelian@popies.net>
Thu, 4 Apr 2002 08:20:19 +0000 (08:20 +0000)
committerStelian Pop <stelian@popies.net>
Thu, 4 Apr 2002 08:20:19 +0000 (08:20 +0000)
CHANGES
compat/include/protocols/dumprestore.h
dump/dump.8.in
dump/dump.h
dump/main.c
dump/traverse.c
restore/extern.h
restore/restore.c
restore/tape.c

diff --git a/CHANGES b/CHANGES
index 9c18c539e35a76e95f14b4866588b48a340731dd..c29c393879f0836fc317de73c0c2bbfaad143616 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,4 @@
-$Id: CHANGES,v 1.169 2002/03/28 14:53:01 stelian Exp $
+$Id: CHANGES,v 1.170 2002/04/04 08:20:19 stelian Exp $
 
 Changes between versions 0.4b27 and 0.4b28 (released ?????????????????)
 =======================================================================
 
 Changes between versions 0.4b27 and 0.4b28 (released ?????????????????)
 =======================================================================
@@ -39,6 +39,16 @@ Changes between versions 0.4b27 and 0.4b28 (released ?????????????????)
        Thanks to Uwe Gohlke <uwe@ugsoft.de> for reporting the bug and
        providing a test case.
 
        Thanks to Uwe Gohlke <uwe@ugsoft.de> for reporting the bug and
        providing a test case.
 
+8.     Added the -m parameter to dump which optimises the output for
+       inodes having been changed but not modified since the last dump
+       ('changed' and 'modified' have the meaning defined in stat(2)).
+       For those inodes, dump will save only the metadata, instead of
+       saving the entire inode contents. Inodes which are either 
+       directories or have been modified since the last dump are saved
+       in a regular way.  Uses of this flag must be consistent, meaning
+       that either every dump in an incremental dump set have the flag,
+       or no one has it.
+
 Changes between versions 0.4b26 and 0.4b27 (released February 15, 2002)
 =======================================================================
 
 Changes between versions 0.4b26 and 0.4b27 (released February 15, 2002)
 =======================================================================
 
index 2c3a945fc851ad88c76a0d45724cd6d7b769057e..d9e72fe0e5e69fd028375c94e5e2ba7fa1c870fc 100644 (file)
@@ -5,7 +5,7 @@
  *     Stelian Pop <stelian@popies.net>, 1999-2000
  *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
  *
  *     Stelian Pop <stelian@popies.net>, 1999-2000
  *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
  *
- *     $Id: dumprestore.h,v 1.16 2002/01/25 14:59:53 stelian Exp $
+ *     $Id: dumprestore.h,v 1.17 2002/04/04 08:20:23 stelian Exp $
  */
 
 /*
  */
 
 /*
@@ -131,6 +131,8 @@ union u_spcl {
 #define DR_NEWHEADER   0x0001  /* new format tape header */
 #define DR_NEWINODEFMT 0x0002  /* new format inodes on tape */
 #define DR_COMPRESSED  0x0080  /* dump tape is compressed */
 #define DR_NEWHEADER   0x0001  /* new format tape header */
 #define DR_NEWINODEFMT 0x0002  /* new format inodes on tape */
 #define DR_COMPRESSED  0x0080  /* dump tape is compressed */
+#define DR_METAONLY    0x0100  /* only the metadata of the inode has
+                                  been dumped */
 #define DR_INODEINFO   0x0002  /* TS_END header contains c_inos information */
 
 
 #define DR_INODEINFO   0x0002  /* TS_END header contains c_inos information */
 
 
index 5cb450e44098edb5cd1ec6488b3aa56c4c3c5674..657f78065382a046730c3d26721aad359bc5ae01 100644 (file)
@@ -30,7 +30,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"    $Id: dump.8.in,v 1.39 2002/02/25 10:00:44 stelian Exp $
+.\"    $Id: dump.8.in,v 1.40 2002/04/04 08:20:23 stelian Exp $
 .\"
 .Dd __DATE__
 .Dt DUMP 8
 .\"
 .Dd __DATE__
 .Dt DUMP 8
@@ -270,6 +270,22 @@ Note that this label is limited
 to be at most LBLSIZE (currently 16) characters, which must include
 the terminating
 .Ql \e0 .
 to be at most LBLSIZE (currently 16) characters, which must include
 the terminating
 .Ql \e0 .
+.It Fl m
+If this flag is specified,
+.Nm
+will optimise the output for inodes having been changed but not
+modified since the last dump ('changed' and 'modified' have the
+meaning defined in stat(2)). For those inodes,
+.Nm
+will save only the metadata, instead of saving the entire inode 
+contents. Inodes which are either directories or have been modified
+since the last dump are saved in a regular way.
+Uses of this flag must be consistent, meaning that either every dump 
+in an incremental dump set have the flag, or no one has it.
+.Pp
+Tapes written using such 'metadata only' inodes will not be compatible
+with the BSD tape format or older versions of
+.Nm restore.
 .It Fl M
 Enable the multi-volume feature. The name specified with 
 .Fl f 
 .It Fl M
 Enable the multi-volume feature. The name specified with 
 .Fl f 
index 2ce50e3c7c8787c7db8567a2293c8963d2c0626c..177329bbc5917b3bddf08637cfbc901d8f6b9deb 100644 (file)
@@ -5,7 +5,7 @@
  *     Stelian Pop <stelian@popies.net>, 1999-2000
  *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
  *
  *     Stelian Pop <stelian@popies.net>, 1999-2000
  *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
  *
- *     $Id: dump.h,v 1.36 2002/01/25 14:59:53 stelian Exp $
+ *     $Id: dump.h,v 1.37 2002/04/04 08:20:23 stelian Exp $
  */
 
 /*-
  */
 
 /*-
@@ -54,6 +54,8 @@ extern int    mapsize;        /* size of the state maps */
 extern char    *usedinomap;    /* map of allocated inodes */
 extern char    *dumpdirmap;    /* map of directories to be dumped */
 extern char    *dumpinomap;    /* map of files to be dumped */
 extern char    *usedinomap;    /* map of allocated inodes */
 extern char    *dumpdirmap;    /* map of directories to be dumped */
 extern char    *dumpinomap;    /* map of files to be dumped */
+extern char    *metainomap;    /* which of the inodes in dumpinomap
+                                  will get only their metadata dumped */
 /*
  * Map manipulation macros.
  */
 /*
  * Map manipulation macros.
  */
@@ -77,6 +79,7 @@ extern char   level;          /* dump level of this dump */
 extern int     Afile;          /* archive file descriptor */
 extern int     bzipflag;       /* compression is done using bzlib */
 extern int     uflag;          /* update flag */
 extern int     Afile;          /* archive file descriptor */
 extern int     bzipflag;       /* compression is done using bzlib */
 extern int     uflag;          /* update flag */
+extern int     mflag;          /* dump metadata only if possible flag */
 extern int     Mflag;          /* multi-volume flag */
 extern int     qflag;          /* quit on errors flag */
 extern int      breademax;      /* maximum number of bread errors before we quit */
 extern int     Mflag;          /* multi-volume flag */
 extern int     qflag;          /* quit on errors flag */
 extern int      breademax;      /* maximum number of bread errors before we quit */
@@ -155,7 +158,7 @@ int mapdirs __P((dump_ino_t maxino, long *tapesize));
 /* file dumping routines */
 void   blksout __P((daddr_t *blkp, int frags, dump_ino_t ino));
 void   bread __P((daddr_t blkno, char *buf, int size));
 /* file dumping routines */
 void   blksout __P((daddr_t *blkp, int frags, dump_ino_t ino));
 void   bread __P((daddr_t blkno, char *buf, int size));
-void   dumpino __P((struct dinode *dp, dump_ino_t ino));
+void   dumpino __P((struct dinode *dp, dump_ino_t ino, int metaonly));
 #ifdef __linux__
 void   dumpdirino __P((struct dinode *dp, dump_ino_t ino));
 #endif
 #ifdef __linux__
 void   dumpdirino __P((struct dinode *dp, dump_ino_t ino));
 #endif
index 3d4e693fc4ea6cb8672edd8a38716cd1959f0121..93c175c73b509e604595f1e874da4890ca4c14aa 100644 (file)
@@ -41,7 +41,7 @@
 
 #ifndef lint
 static const char rcsid[] =
 
 #ifndef lint
 static const char rcsid[] =
-       "$Id: main.c,v 1.70 2002/03/11 10:17:43 stelian Exp $";
+       "$Id: main.c,v 1.71 2002/04/04 08:20:23 stelian Exp $";
 #endif /* not lint */
 
 #include <config.h>
 #endif /* not lint */
 
 #include <config.h>
@@ -96,6 +96,8 @@ int   mapsize;        /* size of the state maps */
 char   *usedinomap;    /* map of allocated inodes */
 char   *dumpdirmap;    /* map of directories to be dumped */
 char   *dumpinomap;    /* map of files to be dumped */
 char   *usedinomap;    /* map of allocated inodes */
 char   *dumpdirmap;    /* map of directories to be dumped */
 char   *dumpinomap;    /* map of files to be dumped */
+char   *metainomap;    /* which of the inodes in dumpinomap will get
+                          only their metadata dumped */
 
 const char *disk;      /* name of the disk file */
 char   tape[MAXPATHLEN];/* name of the tape file */
 
 const char *disk;      /* name of the disk file */
 char   tape[MAXPATHLEN];/* name of the tape file */
@@ -106,6 +108,7 @@ char        level;          /* dump level of this dump */
 int    bzipflag;       /* compression is done using bzlib */
 int    Afile = 0;      /* archive file descriptor */
 int    uflag;          /* update flag */
 int    bzipflag;       /* compression is done using bzlib */
 int    Afile = 0;      /* archive file descriptor */
 int    uflag;          /* update flag */
+int    mflag;          /* dump metadata only if possible */
 int    Mflag;          /* multi-volume flag */
 int    qflag;          /* quit on errors flag */
 int     breademax = 32; /* maximum number of bread errors before we quit */
 int    Mflag;          /* multi-volume flag */
 int    qflag;          /* quit on errors flag */
 int     breademax = 32; /* maximum number of bread errors before we quit */
@@ -248,7 +251,7 @@ main(int argc, char *argv[])
 #ifdef KERBEROS
                            "k"
 #endif
 #ifdef KERBEROS
                            "k"
 #endif
-                           "Mnq"
+                           "mMnq"
 #ifdef USE_QFA
                            "Q:"
 #endif
 #ifdef USE_QFA
                            "Q:"
 #endif
@@ -377,6 +380,10 @@ main(int argc, char *argv[])
                        }
                        break;
 
                        }
                        break;
 
+               case 'm':               /* metadata only flag */
+                       mflag = 1;
+                       break;
+
                case 'M':               /* multi-volume flag */
                        Mflag = 1;
                        break;
                case 'M':               /* multi-volume flag */
                        Mflag = 1;
                        break;
@@ -730,7 +737,9 @@ main(int argc, char *argv[])
        usedinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
        dumpdirmap = (char *)calloc((unsigned) mapsize, sizeof(char));
        dumpinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
        usedinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
        dumpdirmap = (char *)calloc((unsigned) mapsize, sizeof(char));
        dumpinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
-       if (usedinomap == NULL || dumpdirmap == NULL || dumpinomap == NULL)
+       metainomap = (char *)calloc((unsigned) mapsize, sizeof(char));
+       if (usedinomap == NULL || dumpdirmap == NULL || 
+           dumpinomap == NULL || metainomap == NULL)
                quit("out of memory allocating inode maps\n");
        tapesize = 2 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
 
                quit("out of memory allocating inode maps\n");
        tapesize = 2 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
 
@@ -933,7 +942,7 @@ main(int argc, char *argv[])
                 * inodes since this is done in dumpino().
                 */
 #endif
                 * inodes since this is done in dumpino().
                 */
 #endif
-               (void)dumpino(dp, ino);
+               (void)dumpino(dp, ino, mflag && TSTINO(ino, metainomap));
        }
 
        tend_writing = time(NULL);
        }
 
        tend_writing = time(NULL);
@@ -1016,7 +1025,7 @@ usage(void)
 #ifdef KERBEROS
                "k"
 #endif
 #ifdef KERBEROS
                "k"
 #endif
-               "MnqSu"
+               "mMnqSu"
                "] [-A file] [-B records] [-b blocksize]\n"
                "\t%s [-d density] [-e inode#,inode#,...] [-E file] [-f file]\n"
                "\t%s [-h level] [-I nr errors] "
                "] [-A file] [-B records] [-b blocksize]\n"
                "\t%s [-d density] [-e inode#,inode#,...] [-E file] [-f file]\n"
                "\t%s [-h level] [-I nr errors] "
index eda65e1379e87fa4e1417d6f6295b59529795fb4..c8547604a7c0751f14833407938e762acf1ca56f 100644 (file)
@@ -41,7 +41,7 @@
 
 #ifndef lint
 static const char rcsid[] =
 
 #ifndef lint
 static const char rcsid[] =
-       "$Id: traverse.c,v 1.43 2002/02/04 11:18:46 stelian Exp $";
+       "$Id: traverse.c,v 1.44 2002/04/04 08:20:23 stelian Exp $";
 #endif /* not lint */
 
 #include <config.h>
 #endif /* not lint */
 
 #include <config.h>
@@ -217,8 +217,12 @@ blockest(struct dinode const *dp)
 }
 
 /* Auxiliary macro to pick up files changed since previous dump. */
 }
 
 /* Auxiliary macro to pick up files changed since previous dump. */
+#define CSINCE(dp, t) \
+       ((dp)->di_ctime >= (t))
+#define MSINCE(dp, t) \
+       ((dp)->di_mtime >= (t))
 #define        CHANGEDSINCE(dp, t) \
 #define        CHANGEDSINCE(dp, t) \
-       ((dp)->di_mtime >= (t) || (dp)->di_ctime >= (t))
+       (CSINCE(dp, t) || MSINCE(dp, t))
 
 /* The NODUMP_FLAG macro tests if a file has the nodump flag. */
 #ifdef UF_NODUMP
 
 /* The NODUMP_FLAG macro tests if a file has the nodump flag. */
 #ifdef UF_NODUMP
@@ -266,6 +270,8 @@ mapfileino(dump_ino_t ino, struct dinode const *dp, long *tapesize, int *dirskip
                SETINO(ino, dumpdirmap);
        if (WANTTODUMP(dp, ino)) {
                SETINO(ino, dumpinomap);
                SETINO(ino, dumpdirmap);
        if (WANTTODUMP(dp, ino)) {
                SETINO(ino, dumpinomap);
+               if (!MSINCE(dp, spcl.c_ddate))
+                       SETINO(ino, metainomap);
                if (mode != IFREG && mode != IFDIR && mode != IFLNK)
                        *tapesize += 1;
                else
                if (mode != IFREG && mode != IFDIR && mode != IFLNK)
                        *tapesize += 1;
                else
@@ -773,7 +779,7 @@ dumponeblock(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
  * Dump the contents of an inode to tape.
  */
 void
  * Dump the contents of an inode to tape.
  */
 void
-dumpino(struct dinode *dp, dump_ino_t ino)
+dumpino(struct dinode *dp, dump_ino_t ino, int metaonly)
 {
        unsigned long cnt;
        fsizeT size, remaining;
 {
        unsigned long cnt;
        fsizeT size, remaining;
@@ -785,7 +791,12 @@ dumpino(struct dinode *dp, dump_ino_t ino)
 #else
        int ind_level;
 #endif
 #else
        int ind_level;
 #endif
-       u_quad_t i_size = dp->di_size + ((u_quad_t) dp->di_size_high << 32);
+       u_quad_t i_size;
+       
+       if (metaonly)
+               i_size = 0;
+       else 
+               i_size = dp->di_size + ((u_quad_t) dp->di_size_high << 32);
 
        if (newtape) {
                newtape = 0;
 
        if (newtape) {
                newtape = 0;
@@ -814,6 +825,16 @@ dumpino(struct dinode *dp, dump_ino_t ino)
 #endif /* __linux__ */
        spcl.c_type = TS_INODE;
        spcl.c_count = 0;
 #endif /* __linux__ */
        spcl.c_type = TS_INODE;
        spcl.c_count = 0;
+
+       if (metaonly && (dp->di_mode & S_IFMT)) {
+               printf("Write header with spcl.c_count=%d\n",spcl.c_count);
+               spcl.c_flags |= DR_METAONLY;
+               spcl.c_count = 0;
+               writeheader(ino);
+               spcl.c_flags &= ~DR_METAONLY;
+               return;
+       }
+
        switch (dp->di_mode & S_IFMT) {
 
        case 0:
        switch (dp->di_mode & S_IFMT) {
 
        case 0:
index 408169fc5ae49eac8954097cd8b5405a03bfc1fc..0a4cbb1c94232135299eea0e138033ff6432284b 100644 (file)
@@ -5,7 +5,7 @@
  *     Stelian Pop <stelian@popies.net>, 1999-2000
  *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
  *
  *     Stelian Pop <stelian@popies.net>, 1999-2000
  *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
  *
- *     $Id: extern.h,v 1.16 2002/02/04 11:18:46 stelian Exp $
+ *     $Id: extern.h,v 1.17 2002/04/04 08:20:23 stelian Exp $
  */
 
 /*-
  */
 
 /*-
@@ -62,7 +62,7 @@ void           delwhiteout __P((struct entry *));
 dump_ino_t      dirlookup __P((const char *));
 void            dumpsymtable __P((char *, long));
 void            extractdirs __P((int));
 dump_ino_t      dirlookup __P((const char *));
 void            dumpsymtable __P((char *, long));
 void            extractdirs __P((int));
-int             extractfile __P((char *));
+int             extractfile __P((struct entry *, int));
 void            findunreflinks __P((void));
 char           *flagvalues __P((struct entry *));
 void            freeentry __P((struct entry *));
 void            findunreflinks __P((void));
 char           *flagvalues __P((struct entry *));
 void            freeentry __P((struct entry *));
index eba23e13e939584427390ba50949fa4a9249a5c4..854c3fcd392a9880807c8173bb8e12e4c954c13f 100644 (file)
@@ -41,7 +41,7 @@
 
 #ifndef lint
 static const char rcsid[] =
 
 #ifndef lint
 static const char rcsid[] =
-       "$Id: restore.c,v 1.28 2002/02/04 11:21:20 stelian Exp $";
+       "$Id: restore.c,v 1.29 2002/04/04 08:20:23 stelian Exp $";
 #endif /* not lint */
 
 #include <config.h>
 #endif /* not lint */
 
 #include <config.h>
@@ -746,6 +746,7 @@ createleaves(char *symtabfile)
        struct entry *ep;
        dump_ino_t first;
        long curvol;
        struct entry *ep;
        dump_ino_t first;
        long curvol;
+       int doremove;
 
        if (command == 'R') {
                Vprintf(stdout, "Continue extraction of new leaves\n");
 
        if (command == 'R') {
                Vprintf(stdout, "Continue extraction of new leaves\n");
@@ -796,11 +797,11 @@ createleaves(char *symtabfile)
                 * be removed since its type may change from one leaf type
                 * to another (e.g. "file" to "character special").
                 */
                 * be removed since its type may change from one leaf type
                 * to another (e.g. "file" to "character special").
                 */
-               if ((ep->e_flags & EXTRACT) != 0) {
-                       removeleaf(ep);
-                       ep->e_flags &= ~REMOVED;
-               }
-               (void) extractfile(myname(ep));
+               if ((ep->e_flags & EXTRACT) != 0)
+                       doremove = 1;
+               else
+                       doremove = 0;
+               (void) extractfile(ep, doremove);
                ep->e_flags &= ~(NEW|EXTRACT);
                /*
                 * We checkpoint the restore after every tape reel, so
                ep->e_flags &= ~(NEW|EXTRACT);
                /*
                 * We checkpoint the restore after every tape reel, so
@@ -1029,7 +1030,7 @@ createfiles(void)
                        else {
                                msg("restoring %s\n", myname(ep));
 #endif /* USE_QFA */
                        else {
                                msg("restoring %s\n", myname(ep));
 #endif /* USE_QFA */
-                               (void) extractfile(myname(ep));
+                               (void) extractfile(ep, 0);
 #ifdef USE_QFA
                        }
 #endif /* USE_QFA */
 #ifdef USE_QFA
                        }
 #endif /* USE_QFA */
index 43ce99eaddf42ec9bc0b50fb9102a588f4134df6..453b7eb276e533f694cfc73bfdd7d2ae0b8c32c1 100644 (file)
@@ -46,7 +46,7 @@
 
 #ifndef lint
 static const char rcsid[] =
 
 #ifndef lint
 static const char rcsid[] =
-       "$Id: tape.c,v 1.59 2002/03/28 14:53:01 stelian Exp $";
+       "$Id: tape.c,v 1.60 2002/04/04 08:20:23 stelian Exp $";
 #endif /* not lint */
 
 #include <config.h>
 #endif /* not lint */
 
 #include <config.h>
@@ -718,12 +718,24 @@ struct timeval
 #endif
 
 int
 #endif
 
 int
-extractfile(char *name)
+extractfile(struct entry *ep, int doremove)
 {
        unsigned int flags;
        mode_t mode;
        struct timeval timep[2];
 {
        unsigned int flags;
        mode_t mode;
        struct timeval timep[2];
-       struct entry *ep;
+       char *name = myname(ep);
+
+       /* If removal is requested (-r mode) do remove it unless
+        * we are extracting a metadata only inode */
+       if (spcl.c_flags & DR_METAONLY) {
+               Vprintf(stdout, "file %s is metadata only\n", name);
+       }
+       else {
+               if (doremove) {
+                       removeleaf(ep);
+                       ep->e_flags &= ~REMOVED;
+               }
+       }
 
        curfile.name = name;
        curfile.action = USING;
 
        curfile.name = name;
        curfile.action = USING;
@@ -754,7 +766,6 @@ extractfile(char *name)
 
        case IFDIR:
                if (mflag) {
 
        case IFDIR:
                if (mflag) {
-                       ep = lookupname(name);
                        if (ep == NULL || ep->e_flags & EXTRACT)
                                panic("unextracted directory %s\n", name);
                        skipfile();
                        if (ep == NULL || ep->e_flags & EXTRACT)
                                panic("unextracted directory %s\n", name);
                        skipfile();
@@ -769,16 +780,21 @@ extractfile(char *name)
                uid_t luid = curfile.dip->di_uid;
                gid_t lgid = curfile.dip->di_gid;
 #endif
                uid_t luid = curfile.dip->di_uid;
                gid_t lgid = curfile.dip->di_gid;
 #endif
-               lnkbuf[0] = '\0';
-               pathlen = 0;
-               getfile(xtrlnkfile, xtrlnkskip);
-               if (pathlen == 0) {
-                       Vprintf(stdout,
-                           "%s: zero length symbolic link (ignored)\n", name);
-                       return (GOOD);
+               if (! (spcl.c_flags & DR_METAONLY)) {
+                       lnkbuf[0] = '\0';
+                       pathlen = 0;
+                       getfile(xtrlnkfile, xtrlnkskip);
+                       if (pathlen == 0) {
+                               Vprintf(stdout,
+                                   "%s: zero length symbolic link (ignored)\n", name);
+                               return (GOOD);
+                       }
+                       if (linkit(lnkbuf, name, SYMLINK) == FAIL)
+                               return (FAIL);
                }
                }
-               if (linkit(lnkbuf, name, SYMLINK) == FAIL)
-                       return (FAIL);
+               else
+                       skipfile();
+
 #ifdef HAVE_LCHOWN
                (void) lchown(name, luid, lgid);
 #endif
 #ifdef HAVE_LCHOWN
                (void) lchown(name, luid, lgid);
 #endif
@@ -791,12 +807,14 @@ extractfile(char *name)
                        skipfile();
                        return (GOOD);
                }
                        skipfile();
                        return (GOOD);
                }
-               if (uflag && !Nflag)
-                       (void)unlink(name);
-               if (mkfifo(name, mode) < 0) {
-                       warn("%s: cannot create fifo", name);
-                       skipfile();
-                       return (FAIL);
+               if (! (spcl.c_flags & DR_METAONLY)) {
+                       if (uflag && !Nflag)
+                               (void)unlink(name);
+                       if (mkfifo(name, mode) < 0) {
+                               warn("%s: cannot create fifo", name);
+                               skipfile();
+                               return (FAIL);
+                       }
                }
                (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
                (void) chmod(name, mode);
                }
                (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
                (void) chmod(name, mode);
@@ -817,12 +835,14 @@ extractfile(char *name)
                        skipfile();
                        return (GOOD);
                }
                        skipfile();
                        return (GOOD);
                }
-               if (uflag)
-                       (void)unlink(name);
-               if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
-                       warn("%s: cannot create special file", name);
-                       skipfile();
-                       return (FAIL);
+               if (! (spcl.c_flags & DR_METAONLY)) {
+                       if (uflag)
+                               (void)unlink(name);
+                       if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
+                               warn("%s: cannot create special file", name);
+                               skipfile();
+                               return (FAIL);
+                       }
                }
                (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
                (void) chmod(name, mode);
                }
                (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
                (void) chmod(name, mode);
@@ -840,32 +860,41 @@ extractfile(char *name)
                return (GOOD);
 
        case IFREG:
                return (GOOD);
 
        case IFREG:
+       {
+               uid_t luid = curfile.dip->di_uid;
+               gid_t lgid = curfile.dip->di_gid;
+
                Vprintf(stdout, "extract file %s\n", name);
                if (Nflag) {
                        skipfile();
                        return (GOOD);
                }
                Vprintf(stdout, "extract file %s\n", name);
                if (Nflag) {
                        skipfile();
                        return (GOOD);
                }
-               if (uflag)
-                       (void)unlink(name);
-               if ((ofile = OPEN(name, O_WRONLY | O_CREAT | O_TRUNC,
-                   0666)) < 0) {
-                       warn("%s: cannot create file", name);
-                       skipfile();
-                       return (FAIL);
+               if (! (spcl.c_flags & DR_METAONLY)) {
+                       if (uflag)
+                               (void)unlink(name);
+                       if ((ofile = OPEN(name, O_WRONLY | O_CREAT | O_TRUNC,
+                           0666)) < 0) {
+                               warn("%s: cannot create file", name);
+                               skipfile();
+                               return (FAIL);
+                       }
+                       getfile(xtrfile, xtrskip);
+                       (void) close(ofile);
                }
                }
-               (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
-               (void) fchmod(ofile, mode);
+               else
+                       skipfile();
+               (void) chown(name, luid, lgid);
+               (void) chmod(name, mode);
                if (flags)
 #ifdef __linux__
                if (flags)
 #ifdef __linux__
-                       (void) setflags(ofile, flags);
+                       (void) fsetflags(name, flags);
 #else
 #else
-                       (void) fchflags(ofile, flags);
+                       (void) chflags(name, flags);
 #endif
 #endif
-               getfile(xtrfile, xtrskip);
-               (void) close(ofile);
                utimes(name, timep);
                return (GOOD);
        }
                utimes(name, timep);
                return (GOOD);
        }
+       }
        /* NOTREACHED */
 }
 
        /* NOTREACHED */
 }
 
@@ -1260,6 +1289,10 @@ comparefile(char *name)
                        name, mode & 07777, sb.st_mode & 07777);
                do_compare_error;
        }
                        name, mode & 07777, sb.st_mode & 07777);
                do_compare_error;
        }
+       if (spcl.c_flags & DR_METAONLY) {
+               skipfile();
+               return;
+       }
        switch (mode & IFMT) {
        default:
                skipfile();
        switch (mode & IFMT) {
        default:
                skipfile();