diff -Naur rsync-3.0.7/fileio.c rsync-3.0.7.patched/fileio.c --- rsync-3.0.7/fileio.c 2009-01-17 22:41:35.000000000 +0100 +++ rsync-3.0.7.patched/fileio.c 2010-02-26 12:09:50.967310000 +0100 @@ -26,10 +26,54 @@ #endif extern int sparse_files; +extern int inplace; static char last_byte; static OFF_T sparse_seek = 0; +static char sparse_check_buf[16384]; +static char sparse_null_buf[16384]; +int +do_sparse_lseek(int f, OFF_T seekoff) +{ + int ret; + int read_len; + + /* we cannot just skip over the sparse part as we are writing + * inplace and the target might just not be sparse. So check + * first if the target really contains zeroes */ + + while(seekoff) { + int l3 = 0, l4 = 0, rlen; + + read_len = MIN(seekoff, sizeof(sparse_check_buf)); + + rlen = read(f, sparse_check_buf, read_len); + if (rlen < 0 && errno == EINTR) + continue; + if (rlen < 0) + return rlen; + + while(l3 < rlen && sparse_check_buf[l3] == 0) + ++l3; + while(l4 < rlen-l3 && sparse_check_buf[rlen-(l4+1)]==0) + ++l4; + + do_lseek(f, -rlen + l3, SEEK_CUR); + + while((ret = write(f, sparse_null_buf, rlen-(l3+l4))) < 0) { + if (ret < 0 && errno == EINTR) + continue; + return ret; + } + + do_lseek(f, read_len - rlen + l4, SEEK_CUR); + + seekoff -= read_len; + } + return 0; +} + int sparse_end(int f) { int ret; @@ -37,7 +81,14 @@ if (!sparse_seek) return 0; - do_lseek(f, sparse_seek-1, SEEK_CUR); + if (inplace) { + ret = do_sparse_lseek(f, sparse_seek-1); + if (ret < 0) + return ret; + } else { + do_lseek(f, sparse_seek-1, SEEK_CUR); + } + sparse_seek = 0; do { @@ -65,8 +116,14 @@ if (l1 == len) return len; - if (sparse_seek) + if (sparse_seek && inplace) { + ret = do_sparse_lseek(f, sparse_seek); + if (ret < 0) + return ret; + } else if (sparse_seek) { do_lseek(f, sparse_seek, SEEK_CUR); + } + sparse_seek = l2; while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) { diff -Naur rsync-3.0.7/options.c rsync-3.0.7.patched/options.c --- rsync-3.0.7/options.c 2009-12-21 23:40:41.000000000 +0100 +++ rsync-3.0.7.patched/options.c 2010-03-02 08:26:11.218877000 +0100 @@ -1575,14 +1575,6 @@ bwlimit_writemax = 512; } - if (sparse_files && inplace) { - /* Note: we don't check for this below, because --append is - * OK with --sparse (as long as redos are handled right). */ - snprintf(err_buf, sizeof err_buf, - "--sparse cannot be used with --inplace\n"); - return 0; - } - if (append_mode) { if (whole_file > 0) { snprintf(err_buf, sizeof err_buf, diff -Naur rsync-3.0.7/receiver.c rsync-3.0.7.patched/receiver.c --- rsync-3.0.7/receiver.c 2009-04-12 21:48:59.000000000 +0200 +++ rsync-3.0.7.patched/receiver.c 2010-02-26 11:41:12.253338000 +0100 @@ -691,7 +691,10 @@ /* We now check to see if we are writing the file "inplace" */ if (inplace) { - fd2 = do_open(fname, O_WRONLY|O_CREAT, 0600); + if (sparse_files > 0) + fd2 = do_open(fname, O_RDWR|O_CREAT, 0600); + else + fd2 = do_open(fname, O_WRONLY|O_CREAT, 0600); if (fd2 == -1) { rsyserr(FERROR_XFER, errno, "open %s failed", full_fname(fname));