[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
ACL sync from coreutils
From: |
Paul Eggert |
Subject: |
ACL sync from coreutils |
Date: |
Mon, 09 Jan 2006 15:16:25 -0800 |
User-agent: |
Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux) |
I installed this patch from Andreas Gruenbacher, to sync from coreutils:
2006-01-09 Andreas Gruenbacher <address@hidden>
Sync from coreutils.
Add POSIX ACL support
* lib/acl.h (copy_acl, set_acl): Add declarations.
* lib/acl.c (acl_entries): Add fallback implementation for POSIX ACL
systems other than Linux.
(chmod_or_fchmod): New function: use fchmod when possible,
and chmod otherwise.
(file_has_acl): Add a POSIX ACL implementation, with a
Linux-specific subcase.
(copy_acl): Add: copy an acl and S_ISUID, S_ISGID, and
S_ISVTX from one file to another. Fall back to fchmod/chmod when
acls are unsupported.
(set_acl): Add: set a file's acl and S_ISUID, S_ISGID, and
S_ISVTX to a defined value. Fall back to fchmod/chmod when acls
are unsupported.
* m4/acl.m4 (AC_FUNC_ACL): Add POSIX ACL and Linux-specific acl tests.
Index: lib/acl.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/acl.c,v
retrieving revision 1.5
diff -p -u -r1.5 acl.c
--- lib/acl.c 19 Sep 2005 17:28:14 -0000 1.5
+++ lib/acl.c 9 Jan 2006 23:02:07 -0000
@@ -16,48 +16,394 @@
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- Written by Paul Eggert. */
+ Written by Paul Eggert and Andreas Gruenbacher. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef S_ISLNK
# define S_ISLNK(Mode) 0
#endif
+#ifdef HAVE_ACL_LIBACL_H
+# include <acl/libacl.h>
+#endif
+
#include "acl.h"
+#include "error.h"
+#include "quote.h"
#include <errno.h>
#ifndef ENOSYS
# define ENOSYS (-1)
#endif
+#ifndef ENOTSUP
+# define ENOTSUP (-1)
+#endif
-#ifndef MIN_ACL_ENTRIES
-# define MIN_ACL_ENTRIES 4
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# define _(Text) Text
#endif
-/* Return 1 if FILE has a nontrivial access control list, 0 if not,
- and -1 (setting errno) if an error is encountered. */
+#ifndef HAVE_FCHMOD
+# define HAVE_FCHMOD false
+# define fchmod(fd, mode) (-1)
+#endif
+
+/* POSIX 1003.1e (draft 17) */
+#ifndef HAVE_ACL_GET_FD
+# define HAVE_ACL_GET_FD false
+# define acl_get_fd(fd) (NULL)
+#endif
+
+/* POSIX 1003.1e (draft 17) */
+#ifndef HAVE_ACL_SET_FD
+# define HAVE_ACL_SET_FD false
+# define acl_set_fd(fd, acl) (-1)
+#endif
+
+/* Linux-specific */
+#ifndef HAVE_ACL_EXTENDED_FILE
+# define HAVE_ACL_EXTENDED_FILE false
+# define acl_extended_file(name) (-1)
+#endif
+
+/* Linux-specific */
+#ifndef HAVE_ACL_FROM_MODE
+# define HAVE_ACL_FROM_MODE false
+# define acl_from_mode(mode) (NULL)
+#endif
+
+/* We detect presence of POSIX 1003.1e (draft 17 -- abandoned) support
+ by checking for HAVE_ACL_GET_FILE, HAVE_ACL_SET_FILE, and HAVE_ACL_FREE.
+ Systems that have acl_get_file, acl_set_file, and acl_free must also
+ have acl_to_text, acl_from_text, and acl_delete_def_file (all defined
+ in the draft); systems that don't would hit #error statements here. */
+
+#if USE_ACL && HAVE_ACL_GET_FILE && !HAVE_ACL_ENTRIES
+# ifndef HAVE_ACL_TO_TEXT
+# error Must have acl_to_text (see POSIX 1003.1e draft 17).
+# endif
+
+/* Return the number of entries in ACL. Linux implements acl_entries
+ as a more efficient extension than using this workaround. */
+
+static int
+acl_entries (acl_t acl)
+{
+ char *text = acl_to_text (acl, NULL), *t;
+ int entries;
+ if (text == NULL)
+ return -1;
+ for (entries = 0, t = text; ; t++, entries++) {
+ t = strchr (t, '\n');
+ if (t == NULL)
+ break;
+ }
+ acl_free (text);
+ return entries;
+}
+#endif
+
+/* If DESC is a valid file descriptor use fchmod to change the
+ file's mode to MODE on systems that have fchown. On systems
+ that don't have fchown and if DESC is invalid, use chown on
+ NAME instead. */
int
-file_has_acl (char const *file, struct stat const *filestat)
+chmod_or_fchmod (const char *name, int desc, mode_t mode)
{
- /* FIXME: This implementation should work on recent-enough versions
- of HP-UX, Solaris, and Unixware, but it simply returns 0 with
- POSIX 1003.1e (draft 17 -- abandoned), AIX, GNU/Linux, Irix, and
- Tru64. Please see Samba's source/lib/sysacls.c file for
- fix-related ideas. */
+ if (HAVE_FCHMOD && desc != -1)
+ return fchmod (desc, mode);
+ else
+ return chmod (name, mode);
+}
-#if HAVE_ACL && defined GETACLCNT
- if (! S_ISLNK (filestat->st_mode))
+/* Return 1 if NAME has a nontrivial access control list, 0 if
+ NAME only has no or a base access control list, and -1 on
+ error. SB must be set to the stat buffer of FILE. */
+
+int
+file_has_acl (char const *name, struct stat const *sb)
+{
+#if USE_ACL && HAVE_ACL && defined GETACLCNT
+ /* This implementation should work on recent-enough versions of HP-UX,
+ Solaris, and Unixware. */
+
+# ifndef MIN_ACL_ENTRIES
+# define MIN_ACL_ENTRIES 4
+# endif
+
+ if (! S_ISLNK (sb->st_mode))
{
- int n = acl (file, GETACLCNT, 0, NULL);
+ int n = acl (name, GETACLCNT, 0, NULL);
return n < 0 ? (errno == ENOSYS ? 0 : -1) : (MIN_ACL_ENTRIES < n);
}
+#elif USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE
+ /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
+
+ if (! S_ISLNK (sb->st_mode))
+ {
+ int ret;
+
+ if (HAVE_ACL_EXTENDED_FILE)
+ ret = acl_extended_file (name);
+ else
+ {
+ acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
+ if (acl)
+ {
+ ret = (3 < acl_entries (acl));
+ acl_free (acl);
+ if (ret == 0 && S_ISDIR (sb->st_mode))
+ {
+ acl = acl_get_file (name, ACL_TYPE_DEFAULT);
+ if (acl)
+ {
+ ret = (0 < acl_entries (acl));
+ acl_free (acl);
+ }
+ else
+ ret = -1;
+ }
+ }
+ else
+ ret = -1;
+ }
+ if (ret < 0)
+ return (errno == ENOSYS || errno == ENOTSUP) ? 0 : -1;
+ return ret;
+ }
+#endif
+
+ /* FIXME: Add support for AIX, Irix, and Tru64. Please see Samba's
+ source/lib/sysacls.c file for fix-related ideas. */
+
+ return 0;
+}
+
+/* Copy access control lists from one file to another. If SOURCE_DESC is
+ a valid file descriptor, use file descriptor operations, else use
+ filename based operations on SRC_NAME. Likewise for DEST_DESC and
+ DEST_NAME.
+ If access control lists are not available, fchmod the target file to
+ MODE. Also sets the non-permission bits of the destination file
+ (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
+ System call return value semantics. */
+
+int
+copy_acl (const char *src_name, int source_desc, const char *dst_name,
+ int dest_desc, mode_t mode)
+{
+ int ret;
+
+#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
+ /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
+
+ acl_t acl;
+ if (HAVE_ACL_GET_FD && source_desc != -1)
+ acl = acl_get_fd (source_desc);
+ else
+ acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
+ if (acl == NULL)
+ {
+ if (errno == ENOSYS || errno == ENOTSUP)
+ return set_acl (dst_name, dest_desc, mode);
+ else
+ {
+ error (0, errno, "%s", quote (src_name));
+ return -1;
+ }
+ }
+
+ if (HAVE_ACL_SET_FD && dest_desc != -1)
+ ret = acl_set_fd (dest_desc, acl);
+ else
+ ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
+ if (ret != 0)
+ {
+ int saved_errno = errno;
+
+ if (errno == ENOSYS || errno == ENOTSUP)
+ {
+ int n = acl_entries (acl);
+
+ acl_free (acl);
+ if (n == 3)
+ {
+ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
+ saved_errno = errno;
+ else
+ return 0;
+ }
+ else
+ chmod_or_fchmod (dst_name, dest_desc, mode);
+ }
+ else
+ {
+ acl_free (acl);
+ chmod_or_fchmod (dst_name, dest_desc, mode);
+ }
+ error (0, saved_errno, _("preserving permissions for %s"),
+ quote (dst_name));
+ return -1;
+ }
+ else
+ acl_free (acl);
+
+ if (mode & (S_ISUID | S_ISGID | S_ISVTX))
+ {
+ /* We did not call chmod so far, so the special bits have not yet
+ been set. */
+
+ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
+ {
+ error (0, errno, _("preserving permissions for %s"),
+ quote (dst_name));
+ return -1;
+ }
+ }
+
+ if (S_ISDIR (mode))
+ {
+ acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
+ if (acl == NULL)
+ {
+ error (0, errno, "%s", quote (src_name));
+ return -1;
+ }
+
+ if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
+ {
+ error (0, errno, _("preserving permissions for %s"),
+ quote (dst_name));
+ acl_free (acl);
+ return -1;
+ }
+ else
+ acl_free (acl);
+ }
+ return 0;
+#else
+ ret = chmod_or_fchmod (dst_name, dest_desc, mode);
+ if (ret != 0)
+ error (0, errno, _("preserving permissions for %s"), quote (dst_name));
+ return ret;
#endif
+}
+
+/* Set the access control lists of a file. If DESC is a valid file
+ descriptor, use file descriptor operations where available, else use
+ filename based operations on NAME. If access control lists are not
+ available, fchmod the target file to MODE. Also sets the
+ non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
+ to those from MODE if any are set. System call return value
+ semantics. */
+
+int
+set_acl (char const *name, int desc, mode_t mode)
+{
+#if USE_ACL && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
+ /* POSIX 1003.1e draft 17 (abandoned) specific version. */
+ /* We must also have have_acl_from_text and acl_delete_def_file.
+ (acl_delete_def_file could be emulated with acl_init followed
+ by acl_set_file, but acl_set_file with an empty acl is
+ unspecified.) */
+
+# ifndef HAVE_ACL_FROM_TEXT
+# error Must have acl_from_text (see POSIX 1003.1e draft 17).
+# endif
+# ifndef HAVE_ACL_DELETE_DEF_FILE
+# error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
+# endif
+
+ acl_t acl;
+ int ret;
+
+ if (HAVE_ACL_FROM_MODE)
+ {
+ acl = acl_from_mode (mode);
+ if (!acl)
+ {
+ error (0, errno, "%s", quote (name));
+ return -1;
+ }
+ }
+ else
+ {
+ char acl_text[] = "u::---,g::---,o::---";
+
+ if (mode & S_IRUSR) acl_text[ 3] = 'r';
+ if (mode & S_IWUSR) acl_text[ 4] = 'w';
+ if (mode & S_IXUSR) acl_text[ 5] = 'x';
+ if (mode & S_IRGRP) acl_text[10] = 'r';
+ if (mode & S_IWGRP) acl_text[11] = 'w';
+ if (mode & S_IXGRP) acl_text[12] = 'x';
+ if (mode & S_IROTH) acl_text[17] = 'r';
+ if (mode & S_IWOTH) acl_text[18] = 'w';
+ if (mode & S_IXOTH) acl_text[19] = 'x';
+
+ acl = acl_from_text (acl_text);
+ if (!acl)
+ {
+ error (0, errno, "%s", quote (name));
+ return -1;
+ }
+ }
+ if (HAVE_ACL_SET_FD && desc != -1)
+ ret = acl_set_fd (desc, acl);
+ else
+ ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
+ if (ret != 0)
+ {
+ int saved_errno = errno;
+ acl_free (acl);
+
+ if (errno == ENOTSUP || errno == ENOSYS)
+ {
+ if (chmod_or_fchmod (name, desc, mode) != 0)
+ saved_errno = errno;
+ else
+ return 0;
+ }
+ error (0, saved_errno, _("setting permissions for %s"), quote (name));
+ return -1;
+ }
+ else
+ acl_free (acl);
+
+ if (S_ISDIR (mode) && acl_delete_def_file (name))
+ {
+ error (0, errno, _("setting permissions for %s"), quote (name));
+ return -1;
+ }
+
+ if (mode & (S_ISUID | S_ISGID | S_ISVTX))
+ {
+ /* We did not call chmod so far, so the special bits have not yet
+ been set. */
+
+ if (chmod_or_fchmod (name, desc, mode))
+ {
+ error (0, errno, _("preserving permissions for %s"), quote (name));
+ return -1;
+ }
+ }
return 0;
+#else
+ int ret = chmod_or_fchmod (name, desc, mode);
+ if (ret)
+ error (0, errno, _("setting permissions for %s"), quote (name));
+ return ret;
+#endif
}
Index: lib/acl.h
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/acl.h,v
retrieving revision 1.2
diff -p -u -r1.2 acl.h
--- lib/acl.h 14 May 2005 06:03:57 -0000 1.2
+++ lib/acl.h 9 Jan 2006 23:02:07 -0000
@@ -18,11 +18,14 @@
Written by Paul Eggert. */
-#if HAVE_SYS_ACL_H && HAVE_ACL
+#if HAVE_SYS_ACL_H
# include <sys/acl.h>
#endif
-#if ! defined GETACLCNT && defined ACL_CNT
+#if defined HAVE_ACL && ! defined GETACLCNT && defined ACL_CNT
# define GETACLCNT ACL_CNT
#endif
int file_has_acl (char const *, struct stat const *);
+int copy_acl (char const *, int, char const *, int, mode_t);
+int set_acl (char const *, int, mode_t);
+int chmod_or_fchmod (char const *, int, mode_t);
Index: m4/acl.m4
===================================================================
RCS file: /cvsroot/gnulib/gnulib/m4/acl.m4,v
retrieving revision 1.5
diff -p -u -r1.5 acl.m4
--- m4/acl.m4 21 Mar 2005 22:06:27 -0000 1.5
+++ m4/acl.m4 9 Jan 2006 23:02:07 -0000
@@ -14,5 +14,22 @@ AC_DEFUN([AC_FUNC_ACL],
dnl Prerequisites of lib/acl.c.
AC_CHECK_HEADERS(sys/acl.h)
+ if test "$ac_cv_header_sys_acl_h" = yes; then
+ use_acl=1
+ else
+ use_acl=0
+ fi
+ AC_DEFINE_UNQUOTED(USE_ACL, $use_acl,
+ [Define if you want access control list support.])
AC_CHECK_FUNCS(acl)
+ ac_save_LIBS="$LIBS"
+ AC_SEARCH_LIBS(acl_get_file, acl,
+ [test "$ac_cv_search_acl_get_file" = "none required" ||
+ LIB_ACL=$ac_cv_search_acl_get_file])
+ AC_SUBST(LIB_ACL)
+ AC_CHECK_HEADERS(acl/libacl.h)
+ AC_CHECK_FUNCS(acl_get_file acl_get_fd acl_set_file acl_set_fd \
+ acl_free acl_from_mode acl_from_text acl_to_text \
+ acl_delete_def_file acl_entries acl_extended_file)
+ LIBS="$ac_save_LIBS"
])
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- ACL sync from coreutils,
Paul Eggert <=