Change sending/receiving/storing of the rdev value for special files.
Since the value is not needed, the (superfluous) sending of the value
is optimized so that a valid rdev value is sent as efficiently as
possible.  The receiver no longer caches an rdev value for special
files, and the generator will always pass a 0 rdev value to do_mknod()
for special files. Fixes bug #6280.
diff --git a/NEWS b/NEWS
index 574f652..e9a84b4 100644
--- a/NEWS
+++ b/NEWS
@@ -51,3 +51,5 @@
 
     - Complain and die if the user tries to combine --remove-source-files (or
       the deprecated --remove-sent-files) with --read-batch.
+
+    - Fixed an failure transferring special files from Solaris to Linux.
diff --git a/flist.c b/flist.c
index a6107b4..83effc0 100644
--- a/flist.c
+++ b/flist.c
@@ -425,8 +425,7 @@
 	else
 		mode = file->mode;
 
-	if ((preserve_devices && IS_DEVICE(mode))
-	 || (preserve_specials && IS_SPECIAL(mode))) {
+	if (preserve_devices && IS_DEVICE(mode)) {
 		if (protocol_version < 28) {
 			if (tmp_rdev == rdev)
 				xflags |= XMIT_SAME_RDEV_pre28;
@@ -441,6 +440,17 @@
 			if (protocol_version < 30 && (uint32)minor(rdev) <= 0xFFu)
 				xflags |= XMIT_RDEV_MINOR_8_pre30;
 		}
+	} else if (preserve_specials && IS_SPECIAL(mode)) {
+		/* Special files don't need an rdev number, so just make
+		 * the historical transmission of the value efficient. */
+		if (protocol_version < 28)
+			xflags |= XMIT_SAME_RDEV_pre28;
+		else {
+			rdev = MAKEDEV(major(rdev), 0);
+			xflags |= XMIT_SAME_RDEV_MAJOR;
+			if (protocol_version < 30)
+				xflags |= XMIT_RDEV_MINOR_8_pre30;
+		}
 	} else if (protocol_version < 28)
 		rdev = MAKEDEV(0, 0);
 	if (!preserve_uid || ((uid_t)F_OWNER(file) == uid && *lastname))
@@ -725,8 +735,7 @@
 				uid = F_OWNER(first);
 			if (preserve_gid)
 				gid = F_GROUP(first);
-			if ((preserve_devices && IS_DEVICE(mode))
-			 || (preserve_specials && IS_SPECIAL(mode))) {
+			if (preserve_devices && IS_DEVICE(mode)) {
 				uint32 *devp = F_RDEV_P(first);
 				rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
 				extra_len += DEV_EXTRA_CNT * EXTRA_LEN;
@@ -801,7 +810,8 @@
 				rdev_minor = read_int(f);
 			rdev = MAKEDEV(rdev_major, rdev_minor);
 		}
-		extra_len += DEV_EXTRA_CNT * EXTRA_LEN;
+		if (IS_DEVICE(mode))
+			extra_len += DEV_EXTRA_CNT * EXTRA_LEN;
 		file_length = 0;
 	} else if (protocol_version < 28)
 		rdev = MAKEDEV(0, 0);
@@ -942,8 +952,7 @@
 		}
 	}
 
-	if ((preserve_devices && IS_DEVICE(mode))
-	 || (preserve_specials && IS_SPECIAL(mode))) {
+	if (preserve_devices && IS_DEVICE(mode)) {
 		uint32 *devp = F_RDEV_P(file);
 		DEV_MAJOR(devp) = major(rdev);
 		DEV_MINOR(devp) = minor(rdev);
@@ -1257,10 +1266,11 @@
 #endif
 
 #ifdef HAVE_STRUCT_STAT_ST_RDEV
-	if (IS_DEVICE(st.st_mode) || IS_SPECIAL(st.st_mode)) {
+	if (IS_DEVICE(st.st_mode)) {
 		tmp_rdev = st.st_rdev;
 		st.st_size = 0;
-	}
+	} else if (IS_SPECIAL(st.st_mode))
+		st.st_size = 0;
 #endif
 
 	file->flags = flags;
diff --git a/generator.c b/generator.c
index 6c7bf89..fb832af 100644
--- a/generator.c
+++ b/generator.c
@@ -1124,8 +1124,8 @@
 		}
 		switch (type) {
 		case TYPE_DIR:
-			break;
 		case TYPE_SPECIAL:
+			break;
 		case TYPE_DEVICE:
 			devp = F_RDEV_P(file);
 			if (sxp->st.st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)))
@@ -1613,8 +1613,12 @@
 
 	if ((am_root && preserve_devices && IS_DEVICE(file->mode))
 	 || (preserve_specials && IS_SPECIAL(file->mode))) {
-		uint32 *devp = F_RDEV_P(file);
-		dev_t rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
+		dev_t rdev;
+		if (IS_DEVICE(file->mode)) {
+			uint32 *devp = F_RDEV_P(file);
+			rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
+		} else
+			rdev = 0;
 		if (statret == 0) {
 			int del_for_flag;
 			if (IS_DEVICE(file->mode)) {
@@ -1628,7 +1632,7 @@
 			}
 			if (statret == 0
 			 && BITS_EQUAL(sx.st.st_mode, file->mode, _S_IFMT)
-			 && sx.st.st_rdev == rdev) {
+			 && (IS_SPECIAL(sx.st.st_mode) || sx.st.st_rdev == rdev)) {
 				/* The device or special file is identical. */
 				set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
 				if (itemizing)
diff --git a/xattrs.c b/xattrs.c
index 674d357..63b118a 100644
--- a/xattrs.c
+++ b/xattrs.c
@@ -989,7 +989,7 @@
 	fst.st_mode &= (_S_IFMT | CHMOD_BITS);
 	fmode = new_mode & (_S_IFMT | CHMOD_BITS);
 
-	if (IS_DEVICE(fmode) || IS_SPECIAL(fmode)) {
+	if (IS_DEVICE(fmode)) {
 		uint32 *devp = F_RDEV_P(file);
 		rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
 	} else
@@ -1000,7 +1000,7 @@
 	     | (S_ISDIR(fst.st_mode) ? 0700 : 0600);
 	if (fst.st_mode != mode)
 		do_chmod(fname, mode);
-	if (!IS_DEVICE(fst.st_mode) && !IS_SPECIAL(fst.st_mode))
+	if (!IS_DEVICE(fst.st_mode))
 		fst.st_rdev = 0; /* just in case */
 
 	if (mode == fmode && fst.st_rdev == rdev