>From c95fda5536cb9adf75f434e49e6a8f4e95204939 Mon Sep 17 00:00:00 2001 From: Vaclav Ovsik Date: Wed, 6 Jan 2010 23:56:50 +0100 Subject: [PATCH 2/6] The patch write-devices.diff applied. --- generator.c | 3 ++- options.c | 11 +++++++++++ receiver.c | 39 ++++++++++++++++++++++++++++++--------- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/generator.c b/generator.c index a443a3b..f5307b8 100644 --- a/generator.c +++ b/generator.c @@ -40,6 +40,7 @@ extern int preserve_xattrs; extern int preserve_links; extern int preserve_devices; extern int copy_devices; +extern int write_devices; extern int preserve_specials; extern int preserve_hard_links; extern int preserve_executability; @@ -1632,7 +1633,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, fnamecmp_type = FNAMECMP_FNAME; - if (statret == 0 && !S_ISREG(sx.st.st_mode)) { + if (statret == 0 && !(S_ISREG(sx.st.st_mode) || (write_devices && IS_DEVICE(sx.st.st_mode)))) { if (delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_FILE) != 0) goto cleanup; statret = -1; diff --git a/options.c b/options.c index c1854a2..36fef32 100644 --- a/options.c +++ b/options.c @@ -49,6 +49,7 @@ int keep_dirlinks = 0; int copy_dirlinks = 0; int copy_links = 0; int copy_devices = 0; +int write_devices = 0; int preserve_links = 0; int preserve_hard_links = 0; int preserve_acls = 0; @@ -704,6 +705,7 @@ void usage(enum logcode F) rprintf(F," -g, --group preserve group\n"); rprintf(F," --devices preserve device files (super-user only)\n"); rprintf(F," --copy-devices copy device contents as regular file\n"); + rprintf(F," -w --write-devices write to devices as regular files (implies --inplace)\n"); rprintf(F," --specials preserve special files\n"); rprintf(F," -D same as --devices --specials\n"); rprintf(F," -t, --times preserve modification times\n"); @@ -882,6 +884,7 @@ static struct poptOption long_options[] = { {"devices", 0, POPT_ARG_VAL, &preserve_devices, 1, 0, 0 }, {"no-devices", 0, POPT_ARG_VAL, &preserve_devices, 0, 0, 0 }, {"copy-devices", 0, POPT_ARG_NONE, ©_devices, 0, 0, 0 }, + {"write-devices", 'w', POPT_ARG_NONE, 0, 'w', 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 }, @@ -1788,6 +1791,11 @@ int parse_arguments(int *argc_p, const char ***argv_p) return 0; #endif + case 'w': + write_devices = 1; + inplace = 1; + break; + default: /* A large opt value means that set_refuse_options() * turned this option off. */ @@ -2706,6 +2714,9 @@ void server_options(char **args, int *argc_p) if (copy_devices) args[ac++] = "--copy-devices"; + if (write_devices) + args[ac++] = "--write-devices"; + if (ac > MAX_SERVER_ARGS) { /* Not possible... */ rprintf(FERROR, "argc overflow in server_options().\n"); exit_cleanup(RERR_MALLOC); diff --git a/receiver.c b/receiver.c index 3ab893d..bd3f8c2 100644 --- a/receiver.c +++ b/receiver.c @@ -38,6 +38,7 @@ extern int protocol_version; 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; @@ -227,6 +228,7 @@ int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file) 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) { + STRUCT_STAT st; static char file_sum1[MAX_DIGEST_LEN]; struct map_struct *mapbuf; struct sum_struct sum; @@ -366,16 +368,21 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, goto report_write_error; #ifdef HAVE_FTRUNCATE - /* 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 + (void)do_fstat(fd,&st); + /* Makes no sense to attempt to ftruncate() a block device: */ + if (!(IS_DEVICE(st.st_mode))) { + /* 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 #ifdef PREALLOCATE_NEEDS_TRUNCATE - || preallocated_len > offset + || preallocated_len > offset #endif - ) && fd != -1 && do_ftruncate(fd, offset) < 0) { - rsyserr(FERROR_XFER, errno, "ftruncate failed on %s", - full_fname(fname)); + ) && fd != -1 + && do_ftruncate(fd, offset) < 0) { + rsyserr(FERROR_XFER, errno, "ftruncate failed on %s", + full_fname(fname)); + } } #endif @@ -790,11 +797,25 @@ int recv_files(int f_in, int f_out, char *local_name) 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) { -- 1.7.7.3