Hi,

On Tue, Jun 15, 2010 at 04:12:18PM +0100, Stephane Chazelas wrote:
> Hiya,
>
> I can see it's a regular subject on this list.
>
> I, like others wanted to use rsync to synchronise two block
> devices (as it happens one lvm volume and one nbd device served
> by qemu-img on a remote host from a qcow2 disk image so that I
> can keep the old versions)

I already wrote a patch, but without response there.
http://lists.samba.org/archive/rsync/2010-January/024538.html

Oh yeah, the patch is not in the archive! 8-)

Ok, including it here now:

<<<<<<<<<<<<<<<<<<<< snip >>>>>>>>>>>>>>>>>>>>
diff --git a/flist.c b/flist.c
index 6d450bf..68f1ea0 100644
--- a/flist.c
+++ b/flist.c
@@ -63,6 +63,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;
@@ -228,7 +229,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)
@@ -246,6 +247,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
@@ -671,7 +694,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);
 }

@@ -1351,7 +1374,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 e7c1ef7..78169ef 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;
@@ -1181,6 +1182,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) {
@@ -1494,7 +1512,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);
@@ -1532,7 +1550,7 @@ static void recv_generator(char *fname, struct
file_struct *file, int ndx,
        fnamecmp = fname;
        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 6ee3e01..0d60293 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;
@@ -695,6 +696,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");
@@ -863,6 +865,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 },
@@ -1801,6 +1804,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);
@@ -2661,6 +2669,9 @@ void server_options(char **args, int *argc_p)
        else if (remove_source_files)
                args[ac++] = "--remove-sent-files";

+       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 6688dda..ec11802 100644
--- a/receiver.c
+++ b/receiver.c
@@ -37,6 +37,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;
@@ -199,6 +200,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;
@@ -321,10 +323,14 @@ static int receive_data(int f_in, char *fname_r,
int fd_r, OFF_T size_r,
                goto report_write_error;

 #ifdef HAVE_FTRUNCATE
-       if (inplace && fd != -1
-        && ftruncate(fd, offset) < 0) {
-               rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
-                       full_fname(fname));
+       (void)do_fstat(fd,&st);
+       /* Makes no sense to attempt to ftruncate() a block device: */
+       if (!(IS_DEVICE(st.st_mode))) {
+               if (inplace && fd != -1
+                && ftruncate(fd, offset) < 0) {
+                       rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
+                               full_fname(fname));
+               }
        }
 #endif

@@ -732,11 +738,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 cefbe5f..6b6ffea 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;
@@ -397,7 +398,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 aba0009..7096110 100644
--- a/syscall.c
+++ b/syscall.c
@@ -36,6 +36,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 { \
@@ -286,20 +287,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
@@ -308,10 +345,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)
<<<<<<<<<<<<<<<<<<<< snip >>>>>>>>>>>>>>>>>>>>


Can someone review a patch and include it somewhere?
Thanks
--
Zito
-- 
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

Reply via email to