Tweak the copyright year.
[rsync.git] / syscall.c
index e2b1394a911200a063c8cda16db86c4a25b4e2f3..7f29336740f8a5947c0ab79b058e135501d8b0e1 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 1998 Andrew Tridgell
  * Copyright (C) 2002 Martin Pool
- * Copyright (C) 2003-2009 Wayne Davison
+ * Copyright (C) 2003-2019 Wayne Davison
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -38,9 +38,21 @@ 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;
 
+#ifndef S_BLKSIZE
+# if defined hpux || defined __hpux__ || defined __hpux
+#  define S_BLKSIZE 1024
+# elif defined _AIX && defined _I386
+#  define S_BLKSIZE 4096
+# else
+#  define S_BLKSIZE 512
+# endif
+#endif
+
 #define RETURN_ERROR_IF(x,e) \
        do { \
                if (x) { \
@@ -147,13 +159,13 @@ int do_mknod(const char *pathname, mode_t mode, dev_t dev)
        if (S_ISSOCK(mode)) {
                int sock;
                struct sockaddr_un saddr;
+               unsigned int len = strlcpy(saddr.sun_path, pathname, sizeof saddr.sun_path);
+               if (len >= sizeof saddr.sun_path) {
+                       errno = ENAMETOOLONG;
+                       return -1;
+               }
 #ifdef HAVE_SOCKADDR_UN_LEN
-               unsigned int len =
-#endif
-                   strlcpy(saddr.sun_path, pathname, sizeof saddr.sun_path);
-#ifdef HAVE_SOCKADDR_UN_LEN
-               saddr.sun_len = len >= sizeof saddr.sun_path
-                             ? sizeof saddr.sun_path : len + 1;
+               saddr.sun_len = len + 1;
 #endif
                saddr.sun_family = AF_UNIX;
 
@@ -348,6 +360,25 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence)
 #endif
 }
 
+#ifdef HAVE_SETATTRLIST
+int do_setattrlist_times(const char *fname, time_t modtime, uint32 mod_nsec)
+{
+       struct attrlist attrList;
+       struct timespec ts;
+
+       if (dry_run) return 0;
+       RETURN_ERROR_IF_RO_OR_LO;
+
+       ts.tv_sec = modtime;
+       ts.tv_nsec = mod_nsec;
+
+       memset(&attrList, 0, sizeof attrList);
+       attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
+       attrList.commonattr = ATTR_CMN_MODTIME;
+       return setattrlist(fname, &attrList, &ts, sizeof ts, FSOPT_NOFOLLOW);
+}
+#endif
+
 #ifdef HAVE_UTIMENSAT
 int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec)
 {
@@ -423,27 +454,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 ? DO_FALLOC_OPTIONS : 0;
+       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 * S_BLKSIZE;
+       }
+       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
@@ -464,9 +548,14 @@ int do_open_nofollow(const char *pathname, int flags)
 #ifdef O_NOFOLLOW
        fd = open(pathname, flags|O_NOFOLLOW);
 #else
+       if (do_lstat(pathname, &l_st) < 0)
+               return -1;
+       if (S_ISLNK(l_st.st_mode)) {
+               errno = ELOOP;
+               return -1;
+       }
        if ((fd = open(pathname, flags)) < 0)
                return fd;
-
        if (do_fstat(fd, &f_st) < 0) {
          close_and_return_error:
                {
@@ -476,12 +565,6 @@ int do_open_nofollow(const char *pathname, int flags)
                }
                return -1;
        }
-       if (do_lstat(pathname, &l_st) < 0)
-               goto close_and_return_error;
-       if (S_ISLNK(l_st.st_mode)) {
-               errno = ELOOP;
-               goto close_and_return_error;
-       }
        if (l_st.st_dev != f_st.st_dev || l_st.st_ino != f_st.st_ino) {
                errno = EINVAL;
                goto close_and_return_error;