summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWayne Davison <wayne@opencoder.net>2022-03-27 13:36:31 -0700
committerWayne Davison <wayne@opencoder.net>2022-03-27 14:04:59 -0700
commit8aa465117f42cd52119b56f873854a590434ea54 (patch)
treebb405241d214973f95c56565ddc09e5b1382b4fb
parent8977815f5d70d1b6747837b41e7e0b5bd672ef01 (diff)
downloadrsync-8aa465117f42cd52119b56f873854a590434ea54.tar.gz
Add new & improved `--copy-devices` option.
-rw-r--r--NEWS.md6
-rw-r--r--flist.c31
-rw-r--r--options.c7
-rw-r--r--rsync.1.md11
-rw-r--r--rsyncd.conf.5.md7
-rw-r--r--sender.c10
6 files changed, 65 insertions, 7 deletions
diff --git a/NEWS.md b/NEWS.md
index 6dfed8d0..2b08dfa8 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -116,6 +116,12 @@
- Added the [`--fsync`](rsync.1#opt) option (promoted from the patches repo).
+ - Added the [`--copy-devices`](rsync.1#opt) option. Compared to the
+ historical version from the rsync-patches repo, this version: properly
+ handles `--checksum`; fixes a truncation bug when doing an `--inplace` copy
+ onto a longer file; fixes several bugs in the `--itemize` output; and only
+ the sending side needs the enhanced rsync for the copy to work.
+
- Reduced memory usage for an incremental transfer that has a bunch of small
directories.
diff --git a/flist.c b/flist.c
index d72ba609..1ba306bc 100644
--- 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
index d08f0003..93bdb237 100644
--- 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, &copy_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
index ca0ed7f7..313025df 100644
--- 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
index c386403b..c61765a7 100644
--- 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
index 92724c81..9159da4d 100644
--- 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));