* 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.15 2000/05/28 16:52:21 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>
#ifdef __linux__
#include <sys/time.h>
+#include <time.h>
#include <linux/ext2_fs.h>
#include <bsdcompat.h>
#else /* __linux__ */
#include <string.h>
#include <unistd.h>
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif /* HAVE_ZLIB */
+
#ifdef __linux__
#include <ext2fs/ext2fs.h>
#endif
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 */
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));
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;
/*
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 */
}
/*
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;
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);
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);
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);
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")) {
#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
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)
{
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);
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);
cmpfiles(tmpfile, name, &sb);
unlink(tmpfile);
#endif
+#endif /* COMPARE_ONTHEFLY */
return;
}
/* NOTREACHED */
{
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)
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.
/*
* Handle read error.
*/
+#ifdef HAVE_ZLIB
+readerror:
+#endif
if (i < 0) {
fprintf(stderr, "Tape read error while ");
switch (curfile.action) {
#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) {
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++;
}
(long)i, TP_BSIZE);
ntrec = i / TP_BSIZE;
numtrec = ntrec;
+ tbufptr = tapebuf;
Vprintf(stdout, "Tape block size is %ld\n", ntrec);
}
return (x);
}
+#if 0
static u_long
swabl(u_long x)
{
swabst((u_char *)"l", (u_char *)&x);
return (x);
}
+#endif