| 1 | This patch adds the --write-devices option, which will try to write |
| 2 | data into a device when used as a destination. |
| 3 | |
| 4 | To use this patch, run these commands for a successful build: |
| 5 | |
| 6 | patch -p1 <patches/write-devices.diff |
| 7 | ./configure (optional if already run) |
| 8 | make |
| 9 | |
| 10 | This patch has not yet been tested by me (Wayne), but was provided |
| 11 | Darryl Dixon. Thanks! |
| 12 | |
| 13 | based-on: 24079e988fc31af4eba56cd2701fdc5a4154980d |
| 14 | diff --git a/generator.c b/generator.c |
| 15 | --- a/generator.c |
| 16 | +++ b/generator.c |
| 17 | @@ -39,6 +39,7 @@ extern int preserve_acls; |
| 18 | extern int preserve_xattrs; |
| 19 | extern int preserve_links; |
| 20 | extern int preserve_devices; |
| 21 | +extern int write_devices; |
| 22 | extern int preserve_specials; |
| 23 | extern int preserve_hard_links; |
| 24 | extern int preserve_executability; |
| 25 | @@ -1533,7 +1534,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, |
| 26 | fnamecmp = fname; |
| 27 | fnamecmp_type = FNAMECMP_FNAME; |
| 28 | |
| 29 | - if (statret == 0 && !S_ISREG(sx.st.st_mode)) { |
| 30 | + if (statret == 0 && !(S_ISREG(sx.st.st_mode) || (write_devices && IS_DEVICE(sx.st.st_mode)))) { |
| 31 | if (delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_FILE) != 0) |
| 32 | goto cleanup; |
| 33 | statret = -1; |
| 34 | diff --git a/options.c b/options.c |
| 35 | --- a/options.c |
| 36 | +++ b/options.c |
| 37 | @@ -48,6 +48,7 @@ int append_mode = 0; |
| 38 | int keep_dirlinks = 0; |
| 39 | int copy_dirlinks = 0; |
| 40 | int copy_links = 0; |
| 41 | +int write_devices = 0; |
| 42 | int preserve_links = 0; |
| 43 | int preserve_hard_links = 0; |
| 44 | int preserve_acls = 0; |
| 45 | @@ -695,6 +696,7 @@ void usage(enum logcode F) |
| 46 | rprintf(F," -o, --owner preserve owner (super-user only)\n"); |
| 47 | rprintf(F," -g, --group preserve group\n"); |
| 48 | rprintf(F," --devices preserve device files (super-user only)\n"); |
| 49 | + rprintf(F," -w --write-devices write to devices as regular files (implies --inplace)\n"); |
| 50 | rprintf(F," --specials preserve special files\n"); |
| 51 | rprintf(F," -D same as --devices --specials\n"); |
| 52 | rprintf(F," -t, --times preserve modification times\n"); |
| 53 | @@ -863,6 +865,7 @@ static struct poptOption long_options[] = { |
| 54 | {"no-D", 0, POPT_ARG_NONE, 0, OPT_NO_D, 0, 0 }, |
| 55 | {"devices", 0, POPT_ARG_VAL, &preserve_devices, 1, 0, 0 }, |
| 56 | {"no-devices", 0, POPT_ARG_VAL, &preserve_devices, 0, 0, 0 }, |
| 57 | + {"write-devices", 'w', POPT_ARG_NONE, 0, 'w', 0, 0 }, |
| 58 | {"specials", 0, POPT_ARG_VAL, &preserve_specials, 1, 0, 0 }, |
| 59 | {"no-specials", 0, POPT_ARG_VAL, &preserve_specials, 0, 0, 0 }, |
| 60 | {"links", 'l', POPT_ARG_VAL, &preserve_links, 1, 0, 0 }, |
| 61 | @@ -1763,6 +1766,11 @@ int parse_arguments(int *argc_p, const char ***argv_p) |
| 62 | return 0; |
| 63 | #endif |
| 64 | |
| 65 | + case 'w': |
| 66 | + write_devices = 1; |
| 67 | + inplace = 1; |
| 68 | + break; |
| 69 | + |
| 70 | default: |
| 71 | /* A large opt value means that set_refuse_options() |
| 72 | * turned this option off. */ |
| 73 | @@ -2646,6 +2654,9 @@ void server_options(char **args, int *argc_p) |
| 74 | else if (remove_source_files) |
| 75 | args[ac++] = "--remove-sent-files"; |
| 76 | |
| 77 | + if (write_devices) |
| 78 | + args[ac++] = "--write-devices"; |
| 79 | + |
| 80 | if (ac > MAX_SERVER_ARGS) { /* Not possible... */ |
| 81 | rprintf(FERROR, "argc overflow in server_options().\n"); |
| 82 | exit_cleanup(RERR_MALLOC); |
| 83 | diff --git a/receiver.c b/receiver.c |
| 84 | --- a/receiver.c |
| 85 | +++ b/receiver.c |
| 86 | @@ -37,6 +37,7 @@ extern int protocol_version; |
| 87 | extern int relative_paths; |
| 88 | extern int preserve_hard_links; |
| 89 | extern int preserve_perms; |
| 90 | +extern int write_devices; |
| 91 | extern int preserve_xattrs; |
| 92 | extern int basis_dir_cnt; |
| 93 | extern int make_backups; |
| 94 | @@ -198,6 +199,7 @@ int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file) |
| 95 | static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, |
| 96 | const char *fname, int fd, OFF_T total_size) |
| 97 | { |
| 98 | + STRUCT_STAT st; |
| 99 | static char file_sum1[MAX_DIGEST_LEN]; |
| 100 | struct map_struct *mapbuf; |
| 101 | struct sum_struct sum; |
| 102 | @@ -317,10 +319,14 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, |
| 103 | goto report_write_error; |
| 104 | |
| 105 | #ifdef HAVE_FTRUNCATE |
| 106 | - if (inplace && fd != -1 |
| 107 | - && ftruncate(fd, offset) < 0) { |
| 108 | - rsyserr(FERROR_XFER, errno, "ftruncate failed on %s", |
| 109 | - full_fname(fname)); |
| 110 | + (void)do_fstat(fd,&st); |
| 111 | + /* Makes no sense to attempt to ftruncate() a block device: */ |
| 112 | + if (!(IS_DEVICE(st.st_mode))) { |
| 113 | + if (inplace && fd != -1 |
| 114 | + && ftruncate(fd, offset) < 0) { |
| 115 | + rsyserr(FERROR_XFER, errno, "ftruncate failed on %s", |
| 116 | + full_fname(fname)); |
| 117 | + } |
| 118 | } |
| 119 | #endif |
| 120 | |
| 121 | @@ -728,11 +734,25 @@ int recv_files(int f_in, int f_out, char *local_name) |
| 122 | continue; |
| 123 | } |
| 124 | |
| 125 | - if (fd1 != -1 && !S_ISREG(st.st_mode)) { |
| 126 | + if (fd1 != -1 && !(S_ISREG(st.st_mode) || (write_devices && IS_DEVICE(st.st_mode)))) { |
| 127 | close(fd1); |
| 128 | fd1 = -1; |
| 129 | } |
| 130 | |
| 131 | + /* On Linux systems (at least), st_size is typically 0 for devices. |
| 132 | + * If so, try to determine the actual device size. */ |
| 133 | + if (fd1 != -1 && IS_DEVICE(st.st_mode) && st.st_size == 0) { |
| 134 | + OFF_T off = lseek(fd1, 0, SEEK_END); |
| 135 | + if (off == (OFF_T) -1) |
| 136 | + rsyserr(FERROR, errno, "failed to seek to end of %s to determine size", fname); |
| 137 | + else { |
| 138 | + st.st_size = off; |
| 139 | + off = lseek(fd1, 0, SEEK_SET); |
| 140 | + if (off != 0) |
| 141 | + rsyserr(FERROR, errno, "failed to seek back to beginning of %s to read it", fname); |
| 142 | + } |
| 143 | + } |
| 144 | + |
| 145 | /* If we're not preserving permissions, change the file-list's |
| 146 | * mode based on the local permissions and some heuristics. */ |
| 147 | if (!preserve_perms) { |