1 This patch adds the --write-devices option, which will try to write
2 data into a device when used as a destination.
4 To use this patch, run these commands for a successful build:
6 patch -p1 <patches/write-devices.diff
7 ./configure (optional if already run)
10 This patch has not yet been tested by me (Wayne), but was provided
13 based-on: 7c8f180900432e646c0a4bd02e2c4033068dbb7c
14 diff --git a/generator.c 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 @@ -1596,7 +1597,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
27 fnamecmp_type = FNAMECMP_FNAME;
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)
34 diff --git a/options.c b/options.c
37 @@ -48,6 +48,7 @@ int append_mode = 0;
38 int keep_dirlinks = 0;
39 int copy_dirlinks = 0;
41 +int write_devices = 0;
42 int preserve_links = 0;
43 int preserve_hard_links = 0;
44 int preserve_acls = 0;
45 @@ -702,6 +703,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 @@ -879,6 +881,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 @@ -1781,6 +1784,11 @@ int parse_arguments(int *argc_p, const char ***argv_p)
71 /* A large opt value means that set_refuse_options()
72 * turned this option off. */
73 @@ -2680,6 +2688,9 @@ void server_options(char **args, int *argc_p)
74 if (relative_paths && !implied_dirs && (!am_sender || protocol_version >= 30))
75 args[ac++] = "--no-implied-dirs";
78 + args[ac++] = "--write-devices";
80 if (fuzzy_basis && am_sender)
81 args[ac++] = "--fuzzy";
83 diff --git a/receiver.c b/receiver.c
86 @@ -38,6 +38,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 @@ -225,7 +226,7 @@ int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file)
97 static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
98 - const char *fname, int fd, OFF_T total_size)
99 + const char *fname, int fd, struct file_struct *file)
101 static char file_sum1[MAX_DIGEST_LEN];
102 struct map_struct *mapbuf;
103 @@ -275,7 +276,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
104 if (append_mode == 2 && mapbuf) {
105 for (j = CHUNK_SIZE; j < sum.flength; j += CHUNK_SIZE) {
106 if (INFO_GTE(PROGRESS, 1))
107 - show_progress(offset, total_size);
108 + show_progress(offset, F_LENGTH(file));
109 sum_update(map_ptr(mapbuf, offset, CHUNK_SIZE),
112 @@ -283,7 +284,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
113 if (offset < sum.flength) {
114 int32 len = (int32)(sum.flength - offset);
115 if (INFO_GTE(PROGRESS, 1))
116 - show_progress(offset, total_size);
117 + show_progress(offset, F_LENGTH(file));
118 sum_update(map_ptr(mapbuf, offset, len), len);
121 @@ -297,7 +298,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
123 while ((i = recv_token(f_in, &data)) != 0) {
124 if (INFO_GTE(PROGRESS, 1))
125 - show_progress(offset, total_size);
126 + show_progress(offset, F_LENGTH(file));
129 maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH | MSK_ACTIVE_RECEIVER);
130 @@ -373,14 +374,14 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
131 #ifdef PREALLOCATE_NEEDS_TRUNCATE
132 || preallocated_len > offset
134 - ) && fd != -1 && do_ftruncate(fd, offset) < 0) {
135 + ) && fd != -1 && !IS_DEVICE(file->mode) && do_ftruncate(fd, offset) < 0) {
136 rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
141 if (INFO_GTE(PROGRESS, 1))
142 - end_progress(total_size);
143 + end_progress(F_LENGTH(file));
145 if (fd != -1 && offset > 0 && sparse_end(fd, offset) != 0) {
147 @@ -404,9 +405,9 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
151 -static void discard_receive_data(int f_in, OFF_T length)
152 +static void discard_receive_data(int f_in, struct file_struct *file)
154 - receive_data(f_in, NULL, -1, 0, NULL, -1, length);
155 + receive_data(f_in, NULL, -1, 0, NULL, -1, file);
158 static void handle_delayed_updates(char *local_name)
159 @@ -662,7 +663,7 @@ int recv_files(int f_in, int f_out, char *local_name)
160 "(Skipping batched update for%s \"%s\")\n",
161 redoing ? " resend of" : "",
163 - discard_receive_data(f_in, F_LENGTH(file));
164 + discard_receive_data(f_in, file);
165 file->flags |= FLAG_FILE_SENT;
168 @@ -674,13 +675,13 @@ int recv_files(int f_in, int f_out, char *local_name)
169 if (!do_xfers) { /* log the transfer */
170 log_item(FCLIENT, file, iflags, NULL);
172 - discard_receive_data(f_in, F_LENGTH(file));
173 + discard_receive_data(f_in, file);
176 if (write_batch < 0) {
177 log_item(FCLIENT, file, iflags, NULL);
179 - discard_receive_data(f_in, F_LENGTH(file));
180 + discard_receive_data(f_in, file);
184 @@ -763,7 +764,7 @@ int recv_files(int f_in, int f_out, char *local_name)
185 } else if (do_fstat(fd1,&st) != 0) {
186 rsyserr(FERROR_XFER, errno, "fstat %s failed",
187 full_fname(fnamecmp));
188 - discard_receive_data(f_in, F_LENGTH(file));
189 + discard_receive_data(f_in, file);
192 send_msg_int(MSG_NO_SEND, ndx);
193 @@ -778,18 +779,32 @@ int recv_files(int f_in, int f_out, char *local_name)
195 rprintf(FERROR_XFER, "recv_files: %s is a directory\n",
196 full_fname(fnamecmp));
197 - discard_receive_data(f_in, F_LENGTH(file));
198 + discard_receive_data(f_in, file);
201 send_msg_int(MSG_NO_SEND, ndx);
205 - if (fd1 != -1 && !S_ISREG(st.st_mode)) {
206 + if (fd1 != -1 && !(S_ISREG(st.st_mode) || (write_devices && IS_DEVICE(st.st_mode)))) {
211 + /* On Linux systems (at least), st_size is typically 0 for devices.
212 + * If so, try to determine the actual device size. */
213 + if (fd1 != -1 && IS_DEVICE(st.st_mode) && st.st_size == 0) {
214 + OFF_T off = lseek(fd1, 0, SEEK_END);
215 + if (off == (OFF_T) -1)
216 + rsyserr(FERROR, errno, "failed to seek to end of %s to determine size", fname);
219 + off = lseek(fd1, 0, SEEK_SET);
221 + rsyserr(FERROR, errno, "failed to seek back to beginning of %s to read it", fname);
225 /* If we're not preserving permissions, change the file-list's
226 * mode based on the local permissions and some heuristics. */
227 if (!preserve_perms) {
228 @@ -820,7 +835,7 @@ int recv_files(int f_in, int f_out, char *local_name)
232 - discard_receive_data(f_in, F_LENGTH(file));
233 + discard_receive_data(f_in, file);
237 @@ -835,8 +850,7 @@ int recv_files(int f_in, int f_out, char *local_name)
238 rprintf(FINFO, "%s\n", fname);
241 - recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
242 - fname, fd2, F_LENGTH(file));
243 + recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size, fname, fd2, file);
245 log_item(log_code, file, iflags, NULL);