Hi all,

After some googling I found this message regarding the merged
--copy-devices and --write-devices patch dubbed rw-devices.diff:
http://lists.samba.org/archive/rsync/2010-January/024538.html

Unfortunately it seems the patch has not been included in the
rsync-patches and has become a bit out of date. I've updated the patch
so that is applies cleanly again against the rsync git repository at
this moment in time (3.1.0dev IIRC). Could you reconsider including this
patch in at least rsync-patches and perhaps mainline rsync? I have
included the patch as an attachment.

Many thanks and regards,
Erik

P.S. Please copy me in any replies as I'm not actively monitoring this
list.

--
http://ejtaal.net/

diff -ur rsync-prerwdevices/flist.c rsync/flist.c
--- rsync-prerwdevices/flist.c	2011-07-20 14:49:33.000000000 +0100
+++ rsync/flist.c	2011-07-20 17:02:08.000000000 +0100
@@ -60,6 +60,7 @@
 extern int prune_empty_dirs;
 extern int copy_links;
 extern int copy_unsafe_links;
+extern int rw_devices;
 extern int protocol_version;
 extern int sanitize_paths;
 extern int munge_symlinks;
@@ -218,7 +219,7 @@
 #endif
 }
 
-int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks)
+static int link_stat2(const char *path, STRUCT_STAT *stp, int follow_dirlinks)
 {
 #ifdef SUPPORT_LINKS
 	if (copy_links)
@@ -236,6 +237,28 @@
 #endif
 }
 
+int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks)
+{
+	if (link_stat2(path, stp, follow_dirlinks) != 0)
+		return -1;
+	if (rw_devices && S_ISBLK(stp->st_mode) && stp->st_size == 0) {
+		/* On Linux systems (at least), st_size is typically 0 for devices.
+		 * If so, try to determine the actual device size. */
+		int fdx = do_open(path, O_RDONLY, 0);
+		if (fdx == -1)
+			rsyserr(FERROR, errno, "failed to open device %s to determine size", path);
+		else {
+			OFF_T off = lseek(fdx, 0, SEEK_END);
+			if (off == (OFF_T)-1)
+				rsyserr(FERROR, errno, "failed to seek to end of %s to determine size", path);
+			else
+				stp->st_size = off;
+			close(fdx);
+		}
+	}
+	return 0;
+}
+
 static inline int is_daemon_excluded(const char *fname, int is_dir)
 {
 	if (daemon_filter_list.head
@@ -663,7 +686,7 @@
 #endif
 	strlcpy(lastname, fname, MAXPATHLEN);
 
-	if (S_ISREG(mode) || S_ISLNK(mode))
+	if (S_ISREG(mode) || S_ISLNK(mode) || (rw_devices && S_ISBLK(mode)))
 		stats.total_size += F_LENGTH(file);
 }
 
@@ -1343,7 +1366,8 @@
 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 	if (IS_DEVICE(st.st_mode)) {
 		tmp_rdev = st.st_rdev;
-		st.st_size = 0;
+		if (!rw_devices || !S_ISBLK(st.st_mode))
+			st.st_size = 0;
 	} else if (IS_SPECIAL(st.st_mode))
 		st.st_size = 0;
 #endif
diff -ur rsync-prerwdevices/generator.c rsync/generator.c
--- rsync-prerwdevices/generator.c	2011-07-20 14:49:33.000000000 +0100
+++ rsync/generator.c	2011-07-20 17:02:08.000000000 +0100
@@ -39,6 +39,7 @@
 extern int preserve_xattrs;
 extern int preserve_links;
 extern int preserve_devices;
+extern int rw_devices;
 extern int preserve_specials;
 extern int preserve_hard_links;
 extern int preserve_executability;
@@ -1230,6 +1231,23 @@
 
 		statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir);
 		stat_errno = errno;
+
+		if (statret == 0 && IS_DEVICE(sx.st.st_mode) && sx.st.st_size == 0) {
+			/* On Linux systems (at least), st_size is typically 0 for devices.
+			 * If so, try to determine the actual device size. */
+			int fdx = do_open(fname, O_RDONLY, 0);
+			if ( fdx == -1 ) {
+				rsyserr(FERROR, errno, "failed to open device %s to determine size", fname);
+			}
+			else {
+				OFF_T off = lseek(fdx, 0, SEEK_END);
+				if (off == (OFF_T)-1)
+					rsyserr(FERROR, errno, "failed to seek to end of %s to determine size", fname);
+				else
+					sx.st.st_size = off;
+				close(fdx);
+			}
+		}
 	}
 
 	if (missing_args == 2 && file->mode == 0) {
@@ -1558,7 +1576,7 @@
 		goto cleanup;
 	}
 
-	if (!S_ISREG(file->mode)) {
+	if (!(S_ISREG(file->mode) || (rw_devices && IS_DEVICE(file->mode)))) {
 		if (solo_file)
 			fname = f_name(file, NULL);
 		rprintf(FINFO, "skipping non-regular file \"%s\"\n", fname);
@@ -1595,7 +1613,7 @@
 
 	fnamecmp_type = FNAMECMP_FNAME;
 
-	if (statret == 0 && !S_ISREG(sx.st.st_mode)) {
+	if (statret == 0 && !(S_ISREG(sx.st.st_mode) || (rw_devices && IS_DEVICE(sx.st.st_mode)))) {
 		if (delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_FILE) != 0)
 			goto cleanup;
 		statret = -1;
diff -ur rsync-prerwdevices/options.c rsync/options.c
--- rsync-prerwdevices/options.c	2011-07-20 14:49:33.000000000 +0100
+++ rsync/options.c	2011-07-20 17:02:08.000000000 +0100
@@ -48,6 +48,7 @@
 int keep_dirlinks = 0;
 int copy_dirlinks = 0;
 int copy_links = 0;
+int rw_devices = 0;
 int preserve_links = 0;
 int preserve_hard_links = 0;
 int preserve_acls = 0;
@@ -701,6 +702,7 @@
   rprintf(F," -o, --owner                 preserve owner (super-user only)\n");
   rprintf(F," -g, --group                 preserve group\n");
   rprintf(F,"     --devices               preserve device files (super-user only)\n");
+  rprintf(F,"     --rw-devices            read/write device contents as regular file (implies --inplace)\n");
   rprintf(F,"     --specials              preserve special files\n");
   rprintf(F," -D                          same as --devices --specials\n");
   rprintf(F," -t, --times                 preserve modification times\n");
@@ -878,6 +880,7 @@
   {"no-D",             0,  POPT_ARG_NONE,   0, OPT_NO_D, 0, 0 },
   {"devices",          0,  POPT_ARG_VAL,    &preserve_devices, 1, 0, 0 },
   {"no-devices",       0,  POPT_ARG_VAL,    &preserve_devices, 0, 0, 0 },
+  {"rw-devices",       0,  POPT_ARG_NONE,   &rw_devices, 0, 0, 0 },
   {"specials",         0,  POPT_ARG_VAL,    &preserve_specials, 1, 0, 0 },
   {"no-specials",      0,  POPT_ARG_VAL,    &preserve_specials, 0, 0, 0 },
   {"links",           'l', POPT_ARG_VAL,    &preserve_links, 1, 0, 0 },
@@ -1817,6 +1820,11 @@
 
 	set_output_verbosity(verbose, DEFAULT_PRIORITY);
 
+	if (rw_devices) {
+		inplace = 1;
+		ignore_times = 1;
+	}
+
 	if (do_stats) {
 		parse_output_words(info_words, info_levels,
 			verbose > 1 ? "stats3" : "stats2", DEFAULT_PRIORITY);
@@ -2690,6 +2698,9 @@
 	if (preallocate_files && am_sender)
 		args[ac++] = "--preallocate";
 
+	if (rw_devices)
+		args[ac++] = "--rw-devices";
+
 	if (ac > MAX_SERVER_ARGS) { /* Not possible... */
 		rprintf(FERROR, "argc overflow in server_options().\n");
 		exit_cleanup(RERR_MALLOC);
diff -ur rsync-prerwdevices/receiver.c rsync/receiver.c
--- rsync-prerwdevices/receiver.c	2011-07-20 14:49:33.000000000 +0100
+++ rsync/receiver.c	2011-07-20 17:02:08.000000000 +0100
@@ -38,6 +38,7 @@
 extern int relative_paths;
 extern int preserve_hard_links;
 extern int preserve_perms;
+extern int rw_devices;
 extern int preserve_xattrs;
 extern int basis_dir_cnt;
 extern int make_backups;
@@ -227,6 +228,7 @@
 static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
 			const char *fname, int fd, OFF_T total_size)
 {
+	STRUCT_STAT st;
 	static char file_sum1[MAX_DIGEST_LEN];
 	struct map_struct *mapbuf;
 	struct sum_struct sum;
@@ -369,13 +371,17 @@
 	/* inplace: New data could be shorter than old data.
 	 * preallocate_files: total_size could have been an overestimate.
 	 *     Cut off any extra preallocated zeros from dest file. */
-	if ((inplace
-#ifdef PREALLOCATE_NEEDS_TRUNCATE
-	  || preallocated_len > offset
-#endif
-	  ) && fd != -1 && do_ftruncate(fd, offset) < 0) {
-		rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
-			full_fname(fname));
+	(void)do_fstat(fd,&st);
+	/* Makes no sense to attempt to ftruncate() a block device: */
+	if (!(IS_DEVICE(st.st_mode))) {
+		if ((inplace
+	#ifdef PREALLOCATE_NEEDS_TRUNCATE
+		  || preallocated_len > offset
+	#endif
+		  ) && fd != -1 && do_ftruncate(fd, offset) < 0) {
+			rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
+				full_fname(fname));
+		}
 	}
 #endif
 
@@ -785,11 +791,25 @@
 			continue;
 		}
 
-		if (fd1 != -1 && !S_ISREG(st.st_mode)) {
+		if (fd1 != -1 && !(S_ISREG(st.st_mode) || (rw_devices && IS_DEVICE(st.st_mode)))) {
 			close(fd1);
 			fd1 = -1;
 		}
 
+		/* On Linux systems (at least), st_size is typically 0 for devices.
+		 * If so, try to determine the actual device size. */
+		if (fd1 != -1 && IS_DEVICE(st.st_mode) && st.st_size == 0) {
+			OFF_T off = lseek(fd1, 0, SEEK_END);
+			if (off == (OFF_T) -1)
+				rsyserr(FERROR, errno, "failed to seek to end of %s to determine size", fname);
+			else {
+				st.st_size = off;
+				off = lseek(fd1, 0, SEEK_SET);
+				if (off != 0)
+					rsyserr(FERROR, errno, "failed to seek back to beginning of %s to read it", fname);
+			}
+		}
+
 		/* If we're not preserving permissions, change the file-list's
 		 * mode based on the local permissions and some heuristics. */
 		if (!preserve_perms) {
diff -ur rsync-prerwdevices/rsync.c rsync/rsync.c
--- rsync-prerwdevices/rsync.c	2011-07-20 14:49:33.000000000 +0100
+++ rsync/rsync.c	2011-07-20 17:02:08.000000000 +0100
@@ -33,6 +33,7 @@
 extern int preserve_perms;
 extern int preserve_executability;
 extern int preserve_times;
+extern int rw_devices;
 extern int am_root;
 extern int am_server;
 extern int am_sender;
@@ -395,7 +396,8 @@
 
 	if (iflags & ITEM_TRANSFER) {
 		int i = ndx - cur_flist->ndx_start;
-		if (i < 0 || !S_ISREG(cur_flist->files[i]->mode)) {
+		struct file_struct *file = cur_flist->files[i];
+		if (i < 0 || !(S_ISREG(file->mode) || (rw_devices && IS_DEVICE(file->mode)))) {
 			rprintf(FERROR,
 				"received request to transfer non-regular file: %d [%s]\n",
 				ndx, who_am_i());
diff -ur rsync-prerwdevices/syscall.c rsync/syscall.c
--- rsync-prerwdevices/syscall.c	2011-07-20 14:49:33.000000000 +0100
+++ rsync/syscall.c	2011-07-20 17:02:08.000000000 +0100
@@ -40,6 +40,7 @@
 extern int list_only;
 extern int preserve_perms;
 extern int preserve_executability;
+extern int rw_devices;
 
 #define RETURN_ERROR_IF(x,e) \
 	do { \
@@ -306,20 +307,56 @@
 int do_stat(const char *fname, STRUCT_STAT *st)
 {
 #ifdef USE_STAT64_FUNCS
-	return stat64(fname, st);
+	if (stat64(fname, st) != 0)
+		return -1;
 #else
-	return stat(fname, st);
+	if (stat(fname, st) != 0)
+		return -1;
 #endif
+	if (rw_devices && S_ISBLK(st->st_mode) && st->st_size == 0) {
+		/* On Linux systems (at least), st_size is typically 0 for devices.
+		 * If so, try to determine the actual device size. */
+		int fdx = do_open(fname, O_RDONLY, 0);
+		if (fdx == -1)
+			rsyserr(FERROR, errno, "failed to open device %s to determine size", fname);
+		else {
+			OFF_T off = lseek(fdx, 0, SEEK_END);
+			if (off == (OFF_T)-1)
+				rsyserr(FERROR, errno, "failed to seek to end of %s to determine size", fname);
+			else
+				st->st_size = off;
+			close(fdx);
+		}
+	}
+	return 0;
 }
 
 int do_lstat(const char *fname, STRUCT_STAT *st)
 {
 #ifdef SUPPORT_LINKS
 # ifdef USE_STAT64_FUNCS
-	return lstat64(fname, st);
+	if (lstat64(fname, st) != 0)
+		return -1;
 # else
-	return lstat(fname, st);
+	if (lstat(fname, st) != 0)
+		return -1;
 # endif
+	if (rw_devices && S_ISBLK(st->st_mode) && st->st_size == 0) {
+		/* On Linux systems (at least), st_size is typically 0 for devices.
+		 * If so, try to determine the actual device size. */
+		int fdx = do_open(fname, O_RDONLY, 0);
+		if (fdx == -1)
+			rsyserr(FERROR, errno, "failed to open device %s to determine size", fname);
+		else {
+			OFF_T off = lseek(fdx, 0, SEEK_END);
+			if (off == (OFF_T)-1)
+				rsyserr(FERROR, errno, "failed to seek to end of %s to determine size", fname);
+			else
+				st->st_size = off;
+			close(fdx);
+		}
+	}
+	return 0;
 #else
 	return do_stat(fname, st);
 #endif
@@ -328,10 +365,30 @@
 int do_fstat(int fd, STRUCT_STAT *st)
 {
 #ifdef USE_STAT64_FUNCS
-	return fstat64(fd, st);
+	if (fstat64(fd, st) != 0)
+		return -1;
 #else
-	return fstat(fd, st);
+	if (fstat(fd, st) != 0)
+		return -1;
 #endif
+	if (rw_devices && S_ISBLK(st->st_mode) && st->st_size == 0) {
+		/* On Linux systems (at least), st_size is typically 0 for devices.
+		 * If so, try to determine the actual device size. */
+		OFF_T off_save = lseek(fd, 0, SEEK_CUR);
+		if (off_save == (OFF_T)-1)
+			rsyserr(FERROR, errno, "failed to seek on device inode %lld to read current position", (long long int)(st->st_ino));
+		else {
+			OFF_T off = lseek(fd, 0, SEEK_END);
+			if (off == (OFF_T)-1)
+				rsyserr(FERROR, errno, "failed to seek to end on device inode %lld to determine size", (long long int)(st->st_ino));
+			else
+				st->st_size = off;
+			off = lseek(fd, off_save, SEEK_SET);
+			if (off == (OFF_T)-1)
+				rsyserr(FERROR, errno, "failed to seek to origin position on device inode %lld", (long long int)(st->st_ino));
+		}
+	}
+	return 0;
 }
 
 OFF_T do_lseek(int fd, OFF_T offset, int whence)
-- 
Please use reply-all for most replies to avoid omitting the mailing list.
To unsubscribe or change options: https://lists.samba.org/mailman/listinfo/rsync
Before posting, read: http://www.catb.org/~esr/faqs/smart-questions.html

Reply via email to