Updated patches to work with the current trunk.
[rsync/rsync-patches.git] / write-devices.diff
CommitLineData
8763cc5d
WD
1This patch adds the --write-devices option, which will try to write
2data into a device when used as a destination.
3
4To 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
10This patch has not yet been tested by me (Wayne), but was provided
11Darryl Dixon. Thanks!
12
5214a41b 13based-on: 24079e988fc31af4eba56cd2701fdc5a4154980d
8763cc5d
WD
14diff --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;
5214a41b 25@@ -1533,7 +1534,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;
34diff --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 },
5214a41b 61@@ -1763,6 +1766,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. */
5214a41b 73@@ -2646,6 +2654,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);
83diff --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) {