Some `--write-device` fixes.
authorWayne Davison <wayne@opencoder.net>
Sun, 27 Mar 2022 19:26:39 +0000 (12:26 -0700)
committerWayne Davison <wayne@opencoder.net>
Sun, 27 Mar 2022 19:52:26 +0000 (12:52 -0700)
NEWS.md
generator.c
receiver.c
rsync.1.md

diff --git a/NEWS.md b/NEWS.md
index f95c6867b7248c2c24499517e20d3a75f2ee319f..6dfed8d0261984c807f34539c2f558f2febbe887 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
    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.
index 454fd19f347ba8456297b44ad0e02788a6f93f21..278e2a6f68ff03df1253cfddc034295712093dfd 100644 (file)
@@ -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)
index 90e1685be6e2835508b6872293826cf2d1948f91..b3a69da0cb49da526c1018bcb58d111eccd557b9 100644 (file)
@@ -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) {
index 06024916f170a8971456ac12767935305c68e1eb..ca0ed7f7c97003cd608b19ed7832cfedb182ac64 100644 (file)
@@ -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`