* Stelian Pop <pop@noos.fr>, 1999-2000
* Stelian Pop <pop@noos.fr> - Alcôve <www.alcove.fr>, 2000
*
- * $Id: dumprestore.h,v 1.9 2000/12/21 11:14:53 stelian Exp $
+ * $Id: dumprestore.h,v 1.10 2001/02/21 16:13:05 stelian Exp $
*/
/*
*/
#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 */
+
+/* used for compressed dump tapes */
+struct tapebuf {
+ int32_t clen; /* compressed length of data */
+ int32_t unclen; /* uncompressed length of data */
+ char buf[0]; /* the data */
+};
#endif /* !_DUMPRESTORE_H_ */
/* Define this to 64 if you want Large File System support */
#undef _FILE_OFFSET_BITS
+
+/* Define this if you have zlib compression library */
+#undef HAVE_ZLIB
fi
fi
+ac_safe=`echo "zlib.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for zlib.h""... $ac_c" 1>&6
+echo "configure:1831: checking for zlib.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1836 "configure"
+#include "confdefs.h"
+#include <zlib.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1841: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ zlib_h=yes
+else
+ echo "$ac_t""no" 1>&6
+zlib_h=no
+fi
+
+echo $ac_n "checking for compress2 in -lz""... $ac_c" 1>&6
+echo "configure:1864: checking for compress2 in -lz" >&5
+ac_lib_var=`echo z'_'compress2 | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lz $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1872 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char compress2();
+
+int main() {
+compress2()
+; return 0; }
+EOF
+if { (eval echo configure:1883: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ zlib_lib=yes
+else
+ echo "$ac_t""no" 1>&6
+zlib_lib=no
+fi
+
+if test "$zlib_h" = yes -a "$zlib_lib" = yes; then
+ ZLIB="-lz"
+ cat >> confdefs.h <<\EOF
+#define HAVE_ZLIB 1
+EOF
+
+else
+ ZLIB=""
+fi
+
+
for ac_func in err errx verr verrx vwarn vwarnx warn warnx realpath lchown
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1832: checking for $ac_func" >&5
+echo "configure:1918: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1837 "configure"
+#line 1923 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
; return 0; }
EOF
-if { (eval echo configure:1860: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1946: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
done
echo $ac_n "checking for glob""... $ac_c" 1>&6
-echo "configure:1885: checking for glob" >&5
+echo "configure:1971: checking for glob" >&5
if eval "test \"`echo '$''{'ac_cv_func_glob'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1890 "configure"
+#line 1976 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char glob(); below. */
; return 0; }
EOF
-if { (eval echo configure:1913: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1999: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_glob=yes"
else
if test "$ac_cv_func_glob" = "yes"; then
cat > conftest.$ac_ext <<EOF
-#line 1935 "configure"
+#line 2021 "configure"
#include "confdefs.h"
# include <glob.h>
fi
echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1963: checking for ANSI C header files" >&5
+echo "configure:2049: checking for ANSI C header files" >&5
if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 1968 "configure"
+#line 2054 "configure"
#include "confdefs.h"
#include <stdlib.h>
#include <stdarg.h>
#include <float.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1976: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2062: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
cat > conftest.$ac_ext <<EOF
-#line 1993 "configure"
+#line 2079 "configure"
#include "confdefs.h"
#include <string.h>
EOF
if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
cat > conftest.$ac_ext <<EOF
-#line 2011 "configure"
+#line 2097 "configure"
#include "confdefs.h"
#include <stdlib.h>
EOF
:
else
cat > conftest.$ac_ext <<EOF
-#line 2032 "configure"
+#line 2118 "configure"
#include "confdefs.h"
#include <ctype.h>
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
exit (0); }
EOF
-if { (eval echo configure:2043: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2129: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
:
else
fi
echo $ac_n "checking for quad_t""... $ac_c" 1>&6
-echo "configure:2067: checking for quad_t" >&5
+echo "configure:2153: checking for quad_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_quad_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 2072 "configure"
+#line 2158 "configure"
#include "confdefs.h"
#include <sys/types.h>
#if STDC_HEADERS
fi
echo $ac_n "checking for u_quad_t""... $ac_c" 1>&6
-echo "configure:2100: checking for u_quad_t" >&5
+echo "configure:2186: checking for u_quad_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_u_quad_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 2105 "configure"
+#line 2191 "configure"
#include "confdefs.h"
#include <sys/types.h>
#if STDC_HEADERS
s%@MANMODE@%$MANMODE%g
s%@DUMPDATESPATH@%$DUMPDATESPATH%g
s%@CPP@%$CPP%g
+s%@ZLIB@%$ZLIB%g
s%@top_builddir@%$top_builddir%g
CEOF
fi
fi
+dnl
+dnl Check for zlib headers and libraries
+dnl
+AC_CHECK_HEADER(zlib.h, [zlib_h=yes], [zlib_h=no])
+AC_CHECK_LIB(z, compress2, [zlib_lib=yes], [zlib_lib=no])
+if test "$zlib_h" = yes -a "$zlib_lib" = yes; then
+ ZLIB="-lz"
+ AC_DEFINE(HAVE_ZLIB)
+else
+ ZLIB=""
+fi
+AC_SUBST(ZLIB)
+
dnl
dnl Check for library functions
dnl
-# $Id: Makefile.in,v 1.4 1999/10/11 13:31:10 stelian Exp $
+# $Id: Makefile.in,v 1.5 2001/02/21 16:13:05 stelian Exp $
top_srcdir= @top_srcdir@
srcdir= @srcdir@
CFLAGS= @CCOPTS@ -pipe $(OPT) $(GINC) $(INC) $(DEFS) @DUMPDEBUG@
LDFLAGS:= $(LDFLAGS) @STATIC@
-LIBS= $(GLIBS)
+LIBS= $(GLIBS) @ZLIB@
DEPLIBS= ../compat/lib/libcompat.a
PROG= dump
* Stelian Pop <pop@noos.fr>, 1999-2000
* Stelian Pop <pop@noos.fr> - Alcôve <www.alcove.fr>, 2000
*
- * $Id: dump.h,v 1.19 2000/12/21 11:14:53 stelian Exp $
+ * $Id: dump.h,v 1.20 2001/02/21 16:13:05 stelian Exp $
*/
/*-
int etapes; /* estimated number of tapes */
int nonodump; /* if set, do not honor UF_NODUMP user flags */
int unlimited; /* if set, write to end of medium */
-
+int compressed; /* if set, dump is to be compressed */
+long long bytes_written;/* total bytes written to tape */
+long uncomprblks; /* uncompressed blocks written to tape */
int notify; /* notify operator flag */
int blockswritten; /* number of blocks written on current tape */
int tapeno; /* current tape number */
#ifndef lint
static const char rcsid[] =
- "$Id: main.c,v 1.32 2000/12/21 11:14:54 stelian Exp $";
+ "$Id: main.c,v 1.33 2001/02/21 16:13:05 stelian Exp $";
#endif /* not lint */
#include <config.h>
long blocksperfile; /* output blocks per file */
char *host = NULL; /* remote host (if any) */
int sizest = 0; /* return size estimate only */
+int compressed = 0; /* use zlib to compress the output */
+long long bytes_written = 0; /* total bytes written */
+long uncomprblks = 0;/* uncompressed blocks written */
#ifdef __linux__
char *__progname;
obsolete(&argc, &argv);
#ifdef KERBEROS
+#ifdef HAVE_ZLIB
+#define optstring "0123456789aB:b:cd:e:f:F:h:kL:Mns:ST:uWwz"
+#else
#define optstring "0123456789aB:b:cd:e:f:F:h:kL:Mns:ST:uWw"
+#endif /* HAVE_ZLIB */
+#else
+#ifdef HAVE_ZLIB
+#define optstring "0123456789aB:b:cd:e:f:F:h:L:Mns:ST:uWwz"
#else
#define optstring "0123456789aB:b:cd:e:f:F:h:L:Mns:ST:uWw"
-#endif
+#endif /* HAVE_ZLIB */
+#endif /* KERBEROS */
while ((ch = getopt(argc, argv, optstring)) != -1)
#undef optstring
switch (ch) {
case 'w':
lastdump(ch);
exit(X_FINOK); /* do nothing else */
+#ifdef HAVE_ZLIB
+ case 'z':
+ compressed = 1;
+ break;
+#endif /* HAVE_ZLIB */
default:
usage();
msg("Date this dump completed: %s", ctime(&tnow));
msg("Average transfer rate: %ld KB/s\n", xferrate / tapeno);
+ if (compressed) {
+ long tapekb = bytes_written / 1024;
+ double rate = .0005 + (double) spcl.c_tapea / tapekb;
+ msg("Wrote %ldKB uncompressed, %ldKB compressed,"
+ " compression ratio %1.3f\n",
+ spcl.c_tapea, tapekb, rate);
+ }
broadcast("DUMP IS DONE!\7\7\n");
msg("DUMP IS DONE\n");
#ifdef KERBEROS
"k"
#endif
- "MnSu] [-B records] [-b blocksize] [-d density]\n"
+ "MnSu"
+#ifdef HAVE_ZLIB
+ "z"
+#endif
+ "] [-B records] [-b blocksize] [-d density]\n"
"\t%s [-e inode#] [-f file] [-h level] [-s feet] [-T date] filesystem\n"
"\t%s [-W | -w]\n", __progname, white, __progname);
exit(X_STARTUP);
#ifndef lint
static const char rcsid[] =
- "$Id: optr.c,v 1.18 2000/12/21 11:14:54 stelian Exp $";
+ "$Id: optr.c,v 1.19 2001/02/21 16:13:05 stelian Exp $";
#endif /* not lint */
#include <config.h>
print_wmsg(char arg, int dumpme, const char *dev, int level,
const char *mtpt, time_t ddate)
{
- char *date;
+ char *date = NULL;
if (ddate) {
char *d;
#ifndef lint
static const char rcsid[] =
- "$Id: tape.c,v 1.30 2001/02/16 13:38:47 stelian Exp $";
+ "$Id: tape.c,v 1.31 2001/02/21 16:13:05 stelian Exp $";
#endif /* not lint */
#include <config.h>
#include <ext2fs/ext2fs.h>
#endif
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif /* HAVE_ZLIB */
+
#include "dump.h"
int writesize; /* size of malloc()ed buffer for tape */
char *nexttape;
extern pid_t rshpid;
int eot_code = 1;
+long long tapea_bytes = 0; /* bytes_written at start of current volume */
static ssize_t atomic_read __P((int, void *, size_t));
static ssize_t atomic_write __P((int, const void *, size_t));
};
int reqsiz;
+struct slave_results {
+ ssize_t unclen; /* uncompressed length */
+ ssize_t clen; /* compressed length */
+};
+
#define SLAVES 3 /* 1 slave writing, 1 reading, 1 for slack */
struct slave {
int tapea; /* header number at start of this chunk */
static int tapea_volume; /* value of spcl.c_tapea at volume start */
int master; /* pid of master, for sending error signals */
-int tenths; /* length of tape used per block written */
+int tenths; /* length of tape overhead per block written */
static int caught; /* have we caught the signal to proceed? */
static int ready; /* have we reached the lock point without having */
/* received the SIGUSR2 signal from the prev slave? */
* variable, 0.30" to 0.45". The gap is maximal when the tape stops.
*/
if (blocksperfile == 0 && !unlimited)
- tenths = writesize / density +
- (cartridge ? 16 : density == 625 ? 5 : 8);
+ tenths = (cartridge ? 16 : density == 625 ? 5 : 8);
+ else {
+ tenths = 0;
+ density = 1;
+ }
/*
* Allocate tape buffer contiguous with the array of instruction
* packets, so flushtape() can write them together with one write().
#else
ctime(&tnow));
#endif
- msg("Volume %d: %ld tape blocks (%.2fMB)\n", tapeno,
- blocks, ((double)blocks * TP_BSIZE / 1048576));
+ if (! compressed)
+ msg("Volume %d %ld tape blocks (%.2fMB)\n", tapeno,
+ blocks, ((double)blocks * TP_BSIZE / 1048576));
if (ttaken > 0) {
+ long volkb = (bytes_written - tapea_bytes) / 1024;
+ long txfrate = volkb / ttaken;
msg("Volume %d took %d:%02d:%02d\n", tapeno,
ttaken / 3600, (ttaken % 3600) / 60, ttaken % 60);
msg("Volume %d transfer rate: %ld KB/s\n", tapeno,
- blocks / ttaken);
- xferrate += blocks / ttaken;
+ txfrate);
+ xferrate += txfrate;
+ if (compressed) {
+ double rate = .0005 + (double) blocks / (double) volkb;
+ msg("Volume %d %ldKB uncompressed, %ldKB compressed,"
+ " compression ratio %1.3f\n",
+ tapeno, blocks, volkb, rate);
+ }
}
return(tnow);
}
{
int i, blks, got;
long lastfirstrec;
+ struct slave_results returned;
int siz = (char *)nextblock - (char *)slp->req;
/* Read results back from next slave */
if (slp->sent) {
- if (atomic_read( slp->fd, (char *)&got, sizeof got)
- != sizeof got) {
+ if (atomic_read( slp->fd, (char *)&returned, sizeof returned)
+ != sizeof returned) {
perror(" DUMP: error reading command pipe in master");
dumpabort(0);
}
+ got = returned.unclen;
+ bytes_written += returned.clen;
+ if (returned.unclen == returned.clen)
+ uncomprblks++;
slp->sent = 0;
/* Check for errors */
tperror(-got);
/* Check for end of tape */
- if (got < writesize) {
+ if (got == 0) {
msg("End of tape detected\n");
/*
for (i = 0; i < SLAVES; i++) {
if (slaves[i].sent) {
if (atomic_read( slaves[i].fd,
- (char *)&got, sizeof got)
- != sizeof got) {
+ (char *)&returned, sizeof returned)
+ != sizeof returned) {
perror(" DUMP: error reading command pipe in master");
dumpabort(0);
}
slp->inode = curino;
nextblock = slp->tblock;
trecno = 0;
- asize += tenths;
+ asize += tenths + returned.clen / density;
blockswritten += ntrec;
blocksthisvol += ntrec;
if (!pipeout && !unlimited && (blocksperfile ?
{
int f;
int got;
+ struct slave_results returned;
for (f = 0; f < SLAVES; f++) {
/*
* fixme: punt for now.
*/
if (slaves[f].sent) {
- if (atomic_read( slaves[f].fd, (char *)&got, sizeof got)
- != sizeof got) {
+ if (atomic_read( slaves[f].fd, (char *)&returned, sizeof returned)
+ != sizeof returned) {
perror(" DUMP: error reading command pipe in master");
dumpabort(0);
}
+ got = returned.unclen;
+ bytes_written += returned.clen;
+ if (returned.unclen == returned.clen)
+ uncomprblks++;
slaves[f].sent = 0;
if (got < 0)
tperror(-got);
- if (got != writesize) {
+ if (got == 0) {
msg("EOT detected in last 2 tape records!\n");
msg("Use a longer tape, decrease the size estimate\n");
quit("or use no size estimate at all.\n");
register struct slave *tslp;
int i, size, savedtapea, got;
union u_spcl *ntb, *otb;
+ struct slave_results returned;
#ifdef __linux__
int blks;
long lastfirstrec;
* worked ok, otherwise the tape is much too short!
*/
if (slp->sent) {
- if (atomic_read( slp->fd, (char *)&got, sizeof got)
- != sizeof got) {
+ if (atomic_read( slp->fd, (char *)&returned, sizeof returned)
+ != sizeof returned) {
perror(" DUMP: error reading command pipe in master");
dumpabort(0);
}
+ got = returned.unclen;
+ bytes_written += returned.clen;
+ if (returned.clen == returned.unclen)
+ uncomprblks++;
slp->sent = 0;
if (got < 0)
tperror(-got);
- if (got != writesize) {
+ if (got == 0) {
quit("EOT detected at start of the tape!\n");
}
}
slp->firstrec = lastfirstrec + ntrec;
slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
slp->inode = curino;
- asize += tenths;
+ asize += tenths + returned.clen / density;
blockswritten += ntrec;
blocksthisvol += ntrec;
#endif
parentpid = getpid();
tapea_volume = spcl.c_tapea;
+ tapea_bytes = bytes_written;
#ifdef __linux__
(void)time4(&tstart_volume);
#else
spcl.c_volume++;
spcl.c_type = TS_TAPE;
spcl.c_flags |= DR_NEWHEADER;
+ if (compressed)
+ spcl.c_flags |= DR_COMPRESSED;
writeheader((ino_t)slp->inode);
spcl.c_flags &=~ DR_NEWHEADER;
msg("Volume %d started at: %s", tapeno,
}
/*
- * Synchronization - each process has a lockfile, and shares file
- * descriptors to the following process's lockfile. When our write
- * completes, we release our lock on the following process's lock-
- * file, allowing the following process to lock it and proceed. We
- * get the lock back for the next cycle by swapping descriptors.
+ * Synchronization - each process waits for a SIGUSR2 from the
+ * previous process before writing to the tape, and sends SIGUSR2
+ * to the next process when the tape write completes. On tape errors
+ * a SIGUSR1 is sent to the master which then terminates all of the
+ * slaves.
*/
static void
doslave(int cmd, int slave_number)
{
register int nread;
- int nextslave, size, eot_count;
+ int nextslave, size, eot_count, bufsize;
volatile int wrote = 0;
+ char *buffer;
+#ifdef HAVE_ZLIB
+ struct tapebuf *comp_buf = NULL;
+ int compresult, complevel = 6, do_compress = 0;
+ unsigned long worklen;
+#endif /* HAVE_ZLIB */
+ struct slave_results returns;
#ifdef __linux__
errcode_t retval;
#endif
quit("master/slave protocol botched - didn't get pid of next slave.\n");
}
+#ifdef HAVE_ZLIB
+ /* if we're doing a compressed dump, allocate the compress buffer */
+ if (compressed) {
+ comp_buf = malloc(sizeof(struct tapebuf) + TP_BSIZE + writesize);
+ if (comp_buf == NULL)
+ quit("couldn't allocate a compress buffer.\n");
+ }
+#endif /* HAVE_ZLIB */
+
/*
* Get list of blocks to dump, read the blocks into tape buffer
*/
for (trecno = 0; trecno < ntrec;
trecno += p->count, p += p->count) {
- if (p->dblk) {
+ if (p->dblk) { /* read a disk block */
bread(p->dblk, slp->tblock[trecno],
p->count * TP_BSIZE);
- } else {
+ } else { /* read record from pipe */
if (p->count != 1 || atomic_read( cmd,
(char *)slp->tblock[trecno],
TP_BSIZE) != TP_BSIZE)
wrote = 0;
eot_count = 0;
size = 0;
+ buffer = (char *) slp->tblock[0]; /* set write pointer */
+ bufsize = writesize; /* length to write */
+ returns.clen = returns.unclen = bufsize;
+
+#ifdef HAVE_ZLIB
+ /*
+ * If the data can't be compressed it's written with no
+ * prefix as writesize bytes. If it's compressible, it's
+ * written from struct tapebuf with an 8 byte prefix
+ * followed by the data. This will always be less than
+ * writesize. Restore, on a short read, can compare the
+ * length read to the compressed length in the header
+ * to verify that the read was good.
+ */
+
+ if (do_compress) { /* don't compress the first block */
+ comp_buf->clen = comp_buf->unclen = bufsize;
+ worklen = TP_BSIZE + writesize;
+ compresult = compress2(comp_buf->buf, &worklen,
+ (char *)slp->tblock[0], writesize, complevel);
+ if (compresult == Z_OK && worklen <= writesize-32) {
+ /* write the compressed buffer */
+ comp_buf->clen = worklen;
+ buffer = (char *) comp_buf;
+ returns.clen = bufsize = worklen + 8;
+ }
+ }
+ /* compress the remaining blocks */
+ do_compress = compressed;
+#endif /* HAVE_ZLIB */
- while (eot_count < 10 && size < writesize) {
+ while (eot_count < 10 && size < bufsize) {
#ifdef RDUMP
if (host)
- wrote = rmtwrite(slp->tblock[0]+size,
- writesize-size);
+ wrote = rmtwrite(buffer + size, bufsize - size);
else
#endif
- wrote = write(tapefd, slp->tblock[0]+size,
- writesize-size);
+ wrote = write(tapefd, buffer + size, bufsize - size);
#ifdef WRITEDEBUG
printf("slave %d wrote %d\n", slave_number, wrote);
#endif
}
#ifdef WRITEDEBUG
- if (size != writesize)
+ if (size != bufsize)
printf("slave %d only wrote %d out of %d bytes and gave up.\n",
- slave_number, size, writesize);
+ slave_number, size, bufsize);
#endif
/*
}
if (eot_count > 0)
- size = 0;
+ returns.clen = returns.unclen = 0;
/*
* pass errno back to master for special handling
*/
if (wrote < 0)
- size = -errno;
+ returns.unclen = -errno;
/*
- * pass size of write back to master
+ * pass size of data and size of write back to master
* (for EOT handling)
*/
- (void) atomic_write( cmd, (char *)&size, sizeof size);
+ (void) atomic_write( cmd, (char *)&returns, sizeof returns);
/*
- * If partial write, don't want next slave to go.
- * Also jolts him awake.
+ * Signal the next slave to go.
*/
(void) kill(nextslave, SIGUSR2);
}
-# $Id: Makefile.in,v 1.5 2000/05/29 14:17:37 stelian Exp $
+# $Id: Makefile.in,v 1.6 2001/02/21 16:13:05 stelian Exp $
top_srcdir= @top_srcdir@
srcdir= @srcdir@
CFLAGS= @CCOPTS@ -pipe $(OPT) $(DEFS) $(GINC) $(INC) @RESTOREDEBUG@
LDFLAGS:= $(LDFLAGS) @STATIC@
-LIBS= $(GLIBS) -le2p @READLINE@
+LIBS= $(GLIBS) -le2p @READLINE@ @ZLIB@
DEPLIBS= ../compat/lib/libcompat.a
PROG= restore
#ifndef lint
static const char rcsid[] =
- "$Id: main.c,v 1.15 2000/12/21 11:14:54 stelian Exp $";
+ "$Id: main.c,v 1.16 2001/02/21 16:13:05 stelian Exp $";
#endif /* not lint */
#include <config.h>
#include "extern.h"
int bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
-int hflag = 1, mflag = 1, Nflag = 0;
+int hflag = 1, mflag = 1, Nflag = 0, zflag = 0;
int uflag = 0;
int dokerberos = 0;
char command = '\0';
* Stelian Pop <pop@noos.fr>, 1999-2000
* Stelian Pop <pop@noos.fr> - Alcôve <www.alcove.fr>, 2000
*
- * $Id: restore.h,v 1.12 2000/12/21 11:14:54 stelian Exp $
+ * $Id: restore.h,v 1.13 2001/02/21 16:13:05 stelian Exp $
*/
/*
extern int uflag; /* unlink symlink targets */
extern int vflag; /* print out actions taken */
extern int yflag; /* always try to recover from tape errors */
+extern int zflag; /* tape is in compressed format */
/*
* Global variables
*/
#ifndef lint
static const char rcsid[] =
- "$Id: tape.c,v 1.23 2000/12/21 15:01:54 stelian Exp $";
+ "$Id: tape.c,v 1.24 2001/02/21 16:13:05 stelian Exp $";
#endif /* not lint */
#include <config.h>
#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));
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;
{
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) {
/*
* 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