--- generator.c.orig 2017-09-26 19:25:53.000000000 +0200 +++ generator.c 2017-10-01 17:10:28.000000000 +0200 @@ -823,7 +823,7 @@ int save_preserve_xattrs = preserve_xattrs; int ok, fd_w; - if (inplace) { + if (inplace && !partial_dir) { /* Let copy_file open the destination in place. */ fd_w = -1; copy_to = dest; @@ -1787,6 +1787,13 @@ sx.st = partial_st; fnamecmp = partialptr; fnamecmp_type = FNAMECMP_PARTIAL_DIR; + /* We can now have --partial-dir with --inplace, in this case + partialptr will be used as the temp file, so it will be + modified inplace, this to save storage space on receiver. + Then set fnamecmp_type = FNAMECMP_FNAME so that the sender + knows we are modifying the checksumed file inplace. */ + if (inplace) + fnamecmp_type = FNAMECMP_FNAME; statret = 0; } @@ -1794,7 +1801,7 @@ goto notify_others; if (read_batch || whole_file) { - if (inplace && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) { + if (inplace && !partial_dir && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) { if (!(backupptr = get_backup_name(fname))) goto cleanup; if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) @@ -1830,7 +1837,7 @@ goto notify_others; } - if (inplace && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) { + if (inplace && !partial_dir && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) { if (!(backupptr = get_backup_name(fname))) { close(fd); goto cleanup; --- receiver.c.orig 2017-09-26 17:56:18.000000000 +0200 +++ receiver.c 2017-10-02 17:05:17.000000000 +0200 @@ -518,6 +518,7 @@ { int fd1,fd2; STRUCT_STAT st; + STRUCT_STAT partial_st; int iflags, xlen; char *fname, fbuf[MAXPATHLEN]; char xname[MAXPATHLEN]; @@ -541,6 +542,16 @@ if (delay_updates) delayed_bits = bitbag_create(cur_flist->used + 1); + if (inplace && partial_dir) { + /* we will need the partial_dir directory, + let's then create it once for all */ + partialptr = partial_dir_fname("dummy"); + if (!handle_partial_dir(partialptr, PDIR_CREATE)) { + rsyserr(FERROR_XFER, errno, "Unable to create partial-dir for --inplace\n"); + exit_cleanup(RERR_FILEIO); + } + } + while (1) { cleanup_disable(); @@ -689,12 +700,15 @@ continue; } - partialptr = partial_dir ? partial_dir_fname(fname) : fname; + partialptr = partial_dir ? partial_dir_fname(fname) : NULL; if (protocol_version >= 29) { switch (fnamecmp_type) { case FNAMECMP_FNAME: fnamecmp = fname; + /* same existence tests as in generator.c */ + if (inplace && partialptr && link_stat(partialptr, &partial_st, 0) == 0 && S_ISREG(partial_st.st_mode)) + fnamecmp = partialptr; break; case FNAMECMP_PARTIAL_DIR: fnamecmp = partialptr; @@ -733,9 +747,7 @@ fnamecmp_type = FNAMECMP_FNAME; } } else { - /* Reminder: --inplace && --partial-dir are never - * enabled at the same time. */ - if (inplace && make_backups > 0) { + if (inplace && !partial_dir && make_backups > 0) { if (!(fnamecmp = get_backup_name(fname))) fnamecmp = fname; else @@ -765,7 +777,7 @@ } updating_basis_or_equiv = inplace - && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP); + && (fnamecmp == fname || fnamecmp == partialptr || fnamecmp_type == FNAMECMP_BACKUP); if (fd1 == -1) { st.st_mode = 0; @@ -818,7 +830,7 @@ /* We now check to see if we are writing the file "inplace" */ if (inplace) { - fd2 = do_open(fname, O_WRONLY|O_CREAT, 0600); + fd2 = do_open(partialptr ? partialptr : fname, O_WRONLY|O_CREAT, 0600); if (fd2 == -1) { rsyserr(FERROR_XFER, errno, "open %s failed", full_fname(fname)); --- rsync.c.orig 2017-10-01 15:01:56.000000000 +0200 +++ rsync.c 2017-10-01 15:36:50.000000000 +0200 @@ -649,12 +649,15 @@ int ret; const char *temp_copy_name = partialptr && *partialptr != '/' ? partialptr : NULL; - if (inplace) { + if (inplace && !partialptr) { if (DEBUG_GTE(RECV, 1)) rprintf(FINFO, "finishing %s\n", fname); fnametmp = fname; goto do_set_file_attrs; } + if (inplace && partialptr) { + fnametmp = partialptr; + } if (make_backups > 0 && overwriting_basis) { int ok = make_backup(fname, False); --- options.c.orig 2017-10-01 15:12:15.000000000 +0200 +++ options.c 2017-10-04 19:44:12.000000000 +0200 @@ -2251,13 +2251,14 @@ if (inplace) { #ifdef HAVE_FTRUNCATE - if (partial_dir) { + /* We are now able to use partial-dir with inplace */ + /* if (partial_dir) { snprintf(err_buf, sizeof err_buf, "--%s cannot be used with --%s\n", append_mode ? "append" : "inplace", delay_updates ? "delay-updates" : "partial-dir"); return 0; - } + } */ /* --inplace implies --partial for refusal purposes, but we * clear the keep_partial flag for internal logic purposes. */ if (refused_partial) { --- rsync.yo.orig 2015-12-21 21:00:49.000000000 +0100 +++ rsync.yo 2017-10-04 19:52:53.000000000 +0200 @@ -850,7 +850,9 @@ diverging the entire contents of a file that only has minor changes. The option implies bf(--partial) (since an interrupted transfer does not delete -the file), but conflicts with bf(--partial-dir) and bf(--delay-updates). +the file). If used with bf(--partial-dir), or with any option implying it +(bf(--delay-update)), the inplace behavior will take place in the partial +directory, each file being moved to its final destination once completed. Prior to rsync 2.6.4 bf(--inplace) was also incompatible with bf(--compare-dest) and bf(--link-dest).