|
commit f3873b3d88b61167b106e7b9227a20147f8f6197
|
|
Author: Wayne Davison <wayned@samba.org>
|
|
Date: Mon Oct 10 11:49:50 2016 -0700
|
|
|
|
Support --sparse combined with --preallocate or --inplace.
|
|
|
|
The new code tries to punch holes in the destination file using newer
|
|
Linux fallocate features. It also supports a --whole-file + --sparse +
|
|
--inplace copy on any filesystem by truncating the destination file.
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
index b5e4049..e01e124 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -614,6 +614,36 @@ if test x"$rsync_cv_have_fallocate" = x"yes"; then
|
|
AC_DEFINE(HAVE_FALLOCATE, 1, [Define to 1 if you have the fallocate function and it compiles and links without error])
|
|
fi
|
|
|
|
+AC_MSG_CHECKING([for FALLOC_FL_PUNCH_HOLE])
|
|
+AC_PREPROC_IFELSE([AC_LANG_SOURCE([[
|
|
+ #define _GNU_SOURCE 1
|
|
+ #include <linux/falloc.h>
|
|
+ #ifndef FALLOC_FL_PUNCH_HOLE
|
|
+ #error FALLOC_FL_PUNCH_HOLE is missing
|
|
+ #endif
|
|
+ ]])], [
|
|
+ AC_MSG_RESULT([yes])
|
|
+ AC_DEFINE([HAVE_FALLOC_FL_PUNCH_HOLE], [1], [Define if FALLOC_FL_PUNCH_HOLE is available.])
|
|
+ ], [
|
|
+ AC_MSG_RESULT([no])
|
|
+ ]
|
|
+)
|
|
+
|
|
+AC_MSG_CHECKING([for FALLOC_FL_ZERO_RANGE])
|
|
+AC_PREPROC_IFELSE([AC_LANG_SOURCE([[
|
|
+ #define _GNU_SOURCE 1
|
|
+ #include <linux/falloc.h>
|
|
+ #ifndef FALLOC_FL_ZERO_RANGE
|
|
+ #error FALLOC_FL_ZERO_RANGE is missing
|
|
+ #endif
|
|
+ ]])], [
|
|
+ AC_MSG_RESULT([yes])
|
|
+ AC_DEFINE([HAVE_FALLOC_FL_ZERO_RANGE], [1], [Define if FALLOC_FL_ZERO_RANGE is available.])
|
|
+ ], [
|
|
+ AC_MSG_RESULT([no])
|
|
+ ]
|
|
+)
|
|
+
|
|
AC_CACHE_CHECK([for SYS_fallocate],rsync_cv_have_sys_fallocate,[
|
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/syscall.h>
|
|
#include <sys/types.h>]], [[syscall(SYS_fallocate, 0, 0, (loff_t)0, (loff_t)0);]])],[rsync_cv_have_sys_fallocate=yes],[rsync_cv_have_sys_fallocate=no])])
|
|
diff --git a/fileio.c b/fileio.c
|
|
index 70e079d..1e8a562 100644
|
|
--- a/fileio.c
|
|
+++ b/fileio.c
|
|
@@ -35,7 +35,10 @@
|
|
|
|
extern int sparse_files;
|
|
|
|
+OFF_T preallocated_len = 0;
|
|
+
|
|
static OFF_T sparse_seek = 0;
|
|
+static OFF_T sparse_past_write = 0;
|
|
|
|
int sparse_end(int f, OFF_T size)
|
|
{
|
|
@@ -63,8 +66,10 @@ int sparse_end(int f, OFF_T size)
|
|
return ret;
|
|
}
|
|
|
|
-
|
|
-static int write_sparse(int f, char *buf, int len)
|
|
+/* Note that the offset is just the caller letting us know where
|
|
+ * the current file position is in the file. The use_seek arg tells
|
|
+ * us that we should seek over matching data instead of writing it. */
|
|
+static int write_sparse(int f, int use_seek, OFF_T offset, const char *buf, int len)
|
|
{
|
|
int l1 = 0, l2 = 0;
|
|
int ret;
|
|
@@ -77,9 +82,24 @@ static int write_sparse(int f, char *buf, int len)
|
|
if (l1 == len)
|
|
return len;
|
|
|
|
- if (sparse_seek)
|
|
- do_lseek(f, sparse_seek, SEEK_CUR);
|
|
+ if (sparse_seek) {
|
|
+ if (sparse_past_write >= preallocated_len) {
|
|
+ if (do_lseek(f, sparse_seek, SEEK_CUR) < 0)
|
|
+ return -1;
|
|
+ } else if (do_punch_hole(f, sparse_past_write, sparse_seek) < 0) {
|
|
+ sparse_seek = 0;
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
sparse_seek = l2;
|
|
+ sparse_past_write = offset + len - l2;
|
|
+
|
|
+ if (use_seek) {
|
|
+ /* The in-place data already matches. */
|
|
+ if (do_lseek(f, len - (l1+l2), SEEK_CUR) < 0)
|
|
+ return -1;
|
|
+ return len;
|
|
+ }
|
|
|
|
while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) {
|
|
if (ret < 0 && errno == EINTR)
|
|
@@ -96,7 +116,6 @@ static int write_sparse(int f, char *buf, int len)
|
|
return len;
|
|
}
|
|
|
|
-
|
|
static char *wf_writeBuf;
|
|
static size_t wf_writeBufSize;
|
|
static size_t wf_writeBufCnt;
|
|
@@ -118,12 +137,10 @@ int flush_write_file(int f)
|
|
return ret;
|
|
}
|
|
|
|
-
|
|
-/*
|
|
- * write_file does not allow incomplete writes. It loops internally
|
|
- * until len bytes are written or errno is set.
|
|
- */
|
|
-int write_file(int f, char *buf, int len)
|
|
+/* write_file does not allow incomplete writes. It loops internally
|
|
+ * until len bytes are written or errno is set. Note that use_seek and
|
|
+ * offset are only used in sparse processing (see write_sparse()). */
|
|
+int write_file(int f, int use_seek, OFF_T offset, const char *buf, int len)
|
|
{
|
|
int ret = 0;
|
|
|
|
@@ -131,7 +148,8 @@ int write_file(int f, char *buf, int len)
|
|
int r1;
|
|
if (sparse_files > 0) {
|
|
int len1 = MIN(len, SPARSE_WRITE_SIZE);
|
|
- r1 = write_sparse(f, buf, len1);
|
|
+ r1 = write_sparse(f, use_seek, offset, buf, len1);
|
|
+ offset += r1;
|
|
} else {
|
|
if (!wf_writeBuf) {
|
|
wf_writeBufSize = WRITE_SIZE * 8;
|
|
@@ -164,6 +182,30 @@ int write_file(int f, char *buf, int len)
|
|
return ret;
|
|
}
|
|
|
|
+/* An in-place update found identical data at an identical location. We either
|
|
+ * just seek past it, or (for an in-place sparse update), we give the data to
|
|
+ * the sparse processor with the use_seek flag set. */
|
|
+int skip_matched(int fd, OFF_T offset, const char *buf, int len)
|
|
+{
|
|
+ OFF_T pos;
|
|
+
|
|
+ if (sparse_files > 0) {
|
|
+ if (write_file(fd, 1, offset, buf, len) != len)
|
|
+ return -1;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (flush_write_file(fd) < 0)
|
|
+ return -1;
|
|
+
|
|
+ if ((pos = do_lseek(fd, len, SEEK_CUR)) != offset + len) {
|
|
+ rsyserr(FERROR_XFER, errno, "lseek returned %s, not %s",
|
|
+ big_num(pos), big_num(offset));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
|
|
/* This provides functionality somewhat similar to mmap() but using read().
|
|
* It gives sliding window access to a file. mmap() is not used because of
|
|
@@ -271,7 +313,6 @@ char *map_ptr(struct map_struct *map, OFF_T offset, int32 len)
|
|
return map->p + align_fudge;
|
|
}
|
|
|
|
-
|
|
int unmap_file(struct map_struct *map)
|
|
{
|
|
int ret;
|
|
diff --git a/options.c b/options.c
|
|
index 308443b..6ba13b7 100644
|
|
--- a/options.c
|
|
+++ b/options.c
|
|
@@ -714,7 +714,7 @@ void usage(enum logcode F)
|
|
#ifdef SUPPORT_XATTRS
|
|
rprintf(F," --fake-super store/recover privileged attrs using xattrs\n");
|
|
#endif
|
|
- rprintf(F," -S, --sparse handle sparse files efficiently\n");
|
|
+ rprintf(F," -S, --sparse turn sequences of nulls into sparse blocks\n");
|
|
#ifdef SUPPORT_PREALLOCATION
|
|
rprintf(F," --preallocate allocate dest files before writing them\n");
|
|
#else
|
|
@@ -2237,14 +2237,6 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
|
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 --git a/receiver.c b/receiver.c
|
|
index f9b97dd..bed5328 100644
|
|
--- a/receiver.c
|
|
+++ b/receiver.c
|
|
@@ -49,6 +49,7 @@ extern int sparse_files;
|
|
extern int preallocate_files;
|
|
extern int keep_partial;
|
|
extern int checksum_seed;
|
|
+extern int whole_file;
|
|
extern int inplace;
|
|
extern int allowed_lull;
|
|
extern int delay_updates;
|
|
@@ -61,6 +62,9 @@ extern char *basis_dir[MAX_BASIS_DIRS+1];
|
|
extern char sender_file_sum[MAX_DIGEST_LEN];
|
|
extern struct file_list *cur_flist, *first_flist, *dir_flist;
|
|
extern filter_rule_list daemon_filter_list;
|
|
+#ifdef SUPPORT_PREALLOCATION
|
|
+extern OFF_T preallocated_len;
|
|
+#endif
|
|
|
|
static struct bitbag *delayed_bits = NULL;
|
|
static int phase = 0, redoing = 0;
|
|
@@ -241,22 +245,25 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
|
char *data;
|
|
int32 i;
|
|
char *map = NULL;
|
|
-#ifdef SUPPORT_PREALLOCATION
|
|
-#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
|
- OFF_T preallocated_len = 0;
|
|
-#endif
|
|
|
|
+#ifdef SUPPORT_PREALLOCATION
|
|
if (preallocate_files && fd != -1 && total_size > 0 && (!inplace || total_size > size_r)) {
|
|
/* Try to preallocate enough space for file's eventual length. Can
|
|
* reduce fragmentation on filesystems like ext4, xfs, and NTFS. */
|
|
- if (do_fallocate(fd, 0, total_size) == 0) {
|
|
-#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
|
- preallocated_len = total_size;
|
|
-#endif
|
|
- } else
|
|
+ if ((preallocated_len = do_fallocate(fd, 0, total_size)) < 0)
|
|
rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(fname));
|
|
- }
|
|
+ } else
|
|
+#endif
|
|
+ if (inplace) {
|
|
+#ifdef HAVE_FTRUNCATE
|
|
+ /* The most compatible way to create a sparse file is to start with no length. */
|
|
+ if (sparse_files > 0 && whole_file && fd >= 0 && do_ftruncate(fd, 0) == 0)
|
|
+ preallocated_len = 0;
|
|
+ else
|
|
#endif
|
|
+ preallocated_len = size_r;
|
|
+ } else
|
|
+ preallocated_len = 0;
|
|
|
|
read_sum_head(f_in, &sum);
|
|
|
|
@@ -318,7 +325,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
|
|
|
sum_update(data, i);
|
|
|
|
- if (fd != -1 && write_file(fd,data,i) != i)
|
|
+ if (fd != -1 && write_file(fd, 0, offset, data, i) != i)
|
|
goto report_write_error;
|
|
offset += i;
|
|
continue;
|
|
@@ -348,37 +355,33 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
|
|
|
if (updating_basis_or_equiv) {
|
|
if (offset == offset2 && fd != -1) {
|
|
- OFF_T pos;
|
|
- if (flush_write_file(fd) < 0)
|
|
+ if (skip_matched(fd, offset, map, len) < 0)
|
|
goto report_write_error;
|
|
offset += len;
|
|
- if ((pos = do_lseek(fd, len, SEEK_CUR)) != offset) {
|
|
- rsyserr(FERROR_XFER, errno,
|
|
- "lseek of %s returned %s, not %s",
|
|
- full_fname(fname),
|
|
- big_num(pos), big_num(offset));
|
|
- exit_cleanup(RERR_FILEIO);
|
|
- }
|
|
continue;
|
|
}
|
|
}
|
|
- if (fd != -1 && map && write_file(fd, map, len) != (int)len)
|
|
+ if (fd != -1 && map && write_file(fd, 0, offset, map, len) != (int)len)
|
|
goto report_write_error;
|
|
offset += len;
|
|
}
|
|
|
|
- if (flush_write_file(fd) < 0)
|
|
- goto report_write_error;
|
|
+ if (fd != -1 && offset > 0) {
|
|
+ if (sparse_files > 0) {
|
|
+ if (sparse_end(fd, offset) != 0)
|
|
+ goto report_write_error;
|
|
+ } else if (flush_write_file(fd) < 0) {
|
|
+ report_write_error:
|
|
+ rsyserr(FERROR_XFER, errno, "write failed on %s", full_fname(fname));
|
|
+ exit_cleanup(RERR_FILEIO);
|
|
+ }
|
|
+ }
|
|
|
|
#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
|
|
-#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
|
- || preallocated_len > offset
|
|
-#endif
|
|
- ) && fd != -1 && do_ftruncate(fd, offset) < 0) {
|
|
+ if ((inplace || preallocated_len > offset) && fd != -1 && do_ftruncate(fd, offset) < 0) {
|
|
rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
|
|
full_fname(fname));
|
|
}
|
|
@@ -387,13 +390,6 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
|
|
if (INFO_GTE(PROGRESS, 1))
|
|
end_progress(total_size);
|
|
|
|
- if (fd != -1 && offset > 0 && sparse_end(fd, offset) != 0) {
|
|
- report_write_error:
|
|
- rsyserr(FERROR_XFER, errno, "write failed on %s",
|
|
- full_fname(fname));
|
|
- exit_cleanup(RERR_FILEIO);
|
|
- }
|
|
-
|
|
checksum_len = sum_end(file_sum1);
|
|
|
|
if (mapbuf)
|
|
diff --git a/rsync.yo b/rsync.yo
|
|
index bfe43b9..d1e6fdf 100644
|
|
--- a/rsync.yo
|
|
+++ b/rsync.yo
|
|
@@ -376,7 +376,7 @@ to the detailed description below for a complete description. verb(
|
|
-J, --omit-link-times omit symlinks from --times
|
|
--super receiver attempts super-user activities
|
|
--fake-super store/recover privileged attrs using xattrs
|
|
- -S, --sparse handle sparse files efficiently
|
|
+ -S, --sparse turn sequences of nulls into sparse blocks
|
|
--preallocate allocate dest files before writing
|
|
-n, --dry-run perform a trial run with no changes made
|
|
-W, --whole-file copy files whole (w/o delta-xfer algorithm)
|
|
@@ -873,9 +873,7 @@ the same or longer than the size on the sender, the file is skipped. This
|
|
does not interfere with the updating of a file's non-content attributes
|
|
(e.g. permissions, ownership, etc.) when the file does not need to be
|
|
transferred, nor does it affect the updating of any non-regular files.
|
|
-Implies bf(--inplace),
|
|
-but does not conflict with bf(--sparse) (since it is always extending a
|
|
-file's length).
|
|
+Implies bf(--inplace).
|
|
|
|
The use of bf(--append) can be dangerous if you aren't 100% sure that the files
|
|
that are longer have only grown by the appending of data onto the end. You
|
|
@@ -1252,20 +1250,30 @@ This option is overridden by both bf(--super) and bf(--no-super).
|
|
See also the "fake super" setting in the daemon's rsyncd.conf file.
|
|
|
|
dit(bf(-S, --sparse)) Try to handle sparse files efficiently so they take
|
|
-up less space on the destination. Conflicts with bf(--inplace) because it's
|
|
-not possible to overwrite data in a sparse fashion.
|
|
+up less space on the destination. If combined with bf(--inplace) the
|
|
+file created might not end up with sparse blocks with some combinations
|
|
+of kernel version and/or filesystem type. If bf(--whole-file) is in
|
|
+effect (e.g. for a local copy) then it will always work because rsync
|
|
+truncates the file prior to writing out the updated version.
|
|
+
|
|
+Note that versions of rsync older than 3.1.3 will reject the combination of
|
|
+bf(--sparse) and bf(--inplace).
|
|
|
|
dit(bf(--preallocate)) This tells the receiver to allocate each destination
|
|
-file to its eventual size before writing data to the file. Rsync will only use
|
|
-the real filesystem-level preallocation support provided by Linux's
|
|
+file to its eventual size before writing data to the file. Rsync will only
|
|
+use the real filesystem-level preallocation support provided by Linux's
|
|
bf(fallocate)(2) system call or Cygwin's bf(posix_fallocate)(3), not the slow
|
|
-glibc implementation that writes a zero byte into each block.
|
|
+glibc implementation that writes a null byte into each block.
|
|
|
|
Without this option, larger files may not be entirely contiguous on the
|
|
filesystem, but with this option rsync will probably copy more slowly. If the
|
|
destination is not an extent-supporting filesystem (such as ext4, xfs, NTFS,
|
|
etc.), this option may have no positive effect at all.
|
|
|
|
+If combined with bf(--sparse), the file will only have sparse blocks (as
|
|
+opposed to allocated sequences of null bytes) if the kernel version and
|
|
+filesystem type support creating holes in the allocated data.
|
|
+
|
|
dit(bf(-n, --dry-run)) This makes rsync perform a trial run that doesn't
|
|
make any changes (and produces mostly the same output as a real run). It
|
|
is most commonly used in combination with the bf(-v, --verbose) and/or
|
|
diff --git a/syscall.c b/syscall.c
|
|
index ecca2f1..fa53b63 100644
|
|
--- a/syscall.c
|
|
+++ b/syscall.c
|
|
@@ -38,6 +38,8 @@ extern int am_root;
|
|
extern int am_sender;
|
|
extern int read_only;
|
|
extern int list_only;
|
|
+extern int inplace;
|
|
+extern int preallocate_files;
|
|
extern int preserve_perms;
|
|
extern int preserve_executability;
|
|
|
|
@@ -423,27 +425,80 @@ int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec))
|
|
#endif
|
|
|
|
#ifdef SUPPORT_PREALLOCATION
|
|
-int do_fallocate(int fd, OFF_T offset, OFF_T length)
|
|
-{
|
|
#ifdef FALLOC_FL_KEEP_SIZE
|
|
#define DO_FALLOC_OPTIONS FALLOC_FL_KEEP_SIZE
|
|
#else
|
|
#define DO_FALLOC_OPTIONS 0
|
|
#endif
|
|
+
|
|
+OFF_T do_fallocate(int fd, OFF_T offset, OFF_T length)
|
|
+{
|
|
+ int opts = inplace || preallocate_files ? 0 : DO_FALLOC_OPTIONS;
|
|
+ int ret;
|
|
RETURN_ERROR_IF(dry_run, 0);
|
|
RETURN_ERROR_IF_RO_OR_LO;
|
|
+ if (length & 1) /* make the length not match the desired length */
|
|
+ length++;
|
|
+ else
|
|
+ length--;
|
|
#if defined HAVE_FALLOCATE
|
|
- return fallocate(fd, DO_FALLOC_OPTIONS, offset, length);
|
|
+ ret = fallocate(fd, opts, offset, length);
|
|
#elif defined HAVE_SYS_FALLOCATE
|
|
- return syscall(SYS_fallocate, fd, DO_FALLOC_OPTIONS, (loff_t)offset, (loff_t)length);
|
|
+ ret = syscall(SYS_fallocate, fd, opts, (loff_t)offset, (loff_t)length);
|
|
#elif defined HAVE_EFFICIENT_POSIX_FALLOCATE
|
|
- return posix_fallocate(fd, offset, length);
|
|
+ ret = posix_fallocate(fd, offset, length);
|
|
#else
|
|
#error Coding error in SUPPORT_PREALLOCATION logic.
|
|
#endif
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ if (opts == 0) {
|
|
+ STRUCT_STAT st;
|
|
+ if (do_fstat(fd, &st) < 0)
|
|
+ return length;
|
|
+ return st.st_blocks * 512;
|
|
+ }
|
|
+ return 0;
|
|
}
|
|
#endif
|
|
|
|
+/* Punch a hole at pos for len bytes. The current file position must be at pos and will be
|
|
+ * changed to be at pos + len. */
|
|
+int do_punch_hole(int fd, UNUSED(OFF_T pos), int len)
|
|
+{
|
|
+#ifdef HAVE_FALLOCATE
|
|
+# ifdef HAVE_FALLOC_FL_PUNCH_HOLE
|
|
+ if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, pos, len) == 0) {
|
|
+ if (do_lseek(fd, len, SEEK_CUR) != pos + len)
|
|
+ return -1;
|
|
+ return 0;
|
|
+ }
|
|
+# endif
|
|
+# ifdef HAVE_FALLOC_FL_ZERO_RANGE
|
|
+ if (fallocate(fd, FALLOC_FL_ZERO_RANGE, pos, len) == 0) {
|
|
+ if (do_lseek(fd, len, SEEK_CUR) != pos + len)
|
|
+ return -1;
|
|
+ return 0;
|
|
+ }
|
|
+# endif
|
|
+#endif
|
|
+ {
|
|
+ char zeros[4096];
|
|
+ memset(zeros, 0, sizeof zeros);
|
|
+ while (len > 0) {
|
|
+ int chunk = len > (int)sizeof zeros ? (int)sizeof zeros : len;
|
|
+ int wrote = write(fd, zeros, chunk);
|
|
+ if (wrote <= 0) {
|
|
+ if (wrote < 0 && errno == EINTR)
|
|
+ continue;
|
|
+ return -1;
|
|
+ }
|
|
+ len -= wrote;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int do_open_nofollow(const char *pathname, int flags)
|
|
{
|
|
#ifndef O_NOFOLLOW
|
|
diff --git a/t_stub.c b/t_stub.c
|
|
index 26951a6..fc1ee3b 100644
|
|
--- a/t_stub.c
|
|
+++ b/t_stub.c
|
|
@@ -21,6 +21,7 @@
|
|
|
|
#include "rsync.h"
|
|
|
|
+int inplace = 0;
|
|
int modify_window = 0;
|
|
int preallocate_files = 0;
|
|
int protect_args = 0;
|
|
diff --git a/tls.c b/tls.c
|
|
index 45d1e10..d5a2896 100644
|
|
--- a/tls.c
|
|
+++ b/tls.c
|
|
@@ -51,6 +51,8 @@ int link_owner = 0;
|
|
int nsec_times = 0;
|
|
int preserve_perms = 0;
|
|
int preserve_executability = 0;
|
|
+int preallocate_files = 0;
|
|
+int inplace = 0;
|
|
|
|
#ifdef SUPPORT_XATTRS
|
|
|
|
diff --git a/trimslash.c b/trimslash.c
|
|
index 207eaf2..5db6f3e 100644
|
|
--- a/trimslash.c
|
|
+++ b/trimslash.c
|
|
@@ -28,6 +28,8 @@ int read_only = 1;
|
|
int list_only = 0;
|
|
int preserve_perms = 0;
|
|
int preserve_executability = 0;
|
|
+int preallocate_files = 0;
|
|
+int inplace = 0;
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
diff --git a/util.c b/util.c
|
|
index ca38f3e..49c5b71 100644
|
|
--- a/util.c
|
|
+++ b/util.c
|
|
@@ -323,9 +323,7 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
|
|
int ifd;
|
|
char buf[1024 * 8];
|
|
int len; /* Number of bytes read into `buf'. */
|
|
-#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
|
- OFF_T preallocated_len = 0, offset = 0;
|
|
-#endif
|
|
+ OFF_T prealloc_len = 0, offset = 0;
|
|
|
|
if ((ifd = do_open(source, O_RDONLY, 0)) < 0) {
|
|
int save_errno = errno;
|
|
@@ -365,11 +363,8 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
|
|
if (do_fstat(ifd, &srcst) < 0)
|
|
rsyserr(FWARNING, errno, "fstat %s", full_fname(source));
|
|
else if (srcst.st_size > 0) {
|
|
- if (do_fallocate(ofd, 0, srcst.st_size) == 0) {
|
|
-#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
|
- preallocated_len = srcst.st_size;
|
|
-#endif
|
|
- } else
|
|
+ prealloc_len = do_fallocate(ofd, 0, srcst.st_size);
|
|
+ if (prealloc_len < 0)
|
|
rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(dest));
|
|
}
|
|
}
|
|
@@ -384,9 +379,7 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
|
|
errno = save_errno;
|
|
return -1;
|
|
}
|
|
-#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
|
offset += len;
|
|
-#endif
|
|
}
|
|
|
|
if (len < 0) {
|
|
@@ -403,15 +396,13 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
|
|
full_fname(source));
|
|
}
|
|
|
|
-#ifdef PREALLOCATE_NEEDS_TRUNCATE
|
|
/* Source file might have shrunk since we fstatted it.
|
|
* Cut off any extra preallocated zeros from dest file. */
|
|
- if (offset < preallocated_len && do_ftruncate(ofd, offset) < 0) {
|
|
+ if (offset < prealloc_len && do_ftruncate(ofd, offset) < 0) {
|
|
/* If we fail to truncate, the dest file may be wrong, so we
|
|
* must trigger the "partial transfer" error. */
|
|
rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest));
|
|
}
|
|
-#endif
|
|
|
|
if (close(ofd) < 0) {
|
|
int save_errno = errno;
|