Hi, I rebased rw-devices patch for rsync last weekend. Seems to me it works "incrementally". Attached are * six git commits, or * one complete patch on top of current development rsync branch (master branch commit 60ef39705797c9df7069297eb4ed5feab5e88f29).
bobek:/data/soft/rsync/rsync# dd if=/dev/urandom of=/dev/mapper/vg-pokus1 dd: writing to `/dev/mapper/vg-pokus1': No space left on device 65537+0 records in 65536+0 records out 33554432 bytes (34 MB) copied, 6.53098 s, 5.1 MB/s bobek:/data/soft/rsync/rsync# dd if=/dev/mapper/vg-pokus1 of=/dev/mapper/vg-pokus2 65536+0 records in 65536+0 records out 33554432 bytes (34 MB) copied, 2.58308 s, 13.0 MB/s bobek:/data/soft/rsync/rsync# dd if=/dev/urandom bs=1M seek=16 count=1 of=/dev/mapper/vg-pokus2 1+0 records in 1+0 records out 1048576 bytes (1.0 MB) copied, 0.147337 s, 7.1 MB/s bobek:/data/soft/rsync/rsync# ./rsync --rsync-path\="$PWD/rsync" -v --bwlimit=100 --progress --rw-devices /dev/mapper/vg-pokus1 root@localhost:/dev/mapper/vg-pokus2 vg-pokus1 33,554,432 100% 3.14MB/s 0:00:10 (xfr#1, to-chk=0/1) sent 1,076,932 bytes received 40,593 bytes 89,402.00 bytes/sec total size is 33,554,432 speedup is 30.03 Have this patch any chance to get between rsync-patches? I just looked into http://gitweb.samba.org/?p=rsync-patches.git;a=tree and copy-devices.diff and write-devices.diff are in it. Maybe rw-devices patch can replace these two. I think a group of users want to use rsync to copy disk images. Scenario: I want to virtualize some physical machine: * dd a physical dirty disk image from live system to target system, * stop the machine and boot into live system (r.g. System Rescue CD) * rsync disk changes from unmounted clean filesystems to target system, * mabe make some changes (fstab,...)? * start a new virtual machine I think rsync can be interesting in similar scenarios. Regards -- Zito
>From 46267751e24b32d4cdc74cfcdfdba55506f4a766 Mon Sep 17 00:00:00 2001 From: Vaclav Ovsik <vaclav.ov...@i.cz> Date: Wed, 6 Jan 2010 23:51:58 +0100 Subject: [PATCH 1/6] The patch copy-devices.diff applied. --- generator.c | 3 ++- options.c | 6 ++++++ rsync.c | 4 +++- sender.c | 14 ++++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/generator.c b/generator.c index df690da..a443a3b 100644 --- a/generator.c +++ b/generator.c @@ -39,6 +39,7 @@ extern int preserve_acls; extern int preserve_xattrs; extern int preserve_links; extern int preserve_devices; +extern int copy_devices; extern int preserve_specials; extern int preserve_hard_links; extern int preserve_executability; @@ -1594,7 +1595,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, goto cleanup; } - if (!S_ISREG(file->mode)) { + if (!(S_ISREG(file->mode) || (copy_devices && IS_DEVICE(file->mode)))) { if (solo_file) fname = f_name(file, NULL); rprintf(FINFO, "skipping non-regular file \"%s\"\n", fname); diff --git a/options.c b/options.c index 9e95c86..c1854a2 100644 --- a/options.c +++ b/options.c @@ -48,6 +48,7 @@ int append_mode = 0; int keep_dirlinks = 0; int copy_dirlinks = 0; int copy_links = 0; +int copy_devices = 0; int preserve_links = 0; int preserve_hard_links = 0; int preserve_acls = 0; @@ -702,6 +703,7 @@ void usage(enum logcode F) rprintf(F," -o, --owner preserve owner (super-user only)\n"); 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," --specials preserve special files\n"); rprintf(F," -D same as --devices --specials\n"); rprintf(F," -t, --times preserve modification times\n"); @@ -879,6 +881,7 @@ static struct poptOption long_options[] = { {"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 }, + {"copy-devices", 0, POPT_ARG_NONE, ©_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 }, @@ -2700,6 +2703,9 @@ void server_options(char **args, int *argc_p) if (preallocate_files && am_sender) args[ac++] = "--preallocate"; + if (copy_devices) + args[ac++] = "--copy-devices"; + if (ac > MAX_SERVER_ARGS) { /* Not possible... */ rprintf(FERROR, "argc overflow in server_options().\n"); exit_cleanup(RERR_MALLOC); diff --git a/rsync.c b/rsync.c index c42d553..2e4988f 100644 --- a/rsync.c +++ b/rsync.c @@ -33,6 +33,7 @@ extern int preserve_xattrs; extern int preserve_perms; extern int preserve_executability; extern int preserve_times; +extern int copy_devices; extern int am_root; extern int am_server; extern int am_sender; @@ -395,7 +396,8 @@ int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, if (iflags & ITEM_TRANSFER) { int i = ndx - cur_flist->ndx_start; - if (i < 0 || !S_ISREG(cur_flist->files[i]->mode)) { + struct file_struct *file = cur_flist->files[i]; + if (i < 0 || !(S_ISREG(file->mode) || (copy_devices && IS_DEVICE(file->mode)))) { rprintf(FERROR, "received request to transfer non-regular file: %d [%s]\n", ndx, who_am_i()); diff --git a/sender.c b/sender.c index ebc8839..88e3cc6 100644 --- a/sender.c +++ b/sender.c @@ -364,6 +364,20 @@ void send_files(int f_in, int f_out) exit_cleanup(RERR_FILEIO); } + /* On Matt's computer, st_size is falsely 0 for most devices. + * If this happens, try harder to determine the actual device size. */ + if (IS_DEVICE(st.st_mode) && st.st_size == 0) { + OFF_T off = lseek(fd, 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(fd, 0, SEEK_SET); + if (off != 0) + rsyserr(FERROR, errno, "failed to seek back to beginning of %s to read it", fname); + } + } + if (st.st_size) { int32 read_size = MAX(s->blength * 3, MAX_MAP_SIZE); mbuf = map_file(fd, st.st_size, read_size, s->blength); -- 1.7.7.3
>From c95fda5536cb9adf75f434e49e6a8f4e95204939 Mon Sep 17 00:00:00 2001 From: Vaclav Ovsik <vaclav.ov...@i.cz> 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
>From 7bdf827ad62a6460b2afc609166c87db77fe46ab Mon Sep 17 00:00:00 2001 From: Vaclav Ovsik <vaclav.ov...@i.cz> Date: Thu, 7 Jan 2010 15:32:04 +0100 Subject: [PATCH 3/6] write-devices.diff fix - device size determination --- generator.c | 17 +++++++++++++++++ 1 files changed, 17 insertions(+), 0 deletions(-) diff --git a/generator.c b/generator.c index f5307b8..fff8500 100644 --- a/generator.c +++ b/generator.c @@ -1267,6 +1267,23 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir); stat_errno = errno; + + if (statret == 0 && IS_DEVICE(sx.st.st_mode) && sx.st.st_size == 0) { + /* On Linux systems (at least), st_size is typically 0 for devices. + * If so, try to determine the actual device size. */ + int fdx = do_open(fname, O_RDONLY, 0); + if ( fdx == -1 ) { + rsyserr(FERROR, errno, "failed to open device %s to determine size", fname); + } + else { + OFF_T off = lseek(fdx, 0, SEEK_END); + if (off == (OFF_T)-1) + rsyserr(FERROR, errno, "failed to seek to end of %s to determine size", fname); + else + sx.st.st_size = off; + close(fdx); + } + } } if (missing_args == 2 && file->mode == 0) { -- 1.7.7.3
>From 2572ffd91de6b025081405b17937ebc0bf8df3db Mon Sep 17 00:00:00 2001 From: Vaclav Ovsik <vaclav.ov...@i.cz> Date: Thu, 7 Jan 2010 23:03:48 +0100 Subject: [PATCH 4/6] Joined --{copy,write}-devices into --rw-devices --- generator.c | 7 +++---- options.c | 24 ++++++++---------------- receiver.c | 4 ++-- rsync.c | 4 ++-- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/generator.c b/generator.c index fff8500..e1a4685 100644 --- a/generator.c +++ b/generator.c @@ -39,8 +39,7 @@ extern int preserve_acls; extern int preserve_xattrs; extern int preserve_links; extern int preserve_devices; -extern int copy_devices; -extern int write_devices; +extern int rw_devices; extern int preserve_specials; extern int preserve_hard_links; extern int preserve_executability; @@ -1613,7 +1612,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, goto cleanup; } - if (!(S_ISREG(file->mode) || (copy_devices && IS_DEVICE(file->mode)))) { + if (!(S_ISREG(file->mode) || (rw_devices && IS_DEVICE(file->mode)))) { if (solo_file) fname = f_name(file, NULL); rprintf(FINFO, "skipping non-regular file \"%s\"\n", fname); @@ -1650,7 +1649,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) || (write_devices && IS_DEVICE(sx.st.st_mode)))) { + if (statret == 0 && !(S_ISREG(sx.st.st_mode) || (rw_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 36fef32..8da9c20 100644 --- a/options.c +++ b/options.c @@ -48,8 +48,7 @@ int append_mode = 0; int keep_dirlinks = 0; int copy_dirlinks = 0; int copy_links = 0; -int copy_devices = 0; -int write_devices = 0; +int rw_devices = 0; int preserve_links = 0; int preserve_hard_links = 0; int preserve_acls = 0; @@ -704,8 +703,7 @@ void usage(enum logcode F) rprintf(F," -o, --owner preserve owner (super-user only)\n"); 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," --rw-devices read/write device contents as regular file (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"); @@ -883,8 +881,7 @@ static struct poptOption long_options[] = { {"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 }, - {"copy-devices", 0, POPT_ARG_NONE, ©_devices, 0, 0, 0 }, - {"write-devices", 'w', POPT_ARG_NONE, 0, 'w', 0, 0 }, + {"rw-devices", 0, POPT_ARG_NONE, &rw_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 }, @@ -1791,11 +1788,6 @@ 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. */ @@ -1833,6 +1825,9 @@ int parse_arguments(int *argc_p, const char ***argv_p) set_output_verbosity(verbose, DEFAULT_PRIORITY); + if (rw_devices) + inplace = 1; + if (do_stats) { parse_output_words(info_words, info_levels, verbose > 1 ? "stats3" : "stats2", DEFAULT_PRIORITY); @@ -2711,11 +2706,8 @@ void server_options(char **args, int *argc_p) if (preallocate_files && am_sender) args[ac++] = "--preallocate"; - if (copy_devices) - args[ac++] = "--copy-devices"; - - if (write_devices) - args[ac++] = "--write-devices"; + if (rw_devices) + args[ac++] = "--rw-devices"; if (ac > MAX_SERVER_ARGS) { /* Not possible... */ rprintf(FERROR, "argc overflow in server_options().\n"); diff --git a/receiver.c b/receiver.c index bd3f8c2..cf43682 100644 --- a/receiver.c +++ b/receiver.c @@ -38,7 +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 rw_devices; extern int preserve_xattrs; extern int basis_dir_cnt; extern int make_backups; @@ -797,7 +797,7 @@ int recv_files(int f_in, int f_out, char *local_name) continue; } - if (fd1 != -1 && !(S_ISREG(st.st_mode) || (write_devices && IS_DEVICE(st.st_mode)))) { + if (fd1 != -1 && !(S_ISREG(st.st_mode) || (rw_devices && IS_DEVICE(st.st_mode)))) { close(fd1); fd1 = -1; } diff --git a/rsync.c b/rsync.c index 2e4988f..7e2184b 100644 --- a/rsync.c +++ b/rsync.c @@ -33,7 +33,7 @@ extern int preserve_xattrs; extern int preserve_perms; extern int preserve_executability; extern int preserve_times; -extern int copy_devices; +extern int rw_devices; extern int am_root; extern int am_server; extern int am_sender; @@ -397,7 +397,7 @@ int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, if (iflags & ITEM_TRANSFER) { int i = ndx - cur_flist->ndx_start; struct file_struct *file = cur_flist->files[i]; - if (i < 0 || !(S_ISREG(file->mode) || (copy_devices && IS_DEVICE(file->mode)))) { + if (i < 0 || !(S_ISREG(file->mode) || (rw_devices && IS_DEVICE(file->mode)))) { rprintf(FERROR, "received request to transfer non-regular file: %d [%s]\n", ndx, who_am_i()); -- 1.7.7.3
>From 5c14c5320c638ce2a32857dd3deee8214bd53673 Mon Sep 17 00:00:00 2001 From: Vaclav Ovsik <vaclav.ov...@i.cz> Date: Mon, 11 Jan 2010 00:45:20 +0100 Subject: [PATCH 5/6] Fixed handling of block dev size everywhere --- flist.c | 30 +++++++++++++++++++++++-- options.c | 4 ++- sender.c | 14 ------------ syscall.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 93 insertions(+), 24 deletions(-) diff --git a/flist.c b/flist.c index 6ec3c39..a8cc01c 100644 --- a/flist.c +++ b/flist.c @@ -60,6 +60,7 @@ extern int non_perishable_cnt; extern int prune_empty_dirs; extern int copy_links; extern int copy_unsafe_links; +extern int rw_devices; extern int protocol_version; extern int sanitize_paths; extern int munge_symlinks; @@ -219,7 +220,7 @@ static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf) #endif } -int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks) +static int link_stat2(const char *path, STRUCT_STAT *stp, int follow_dirlinks) { #ifdef SUPPORT_LINKS if (copy_links) @@ -237,6 +238,28 @@ int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks) #endif } +int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks) +{ + if (link_stat2(path, stp, follow_dirlinks) != 0) + return -1; + if (rw_devices && S_ISBLK(stp->st_mode) && stp->st_size == 0) { + /* On Linux systems (at least), st_size is typically 0 for devices. + * If so, try to determine the actual device size. */ + int fdx = do_open(path, O_RDONLY, 0); + if (fdx == -1) + rsyserr(FERROR, errno, "failed to open device %s to determine size", path); + else { + OFF_T off = lseek(fdx, 0, SEEK_END); + if (off == (OFF_T)-1) + rsyserr(FERROR, errno, "failed to seek to end of %s to determine size", path); + else + stp->st_size = off; + close(fdx); + } + } + return 0; +} + static inline int is_daemon_excluded(const char *fname, int is_dir) { if (daemon_filter_list.head @@ -664,7 +687,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, #endif strlcpy(lastname, fname, MAXPATHLEN); - if (S_ISREG(mode) || S_ISLNK(mode)) + if (S_ISREG(mode) || S_ISLNK(mode) || (rw_devices && S_ISBLK(mode))) stats.total_size += F_LENGTH(file); } @@ -1344,7 +1367,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, #ifdef HAVE_STRUCT_STAT_ST_RDEV if (IS_DEVICE(st.st_mode)) { tmp_rdev = st.st_rdev; - st.st_size = 0; + if (!rw_devices || !S_ISBLK(st.st_mode)) + st.st_size = 0; } else if (IS_SPECIAL(st.st_mode)) st.st_size = 0; #endif diff --git a/options.c b/options.c index 8da9c20..7a0fb9f 100644 --- a/options.c +++ b/options.c @@ -1825,8 +1825,10 @@ int parse_arguments(int *argc_p, const char ***argv_p) set_output_verbosity(verbose, DEFAULT_PRIORITY); - if (rw_devices) + if (rw_devices) { inplace = 1; + ignore_times = 1; + } if (do_stats) { parse_output_words(info_words, info_levels, diff --git a/sender.c b/sender.c index 88e3cc6..ebc8839 100644 --- a/sender.c +++ b/sender.c @@ -364,20 +364,6 @@ void send_files(int f_in, int f_out) exit_cleanup(RERR_FILEIO); } - /* On Matt's computer, st_size is falsely 0 for most devices. - * If this happens, try harder to determine the actual device size. */ - if (IS_DEVICE(st.st_mode) && st.st_size == 0) { - OFF_T off = lseek(fd, 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(fd, 0, SEEK_SET); - if (off != 0) - rsyserr(FERROR, errno, "failed to seek back to beginning of %s to read it", fname); - } - } - if (st.st_size) { int32 read_size = MAX(s->blength * 3, MAX_MAP_SIZE); mbuf = map_file(fd, st.st_size, read_size, s->blength); diff --git a/syscall.c b/syscall.c index 5a7c8e8..b9a0b0e 100644 --- a/syscall.c +++ b/syscall.c @@ -40,6 +40,7 @@ extern int read_only; extern int list_only; extern int preserve_perms; extern int preserve_executability; +extern int rw_devices; #define RETURN_ERROR_IF(x,e) \ do { \ @@ -306,20 +307,56 @@ int do_mkstemp(char *template, mode_t perms) int do_stat(const char *fname, STRUCT_STAT *st) { #ifdef USE_STAT64_FUNCS - return stat64(fname, st); + if (stat64(fname, st) != 0) + return -1; #else - return stat(fname, st); + if (stat(fname, st) != 0) + return -1; #endif + if (rw_devices && S_ISBLK(st->st_mode) && st->st_size == 0) { + /* On Linux systems (at least), st_size is typically 0 for devices. + * If so, try to determine the actual device size. */ + int fdx = do_open(fname, O_RDONLY, 0); + if (fdx == -1) + rsyserr(FERROR, errno, "failed to open device %s to determine size", fname); + else { + OFF_T off = lseek(fdx, 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; + close(fdx); + } + } + return 0; } int do_lstat(const char *fname, STRUCT_STAT *st) { #ifdef SUPPORT_LINKS # ifdef USE_STAT64_FUNCS - return lstat64(fname, st); + if (lstat64(fname, st) != 0) + return -1; # else - return lstat(fname, st); + if (lstat(fname, st) != 0) + return -1; # endif + if (rw_devices && S_ISBLK(st->st_mode) && st->st_size == 0) { + /* On Linux systems (at least), st_size is typically 0 for devices. + * If so, try to determine the actual device size. */ + int fdx = do_open(fname, O_RDONLY, 0); + if (fdx == -1) + rsyserr(FERROR, errno, "failed to open device %s to determine size", fname); + else { + OFF_T off = lseek(fdx, 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; + close(fdx); + } + } + return 0; #else return do_stat(fname, st); #endif @@ -328,10 +365,30 @@ int do_lstat(const char *fname, STRUCT_STAT *st) int do_fstat(int fd, STRUCT_STAT *st) { #ifdef USE_STAT64_FUNCS - return fstat64(fd, st); + if (fstat64(fd, st) != 0) + return -1; #else - return fstat(fd, st); + if (fstat(fd, st) != 0) + return -1; #endif + if (rw_devices && S_ISBLK(st->st_mode) && st->st_size == 0) { + /* On Linux systems (at least), st_size is typically 0 for devices. + * If so, try to determine the actual device size. */ + OFF_T off_save = lseek(fd, 0, SEEK_CUR); + if (off_save == (OFF_T)-1) + rsyserr(FERROR, errno, "failed to seek on device inode %lld to read current position", (long long int)(st->st_ino)); + else { + OFF_T off = lseek(fd, 0, SEEK_END); + if (off == (OFF_T)-1) + rsyserr(FERROR, errno, "failed to seek to end on device inode %lld to determine size", (long long int)(st->st_ino)); + else + st->st_size = off; + off = lseek(fd, off_save, SEEK_SET); + if (off == (OFF_T)-1) + rsyserr(FERROR, errno, "failed to seek to origin position on device inode %lld", (long long int)(st->st_ino)); + } + } + return 0; } OFF_T do_lseek(int fd, OFF_T offset, int whence) -- 1.7.7.3
>From c8ca5aa592a3c610c308bed9c603a1b9d0affe76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Ovs=C3=ADk?= <vaclav.ov...@gmail.com> Date: Tue, 1 Mar 2011 19:22:24 +0100 Subject: [PATCH 6/6] Handle symlink on source device --- flist.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/flist.c b/flist.c index a8cc01c..5b888c7 100644 --- a/flist.c +++ b/flist.c @@ -223,7 +223,7 @@ static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf) static int link_stat2(const char *path, STRUCT_STAT *stp, int follow_dirlinks) { #ifdef SUPPORT_LINKS - if (copy_links) + if (copy_links || rw_devices) return x_stat(path, stp, NULL); if (x_lstat(path, stp, NULL) < 0) return -1; -- 1.7.7.3
diff --git a/flist.c b/flist.c index 6ec3c39..5b888c7 100644 --- a/flist.c +++ b/flist.c @@ -60,6 +60,7 @@ extern int non_perishable_cnt; extern int prune_empty_dirs; extern int copy_links; extern int copy_unsafe_links; +extern int rw_devices; extern int protocol_version; extern int sanitize_paths; extern int munge_symlinks; @@ -219,10 +220,10 @@ static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf) #endif } -int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks) +static int link_stat2(const char *path, STRUCT_STAT *stp, int follow_dirlinks) { #ifdef SUPPORT_LINKS - if (copy_links) + if (copy_links || rw_devices) return x_stat(path, stp, NULL); if (x_lstat(path, stp, NULL) < 0) return -1; @@ -237,6 +238,28 @@ int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks) #endif } +int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks) +{ + if (link_stat2(path, stp, follow_dirlinks) != 0) + return -1; + if (rw_devices && S_ISBLK(stp->st_mode) && stp->st_size == 0) { + /* On Linux systems (at least), st_size is typically 0 for devices. + * If so, try to determine the actual device size. */ + int fdx = do_open(path, O_RDONLY, 0); + if (fdx == -1) + rsyserr(FERROR, errno, "failed to open device %s to determine size", path); + else { + OFF_T off = lseek(fdx, 0, SEEK_END); + if (off == (OFF_T)-1) + rsyserr(FERROR, errno, "failed to seek to end of %s to determine size", path); + else + stp->st_size = off; + close(fdx); + } + } + return 0; +} + static inline int is_daemon_excluded(const char *fname, int is_dir) { if (daemon_filter_list.head @@ -664,7 +687,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, #endif strlcpy(lastname, fname, MAXPATHLEN); - if (S_ISREG(mode) || S_ISLNK(mode)) + if (S_ISREG(mode) || S_ISLNK(mode) || (rw_devices && S_ISBLK(mode))) stats.total_size += F_LENGTH(file); } @@ -1344,7 +1367,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, #ifdef HAVE_STRUCT_STAT_ST_RDEV if (IS_DEVICE(st.st_mode)) { tmp_rdev = st.st_rdev; - st.st_size = 0; + if (!rw_devices || !S_ISBLK(st.st_mode)) + st.st_size = 0; } else if (IS_SPECIAL(st.st_mode)) st.st_size = 0; #endif diff --git a/generator.c b/generator.c index df690da..e1a4685 100644 --- a/generator.c +++ b/generator.c @@ -39,6 +39,7 @@ extern int preserve_acls; extern int preserve_xattrs; extern int preserve_links; extern int preserve_devices; +extern int rw_devices; extern int preserve_specials; extern int preserve_hard_links; extern int preserve_executability; @@ -1265,6 +1266,23 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir); stat_errno = errno; + + if (statret == 0 && IS_DEVICE(sx.st.st_mode) && sx.st.st_size == 0) { + /* On Linux systems (at least), st_size is typically 0 for devices. + * If so, try to determine the actual device size. */ + int fdx = do_open(fname, O_RDONLY, 0); + if ( fdx == -1 ) { + rsyserr(FERROR, errno, "failed to open device %s to determine size", fname); + } + else { + OFF_T off = lseek(fdx, 0, SEEK_END); + if (off == (OFF_T)-1) + rsyserr(FERROR, errno, "failed to seek to end of %s to determine size", fname); + else + sx.st.st_size = off; + close(fdx); + } + } } if (missing_args == 2 && file->mode == 0) { @@ -1594,7 +1612,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, goto cleanup; } - if (!S_ISREG(file->mode)) { + if (!(S_ISREG(file->mode) || (rw_devices && IS_DEVICE(file->mode)))) { if (solo_file) fname = f_name(file, NULL); rprintf(FINFO, "skipping non-regular file \"%s\"\n", fname); @@ -1631,7 +1649,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) || (rw_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 9e95c86..7a0fb9f 100644 --- a/options.c +++ b/options.c @@ -48,6 +48,7 @@ int append_mode = 0; int keep_dirlinks = 0; int copy_dirlinks = 0; int copy_links = 0; +int rw_devices = 0; int preserve_links = 0; int preserve_hard_links = 0; int preserve_acls = 0; @@ -702,6 +703,7 @@ void usage(enum logcode F) rprintf(F," -o, --owner preserve owner (super-user only)\n"); rprintf(F," -g, --group preserve group\n"); rprintf(F," --devices preserve device files (super-user only)\n"); + rprintf(F," --rw-devices read/write device contents as regular file (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"); @@ -879,6 +881,7 @@ static struct poptOption long_options[] = { {"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 }, + {"rw-devices", 0, POPT_ARG_NONE, &rw_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 }, @@ -1822,6 +1825,11 @@ int parse_arguments(int *argc_p, const char ***argv_p) set_output_verbosity(verbose, DEFAULT_PRIORITY); + if (rw_devices) { + inplace = 1; + ignore_times = 1; + } + if (do_stats) { parse_output_words(info_words, info_levels, verbose > 1 ? "stats3" : "stats2", DEFAULT_PRIORITY); @@ -2700,6 +2708,9 @@ void server_options(char **args, int *argc_p) if (preallocate_files && am_sender) args[ac++] = "--preallocate"; + if (rw_devices) + args[ac++] = "--rw-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..cf43682 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 rw_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) || (rw_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) { diff --git a/rsync.c b/rsync.c index c42d553..7e2184b 100644 --- a/rsync.c +++ b/rsync.c @@ -33,6 +33,7 @@ extern int preserve_xattrs; extern int preserve_perms; extern int preserve_executability; extern int preserve_times; +extern int rw_devices; extern int am_root; extern int am_server; extern int am_sender; @@ -395,7 +396,8 @@ int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, if (iflags & ITEM_TRANSFER) { int i = ndx - cur_flist->ndx_start; - if (i < 0 || !S_ISREG(cur_flist->files[i]->mode)) { + struct file_struct *file = cur_flist->files[i]; + if (i < 0 || !(S_ISREG(file->mode) || (rw_devices && IS_DEVICE(file->mode)))) { rprintf(FERROR, "received request to transfer non-regular file: %d [%s]\n", ndx, who_am_i()); diff --git a/syscall.c b/syscall.c index 5a7c8e8..b9a0b0e 100644 --- a/syscall.c +++ b/syscall.c @@ -40,6 +40,7 @@ extern int read_only; extern int list_only; extern int preserve_perms; extern int preserve_executability; +extern int rw_devices; #define RETURN_ERROR_IF(x,e) \ do { \ @@ -306,20 +307,56 @@ int do_mkstemp(char *template, mode_t perms) int do_stat(const char *fname, STRUCT_STAT *st) { #ifdef USE_STAT64_FUNCS - return stat64(fname, st); + if (stat64(fname, st) != 0) + return -1; #else - return stat(fname, st); + if (stat(fname, st) != 0) + return -1; #endif + if (rw_devices && S_ISBLK(st->st_mode) && st->st_size == 0) { + /* On Linux systems (at least), st_size is typically 0 for devices. + * If so, try to determine the actual device size. */ + int fdx = do_open(fname, O_RDONLY, 0); + if (fdx == -1) + rsyserr(FERROR, errno, "failed to open device %s to determine size", fname); + else { + OFF_T off = lseek(fdx, 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; + close(fdx); + } + } + return 0; } int do_lstat(const char *fname, STRUCT_STAT *st) { #ifdef SUPPORT_LINKS # ifdef USE_STAT64_FUNCS - return lstat64(fname, st); + if (lstat64(fname, st) != 0) + return -1; # else - return lstat(fname, st); + if (lstat(fname, st) != 0) + return -1; # endif + if (rw_devices && S_ISBLK(st->st_mode) && st->st_size == 0) { + /* On Linux systems (at least), st_size is typically 0 for devices. + * If so, try to determine the actual device size. */ + int fdx = do_open(fname, O_RDONLY, 0); + if (fdx == -1) + rsyserr(FERROR, errno, "failed to open device %s to determine size", fname); + else { + OFF_T off = lseek(fdx, 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; + close(fdx); + } + } + return 0; #else return do_stat(fname, st); #endif @@ -328,10 +365,30 @@ int do_lstat(const char *fname, STRUCT_STAT *st) int do_fstat(int fd, STRUCT_STAT *st) { #ifdef USE_STAT64_FUNCS - return fstat64(fd, st); + if (fstat64(fd, st) != 0) + return -1; #else - return fstat(fd, st); + if (fstat(fd, st) != 0) + return -1; #endif + if (rw_devices && S_ISBLK(st->st_mode) && st->st_size == 0) { + /* On Linux systems (at least), st_size is typically 0 for devices. + * If so, try to determine the actual device size. */ + OFF_T off_save = lseek(fd, 0, SEEK_CUR); + if (off_save == (OFF_T)-1) + rsyserr(FERROR, errno, "failed to seek on device inode %lld to read current position", (long long int)(st->st_ino)); + else { + OFF_T off = lseek(fd, 0, SEEK_END); + if (off == (OFF_T)-1) + rsyserr(FERROR, errno, "failed to seek to end on device inode %lld to determine size", (long long int)(st->st_ino)); + else + st->st_size = off; + off = lseek(fd, off_save, SEEK_SET); + if (off == (OFF_T)-1) + rsyserr(FERROR, errno, "failed to seek to origin position on device inode %lld", (long long int)(st->st_ino)); + } + } + return 0; } OFF_T do_lseek(int fd, OFF_T offset, int whence)
-- Please use reply-all for most replies to avoid omitting the mailing list. To unsubscribe or change options: https://lists.samba.org/mailman/listinfo/rsync Before posting, read: http://www.catb.org/~esr/faqs/smart-questions.html