diff options
author | Wayne Davison <wayne@opencoder.net> | 2022-03-27 13:36:31 -0700 |
---|---|---|
committer | Wayne Davison <wayne@opencoder.net> | 2022-03-27 14:04:59 -0700 |
commit | 8aa465117f42cd52119b56f873854a590434ea54 (patch) | |
tree | bb405241d214973f95c56565ddc09e5b1382b4fb | |
parent | 8977815f5d70d1b6747837b41e7e0b5bd672ef01 (diff) | |
download | rsync-8aa465117f42cd52119b56f873854a590434ea54.tar.gz |
Add new & improved `--copy-devices` option.
-rw-r--r-- | NEWS.md | 6 | ||||
-rw-r--r-- | flist.c | 31 | ||||
-rw-r--r-- | options.c | 7 | ||||
-rw-r--r-- | rsync.1.md | 11 | ||||
-rw-r--r-- | rsyncd.conf.5.md | 7 | ||||
-rw-r--r-- | sender.c | 10 |
6 files changed, 65 insertions, 7 deletions
@@ -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. @@ -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; @@ -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"; @@ -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: @@ -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)); |