+int do_open(const char *pathname, int flags, mode_t mode)
+{
+ if (flags != O_RDONLY) {
+ RETURN_ERROR_IF(dry_run, 0);
+ RETURN_ERROR_IF_RO_OR_LO;
+ }
+
+ return open(pathname, flags | O_BINARY, mode);
+}
+
+#ifdef HAVE_CHMOD
+int do_chmod(const char *path, mode_t mode)
+{
+ int code;
+ if (dry_run) return 0;
+ RETURN_ERROR_IF_RO_OR_LO;
+#ifdef HAVE_LCHMOD
+ code = lchmod(path, mode & CHMOD_BITS);
+#else
+ if (S_ISLNK(mode)) {
+# if defined HAVE_SETATTRLIST
+ struct attrlist attrList;
+ uint32_t m = mode & CHMOD_BITS; /* manpage is wrong: not mode_t! */
+
+ memset(&attrList, 0, sizeof attrList);
+ attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
+ attrList.commonattr = ATTR_CMN_ACCESSMASK;
+ code = setattrlist(path, &attrList, &m, sizeof m, FSOPT_NOFOLLOW);
+# else
+ code = 1;
+# endif
+ } else
+ code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */
+#endif /* !HAVE_LCHMOD */
+ if (code != 0 && (preserve_perms || preserve_executability))
+ return code;
+ return 0;
+}
+#endif
+
+int do_rename(const char *fname1, const char *fname2)
+{
+ if (dry_run) return 0;
+ RETURN_ERROR_IF_RO_OR_LO;
+ return rename(fname1, fname2);
+}
+
+#ifdef HAVE_FTRUNCATE
+int do_ftruncate(int fd, OFF_T size)
+{
+ int ret;
+
+ if (dry_run) return 0;
+ RETURN_ERROR_IF_RO_OR_LO;
+
+ do {
+ ret = ftruncate(fd, size);
+ } while (ret < 0 && errno == EINTR);
+
+ return ret;
+}
+#endif
+
+void trim_trailing_slashes(char *name)
+{
+ int l;
+ /* Some BSD systems cannot make a directory if the name
+ * contains a trailing slash.
+ * <http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2734739.html> */
+
+ /* Don't change empty string; and also we can't improve on
+ * "/" */
+
+ l = strlen(name);
+ while (l > 1) {
+ if (name[--l] != '/')
+ break;
+ name[l] = '\0';
+ }
+}
+
+int do_mkdir(char *fname, mode_t mode)
+{
+ if (dry_run) return 0;
+ RETURN_ERROR_IF_RO_OR_LO;
+ trim_trailing_slashes(fname);
+ return mkdir(fname, mode);
+}
+
+/* like mkstemp but forces permissions */
+int do_mkstemp(char *template, mode_t perms)
+{
+ RETURN_ERROR_IF(dry_run, 0);
+ RETURN_ERROR_IF(read_only, EROFS);
+ perms |= S_IWUSR;
+
+#if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64)
+ {
+ int fd = mkstemp(template);
+ if (fd == -1)
+ return -1;
+ if (fchmod(fd, perms) != 0 && preserve_perms) {
+ int errno_save = errno;
+ close(fd);
+ unlink(template);
+ errno = errno_save;
+ return -1;
+ }
+#if defined HAVE_SETMODE && O_BINARY
+ setmode(fd, O_BINARY);
+#endif
+ return fd;
+ }
+#else
+ if (!mktemp(template))
+ return -1;
+ return do_open(template, O_RDWR|O_EXCL|O_CREAT, perms);
+#endif
+}
+
+int do_stat(const char *fname, STRUCT_STAT *st)
+{
+#ifdef USE_STAT64_FUNCS
+ return stat64(fname, st);
+#else
+ return stat(fname, st);
+#endif
+}
+
+int do_lstat(const char *fname, STRUCT_STAT *st)
+{
+#ifdef SUPPORT_LINKS
+# ifdef USE_STAT64_FUNCS
+ return lstat64(fname, st);
+# else
+ return lstat(fname, st);
+# endif
+#else
+ return do_stat(fname, st);
+#endif
+}
+
+int do_fstat(int fd, STRUCT_STAT *st)
+{
+#ifdef USE_STAT64_FUNCS
+ return fstat64(fd, st);
+#else
+ return fstat(fd, st);
+#endif
+}
+
+OFF_T do_lseek(int fd, OFF_T offset, int whence)
+{
+#ifdef HAVE_LSEEK64
+#if !SIZEOF_OFF64_T
+ OFF_T lseek64();
+#else
+ off64_t lseek64();
+#endif
+ return lseek64(fd, offset, whence);
+#else
+ return lseek(fd, offset, whence);
+#endif
+}
+
+#ifdef HAVE_UTIMENSAT
+int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec)
+{
+ struct timespec t[2];
+
+ if (dry_run) return 0;
+ RETURN_ERROR_IF_RO_OR_LO;
+
+ t[0].tv_sec = 0;
+ t[0].tv_nsec = UTIME_NOW;
+ t[1].tv_sec = modtime;
+ t[1].tv_nsec = mod_nsec;
+ return utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW);
+}
+#endif
+
+#ifdef HAVE_LUTIMES
+int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec)
+{
+ struct timeval t[2];
+
+ if (dry_run) return 0;
+ RETURN_ERROR_IF_RO_OR_LO;
+
+ t[0].tv_sec = time(NULL);
+ t[0].tv_usec = 0;
+ t[1].tv_sec = modtime;
+ t[1].tv_usec = mod_nsec / 1000;
+ return lutimes(fname, t);
+}
+#endif
+
+#ifdef HAVE_UTIMES
+int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec)
+{
+ struct timeval t[2];
+
+ if (dry_run) return 0;
+ RETURN_ERROR_IF_RO_OR_LO;
+
+ t[0].tv_sec = time(NULL);
+ t[0].tv_usec = 0;
+ t[1].tv_sec = modtime;
+ t[1].tv_usec = mod_nsec / 1000;
+ return utimes(fname, t);
+}
+
+#elif defined HAVE_UTIME
+int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec))
+{
+#ifdef HAVE_STRUCT_UTIMBUF
+ struct utimbuf tbuf;
+#else
+ time_t t[2];
+#endif
+
+ if (dry_run) return 0;
+ RETURN_ERROR_IF_RO_OR_LO;
+
+# ifdef HAVE_STRUCT_UTIMBUF
+ tbuf.actime = time(NULL);
+ tbuf.modtime = modtime;
+ return utime(fname, &tbuf);
+# else
+ t[0] = time(NULL);
+ t[1] = modtime;
+ return utime(fname, t);
+# endif
+}
+
+#else
+#error Need utimes or utime function.
+#endif
+
+#ifdef SUPPORT_PREALLOCATION
+int do_fallocate(int fd, OFF_T offset, OFF_T length)