Commit | Line | Data |
---|---|---|
8763cc5d WD |
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 | ||
c1ff70aa | 13 | based-on: a01e3b490eb36ccf9e704840e1b6683dab867550 |
8763cc5d WD |
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; | |
c1ff70aa | 25 | @@ -1532,7 +1533,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, |
8763cc5d WD |
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 }, | |
c1ff70aa | 61 | @@ -1764,6 +1767,11 @@ int parse_arguments(int *argc_p, const char ***argv_p) |
8763cc5d WD |
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. */ | |
c1ff70aa | 73 | @@ -2661,6 +2669,9 @@ void server_options(char **args, int *argc_p) |
8763cc5d WD |
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) { |