summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarren Tucker <dtucker@dtucker.net>2019-01-18 11:09:01 +1100
committerDarren Tucker <dtucker@dtucker.net>2019-01-18 11:09:01 +1100
commita6258e5dc314c7d504ac9f0fbc3be96475581dbe (patch)
tree19047ce95b4608e7791ef419452c000055a6dac7
parent091093d25802b87d3b2b09f2c88d9f33e1ae5562 (diff)
Add minimal fchownat and fchmodat implementations.
Fixes builds on at least OS X Lion, NetBSD 6 and Solaris 10.
-rw-r--r--configure.ac2
-rw-r--r--openbsd-compat/bsd-misc.c58
-rw-r--r--openbsd-compat/bsd-misc.h12
3 files changed, 72 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 2d1dafde..8e92d159 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1719,7 +1719,9 @@ AC_CHECK_FUNCS([ \
errx \
explicit_bzero \
fchmod \
+ fchmodat \
fchown \
+ fchownat \
flock \
freeaddrinfo \
freezero \
diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c
index 4bae9654..d3a41df5 100644
--- a/openbsd-compat/bsd-misc.c
+++ b/openbsd-compat/bsd-misc.c
@@ -154,6 +154,64 @@ utimensat(int fd, const char *path, const struct timespec times[2],
}
#endif
+#ifndef HAVE_FCHOWNAT
+/*
+ * A limited implementation of fchownat() that only implements the
+ * functionality used by OpenSSH, currently only AT_FDCWD and
+ * AT_SYMLINK_NOFOLLOW.
+ */
+int
+fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag)
+{
+ int ret, oflags = O_WRONLY;
+
+ if (fd != AT_FDCWD) {
+ errno = ENOSYS;
+ return -1;
+ }
+# ifndef HAVE_FCHOWN
+ return chown(pathname, owner, group);
+# else
+ if (flag & AT_SYMLINK_NOFOLLOW)
+ oflags |= O_NOFOLLOW;
+ if ((fd = open(path, oflags)) == -1)
+ return -1;
+ ret = fchown(fd, owner, group);
+ close(fd);
+ return ret;
+# endif
+}
+#endif
+
+#ifndef HAVE_FCHMODAT
+/*
+ * A limited implementation of fchmodat() that only implements the
+ * functionality used by OpenSSH, currently only AT_FDCWD and
+ * AT_SYMLINK_NOFOLLOW.
+ */
+int
+fchmodat(int fd, const char *path, mode_t mode, int flag)
+{
+ int ret, oflags = O_WRONLY;
+
+ if (fd != AT_FDCWD) {
+ errno = ENOSYS;
+ return -1;
+ }
+# ifndef HAVE_FCHMOD
+ return chown(pathname, owner, group);
+# else
+ if (flag & AT_SYMLINK_NOFOLLOW)
+ oflags |= O_NOFOLLOW;
+ if ((fd = open(path, oflags)) == -1)
+ return -1;
+ ret = fchmod(fd, mode);
+ close(fd);
+ return ret;
+# endif
+}
+#endif
+
#ifndef HAVE_TRUNCATE
int truncate(const char *path, off_t length)
{
diff --git a/openbsd-compat/bsd-misc.h b/openbsd-compat/bsd-misc.h
index 584c2b5e..cb158cd5 100644
--- a/openbsd-compat/bsd-misc.h
+++ b/openbsd-compat/bsd-misc.h
@@ -72,6 +72,18 @@ int utimes(char *, struct timeval *);
int utimensat(int, const char *, const struct timespec[2], int);
#endif
+#ifndef AT_FDCWD
+# define AT_FDCWD (-2)
+#endif
+
+#ifndef HAVE_FCHMODAT
+int fchmodat(int, const char *, mode_t, int);
+#endif
+
+#ifndef HAVE_FCHOWNAT
+int fchownat(int, const char *, uid_t, gid_t, int);
+#endif
+
#ifndef HAVE_TRUNCATE
int truncate (const char *, off_t);
#endif /* HAVE_TRUNCATE */