>From 5c14c5320c638ce2a32857dd3deee8214bd53673 Mon Sep 17 00:00:00 2001 From: Vaclav Ovsik 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