From 01c94277bbfc18bf2a6a985a49da53ae105d44c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Erik=20S=C3=B8rnes?= <ejs@nilu.no>
Date: Thu, 30 Oct 2014 14:08:17 +0100
Subject: [PATCH] add --unique switch

---
 include/libacl_nfs4.h                |  8 +++++---
 libnfs4acl/nfs4_acl_utils.c          | 25 +++++++++++++++++++++++++
 libnfs4acl/nfs4_insert_file_aces.c   |  4 ++--
 libnfs4acl/nfs4_insert_string_aces.c | 18 +++++++++++++-----
 libnfs4acl/nfs4_remove_string_aces.c |  2 +-
 man/man1/nfs4_setfacl.1              |  3 +++
 nfs4_setfacl/nfs4_setfacl.c          | 16 +++++++++++-----
 7 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/include/libacl_nfs4.h b/include/libacl_nfs4.h
index 2f7cc28..0e4e74d 100644
--- a/include/libacl_nfs4.h
+++ b/include/libacl_nfs4.h
@@ -156,6 +156,8 @@ enum {	ACL_NFS4_NOT_USED = 0,
 		ACL_NFS4_USED
 };
 
+enum { ACE_NOT_UNIQUE, ACE_UNIQUE } add_condition;
+
 struct ace_container {
 	struct nfs4_ace *ace;
 	TAILQ_ENTRY(ace_container) l_ace;
@@ -182,8 +184,8 @@ extern int			nfs4_insert_ace_at(struct nfs4_acl *acl, struct nfs4_ace *ace, unsi
 extern struct nfs4_ace *	nfs4_new_ace(int is_directory, u32 type, u32 flag, u32 access_mask, int whotype, char* who);
 extern struct nfs4_acl *	nfs4_new_acl(u32);
 
-extern int 			nfs4_insert_file_aces(struct nfs4_acl *acl, FILE* fd, unsigned int index);
-extern int 			nfs4_insert_string_aces(struct nfs4_acl *acl, const char *acl_spec, unsigned int index);
+extern int 			nfs4_insert_file_aces(struct nfs4_acl *acl, FILE* fd, unsigned int index, int add_condition);
+extern int 			nfs4_insert_string_aces(struct nfs4_acl *acl, const char *acl_spec, unsigned int index, int add_condition);
 extern int			nfs4_replace_ace(struct nfs4_acl *acl, struct nfs4_ace *old_ace, struct nfs4_ace *new_ace);
 extern int			nfs4_replace_ace_spec(struct nfs4_acl *acl, char *from_ace_spec, char *to_ace_spec);
 extern int			nfs4_remove_file_aces(struct nfs4_acl *acl, FILE *fd);
@@ -194,7 +196,7 @@ extern int			nfs4_remove_string_aces(struct nfs4_acl *acl, char *string);
 extern struct nfs4_ace * 	nfs4_ace_from_string(char *ace_spec, int is_dir);
 extern struct nfs4_acl * 	nfs4_acl_for_path(const char *path);
 extern char *			nfs4_acl_spec_from_file(FILE *f);
-
+extern int   			nfs4_ace_is_in_acl(struct nfs4_acl *acl, struct nfs4_ace *ace);
 
 /** Access Functions **/
 extern int			acl_nfs4_get_who(struct nfs4_ace*, int*, char**);
diff --git a/libnfs4acl/nfs4_acl_utils.c b/libnfs4acl/nfs4_acl_utils.c
index ae476e6..820a896 100644
--- a/libnfs4acl/nfs4_acl_utils.c
+++ b/libnfs4acl/nfs4_acl_utils.c
@@ -172,3 +172,28 @@ int nfs4_ace_cmp(struct nfs4_ace *lhs, struct nfs4_ace *rhs)
 		return 0;
 	return 1;
 }
+
+/*
+ * returns 0 if acl contains ace
+ * returns -2 (-ENOENT) if ace not found in acl
+ */
+
+int nfs4_ace_is_in_acl(struct nfs4_acl *acl, struct nfs4_ace *ace) 
+{
+	struct nfs4_ace *existing_ace;
+	int err = -2;
+
+	if (acl == NULL || acl->naces == 0)
+		goto out;
+	if (ace == NULL ) 
+		goto out;
+
+	for (existing_ace = nfs4_get_first_ace(acl); existing_ace != NULL; existing_ace = nfs4_get_next_ace(&existing_ace))
+		if (!nfs4_ace_cmp(existing_ace, ace)) {
+			err = 0;
+			break;
+		}
+out:
+	return err;
+}
+
diff --git a/libnfs4acl/nfs4_insert_file_aces.c b/libnfs4acl/nfs4_insert_file_aces.c
index e8b3582..98237ea 100644
--- a/libnfs4acl/nfs4_insert_file_aces.c
+++ b/libnfs4acl/nfs4_insert_file_aces.c
@@ -44,11 +44,11 @@
  * output
  *	0 on success OR -1 on error.
  */
-int nfs4_insert_file_aces(struct nfs4_acl *acl, FILE* fp, unsigned int index)
+int nfs4_insert_file_aces(struct nfs4_acl *acl, FILE* fp, unsigned int index, int add_condition)
 {
 	char *acl_spec;
 
 	if ((acl_spec = nfs4_acl_spec_from_file(fp)) == NULL)
 		return -1;
-	return nfs4_insert_string_aces(acl, acl_spec, index);
+	return nfs4_insert_string_aces(acl, acl_spec, index, add_condition);
 }
diff --git a/libnfs4acl/nfs4_insert_string_aces.c b/libnfs4acl/nfs4_insert_string_aces.c
index 5a482d5..d0eee32 100644
--- a/libnfs4acl/nfs4_insert_string_aces.c
+++ b/libnfs4acl/nfs4_insert_string_aces.c
@@ -36,7 +36,7 @@
  * nfs4_insert_string_aces - read ACE entries from spec string into struct nfs4_acl
  */
 
-int nfs4_insert_string_aces(struct nfs4_acl *acl, const char *acl_spec, unsigned int index)
+int nfs4_insert_string_aces(struct nfs4_acl *acl, const char *acl_spec, unsigned int index, int add_condition)
 {
 	char *s, *sp, *ssp;
 	struct nfs4_ace *ace;
@@ -51,11 +51,19 @@ int nfs4_insert_string_aces(struct nfs4_acl *acl, const char *acl_spec, unsigned
 
 		if ((ace = nfs4_ace_from_string(ssp, acl->is_directory)) == NULL)
 			goto out_failed;
+		/* ace is added wether it is already present or not */
+		if ( add_condition == ACE_NOT_UNIQUE ) 
+			if (nfs4_insert_ace_at(acl, ace, index++)) {
+				free(ace);
+				goto out_failed;
+			}
+		/* ace is only added if it is not already present */
+		if ( add_condition == ACE_UNIQUE && nfs4_ace_is_in_acl(acl, ace) == -2 ) 
+                        if (nfs4_insert_ace_at(acl, ace, index++)) {
+                                free(ace);
+                                goto out_failed;
+                        }
 
-		if (nfs4_insert_ace_at(acl, ace, index++)) {
-			free(ace);
-			goto out_failed;
-		}
 	}
 	if (acl->naces == 0)
 		goto out_failed;
diff --git a/libnfs4acl/nfs4_remove_string_aces.c b/libnfs4acl/nfs4_remove_string_aces.c
index ff241d9..97a1624 100644
--- a/libnfs4acl/nfs4_remove_string_aces.c
+++ b/libnfs4acl/nfs4_remove_string_aces.c
@@ -44,7 +44,7 @@ int nfs4_remove_string_aces(struct nfs4_acl *acl, char *acl_spec)
 	if ((anti_acl = nfs4_new_acl(acl->is_directory)) == NULL)
 		goto out;
 	
-	if (nfs4_insert_string_aces(anti_acl, acl_spec, 0))
+	if (nfs4_insert_string_aces(anti_acl, acl_spec, 0, 0))
 		goto out;
 
 	for (anti_ace = nfs4_get_first_ace(anti_acl); anti_ace != NULL; anti_ace = nfs4_get_next_ace(&anti_ace))
diff --git a/man/man1/nfs4_setfacl.1 b/man/man1/nfs4_setfacl.1
index a316bf2..25661e2 100644
--- a/man/man1/nfs4_setfacl.1
+++ b/man/man1/nfs4_setfacl.1
@@ -101,6 +101,9 @@ in conjunction with
 in conjunction with
 .BR -R / --recursive ", a physical walk skips all symbolic links."
 .TP
+.BR "-u" , " --unique"
+avoids adding duplicate ace's if they are already present.
+.TP
 .BR --test	 
 display results of 
 .BR COMMAND ,
diff --git a/nfs4_setfacl/nfs4_setfacl.c b/nfs4_setfacl/nfs4_setfacl.c
index a958ac1..efa5741 100644
--- a/nfs4_setfacl/nfs4_setfacl.c
+++ b/nfs4_setfacl/nfs4_setfacl.c
@@ -98,6 +98,7 @@ static struct option long_options[] = {
 	{ "edit",		0, 0, 'e' },
 	{ "test",		0, 0, 't' },
 	{ "help",		0, 0, 'h' },
+  	{ "unique",		0, 0, 'u' },
 	{ "version",		0, 0, 'v' },
 	{ "more-help",		0, 0, 'H' },
 	{ "recursive",		0, 0, 'R' },
@@ -130,6 +131,7 @@ int main(int argc, char **argv)
 	int numpaths = 0, curpath = 0;
 	char *tmp, **paths = NULL, *path = NULL, *spec_file = NULL;
 	FILE *s_fp = NULL;
+	add_condition = ACE_NOT_UNIQUE;
 
 	if (!strcmp(basename(argv[0]), "nfs4_editfacl")) {
 		action = EDIT_ACTION;
@@ -141,7 +143,7 @@ int main(int argc, char **argv)
 		return err;
 	}
 
-	while ((opt = getopt_long(argc, argv, "-:a:A:s:S:x:X:m:ethvHRPL", long_options, NULL)) != -1) {
+	while ((opt = getopt_long(argc, argv, "-:a:A:s:S:x:X:m:ethvuHRPL", long_options, NULL)) != -1) {
 		switch (opt) {
 			case 'a':
 				mod_string = optarg;
@@ -208,6 +210,10 @@ int main(int argc, char **argv)
 				is_test = 1;
 				break;
 
+                        case 'u':
+                                add_condition = ACE_UNIQUE;
+                                break;
+
 			case 'R':
 				do_recursive = YES_RECURSIVE;
 				break;
@@ -233,7 +239,6 @@ int main(int argc, char **argv)
 			case 'v':
 				printf("%s %s\n", basename(argv[0]), VERSION);
 				return 0;
-
 			case ':':
 				/* missing argument */
 				switch (optopt) {
@@ -383,7 +388,7 @@ static int do_apply_action(const char *path, const struct stat *_st)
 		/* default to prepending */
 		if (ace_index < 1)
 			ace_index = 1;
-		if (nfs4_insert_string_aces(acl, mod_string, (ace_index - 1))) {
+		if (nfs4_insert_string_aces(acl, mod_string, (ace_index - 1), add_condition)) {
 			fprintf(stderr, "Failed while inserting ACE(s) (at index %d).\n", ace_index);
 			goto failed;
 		}
@@ -414,7 +419,7 @@ static int do_apply_action(const char *path, const struct stat *_st)
 		break;
 
 	case SUBSTITUTE_ACTION:
-		if (nfs4_insert_string_aces(acl, mod_string, 0)) {
+		if (nfs4_insert_string_aces(acl, mod_string, 0, 0)) {
 			fprintf(stderr, "Failed while inserting ACE(s).\n");
 			goto failed;
 		}
@@ -474,7 +479,7 @@ static struct nfs4_acl* edit_ACL(struct nfs4_acl *acl, const char *path, const s
 	}
 	if (open_editor(tmp_name))
 		goto failed;
-	if (nfs4_insert_file_aces(newacl, tmp_fp, 0)) {
+	if (nfs4_insert_file_aces(newacl, tmp_fp, 0, add_condition)) {
 		fprintf(stderr, "Failed loading ACL from edit tempfile %s. Aborting.\n", tmp_name);
 		goto failed;
 	}
@@ -556,6 +561,7 @@ static void __usage(const char *name, int is_ef)
 	"   -R, --recursive	 recursively apply to all files and directories\n"
 	"   -L, --logical	 logical walk, follow symbolic links\n"
 	"   -P, --physical	 physical walk, do not follow symbolic links\n"
+	"   -u, --unique		 only add ace's when they are unique in acl\n"
 	"   --test	 	 print resulting ACL, do not save changes\n"
 	"\n"
 	"     NOTE: if \"-\" is given with -A/-X/-S, entries will be read from stdin.\n\n";
-- 
GitLab