+++ /dev/null
-This patch adds the --copy-devices option, which will try to copy
-the data inside a device instead of duplicating the device node.
-
-To use this patch, run these commands for a successful build:
-
- patch -p1 <patches/copy-devices.diff
- ./prepare-source
- ./configure (optional if already run)
- make
-
-based-on: 8977815f5d70d1b6747837b41e7e0b5bd672ef01
-diff --git a/flist.c b/flist.c
---- a/flist.c
-+++ b/flist.c
-@@ -43,6 +43,7 @@ extern int use_qsort;
- extern int xfer_dirs;
- extern int filesfrom_fd;
- extern int one_file_system;
-+extern int copy_devices;
- extern int copy_dirlinks;
- extern int preserve_uid;
- extern int preserve_gid;
-@@ -700,6 +701,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
- int alloc_len, basename_len, linkname_len;
- int extra_len = file_extra_cnt * EXTRA_LEN;
- int first_hlink_ndx = -1;
-+ char real_ISREG_entry;
- int64 file_length;
- #ifdef CAN_SET_NSEC
- uint32 modtime_nsec;
-@@ -814,6 +816,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
- linkname_len = strlen(F_SYMLINK(first)) + 1;
- else
- linkname_len = 0;
-+ real_ISREG_entry = S_ISREG(mode) ? 1 : 0;
- goto create_object;
- }
- }
-@@ -941,10 +944,20 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
- #endif
- linkname_len = 0;
-
-+ if (copy_devices && IS_DEVICE(mode)) {
-+ /* This is impossible in the official release, but some pre-release patches
-+ * didn't convert the device into a file before sending, so we'll do it here
-+ * (even though the length is typically 0 and any checksum data is zeros). */
-+ mode = S_IFREG | (mode & ACCESSPERMS);
-+ modtime = time(NULL); /* The mtime on the device is not up-to-date, so set it to "now". */
-+ real_ISREG_entry = 0;
-+ } else
-+ real_ISREG_entry = S_ISREG(mode) ? 1 : 0;
-+
- #ifdef SUPPORT_HARD_LINKS
- create_object:
- if (preserve_hard_links) {
-- if (protocol_version < 28 && S_ISREG(mode))
-+ if (protocol_version < 28 && real_ISREG_entry)
- xflags |= XMIT_HLINKED;
- if (xflags & XMIT_HLINKED)
- extra_len += (inc_recurse+1) * EXTRA_LEN;
-@@ -1160,8 +1173,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
- }
- #endif
-
-- if (always_checksum && (S_ISREG(mode) || protocol_version < 28)) {
-- if (S_ISREG(mode))
-+ if (always_checksum && (real_ISREG_entry || protocol_version < 28)) {
-+ if (real_ISREG_entry)
- bp = F_SUM(file);
- else {
- /* Prior to 28, we get a useless set of nulls. */
-@@ -1360,6 +1373,18 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
- linkname_len = 0;
- #endif
-
-+ if (copy_devices && am_sender && IS_DEVICE(st.st_mode)) {
-+ if (st.st_size == 0) {
-+ int fd = do_open(fname, O_RDONLY, 0);
-+ if (fd >= 0) {
-+ st.st_size = get_device_size(fd, fname);
-+ close(fd);
-+ }
-+ }
-+ st.st_mode = S_IFREG | (st.st_mode & ACCESSPERMS);
-+ st.st_mtime = time(NULL); /* The mtime on the device is not up-to-date, so set it to "now". */
-+ }
-+
- #ifdef ST_MTIME_NSEC
- if (st.ST_MTIME_NSEC && protocol_version >= 31)
- extra_len += EXTRA_LEN;
-diff --git a/options.c b/options.c
---- a/options.c
-+++ b/options.c
-@@ -47,6 +47,7 @@ int append_mode = 0;
- int keep_dirlinks = 0;
- int copy_dirlinks = 0;
- int copy_links = 0;
-+int copy_devices = 0;
- int write_devices = 0;
- int preserve_links = 0;
- int preserve_hard_links = 0;
-@@ -656,6 +657,7 @@ static struct poptOption long_options[] = {
- {"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 },
-+ {"copy-devices", 0, POPT_ARG_NONE, ©_devices, 0, 0, 0 },
- {"write-devices", 0, POPT_ARG_VAL, &write_devices, 1, 0, 0 },
- {"no-write-devices", 0, POPT_ARG_VAL, &write_devices, 0, 0, 0 },
- {"specials", 0, POPT_ARG_VAL, &preserve_specials, 1, 0, 0 },
-@@ -949,6 +951,7 @@ static void set_refuse_options(void)
- || strcmp("iconv", longName) == 0
- || strcmp("no-iconv", longName) == 0
- || strcmp("checksum-seed", longName) == 0
-+ || strcmp("copy-devices", longName) == 0 /* disable wild-match (it gets refused below) */
- || strcmp("write-devices", longName) == 0 /* disable wild-match (it gets refused below) */
- || strcmp("log-format", longName) == 0 /* aka out-format (NOT log-file-format) */
- || strcmp("sender", longName) == 0
-@@ -960,6 +963,7 @@ static void set_refuse_options(void)
- assert(list_end != NULL);
-
- if (am_daemon) { /* Refused by default, but can be accepted via a negated exact match. */
-+ parse_one_refuse_match(0, "copy-devices", list_end);
- parse_one_refuse_match(0, "write-devices", list_end);
- }
-
-@@ -2917,6 +2921,9 @@ void server_options(char **args, int *argc_p)
- else if (remove_source_files)
- args[ac++] = "--remove-sent-files";
-
-+ if (copy_devices && !am_sender)
-+ args[ac++] = "--copy-devices";
-+
- if (preallocate_files && am_sender)
- args[ac++] = "--preallocate";
-
-diff --git a/rsync.1.md b/rsync.1.md
---- a/rsync.1.md
-+++ b/rsync.1.md
-@@ -373,6 +373,8 @@ has its own detailed description later in this manpage.
- --owner, -o preserve owner (super-user only)
- --group, -g preserve group
- --devices preserve device files (super-user only)
-+--copy-devices copy device contents as a regular file
-+--write-devices write to devices as files (implies --inplace)
- --specials preserve special files
- -D same as --devices --specials
- --times, -t preserve modification times
-@@ -385,7 +387,6 @@ has its own detailed description later in this manpage.
- --fake-super store/recover privileged attrs using xattrs
- --sparse, -S turn sequences of nulls into sparse blocks
- --preallocate allocate dest files before writing them
----write-devices write to devices as files (implies --inplace)
- --dry-run, -n perform a trial run with no changes made
- --whole-file, -W copy files whole (w/o delta-xfer algorithm)
- --checksum-choice=STR choose the checksum algorithm (aka --cc)
-@@ -1473,6 +1474,14 @@ your home directory (remove the '=' for that).
- The `-D` option is equivalent to "[`--devices`](#opt)
- [`--specials`](#opt)".
-
-+0. `--copy-devices`
-+
-+ This tells rsync to treat a device on the sending side as a regular file,
-+ allowing it to be copied to a normal destination file (or another device
-+ if `--write-devices` was also specifed).
-+
-+ This option is refused by default by an rsync daemon.
-+
- 0. `--write-devices`
-
- This tells rsync to treat a device on the receiving side as a regular file,
-diff --git a/rsyncd.conf.5.md b/rsyncd.conf.5.md
---- a/rsyncd.conf.5.md
-+++ b/rsyncd.conf.5.md
-@@ -933,9 +933,10 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
- If you are un-refusing the compress option, you may want to match
- "`!compress*`" if you also want to allow the `--compress-level` option.
-
-- Note that the "write-devices" option is refused by default, but can be
-- explicitly accepted with "`!write-devices`". The options "log-file" and
-- "log-file-format" are forcibly refused and cannot be accepted.
-+ Note that the "copy-devices" & "write-devices" options are refused by
-+ default, but they can be explicitly accepted with "`!copy-devices`" and/or
-+ "`!write-devices`". The options "log-file" and "log-file-format" are
-+ forcibly refused and cannot be accepted.
-
- Here are all the options that are not matched by wild-cards:
-
-diff --git a/sender.c b/sender.c
---- a/sender.c
-+++ b/sender.c
-@@ -37,6 +37,7 @@ extern int io_error;
- extern int flist_eof;
- extern int whole_file;
- extern int allowed_lull;
-+extern int copy_devices;
- extern int preserve_xattrs;
- extern int protocol_version;
- extern int remove_source_files;
-@@ -366,6 +367,15 @@ void send_files(int f_in, int f_out)
- exit_cleanup(RERR_FILEIO);
- }
-
-+ if (IS_DEVICE(st.st_mode)) {
-+ if (!copy_devices) {
-+ rprintf(FERROR, "attempt to copy device contents without --copy-devices\n");
-+ exit_cleanup(RERR_PROTOCOL);
-+ }
-+ if (st.st_size == 0)
-+ st.st_size = get_device_size(fd, fname);
-+ }
-+
- if (append_mode > 0 && st.st_size < F_LENGTH(file)) {
- rprintf(FWARNING, "skipped diminished file: %s\n",
- full_fname(fname));