int keep_dirlinks = 0;
int copy_dirlinks = 0;
int copy_links = 0;
+int write_devices = 0;
int preserve_links = 0;
int preserve_hard_links = 0;
int preserve_acls = 0;
#else
rprintf(F," --preallocate pre-allocate dest files on remote receiver\n");
#endif
+ rprintf(F," --write-devices write to devices as files (implies --inplace)\n");
rprintf(F," -n, --dry-run perform a trial run with no changes made\n");
rprintf(F," -W, --whole-file copy files whole (without delta-xfer algorithm)\n");
rprintf(F," --checksum-choice=STR choose the checksum algorithms\n");
{"no-D", 0, POPT_ARG_NONE, 0, OPT_NO_D, 0, 0 },
{"devices", 0, POPT_ARG_VAL, &preserve_devices, 1, 0, 0 },
{"no-devices", 0, POPT_ARG_VAL, &preserve_devices, 0, 0, 0 },
+ {"write-devices", 0, POPT_ARG_VAL, &write_devices, 1, 0, 0 },
+ {"no-write-devices", 0, POPT_ARG_VAL, &write_devices, 0, 0, 0 },
{"specials", 0, POPT_ARG_VAL, &preserve_specials, 1, 0, 0 },
{"no-specials", 0, POPT_ARG_VAL, &preserve_specials, 0, 0, 0 },
{"links", 'l', POPT_ARG_VAL, &preserve_links, 1, 0, 0 },
if (!*lp_charset(module_id))
set_refuse_options("iconv");
#endif
+ set_refuse_options("write-devices");
}
#ifdef ICONV_OPTION
inplace = 1;
}
+ if (write_devices) {
+ if (refused_inplace) {
+ create_refuse_error(refused_inplace);
+ return 0;
+ }
+ inplace = 1;
+ }
+
if (delay_updates && !partial_dir)
partial_dir = tmp_partialdir;
if (relative_paths && !implied_dirs && (!am_sender || protocol_version >= 30))
args[ac++] = "--no-implied-dirs";
+ if (write_devices)
+ args[ac++] = "--write-devices";
+
if (remove_source_files == 1)
args[ac++] = "--remove-source-files";
else if (remove_source_files)
extern int relative_paths;
extern int preserve_hard_links;
extern int preserve_perms;
+extern int write_devices;
extern int preserve_xattrs;
extern int basis_dir_cnt;
extern int make_backups;
}
static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
- const char *fname, int fd, OFF_T total_size)
+ const char *fname, int fd, struct file_struct *file)
{
static char file_sum1[MAX_DIGEST_LEN];
struct map_struct *mapbuf;
struct sum_struct sum;
int sum_len;
int32 len;
+ OFF_T total_size = F_LENGTH(file);
OFF_T offset = 0;
OFF_T offset2;
char *data;
/* inplace: New data could be shorter than old data.
* preallocate_files: total_size could have been an overestimate.
* Cut off any extra preallocated zeros from dest file. */
- if ((inplace || preallocated_len > offset) && fd != -1 && do_ftruncate(fd, offset) < 0) {
+ if ((inplace || preallocated_len > offset) && fd != -1 && !IS_DEVICE(file->mode) && do_ftruncate(fd, offset) < 0) {
rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
full_fname(fname));
}
}
-static void discard_receive_data(int f_in, OFF_T length)
+static void discard_receive_data(int f_in, struct file_struct *file)
{
- receive_data(f_in, NULL, -1, 0, NULL, -1, length);
+ receive_data(f_in, NULL, -1, 0, NULL, -1, file);
}
static void handle_delayed_updates(char *local_name)
"(Skipping batched update for%s \"%s\")\n",
redoing ? " resend of" : "",
fname);
- discard_receive_data(f_in, F_LENGTH(file));
+ discard_receive_data(f_in, file);
file->flags |= FLAG_FILE_SENT;
continue;
}
if (!do_xfers) { /* log the transfer */
log_item(FCLIENT, file, iflags, NULL);
if (read_batch)
- discard_receive_data(f_in, F_LENGTH(file));
+ discard_receive_data(f_in, file);
continue;
}
if (write_batch < 0) {
log_item(FCLIENT, file, iflags, NULL);
if (!am_server)
- discard_receive_data(f_in, F_LENGTH(file));
+ discard_receive_data(f_in, file);
if (inc_recurse)
send_msg_int(MSG_SUCCESS, ndx);
continue;
} else if (do_fstat(fd1,&st) != 0) {
rsyserr(FERROR_XFER, errno, "fstat %s failed",
full_fname(fnamecmp));
- discard_receive_data(f_in, F_LENGTH(file));
+ discard_receive_data(f_in, file);
close(fd1);
if (inc_recurse)
send_msg_int(MSG_NO_SEND, ndx);
*/
rprintf(FERROR_XFER, "recv_files: %s is a directory\n",
full_fname(fnamecmp));
- discard_receive_data(f_in, F_LENGTH(file));
+ discard_receive_data(f_in, file);
close(fd1);
if (inc_recurse)
send_msg_int(MSG_NO_SEND, ndx);
continue;
}
- if (fd1 != -1 && !S_ISREG(st.st_mode)) {
+ if (fd1 != -1 && !(S_ISREG(st.st_mode) || (write_devices && IS_DEVICE(st.st_mode)))) {
close(fd1);
fd1 = -1;
}
+ /* On Linux systems (at least), st_size is typically 0 for devices.
+ * If so, try to determine the actual device size. */
+ if (fd1 != -1 && IS_DEVICE(st.st_mode) && st.st_size == 0) {
+ OFF_T off = lseek(fd1, 0, SEEK_END);
+ if (off == (OFF_T) -1)
+ rsyserr(FERROR, errno, "failed to seek to end of %s to determine size", fname);
+ else {
+ st.st_size = off;
+ off = lseek(fd1, 0, SEEK_SET);
+ if (off != 0)
+ rsyserr(FERROR, errno, "failed to seek back to beginning of %s to read it", fname);
+ }
+ }
+
/* If we're not preserving permissions, change the file-list's
* mode based on the local permissions and some heuristics. */
if (!preserve_perms) {
}
if (fd2 == -1) {
- discard_receive_data(f_in, F_LENGTH(file));
+ discard_receive_data(f_in, file);
if (fd1 != -1)
close(fd1);
if (inc_recurse)
rprintf(FINFO, "%s\n", fname);
/* recv file data */
- recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
- fname, fd2, F_LENGTH(file));
+ recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size, fname, fd2, file);
log_item(log_code, file, iflags, NULL);
--fake-super store/recover privileged attrs using xattrs
-S, --sparse turn sequences of nulls into sparse blocks
--preallocate allocate dest files before writing
+ --write-devices write to devices as files (implies --inplace)
-n, --dry-run perform a trial run with no changes made
-W, --whole-file copy files whole (w/o delta-xfer algorithm)
--checksum-choice=STR choose the checksum algorithms
dit(bf(-D)) The bf(-D) option is equivalent to bf(--devices) bf(--specials).
+dit(bf(--write-devices)) This tells rsync to treat a device on the receiving
+side as a regular file, allowing the writing of file data into a device.
+
+This option implies the bf(--inplace) 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.
+
+This option is refused by an rsync daemon.
+
dit(bf(-t, --times)) This tells rsync to transfer modification times along
with the files and update them on the remote system. Note that if this
option is not used, the optimization that excludes files that have not been