From 9dd62525f3b98d692e031f22c02be8f775966503 Mon Sep 17 00:00:00 2001
From: Wayne Davison <wayne@opencoder.net>
Date: Sun, 29 Nov 2020 09:33:54 -0800
Subject: [PATCH] Work around glibc's lchmod() issue a better way.

---
 syscall.c    | 34 +++++++++++++++++++++-------------
 1 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/syscall.c b/syscall.c
index b9c3b4e..11d10e4 100644
--- a/syscall.c
+++ b/syscall.c
@@ -227,27 +227,35 @@ int do_open(const char *pathname, int flags, mode_t mode)
 #ifdef HAVE_CHMOD
 int do_chmod(const char *path, mode_t mode)
 {
+	static int switch_step = 0;
 	int code;
 	if (dry_run) return 0;
 	RETURN_ERROR_IF_RO_OR_LO;
+	switch (switch_step) {
 #ifdef HAVE_LCHMOD
-	code = lchmod(path, mode & CHMOD_BITS);
-#else
-	if (S_ISLNK(mode)) {
+#include "case_N.h"
+		if ((code = lchmod(path, mode & CHMOD_BITS)) == 0 || errno != ENOTSUP)
+			break;
+		switch_step++;
+#endif
+
+#include "case_N.h"
+		if (S_ISLNK(mode)) {
 # if defined HAVE_SETATTRLIST
-		struct attrlist attrList;
-		uint32_t m = mode & CHMOD_BITS; /* manpage is wrong: not mode_t! */
+			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);
+			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;
+			code = 1;
 # endif
-	} else
-		code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */
-#endif /* !HAVE_LCHMOD */
+		} else
+			code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */
+		break;
+	}
 	if (code != 0 && (preserve_perms || preserve_executability))
 		return code;
 	return 0;
-- 
1.8.3.1

