]> git.wh0rd.org - dump.git/blobdiff - restore/tape.c
64bit and glibc 2.2.2 fixes.
[dump.git] / restore / tape.c
index d393469355c703b0afc4a22e23bfae384350b503..45d19d22aa8234a12480f424459aeb8e5a513961 100644 (file)
@@ -2,7 +2,8 @@
  *     Ported to Linux's Second Extended File System as part of the
  *     dump and restore backup suit
  *     Remy Card <card@Linux.EU.Org>, 1994-1997
- *     Stelian Pop <pop@cybercable.fr>, 1999-2000
+ *     Stelian Pop <pop@noos.fr>, 1999-2000
+ *     Stelian Pop <pop@noos.fr> - AlcĂ´ve <www.alcove.fr>, 2000
  */
 
 /*
 
 #ifndef lint
 static const char rcsid[] =
-       "$Id: tape.c,v 1.14 2000/03/03 11:00:55 stelian Exp $";
+       "$Id: tape.c,v 1.25 2001/02/22 10:57:40 stelian Exp $";
 #endif /* not lint */
 
+#include <config.h>
 #include <sys/param.h>
 #include <sys/file.h>
 #include <sys/mtio.h>
@@ -55,6 +57,7 @@ static const char rcsid[] =
 
 #ifdef __linux__
 #include <sys/time.h>
+#include <time.h>
 #include <linux/ext2_fs.h>
 #include <bsdcompat.h>
 #else  /* __linux__ */
@@ -70,6 +73,10 @@ static const char rcsid[] =
 #include <string.h>
 #include <unistd.h>
 
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif /* HAVE_ZLIB */
+
 #ifdef __linux__
 #include <ext2fs/ext2fs.h>
 #endif
@@ -86,6 +93,11 @@ static char  magtapeprefix[MAXPATHLEN];
 static int     blkcnt;
 static int     numtrec;
 static char    *tapebuf;
+static char    *tbufptr = NULL;        /* active tape buffer */
+#ifdef HAVE_ZLIB
+static char    *comprbuf;              /* uncompress work buf */
+static size_t  comprlen;
+#endif
 static union   u_spcl endoftapemark;
 static long    blksread;               /* blocks read since last header */
 static long    tpblksread = 0;         /* TP_BSIZE blocks read */
@@ -113,7 +125,9 @@ static int   gethead __P((struct s_spcl *));
 static void     readtape __P((char *));
 static void     setdumpnum __P((void));
 static u_int    swabi __P((u_int));
+#if 0
 static u_long   swabl __P((u_long));
+#endif
 static u_char  *swab64 __P((u_char *, int));
 static u_char  *swab32 __P((u_char *, int));
 static u_char  *swab16 __P((u_char *, int));
@@ -125,6 +139,15 @@ static void         xtrmap __P((char *, size_t));
 static void     xtrmapskip __P((char *, size_t));
 static void     xtrskip __P((char *, size_t));
 
+#define COMPARE_ONTHEFLY 1
+
+#if COMPARE_ONTHEFLY
+static int     ifile;          /* input file for compare */
+static int     cmperror;       /* compare error */
+static void    xtrcmpfile __P((char *, size_t));
+static void    xtrcmpskip __P((char *, size_t));
+#endif
+
 static int readmapflag;
 
 /*
@@ -188,6 +211,14 @@ newtapebuf(long size)
        if (tapebuf == NULL)
                errx(1, "Cannot allocate space for tape buffer");
        tapebufsize = size;
+#ifdef HAVE_ZLIB
+       if (comprbuf != NULL)
+               free(comprbuf);
+       comprlen = size * TP_BSIZE;
+       comprbuf = malloc(comprlen);
+       if (comprbuf == NULL)
+               errx(1, "Cannot allocate space for uncompress buffer");
+#endif /* HAVE_ZLIB */
 }
 
 /*
@@ -226,6 +257,15 @@ setup(void)
                        errx(1, "Tape is not a dump tape");
                fprintf(stderr, "Converting to new file system format.\n");
        }
+
+       if (spcl.c_flags & DR_COMPRESSED) {
+               fprintf(stderr, "Dump tape is compressed.\n");
+#ifdef HAVE_ZLIB
+               zflag = 1;
+#else
+               errx(1,"This restore version doesn't support decompression");
+#endif /* HAVE_ZLIB */
+       }
        if (pipein) {
                endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
                endoftapemark.s_spcl.c_type = TS_END;
@@ -270,7 +310,7 @@ setup(void)
        Dprintf(stdout, "maxino = %ld\n", (long)maxino);
        map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
        if (map == NULL)
-               panic("no memory for active inode map\n");
+               errx(1, "no memory for active inode map");
        usedinomap = map;
        curfile.action = USING;
        getfile(xtrmap, xtrmapskip);
@@ -278,7 +318,7 @@ setup(void)
                errx(1, "Cannot find file dump list");
        map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
        if (map == (char *)NULL)
-               panic("no memory for file dump list\n");
+               errx(1, "no memory for file dump list");
        dumpmap = map;
        curfile.action = USING;
        getfile(xtrmap, xtrmapskip);
@@ -350,7 +390,7 @@ again:
                do      {
                        fprintf(stderr, "Specify next volume #: ");
                        (void) fflush(stderr);
-                       (void) fgets(buf, BUFSIZ, terminal);
+                       (void) fgets(buf, TP_BSIZE, terminal);
                } while (!feof(terminal) && buf[0] == '\n');
                if (feof(terminal))
                        exit(1);
@@ -375,7 +415,7 @@ again:
                fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
                fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
                (void) fflush(stderr);
-               (void) fgets(buf, BUFSIZ, terminal);
+               (void) fgets(buf, TP_BSIZE, terminal);
                if (feof(terminal))
                        exit(1);
                if (!strcmp(buf, "none\n")) {
@@ -537,9 +577,9 @@ printdumpinfo(void)
 #endif
        if (spcl.c_host[0] == '\0')
                return;
-       fprintf(stderr, "Level %d dump of %s on %s:%s\n",
+       fprintf(stdout, "Level %d dump of %s on %s:%s\n",
                spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
-       fprintf(stderr, "Label: %s\n", spcl.c_label);
+       fprintf(stdout, "Label: %s\n", spcl.c_label);
 }
 
 int
@@ -873,6 +913,63 @@ xtrnull(char *buf, size_t size)
        return;
 }
 
+#if COMPARE_ONTHEFLY
+/*
+ * Compare the next block of a file.
+ */
+static void
+xtrcmpfile(char *buf, size_t size)
+{
+       static char cmpbuf[MAXBSIZE];
+
+       if (cmperror)
+               return;
+       
+       if (read(ifile, cmpbuf, size) != size) {
+               fprintf(stderr, "%s: size has changed.\n", 
+                       curfile.name);
+               cmperror = 1;
+               return;
+       }
+       
+       if (memcmp(buf, cmpbuf, size) != 0) {
+               fprintf(stderr, "%s: tape and disk copies are different\n",
+                       curfile.name);
+               cmperror = 1;
+               return;
+       }
+}
+
+/*
+ * Skip over a hole in a file.
+ */
+static void
+xtrcmpskip(char *buf, size_t size)
+{
+       static char cmpbuf[MAXBSIZE];
+       int i;
+
+       if (cmperror)
+               return;
+       
+       if (read(ifile, cmpbuf, size) != size) {
+               fprintf(stderr, "%s: size has changed.\n", 
+                       curfile.name);
+               cmperror = 1;
+               return;
+       }
+
+       for (i = 0; i < size; ++i)
+               if (cmpbuf[i] != '\0') {
+                       fprintf(stderr, "%s: tape and disk copies are different\n",
+                               curfile.name);
+                       cmperror = 1;
+                       return;
+               }
+}
+#endif /* COMPARE_ONTHEFLY */
+
+#if !COMPARE_ONTHEFLY
 static int
 do_cmpfiles(int fd_tape, int fd_disk, long size)
 {
@@ -918,12 +1015,14 @@ cmpfiles(char *tapefile, char *diskfile, struct stat *sbuf_disk)
        if (stat(tapefile, &sbuf_tape) != 0) {
                panic("Can't lstat tmp file %s: %s\n", tapefile,
                      strerror(errno));
+               compare_errors = 1;
        }
 
        if (sbuf_disk->st_size != sbuf_tape.st_size) {
                fprintf(stderr,
                        "%s: size changed from %ld to %ld.\n",
                        diskfile, (long)sbuf_tape.st_size, (long)sbuf_disk->st_size);
+               compare_errors = 1;
 #ifdef COMPARE_FAIL_KEEP_FILE
                return (0);
 #else
@@ -933,10 +1032,12 @@ cmpfiles(char *tapefile, char *diskfile, struct stat *sbuf_disk)
 
        if ((fd_tape = open(tapefile, O_RDONLY)) < 0) {
                panic("Can't open %s: %s\n", tapefile, strerror(errno));
+               compare_errors = 1;
        }
        if ((fd_disk = open(diskfile, O_RDONLY)) < 0) {
                close(fd_tape);
                panic("Can't open %s: %s\n", diskfile, strerror(errno));
+               compare_errors = 1;
        }
 
        if (do_cmpfiles(fd_tape, fd_disk, sbuf_tape.st_size)) {
@@ -944,6 +1045,7 @@ cmpfiles(char *tapefile, char *diskfile, struct stat *sbuf_disk)
                        diskfile);
                close(fd_tape);
                close(fd_disk);
+               compare_errors = 1;
 #ifdef COMPARE_FAIL_KEEP_FILE
                /* rename the file to live in /tmp */
                /* rename `tapefile' to /tmp/<basename of diskfile> */
@@ -977,19 +1079,26 @@ cmpfiles(char *tapefile, char *diskfile, struct stat *sbuf_disk)
        return (1);
 #endif
 }
+#endif /* !COMPARE_ONTHEFLY */
 
+#if !COMPARE_ONTHEFLY
 static char tmpfilename[MAXPATHLEN];
+#endif
 
 void
 comparefile(char *name)
 {
-       static char *tmpfile = NULL;
        int mode;
-       struct stat sb, stemp;
+       struct stat sb;
        int r;
+#if !COMPARE_ONTHEFLY
+       static char *tmpfile = NULL;
+       struct stat stemp;
+#endif
 
        if ((r = lstat(name, &sb)) != 0) {
                warn("%s: does not exist (%d)", name, r);
+               compare_errors = 1;
                skipfile();
                return;
        }
@@ -1004,6 +1113,7 @@ comparefile(char *name)
        if (sb.st_mode != mode) {
                fprintf(stderr, "%s: mode changed from 0%o to 0%o.\n",
                        name, mode & 07777, sb.st_mode & 07777);
+               compare_errors = 1;
        }
        switch (mode & IFMT) {
        default:
@@ -1025,6 +1135,7 @@ comparefile(char *name)
                if (!(sb.st_mode & S_IFLNK)) {
                        fprintf(stderr, "%s: is no longer a symbolic link\n",
                                name);
+                       compare_errors = 1;
                        return;
                }
                lnkbuf[0] = '\0';
@@ -1034,17 +1145,20 @@ comparefile(char *name)
                        fprintf(stderr,
                                "%s: zero length symbolic link (ignored)\n",
                                name);
+                       compare_errors = 1;
                        return;
                }
                if ((lsize = readlink(name, lbuf, MAXPATHLEN)) < 0) {
                        panic("readlink of %s failed: %s", name,
                              strerror(errno));
+                       compare_errors = 1;
                }
                lbuf[lsize] = 0;
                if (strcmp(lbuf, lnkbuf) != 0) {
                        fprintf(stderr,
                                "%s: symbolic link changed from %s to %s.\n",
                                name, lnkbuf, lbuf);
+                       compare_errors = 1;
                        return;
                }
                return;
@@ -1055,6 +1169,7 @@ comparefile(char *name)
                if (!(sb.st_mode & (S_IFCHR|S_IFBLK))) {
                        fprintf(stderr, "%s: no longer a special file\n",
                                name);
+                       compare_errors = 1;
                        skipfile();
                        return;
                }
@@ -1067,11 +1182,34 @@ comparefile(char *name)
                                (int)curfile.dip->di_rdev & 0xff,
                                ((int)sb.st_rdev >> 8) & 0xff,
                                (int)sb.st_rdev & 0xff);
+                       compare_errors = 1;
                }
                skipfile();
                return;
 
        case IFREG:
+#if COMPARE_ONTHEFLY
+               if ((ifile = open(name, O_RDONLY)) < 0) {
+                       panic("Can't open %s: %s\n", name, strerror(errno));
+                       skipfile();
+                       compare_errors = 1;
+               }
+               else {
+                       cmperror = 0;
+                       getfile(xtrcmpfile, xtrcmpskip);
+                       if (!cmperror) {
+                               char c;
+                               if (read(ifile, &c, 1) != 0) {
+                                       fprintf(stderr, "%s: size has changed.\n", 
+                                               name);
+                                       cmperror = 1;
+                               }
+                       }
+                       if (cmperror)
+                               compare_errors = 1;
+                       close(ifile);
+               }
+#else
                if (tmpfile == NULL) {
                        /* argument to mktemp() must not be in RO space: */
                        snprintf(tmpfilename, sizeof(tmpfilename), "%s/restoreCXXXXXX", tmpdir);
@@ -1094,6 +1232,7 @@ comparefile(char *name)
                cmpfiles(tmpfile, name, &sb);
                unlink(tmpfile);
 #endif
+#endif /* COMPARE_ONTHEFLY */
                return;
        }
        /* NOTREACHED */
@@ -1108,13 +1247,19 @@ readtape(char *buf)
 {
        ssize_t rd, newvol, i;
        int cnt, seek_failed;
+#ifdef HAVE_ZLIB
+       int cresult;
+       struct tapebuf* tpb;
+       unsigned long worklen;
+#endif
 
        if (blkcnt < numtrec) {
-               memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
+               memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
                blksread++;
                tpblksread++;
                return;
        }
+       tbufptr = tapebuf;
        for (i = 0; i < ntrec; i++)
                ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
        if (numtrec == 0)
@@ -1128,6 +1273,28 @@ getmore:
        else
 #endif
                i = read(mt, &tapebuf[rd], cnt);
+
+#ifdef HAVE_ZLIB
+       if (i < 0)
+               goto readerror;
+       if (i == 0 && !pipein)
+               goto endoftape;
+
+       if (zflag  && i != ntrec * TP_BSIZE) {
+               tpb = (struct tapebuf *) tapebuf;
+               if (i != tpb->clen + sizeof(struct tapebuf))
+                       errx(1,"tape is not a compressed dump tape");
+               worklen = comprlen;
+               cresult = uncompress(comprbuf, &worklen, tpb->buf, tpb->clen);
+               if (cresult != Z_OK)
+                       errx(1,"tape is not a compressed dump tape");
+               if (worklen != tpb->unclen)
+                       errx(1,"decompression error, length mismatch");
+               i = worklen;
+               tbufptr = comprbuf;
+       }
+#endif /* HAVE_ZLIB */
+
        /*
         * Check for mid-tape short read error.
         * If found, skip rest of buffer and start with the next.
@@ -1162,6 +1329,9 @@ getmore:
        /*
         * Handle read error.
         */
+#ifdef HAVE_ZLIB
+readerror:
+#endif
        if (i < 0) {
                fprintf(stderr, "Tape read error while ");
                switch (curfile.action) {
@@ -1190,12 +1360,19 @@ getmore:
 #endif
                        seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
 
-               if (seek_failed)
-                       err(1, "continuation failed");
+               if (seek_failed) {
+                       warn("continuation failed");
+                       if (!yflag && !reply("assume end-of-tape and continue"))
+                               exit(1);
+                       i = 0;
+               }
        }
        /*
         * Handle end of tape.
         */
+#ifdef HAVE_ZLIB
+endoftape:
+#endif
        if (i == 0) {
                Vprintf(stdout, "End-of-tape encountered\n");
                if (!pipein) {
@@ -1213,7 +1390,7 @@ getmore:
                memmove(&tapebuf[rd], &endoftapemark, TP_BSIZE);
        }
        blkcnt = 0;
-       memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
+       memmove(buf, &tbufptr[(blkcnt++ * TP_BSIZE)], TP_BSIZE);
        blksread++;
        tpblksread++;
 }
@@ -1240,6 +1417,7 @@ findtapeblksize(void)
                                (long)i, TP_BSIZE);
        ntrec = i / TP_BSIZE;
        numtrec = ntrec;
+       tbufptr = tapebuf;
        Vprintf(stdout, "Tape block size is %ld\n", ntrec);
 }
 
@@ -1677,9 +1855,11 @@ swabi(u_int x)
        return (x);
 }
 
+#if 0
 static u_long
 swabl(u_long x)
 {
        swabst((u_char *)"l", (u_char *)&x);
        return (x);
 }
+#endif