rdist 6.1.2
authordm <dm@openbsd.org>
Tue, 5 Mar 1996 03:15:56 +0000 (03:15 +0000)
committerdm <dm@openbsd.org>
Tue, 5 Mar 1996 03:15:56 +0000 (03:15 +0000)
30 files changed:
usr.bin/rdist/child.c
usr.bin/rdist/client.c
usr.bin/rdist/common.c
usr.bin/rdist/config-data.h
usr.bin/rdist/config-def.h
usr.bin/rdist/config.h
usr.bin/rdist/defs.h
usr.bin/rdist/distopt.c
usr.bin/rdist/docmd.c
usr.bin/rdist/expand.c
usr.bin/rdist/gram.y
usr.bin/rdist/isexec.c
usr.bin/rdist/lookup.c
usr.bin/rdist/message.c
usr.bin/rdist/os-openbsd.h
usr.bin/rdist/pathnames.h
usr.bin/rdist/paths.h [new file with mode: 0644]
usr.bin/rdist/rdist.1
usr.bin/rdist/rdist.c
usr.bin/rdist/rshrcmd.c
usr.bin/rdist/setargs.c
usr.bin/rdist/signal.c
usr.bin/rdist/types.h
usr.bin/rdist/version.h
usr.bin/rdistd/filesys.c
usr.bin/rdistd/filesys.h
usr.bin/rdistd/message.c
usr.bin/rdistd/rdistd.1
usr.bin/rdistd/rdistd.c
usr.bin/rdistd/server.c

index 5beac4e..cf4e65a 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: child.c,v 1.1 1996/02/03 12:12:09 dm Exp $";
+"$Id: child.c,v 1.2 1996/03/05 03:15:56 dm Exp $";
 
 static char sccsid[] = "@(#)docmd.c    5.1 (Berkeley) 6/6/85";
 
index 14bd028..bf0cd9b 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: client.c,v 1.1 1996/02/03 12:12:11 dm Exp $";
+"$Id: client.c,v 1.2 1996/03/05 03:15:57 dm Exp $";
 
 static char sccsid[] = "@(#)client.c";
 
@@ -565,6 +565,17 @@ static int senddir(rname, opts, stb, user, group, destdir)
        int len;
        int didupdate = 0;
 
+       /*
+        * Don't descend into directory
+        */
+       if (IS_ON(opts, DO_NODESCEND))
+               return(0);
+
+       if ((d = opendir(target)) == NULL) {
+               error("%s: opendir failed: %s", target, SYSERR);
+               return(-1);
+       }
+
        /*
         * Send recvdir command in recvit() format.
         */
@@ -573,21 +584,10 @@ static int senddir(rname, opts, stb, user, group, destdir)
        if (response() < 0)
                return(-1);
 
-       /*
-        * Don't descend into directory
-        */
-       if (IS_ON(opts, DO_NODESCEND))
-               return(0);
-
        if (IS_ON(opts, DO_REMOVE))
                if (rmchk(opts) > 0)
                        ++didupdate;
        
-       if ((d = opendir(target)) == NULL) {
-               error("%s: opendir failed: %s", target, SYSERR);
-               return(-1);
-       }
-
        optarget = ptarget;
        len = ptarget - target;
        while (dp = readdir(d)) {
index 80c9b11..76bfae3 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: common.c,v 1.1 1996/02/03 12:12:12 dm Exp $";
+"$Id: common.c,v 1.2 1996/03/05 03:15:58 dm Exp $";
 
 static char sccsid[] = "@(#)common.c";
 
@@ -71,6 +71,7 @@ int                   contimedout = FALSE;    /* Connection timed out */
 int                    proto_version = -1;     /* Protocol version */
 int                    rtimeout = RTIMEOUT;    /* Response time out */
 jmp_buf                        finish_jmpbuf;          /* Finish() jmp buffer */
+int                    setjmp_ok = FALSE;      /* setjmp()/longjmp() status */
 char                 **realargv;               /* Real main() argv */
 int                    realargc;               /* Real main() argc */
 opt_t                  options = 0;            /* Global install options */
@@ -186,6 +187,16 @@ extern void finish()
         * There's no valid finish_jmpbuf for the rdist master parent.
         */
        if (!do_fork || amchild || isserver) {
+
+               if (!setjmp_ok) {
+#ifdef DEBUG_SETJMP
+                       error("attemping longjmp() without target");
+                       abort();
+#else
+                       exit(1);
+#endif
+               }
+
                longjmp(finish_jmpbuf, 1);
                /*NOTREACHED*/
                error("Unexpected failure of longjmp() in finish()");
index 9641dc5..71304be 100644 (file)
@@ -33,7 +33,7 @@
  */
 
 /*
- * $Id: config-data.h,v 1.1 1996/02/03 12:12:14 dm Exp $
+ * $Id: config-data.h,v 1.2 1996/03/05 03:15:59 dm Exp $
  * @(#)configdata.h
  */
 
index b6d24f9..15ec973 100644 (file)
@@ -33,7 +33,7 @@
  */
 
 /*
- * $Id: config-def.h,v 1.1 1996/02/03 12:12:15 dm Exp $
+ * $Id: config-def.h,v 1.2 1996/03/05 03:16:00 dm Exp $
  * @(#)configdef.h
  */
 
index f593de6..26a9b8b 100644 (file)
@@ -33,7 +33,7 @@
  */
 
 /*
- * $Id: config.h,v 1.1 1996/02/03 12:12:16 dm Exp $
+ * $Id: config.h,v 1.2 1996/03/05 03:16:01 dm Exp $
  * @(#)config.h
  */
 
@@ -65,7 +65,7 @@
  * don't have the old rdist, then uncomment the "#undef" line.
  */
 #ifndef _PATH_OLDRDIST
-#define _PATH_OLDRDIST "/usr/bin/oldrdist"     /* Enable compat */
+#define _PATH_OLDRDIST "/usr/ucb/oldrdist"     /* Enable compat */
 #endif
 /*#undef  _PATH_OLDRDIST*/                             /* Disable compat */
 
index c369e49..203ef8e 100644 (file)
@@ -34,7 +34,7 @@
  */
 
 /*
- * $Id: defs.h,v 1.2 1996/02/03 12:12:18 dm Exp $
+ * $Id: defs.h,v 1.3 1996/03/05 03:16:01 dm Exp $
  * @(#)defs.h      5.2 (Berkeley) 3/20/86
  */
 
@@ -328,6 +328,7 @@ extern int          realargc;       /* Real argc */
 extern int             rem_r;          /* Remote file descriptor, reading */
 extern int             rem_w;          /* Remote file descriptor, writing */
 extern int             rtimeout;       /* Response time out in seconds */
+extern int             setjmp_ok;      /* setjmp/longjmp flag */
 extern UID_T           userid;         /* User ID of rdist user */
 extern jmp_buf                 finish_jmpbuf;  /* Setjmp buffer for finish() */
 extern struct group    *gr;    /* pointer to static area used by getgrent */
index 9123ee5..465f1cf 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: distopt.c,v 1.1 1996/02/03 12:12:20 dm Exp $";
+"$Id: distopt.c,v 1.2 1996/03/05 03:16:02 dm Exp $";
 
 static char sccsid[] = "@(#)distopt.c";
 
@@ -68,6 +68,7 @@ DISTOPTINFO distoptinfo[] = {
        { DO_QUIET,             "quiet" },
        { DO_REMOVE,            "remove" },
        { DO_SAVETARGETS,       "savetargets" },
+       { DO_SPARSE,            "sparse" },
        { DO_VERIFY,            "verify" },
        { DO_WHOLE,             "whole" },
        { DO_YOUNGER,           "younger" },
index f9ac062..85ac25d 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: docmd.c,v 1.2 1996/02/03 12:12:22 dm Exp $";
+"$Id: docmd.c,v 1.3 1996/03/05 03:16:03 dm Exp $";
 
 static char sccsid[] = "@(#)docmd.c    5.1 (Berkeley) 6/6/85";
 
@@ -432,6 +432,11 @@ static void doarrow(cmd, filev)
        char *rhost;
        int didupdate = 0;
 
+        if (setjmp_ok) {
+               error("reentrant call to doarrow");
+               abort();
+       }
+
        if (!cmd) {
                debugmsg(DM_MISC, "doarrow() NULL cmd parameter");
                return;
@@ -461,12 +466,15 @@ static void doarrow(cmd, filev)
                }
 
                if (setjmp(finish_jmpbuf)) {
+                       setjmp_ok = FALSE;
                        debugmsg(DM_MISC, "setjmp to finish_jmpbuf");
                        markfailed(cmd, cmds);
                        return;
                }
+               setjmp_ok = TRUE;
 
                if (!makeconn(rhost)) {
+                       setjmp_ok = FALSE;
                        markfailed(cmd, cmds);
                        return;
                }
@@ -583,6 +591,7 @@ done:
                }
                ihead = NULL;
        }
+       setjmp_ok = FALSE;
 }
 
 okname(name)
index 82aec43..756d9b8 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: expand.c,v 1.2 1996/02/03 12:12:23 dm Exp $";
+"$Id: expand.c,v 1.3 1996/03/05 03:16:04 dm Exp $";
 
 static char sccsid[] = "@(#)expand.c   5.2 (Berkeley) 3/28/86";
 
index 9e4d451..b8a5864 100644 (file)
@@ -35,7 +35,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: gram.y,v 1.2 1996/02/03 12:12:26 dm Exp $";
+"$Id: gram.y,v 1.3 1996/03/05 03:16:05 dm Exp $";
 
 static char *sccsid = "@(#)gram.y      5.2 (Berkeley) 85/06/21";
 
index 27a6ec4..571f9d7 100644 (file)
@@ -32,7 +32,7 @@
  */
 #ifndef lint
 static char RCSid[] = 
-"$Id: isexec.c,v 1.1 1996/02/03 12:12:27 dm Exp $";
+"$Id: isexec.c,v 1.2 1996/03/05 03:16:06 dm Exp $";
 
 static char sccsid[] = "@(#)client.c";
 
index 1477ac1..327c16c 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: lookup.c,v 1.2 1996/02/03 12:12:29 dm Exp $";
+"$Id: lookup.c,v 1.3 1996/03/05 03:16:07 dm Exp $";
 
 static char sccsid[] = "@(#)lookup.c   5.1 (Berkeley) 6/6/85";
 
index 8724bc5..844b1bb 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: message.c,v 1.1 1996/02/03 12:12:32 dm Exp $";
+"$Id: message.c,v 1.2 1996/03/05 03:16:08 dm Exp $";
 
 static char sccsid[] = "@(#)common.c";
 
index 8abf35f..14e8109 100644 (file)
@@ -33,7 +33,7 @@
  */
 
 /*
- * $Id: os-openbsd.h,v 1.1 1996/02/03 12:12:33 dm Exp $
+ * $Id: os-openbsd.h,v 1.2 1996/03/05 03:16:09 dm Exp $
  */
 
 /*
@@ -72,7 +72,9 @@
  * Determine what routines we have to get filesystem info.
  */
 #define FSI_TYPE       FSI_GETFSSTAT
-#define FSTYPENAME     1
+#ifndef FSTYPENAME
+#define FSTYPENAME     1               /* For OpenBSD 1.x */
+#endif
 
 /*
  * Type of non-blocking I/O.
index 5aeefd1..3a2475d 100644 (file)
@@ -32,7 +32,7 @@
  */
 
 /*
- * $Id: pathnames.h,v 1.2 1996/02/03 12:12:35 dm Exp $
+ * $Id: pathnames.h,v 1.3 1996/03/05 03:16:09 dm Exp $
  * @(#)pathnames.h     5.4 (Berkeley) 8/27/90
  */
 
diff --git a/usr.bin/rdist/paths.h b/usr.bin/rdist/paths.h
new file mode 100644 (file)
index 0000000..ba99f79
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * 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 University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * $Id: paths.h,v 1.1 1996/03/05 03:20:21 dm Exp $
+ * @(#)paths.h
+ */
+
+/*
+ * This file should be used for those systems without their own
+ * <paths.h> system include file.
+ */
+
+#ifndef _PATH_SENDMAIL
+#define _PATH_SENDMAIL         "/usr/lib/sendmail"
+#endif
+#ifndef _PATH_TMP
+#define _PATH_TMP              "/tmp"
+#endif
+#ifndef _PATH_DEVNULL
+#define _PATH_DEVNULL          "/dev/null"
+#endif
+#ifndef _PATH_BSHELL
+#define _PATH_BSHELL           "/bin/sh"
+#endif
+
+#ifndef _PATH_REMSH
+#define _PATH_REMSH            "/usr/ucb/rsh"          /* Remote shell */
+#endif
index e5d3e42..b6e8e6f 100644 (file)
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"    $Id: rdist.1,v 1.2 1996/02/03 12:12:37 dm Exp $
+.\"    $Id: rdist.1,v 1.3 1996/03/05 03:16:10 dm Exp $
 .\"    @(#)rdist.1     6.6 (Berkeley) 5/13/86
 .\"
-.TH RDIST 1 "March 14, 1994"
+.TH RDIST 1 "January 29, 1996"
 .UC 6
 .SH NAME
 rdist \- remote file distribution client program
@@ -452,6 +452,12 @@ Any target file that is updates is first rename from
 .B file
 to
 .B file.OLD.
+.IP \fBsparse\fR
+Enable checking for sparse (aka \fIwholely\fR) files.  One of the most
+common types of sparse files are those produced by
+.B ndbm(3).
+This option adds some additional processing overhead so it should
+only be enabled for targets likely to contain sparse files.
 .RE
 .TP
 .B "\-p \fI<rdistd-path>\fR"
index c07386e..96fb780 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: rdist.c,v 1.1 1996/02/03 12:12:38 dm Exp $";
+"$Id: rdist.c,v 1.2 1996/03/05 03:16:11 dm Exp $";
 
 static char sccsid[] = "@(#)main.c     5.1 (Berkeley) 6/6/85";
 
index 3383edc..24e4a9d 100644 (file)
@@ -6,7 +6,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: rshrcmd.c,v 1.1 1996/02/03 12:12:40 dm Exp $";
+"$Id: rshrcmd.c,v 1.2 1996/03/05 03:16:12 dm Exp $";
 #endif
 
 #include       "defs.h"
index 815ffe3..2b54bd6 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: setargs.c,v 1.1 1996/02/03 12:12:43 dm Exp $";
+"$Id: setargs.c,v 1.2 1996/03/05 03:16:13 dm Exp $";
 
 static char sccsid[] = "@(#)setargs.c";
 
index 7138271..9b45814 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: signal.c,v 1.1 1996/02/03 12:12:44 dm Exp $";
+"$Id: signal.c,v 1.2 1996/03/05 03:16:13 dm Exp $";
 
 static char sccsid[] = "@(#)signal.c";
 
index 63483c0..5c7510c 100644 (file)
@@ -2,7 +2,7 @@
 #define __myTYPES_H__
 
 /*
- * $Id: types.h,v 1.1 1996/02/03 12:12:45 dm Exp $
+ * $Id: types.h,v 1.2 1996/03/05 03:16:15 dm Exp $
  */
 
 /*
@@ -29,6 +29,7 @@
 #define DO_CHKSYM              0x020000
 #define DO_NUMCHKGROUP         0x040000
 #define DO_NUMCHKOWNER         0x080000
+#define DO_SPARSE              0x100000
 
 /*
  * Dist option information
index 7f30f9b..1bbe11b 100644 (file)
@@ -32,7 +32,7 @@
  */
 
 /*
- * $Id: version.h,v 1.1 1996/02/03 12:12:47 dm Exp $
+ * $Id: version.h,v 1.2 1996/03/05 03:16:15 dm Exp $
  */
 
 /*
@@ -50,7 +50,7 @@
 /*
  * Patch level
  */
-#define PATCHLEVEL             1
+#define PATCHLEVEL             2
 
 /*
  * Distribution status
index 5f7586f..135eb79 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: filesys.c,v 1.1 1996/02/03 12:12:57 dm Exp $";
+"$Id: filesys.c,v 1.2 1996/03/05 03:16:17 dm Exp $";
 
 static char sccsid[] = "@(#)filesys.c";
 
@@ -355,7 +355,11 @@ int is_nfs_mounted(path, statbuf, isvalid)
        if ((mnt = (mntent_t *) getmntpt(path, statbuf, isvalid)) == NULL)
                return(-1);
 
-       if (strcmp(mnt->me_type, METYPE_NFS) == 0)
+       /*
+        * We treat "cachefs" just like NFS
+        */
+       if ((strcmp(mnt->me_type, METYPE_NFS) == 0) ||
+           (strcmp(mnt->me_type, "cachefs") == 0))
                return(1);
 
        return(0);
index 6416b36..130df97 100644 (file)
@@ -32,7 +32,7 @@
  */
 
 /*
- * $Id: filesys.h,v 1.1 1996/02/03 12:12:58 dm Exp $
+ * $Id: filesys.h,v 1.2 1996/03/05 03:16:18 dm Exp $
  * @(#)filesys.h
  */
 
index 4b753ad..4880965 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: message.c,v 1.1 1996/02/03 12:12:59 dm Exp $";
+"$Id: message.c,v 1.2 1996/03/05 03:16:18 dm Exp $";
 
 static char sccsid[] = "@(#)common.c";
 
index 10eca5e..eaa17ab 100644 (file)
@@ -30,7 +30,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"    $Id: rdistd.1,v 1.1 1996/02/03 12:13:01 dm Exp $
+.\"    $Id: rdistd.1,v 1.2 1996/03/05 03:16:19 dm Exp $
 .\"    @(#)rdistd.8    6.6 (Berkeley) 5/13/86
 .\"
 .TH RDISTD 8 "June 21, 1992"
index db04524..09e4d65 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static char RCSid[] = 
-"$Id: rdistd.c,v 1.1 1996/02/03 12:13:02 dm Exp $";
+"$Id: rdistd.c,v 1.2 1996/03/05 03:16:20 dm Exp $";
 
 static char sccsid[] = "@(#)rdistd.c";
 
index 7331068..107e78e 100644 (file)
@@ -32,7 +32,7 @@
  */
 #ifndef lint
 static char RCSid[] = 
-"$Id: server.c,v 1.1 1996/02/03 12:13:03 dm Exp $";
+"$Id: server.c,v 1.2 1996/03/05 03:16:21 dm Exp $";
 
 static char sccsid[] = "@(#)server.c   5.3 (Berkeley) 6/7/86";
 
@@ -186,6 +186,8 @@ static int fchog(fd, file, owner, group, mode)
        static char last_group[128];
        static char last_owner[128];
        static GID_T last_gid = (GID_T)-2;
+       static UID_T last_uid = (UID_T)-2;
+       static GID_T last_primegid;
        extern char *locuser;
        register int i;
        UID_T uid;
@@ -196,7 +198,8 @@ static int fchog(fd, file, owner, group, mode)
        if (userid == 0) {      /* running as root; take anything */
                if (*owner == ':') {
                        uid = (UID_T) atoi(owner + 1);
-               } else if (pw == NULL || strcmp(owner, last_owner) != 0) {
+               } else if (last_uid == (UID_T)-2 ||
+                          strcmp(owner, last_owner) != 0) {
                        if ((pw = getpwnam(owner)) == NULL) {
                                if (mode != -1 && IS_ON(mode, S_ISUID)) {
                                        message(MT_NOTICE,
@@ -209,12 +212,13 @@ static int fchog(fd, file, owner, group, mode)
                                        "%s: unknown login name \"%s\"",
                                                target, owner);
                        } else {
-                               uid = pw->pw_uid;
+                               uid      = last_uid      = pw->pw_uid;
+                               primegid = last_primegid = pw->pw_gid;
                                strcpy(last_owner, owner);
                        }
                } else {
-                       uid = pw->pw_uid;
-                       primegid = pw->pw_gid;
+                       uid = last_uid;
+                       primegid = last_primegid;
                }
                if (*group == ':') {
                        gid = (GID_T) atoi(group + 1);
@@ -709,6 +713,24 @@ static char *savetarget(file)
        return(savefile);
 }
 
+/*
+ * See if buf is all zeros (sparse check)
+ */
+static int iszeros (buf, size)
+       char *buf;
+       off_t size;
+{
+       while (size > 0) {
+           if (*buf != CNULL)
+               return(0);
+           buf++;
+           size--;
+       }
+
+       return(1);
+}
+
+  
 /*
  * Receive a file
  */
@@ -722,7 +744,7 @@ static void recvfile(new, opts, mode, owner, group, mtime, atime, size)
        time_t atime;
        off_t size;
 {
-       int f, wrerr, olderrno;
+       int f, wrerr, olderrno, lastwashole = 0, wassparse = 0;
        off_t i;
        register char *cp;
        char *savefile = NULL;
@@ -768,7 +790,31 @@ static void recvfile(new, opts, mode, owner, group, mtime, atime, size)
                amt = BUFSIZ;
                if (i + amt > size)
                        amt = size - i;
-               if (wrerr == 0 && xwrite(f, buf, amt) != amt) {
+               if (IS_ON(opts, DO_SPARSE) && iszeros(buf, amt)) {
+                       if (lseek (f, amt, SEEK_CUR) < 0L) {
+                               olderrno = errno;
+                               wrerr++;
+                       }
+                       lastwashole = 1;
+                       wassparse++;
+               } else {
+                       if (wrerr == 0 && xwrite(f, buf, amt) != amt) {
+                               olderrno = errno;
+                               wrerr++;
+                       }
+                       lastwashole = 0;
+               }
+       }
+
+       if (lastwashole) {
+#if    defined(HAVE_FTRUNCATE)
+               if (write (f, "", 1) != 1 || ftruncate (f, size) < 0)
+#else
+               /* Seek backwards one character and write a null.  */
+               if (lseek (f, (off_t) -1, SEEK_CUR) < 0L
+                   || write (f, "", 1) != 1)
+#endif
+               {
                        olderrno = errno;
                        wrerr++;
                }
@@ -779,6 +825,7 @@ static void recvfile(new, opts, mode, owner, group, mtime, atime, size)
                (void) unlink(new);
                return;
        }
+
        if (wrerr) {
                error("%s: Write error: %s", new, strerror(olderrno));
                (void) close(f);
@@ -895,6 +942,9 @@ static void recvfile(new, opts, mode, owner, group, mtime, atime, size)
                }
        }
 
+       if (wassparse)
+               message (MT_NOTICE, "%s: was sparse", target);
+
        if (IS_ON(opts, DO_COMPARE))
                message(MT_REMOTE|MT_CHANGE, "%s: updated", target);
        else
@@ -1508,8 +1558,11 @@ extern void server()
        register int n;
        extern jmp_buf finish_jmpbuf;
 
-       if (setjmp(finish_jmpbuf))
+       if (setjmp(finish_jmpbuf)) {
+               setjmp_ok = FALSE;
                return;
+       }
+        setjmp_ok = TRUE;
        (void) signal(SIGHUP, sighandler);
        (void) signal(SIGINT, sighandler);
        (void) signal(SIGQUIT, sighandler);
@@ -1530,17 +1583,20 @@ extern void server()
        (void) sendcmd(S_VERSION, NULL);
 
        if (remline(cmdbuf, sizeof(cmdbuf), TRUE) < 0) {
+               setjmp_ok = FALSE;
                error("server: expected control record");
                return;
        }
 
        if (cmdbuf[0] != S_VERSION || !isdigit(cmdbuf[1])) {
+               setjmp_ok = FALSE;
                error("Expected version command, received: \"%s\".", cmdbuf);
                return;
        }
 
        proto_version = atoi(&cmdbuf[1]);
        if (proto_version != VERSION) {
+               setjmp_ok = FALSE;
                error("Protocol version %d is not supported.", proto_version);
                return;
        }
@@ -1553,8 +1609,10 @@ extern void server()
         */
        for ( ; ; ) {
                n = remline(cp = cmdbuf, sizeof(cmdbuf), TRUE);
-               if (n == -1)            /* EOF */
+               if (n == -1) {          /* EOF */
+                       setjmp_ok = FALSE;
                        return;
+               }
                if (n == 0) {
                        error("server: expected control record");
                        continue;
@@ -1631,6 +1689,7 @@ extern void server()
                case C_FERRMSG:         /* Fatal error message */
                        if (cp && *cp)
                                message(MT_FERROR|MT_NOREMOTE, "%s", cp);
+                       setjmp_ok = FALSE;
                        return;
 
                default: