*
* 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
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) { \
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;
#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)
{
#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
#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:
{
}
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;