From ab7e231a8239c3d85e0ac0c97513a6100effabd2 Mon Sep 17 00:00:00 2001
From: David Bartley
Date: Sat, 9 May 2009 03:23:19 -0400
Subject: [PATCH] Add support for returning access control list text.
---
ChangeLog | 11 +++
lib/acl.h | 10 ++-
lib/file-has-acl.c | 156 +++++++++++++++++++++++++++++++++++++++++----
lib/free-acl-text.c | 46 +++++++++++++
m4/acl.m4 | 2 +-
modules/acl | 3 +-
tests/test-file-has-acl.c | 3 +-
7 files changed, 213 insertions(+), 18 deletions(-)
create mode 100644 lib/free-acl-text.c
diff --git a/ChangeLog b/ChangeLog
index 2f2055d..be88e39 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2009-05-09 David Bartley
+
+ Add support for returning access control list text
+ * lib/file-has-acl.c: Add additional parameters for returning access
+ and default access control lists.
+ * lib/free-acl-text.c: Add free_acl_text function.
+ * lib/acl.h: Add free_acl_text function and file_has_acl flags.
+ * m4/acl.m4: Check for acl_to_any_text.
+ * modules/acl: Add free-acl-text.c
+ * tests/test-file-has-acl.c: Update per changes to file_has_acl.
+
2009-05-08 Bruno Haible
* lib/sys_socket.in.h (_SS_PADSIZE): Use a conditional expression
diff --git a/lib/acl.h b/lib/acl.h
index fcb00f5..3fdb3bc 100644
--- a/lib/acl.h
+++ b/lib/acl.h
@@ -1,6 +1,6 @@
/* acl.c - access control lists
- Copyright (C) 2002, 2008 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2008, 2009 Free Software Foundation, Inc.
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
@@ -20,7 +20,13 @@
#include
#include
-int file_has_acl (char const *, struct stat const *);
+/* Flags for file_has_acl. */
+#define GL_ACL_SHORT_FORMAT 0x01
+#define GL_ACL_NUMERIC_IDS 0x02
+#define GL_ACL_PRINT_INDENTS 0x04
+
+int file_has_acl (char const *, struct stat const *, int, char **, char**);
+void free_acl_text (char *);
int copy_acl (char const *, int, char const *, int, mode_t);
int set_acl (char const *, int, mode_t);
int qset_acl (char const *, int, mode_t);
diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c
index c3b77c3..e3505ca 100644
--- a/lib/file-has-acl.c
+++ b/lib/file-has-acl.c
@@ -15,7 +15,8 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
- Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */
+ Written by Paul Eggert, Andreas Grünbacher, Bruno Haible, and
+ David Bartley. */
#include
@@ -120,6 +121,17 @@ acl_access_nontrivial (acl_t acl)
#elif USE_ACL && HAVE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
+static void
+replace_chr (char *str, char c1, char c2)
+{
+ while (*str)
+ {
+ if (*str == c1)
+ *str = c2;
+ str++;
+ }
+}
+
# if !defined ACL_NO_TRIVIAL /* Solaris <= 10, Cygwin */
/* Test an ACL retrieved with GETACL.
@@ -269,12 +281,22 @@ acl_nontrivial (struct acl *a)
/* Return 1 if NAME has a nontrivial access control list, 0 if NAME
only has no or a base access control list, and -1 (setting errno)
- on error. SB must be set to the stat buffer of FILE. */
+ on error. SB must be set to the stat buffer of FILE. If ATEXT and
+ DTEXT are non-null they will be filled with a text representation
+ of the access and default (if applicable) access control list if
+ it is nontrivial. FLAGS contains formatting flags for ATEXT and
+ DTEXT. atext and dtext should be free'd by calling free_acl_text. */
int
-file_has_acl (char const *name, struct stat const *sb)
+file_has_acl (char const *name, struct stat const *sb, int flags,
+ char **atext, char **dtext)
{
#if USE_ACL
+ if (dtext)
+ *dtext = NULL;
+ if (atext)
+ *atext = NULL;
+
if (! S_ISLNK (sb->st_mode))
{
# if HAVE_ACL_GET_FILE
@@ -283,14 +305,14 @@ file_has_acl (char const *name, struct stat const *sb)
/* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
int ret;
- if (HAVE_ACL_EXTENDED_FILE) /* Linux */
+ if (! atext && ! dtext && HAVE_ACL_EXTENDED_FILE) /* Linux */
{
/* On Linux, acl_extended_file is an optimized function: It only
makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
ACL_TYPE_DEFAULT. */
ret = acl_extended_file (name);
}
- else /* FreeBSD, MacOS X, IRIX, Tru64 */
+ else /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
{
# if HAVE_ACL_TYPE_EXTENDED /* MacOS X */
/* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
@@ -302,17 +324,47 @@ file_has_acl (char const *name, struct stat const *sb)
if (acl)
{
ret = acl_extended_nontrivial (acl);
+ if (ret && atext)
+ {
+ *atext = acl_to_text (acl, &len);
+ if (! *atext)
+ ret = -1;
+ }
acl_free (acl);
}
else
ret = -1;
-# else /* FreeBSD, IRIX, Tru64 */
+# else /* Linux, FreeBSD, IRIX, Tru64 */
acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
if (acl)
{
int saved_errno;
+ ssize_t len;
ret = acl_access_nontrivial (acl);
+ if (ret && atext)
+ {
+# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
+ if (flags & GL_ACL_SHORT_FORMAT)
+ *atext = acl_to_short_text (acl, &len);
+ else
+ *atext = acl_to_text (acl, &len);
+# elif HAVE_ACL_TO_ANY_TEXT /* Linux */
+ int flags2 = TEXT_SOME_EFFECTIVE;
+ if (flags & GL_ACL_SHORT_FORMAT)
+ flags2 |= TEXT_ABBREVIATE;
+ if (flags & GL_ACL_NUMERIC_IDS)
+ flags2 |= TEXT_NUMERIC_IDS;
+ if (flags & GL_ACL_PRINT_INDENTS)
+ flags2 |= TEXT_SMART_INDENT;
+ *atext = acl_to_any_text (acl, "", '\n', flags2);
+# else /* FreeBSD, Tru64 */
+
+ *atext = acl_to_text (acl, &len);
+# endif
+ if (! *atext)
+ ret = -1;
+ }
saved_errno = errno;
acl_free (acl);
errno = saved_errno;
@@ -320,19 +372,47 @@ file_has_acl (char const *name, struct stat const *sb)
/* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always
returns NULL with errno not set. There is no point in
making this call. */
-# else /* FreeBSD, IRIX */
+# else /* Linux, FreeBSD, IRIX */
/* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS)
and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory
either both succeed or both fail; it depends on the
filesystem. Therefore there is no point in making the second
- call if the first one already failed. */
- if (ret == 0 && S_ISDIR (sb->st_mode))
+ call if the first one already failed. If the access acl is
+ non-trivial and dtext is null we don't need to continue. */
+ if ((ret == 0 || (ret == 1 && dtext)) && S_ISDIR (sb->st_mode))
{
acl = acl_get_file (name, ACL_TYPE_DEFAULT);
if (acl)
{
- ret = (0 < acl_entries (acl));
+ if (acl_entries (acl) > 0)
+ {
+ ret = 1;
+ if (dtext)
+ {
+# if HAVE_ACL_TO_SHORT_TEXT /* IRIX */
+ if (! (flags & GL_ACL_SHORT_FORMAT))
+ *dtext = acl_to_short_text (acl, &len);
+ else
+ *dtext = acl_to_text (acl, &len);
+# elif HAVE_ACL_TO_ANY_TEXT /* Linux */
+ int flags2 = TEXT_SOME_EFFECTIVE;
+ if (flags & GL_ACL_SHORT_FORMAT)
+ flags2 |= TEXT_ABBREVIATE;
+ if (flags & GL_ACL_NUMERIC_IDS)
+ flags2 |= TEXT_NUMERIC_IDS;
+ if (flags & GL_ACL_PRINT_INDENTS)
+ flags2 |= TEXT_SMART_INDENT;
+ *dtext = acl_to_any_text (acl, "", '\n', flags2);
+# else /* FreeBSD */
+ *dtext = acl_to_text (acl, &len);
+# endif
+ if (! *dtext)
+ ret = -1;
+ }
+ }
+ saved_errno = errno;
acl_free (acl);
+ errno = saved_errno;
}
else
ret = -1;
@@ -344,7 +424,22 @@ file_has_acl (char const *name, struct stat const *sb)
# endif
}
if (ret < 0)
- return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1;
+ {
+ if (atext)
+ {
+ free_acl_text (*atext);
+ *atext = NULL;
+ }
+/* Linux, FreeBSD, IRIX */
+# if HAVE_ACL_GET_FILE && ! HAVE_ACL_TYPE_EXTENDED && ! HAVE_ACL_FREE_TEXT
+ if (dtext)
+ {
+ free_acl_text (*dtext);
+ *dtext = NULL;
+ }
+# endif
+ return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1;
+ }
return ret;
# elif HAVE_ACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */
@@ -354,7 +449,32 @@ file_has_acl (char const *name, struct stat const *sb)
/* Solaris 10 (newer version), which has additional API declared in
(acl_t) and implemented in libsec (acl_set, acl_trivial,
acl_fromtext, ...). */
- return acl_trivial (name);
+ if (atext)
+ {
+ int ret;
+ acl_t *aclp;
+
+ ret = acl_get (name, ACL_NO_TRIVIAL, &aclp);
+ if (ret == 0)
+ {
+ if (aclp)
+ {
+ int flags2 = 0;
+ if (flags & GL_ACL_SHORT_FORMAT)
+ flags2 |= ACL_COMPACT_FMT;
+ *atext = acl_totext (aclp, flags2);
+ if (*atext)
+ replace_chr (*atext, ',', '\n');
+ else
+ ret = -1;
+ acl_free (aclp);
+ }
+ else
+ ret = 0;
+ }
+ }
+ else
+ return acl_trivial (name);
# else /* Solaris, Cygwin, general case */
@@ -384,7 +504,7 @@ file_has_acl (char const *name, struct stat const *sb)
returns only 3 entries for files with no ACL. But this is safe:
If there are more than 4 entries, there cannot be only the
"user::", "group::", "other:", and "mask:" entries. */
- if (count > 4)
+ if (! atext && count > 4)
return 1;
entries = (aclent_t *) malloc (count * sizeof (aclent_t));
@@ -397,6 +517,16 @@ file_has_acl (char const *name, struct stat const *sb)
{
if (acl_nontrivial (count, entries))
{
+ if (atext)
+ {
+ *atext = acltotext (entries, count);
+ if (! *atext)
+ {
+ free (entries);
+ return -1;
+ }
+ replace_chr (*atext, ',', '\n');
+ }
free (entries);
return 1;
}
diff --git a/lib/free-acl-text.c b/lib/free-acl-text.c
new file mode 100644
index 0000000..230808d
--- /dev/null
+++ b/lib/free-acl-text.c
@@ -0,0 +1,46 @@
+/* Free text allocated by file_has_acl.
+
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+ Written by David Bartley. */
+
+#include
+
+#include
+
+#include "acl.h"
+
+#include "acl-internal.h"
+
+
+/* Free text allocated by file_has_acl. */
+
+void
+free_acl_text (char *text)
+{
+#if USE_ACL
+ if (text)
+ {
+# if HAVE_ACL_FREE_TEXT /* Tru64 */
+ acl_free_text (text);
+# elif HAVE_ACL_FREE /* Linux, FreeBSD, MacOS X, IRIX */
+ acl_free (text);
+# else /* Solaris */
+ free (text);
+# endif
+ }
+#endif
+}
diff --git a/m4/acl.m4 b/m4/acl.m4
index 5340e2e..ce7ff85 100644
--- a/m4/acl.m4
+++ b/m4/acl.m4
@@ -36,7 +36,7 @@ AC_DEFUN([gl_FUNC_ACL],
acl_delete_def_file acl_extended_file \
acl_delete_fd_np acl_delete_file_np \
acl_copy_ext_native acl_create_entry_np \
- acl_to_short_text acl_free_text])
+ acl_to_short_text acl_to_any_text acl_free_text])
# If the acl_get_file bug is detected, don't enable the ACL support.
gl_ACL_GET_FILE([use_acl=1], [])
if test $use_acl = 1; then
diff --git a/modules/acl b/modules/acl
index 2185242..2e57b0b 100644
--- a/modules/acl
+++ b/modules/acl
@@ -8,6 +8,7 @@ lib/acl_entries.c
lib/set-mode-acl.c
lib/copy-acl.c
lib/file-has-acl.c
+lib/free-acl-text.c
m4/acl.m4
Depends-on:
@@ -20,7 +21,7 @@ configure.ac:
gl_FUNC_ACL
Makefile.am:
-lib_SOURCES += set-mode-acl.c copy-acl.c file-has-acl.c
+lib_SOURCES += set-mode-acl.c copy-acl.c file-has-acl.c free-acl-text.c
Include:
"acl.h"
diff --git a/tests/test-file-has-acl.c b/tests/test-file-has-acl.c
index 5685f41..e1ace65 100644
--- a/tests/test-file-has-acl.c
+++ b/tests/test-file-has-acl.c
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
@@ -65,7 +66,7 @@ main (int argc, char *argv[])
#if USE_ACL
{
- int ret = file_has_acl (file, &statbuf);
+ int ret = file_has_acl (file, &statbuf, 0, NULL, NULL);
if (ret < 0)
{
fprintf (stderr, "could not access the ACL of file \"%s\"\n", file);
--
1.5.6.5