summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWayne Davison <wayne@opencoder.net>2022-03-27 12:26:39 -0700
committerWayne Davison <wayne@opencoder.net>2022-03-27 12:52:26 -0700
commit8977815f5d70d1b6747837b41e7e0b5bd672ef01 (patch)
treeadd05cd3b2852ce7c59c413c3b576afc0389611f
parenta48c20c97c151e297d79327912e5c294450c342b (diff)
downloadrsync-8977815f5d70d1b6747837b41e7e0b5bd672ef01.tar.gz
Some `--write-device` fixes.
-rw-r--r--NEWS.md6
-rw-r--r--generator.c18
-rw-r--r--receiver.c10
-rw-r--r--rsync.1.md4
4 files changed, 24 insertions, 14 deletions
diff --git a/NEWS.md b/NEWS.md
index f95c6867..6dfed8d0 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -87,6 +87,12 @@
per-file compression skipping has apparently never worked, so it is now
documented as being ineffective.
+ - Fixed a truncate error when a `--write-devices` copy wrote a file onto a
+ device that was shorter than the device.
+
+ - Made `--write-devices` support both `--checksum` and `--no-whole-file` when
+ copying to a device.
+
- Improved how the [`--stop-at`](rsync.1#opt), [`--stop-after`](rsync.1#opt),
and (the deprecated) [`--time-limit`](rsync.1#opt) options check to see if
the allowed time is over, which should make rsync exit more consistently.
diff --git a/generator.c b/generator.c
index 454fd19f..278e2a6f 100644
--- a/generator.c
+++ b/generator.c
@@ -35,11 +35,11 @@ extern int inc_recurse;
extern int relative_paths;
extern int implied_dirs;
extern int keep_dirlinks;
+extern int write_devices;
extern int preserve_acls;
extern int preserve_xattrs;
extern int preserve_links;
extern int preserve_devices;
-extern int write_devices;
extern int preserve_specials;
extern int preserve_hard_links;
extern int preserve_executability;
@@ -1793,6 +1793,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
goto cleanup;
}
+ if (write_devices && IS_DEVICE(sx.st.st_mode) && sx.st.st_size == 0) {
+ /* This early open into fd skips the regular open below. */
+ if ((fd = do_open(fnamecmp, O_RDONLY, 0)) >= 0)
+ real_sx.st.st_size = sx.st.st_size = get_device_size(fd, fnamecmp);
+ }
+
if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
;
else if (fnamecmp_type >= FNAMECMP_FUZZY)
@@ -1858,7 +1864,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
}
/* open the file */
- if ((fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) {
+ if (fd < 0 && (fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) {
rsyserr(FERROR, errno, "failed to open %s, continuing",
full_fname(fnamecmp));
pretend_missing:
@@ -1875,11 +1881,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
if (inplace && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) {
if (!(backupptr = get_backup_name(fname))) {
- close(fd);
goto cleanup;
}
if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) {
- close(fd);
goto pretend_missing;
}
if (robust_unlink(backupptr) && errno != ENOENT) {
@@ -1887,14 +1891,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
full_fname(backupptr));
unmake_file(back_file);
back_file = NULL;
- close(fd);
goto cleanup;
}
if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
rsyserr(FERROR_XFER, errno, "open %s", full_fname(backupptr));
unmake_file(back_file);
back_file = NULL;
- close(fd);
goto cleanup;
}
fnamecmp_type = FNAMECMP_BACKUP;
@@ -1945,7 +1947,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
write_sum_head(f_out, NULL);
else if (sx.st.st_size <= 0) {
write_sum_head(f_out, NULL);
- close(fd);
} else {
if (generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy) < 0) {
rprintf(FWARNING,
@@ -1953,10 +1954,11 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
fnamecmp);
write_sum_head(f_out, NULL);
}
- close(fd);
}
cleanup:
+ if (fd >= 0)
+ close(fd);
if (back_file) {
int save_preserve_xattrs = preserve_xattrs;
if (f_copy >= 0)
diff --git a/receiver.c b/receiver.c
index 90e1685b..b3a69da0 100644
--- a/receiver.c
+++ b/receiver.c
@@ -808,14 +808,16 @@ int recv_files(int f_in, int f_out, char *local_name)
continue;
}
- if (fd1 != -1 && !(S_ISREG(st.st_mode) || (write_devices && IS_DEVICE(st.st_mode)))) {
+ if (write_devices && IS_DEVICE(st.st_mode)) {
+ if (fd1 != -1 && st.st_size == 0)
+ st.st_size = get_device_size(fd1, fname);
+ /* Mark the file entry as a device so that we don't try to truncate it later on. */
+ file->mode = S_IFBLK | (file->mode & ACCESSPERMS);
+ } else if (fd1 != -1 && !(S_ISREG(st.st_mode))) {
close(fd1);
fd1 = -1;
}
- if (fd1 != -1 && IS_DEVICE(st.st_mode) && st.st_size == 0)
- st.st_size = get_device_size(fd1, 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 --git a/rsync.1.md b/rsync.1.md
index 06024916..ca0ed7f7 100644
--- a/rsync.1.md
+++ b/rsync.1.md
@@ -1481,9 +1481,9 @@ your home directory (remove the '=' for that).
This option implies the [`--inplace`](#opt) option.
Be careful using this, as you should know what devices are present on the
- receiving side of the transfer, especially if running rsync as root.
+ receiving side of the transfer, especially when running rsync as root.
- This option is refused by an rsync daemon.
+ This option is refused by default by an rsync daemon.
0. `--times`, `-t`