fallocate() is linux specific and will preallocate the space on disk for
the entire file. FALLOC_FL_KEEP_SIZE does not change the filesize as
reported by stat(). An aborted transfer will have preallocated disk space
which is not "visible" via stat(). This shouldn't matter unless
the user
does complet his transfer.
An alternative would be to use ftruncate() and shorten the file to the
size which has been transfered in case of an error.
posix_fallocate() isn't used because this function maybe implemented by
multiple write() calls which is not what I had in mind.
Signed-off-by: Sebastian Andrzej Siewior <sebastian at breakpoint.cc>
---
configure.in | 9 +++++++++
receiver.c | 9 ++++++++-
rsync.h | 4 ++++
syscall.c | 9 +++++++++
4 files changed, 30 insertions(+), 1 deletions(-)
diff --git a/configure.in b/configure.in
index 9de88d1..3e6ce55 100644
--- a/configure.in
+++ b/configure.in
@@ -761,6 +761,15 @@ if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" !=
x"no"; then
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [Define to 1 if gettimeofday() takes a
time-zone arg])
fi
+AC_CACHE_CHECK([if fallocate with mode FALLOC_FL_KEEP_SIZE is
available],rsync_cv_HAVE_FALLOCATE,[
+AC_TRY_LINK([#include <fcntl.h>
+#include <linux/falloc.h>],
+[exit(fallocate(0, FALLOC_FL_KEEP_SIZE, 0, 10));],
+rsync_cv_HAVE_FALLOCATE=yes,rsync_cv_HAVE_FALLOCATE=no)])
+if test x"$rsync_cv_HAVE_FALLOCATE" != x"no"; then
+ AC_DEFINE(HAVE_FALLOCATE, 1, [Define to 1 if fallocate() and
FALLOC_FL_KEEP_SIZE are available])
+fi
+
AC_CACHE_CHECK([for C99 vsnprintf],rsync_cv_HAVE_C99_VSNPRINTF,[
AC_TRY_RUN([
#include <sys/types.h>
diff --git a/receiver.c b/receiver.c
index 6688dda..0fa8782 100644
--- a/receiver.c
+++ b/receiver.c
@@ -774,7 +774,14 @@ int recv_files(int f_in, int f_out, char *local_name)
send_msg_int(MSG_NO_SEND, ndx);
continue;
}
-
+#ifdef HAVE_FALLOCATE
+ if (!sparse_files)
+ /*
+ * If this fails then either the filesystem does not
+ * support this feature or we run out of disk space.
+ */
+ do_fallocate(fd2, FALLOC_FL_KEEP_SIZE, 0, F_LENGTH(file));
+#endif
/* log the transfer */
if (log_before_transfer)
log_item(FCLIENT, file, iflags, NULL);
diff --git a/rsync.h b/rsync.h
index 731f4fe..b293edc 100644
--- a/rsync.h
+++ b/rsync.h
@@ -1241,3 +1241,7 @@ int inet_pton(int af, const char *src, void *dst);
#ifdef MAINTAINER_MODE
const char *get_panic_action(void);
#endif
+
+#ifdef HAVE_FALLOCATE
+#include <linux/falloc.h>
+#endif
diff --git a/syscall.c b/syscall.c
index aba0009..854010e 100644
--- a/syscall.c
+++ b/syscall.c
@@ -189,6 +189,15 @@ int do_open(const char *pathname, int flags, mode_t mode)
return open(pathname, flags | O_BINARY, mode);
}
+#ifdef HAVE_FALLOCATE
+int do_fallocate(int fd, int mode, OFF_T offset, OFF_T len)
+{
+ RETURN_ERROR_IF(dry_run, 0);
+ RETURN_ERROR_IF_RO_OR_LO;
+ return fallocate(fd, mode, offset, len);
+}
+#endif
+
#ifdef HAVE_CHMOD
int do_chmod(const char *path, mode_t mode)
{
--
1.6.6.1