From: Paul Eggert Date: Mon, 19 Mar 2007 21:58:57 +0000 (+0000) Subject: Add limited support for Solaris 10 ZFS-style ACLs: just enough to X-Git-Tag: cvs-readonly~742 X-Git-Url: http://erislabs.net/gitweb/?a=commitdiff_plain;h=e37fe028c558a3d0a80b347b745e162f549ea295;p=gnulib.git Add limited support for Solaris 10 ZFS-style ACLs: just enough to handle file_has_acl. * lib/acl-internal.h, lib/acl_entries.c, lib/file-has-acl.c: New files. * lib/acl.c: Move header inclusions and related macro defns into lib/acl-internal.h. (S_ISLNK): Remove defn, since that's now done for us. (file_has_acl): Move to lib/file-has-acl.c. Call acl_trivial if available. This is the crucial part of the fix. (acl_entries): Move to lib/acl_entries.c. Now extern, since it's shared within the library. Rewrite a bit, partly to make it compatible with the GNU coding style. * m4/acl.m4 (AC_FUNC_ACL): Add AC_LIBOBJ([file-has-acl]). Remove unnecessary double-quotes. Don't test for acl_to_text; the build will catch that. Replace acl_entries if it doesn't exist and it is needed. Check for -lsec and acl_trivial (as used on Solaris 10). * modules/acl (Files): Add lib/acl-internal.h, lib/acl_entries.c, lib/file-has-acl.c. (Depends-on): Add sys_stat, for S_ISLNK. --- diff --git a/ChangeLog b/ChangeLog index 2a15f8d75..2c8bd8452 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2007-03-19 Paul Eggert + + Add limited support for Solaris 10 ZFS-style ACLs: just enough to + handle file_has_acl. + * lib/acl-internal.h, lib/acl_entries.c, lib/file-has-acl.c: New files. + * lib/acl.c: Move header inclusions and related macro defns into + lib/acl-internal.h. + (S_ISLNK): Remove defn, since that's now done for us. + (file_has_acl): Move to lib/file-has-acl.c. + Call acl_trivial if available. This is the crucial part of the fix. + (acl_entries): Move to lib/acl_entries.c. Now extern, since it's + shared within the library. Rewrite a bit, partly to make it compatible + with the GNU coding style. + * m4/acl.m4 (AC_FUNC_ACL): Add AC_LIBOBJ([file-has-acl]). + Remove unnecessary double-quotes. + Don't test for acl_to_text; the build will catch that. + Replace acl_entries if it doesn't exist and it is needed. + Check for -lsec and acl_trivial (as used on Solaris 10). + * modules/acl (Files): Add lib/acl-internal.h, lib/acl_entries.c, + lib/file-has-acl.c. + (Depends-on): Add sys_stat, for S_ISLNK. + 2007-03-19 Ben Pfaff * doc/gnulib.texi: Fix typos. diff --git a/lib/acl-internal.h b/lib/acl-internal.h new file mode 100644 index 000000000..c37a7c19e --- /dev/null +++ b/lib/acl-internal.h @@ -0,0 +1,90 @@ +/* Internal implementation of access control lists. + + Copyright (C) 2002, 2003, 2005, 2006, 2007 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 2, 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, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Written by Paul Eggert and Andreas Gruenbacher. */ + +#include + +#include "acl.h" + +#include +#include + +#ifdef HAVE_ACL_LIBACL_H +# include +#endif + +#include "error.h" +#include "quote.h" + +#include +#ifndef ENOSYS +# define ENOSYS (-1) +#endif +#ifndef ENOTSUP +# define ENOTSUP (-1) +#endif + +#if ENABLE_NLS +# include +# define _(Text) gettext (Text) +#else +# define _(Text) Text +#endif + +#ifndef HAVE_FCHMOD +# define HAVE_FCHMOD false +# define fchmod(fd, mode) (-1) +#endif + +#ifndef MIN_ACL_ENTRIES +# define MIN_ACL_ENTRIES 4 +#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 + +#define ACL_NOT_WELL_SUPPORTED(Errno) \ + (Errno == ENOTSUP || Errno == ENOSYS || Errno == EINVAL) + +/* Define a replacement for acl_entries if needed. */ +#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE && !HAVE_ACL_ENTRIES +# define acl_entries rpl_acl_entries +int acl_entries (acl_t); +#endif diff --git a/lib/acl.c b/lib/acl.c index 81fc470c1..84c595ab2 100644 --- a/lib/acl.c +++ b/lib/acl.c @@ -22,97 +22,7 @@ #include "acl.h" -#include -#include -#include -#ifndef S_ISLNK -# define S_ISLNK(Mode) 0 -#endif - -#ifdef HAVE_ACL_LIBACL_H -# include -#endif - -#include "error.h" -#include "quote.h" - -#include -#ifndef ENOSYS -# define ENOSYS (-1) -#endif -#ifndef ENOTSUP -# define ENOTSUP (-1) -#endif - -#if ENABLE_NLS -# include -# define _(Text) gettext (Text) -#else -# define _(Text) Text -#endif - -#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 - -#define ACL_NOT_WELL_SUPPORTED(Errno) \ - (Errno == ENOTSUP || Errno == ENOSYS || Errno == EINVAL) - -/* We detect the 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 +#include "acl-internal.h" /* If DESC is a valid file descriptor use fchmod to change the file's mode to MODE on systems that have fchown. On systems @@ -128,69 +38,6 @@ chmod_or_fchmod (const char *name, int desc, mode_t mode) return chmod (name, 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 (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 ACL_NOT_WELL_SUPPORTED (errno) ? 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 diff --git a/lib/acl_entries.c b/lib/acl_entries.c new file mode 100644 index 000000000..25c8bb825 --- /dev/null +++ b/lib/acl_entries.c @@ -0,0 +1,39 @@ +/* Return the number of entries in an ACL. + + Copyright (C) 2002, 2003, 2005, 2006, 2007 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 2, 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, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Written by Paul Eggert and Andreas Gruenbacher. */ + +#include + +#include "acl-internal.h" + +/* Return the number of entries in ACL. */ + +int +acl_entries (acl_t acl) +{ + char *t; + int entries = 0; + char *text = acl_to_text (acl, NULL); + if (! text) + return -1; + for (t = text; *t; t++) + entries += (*t == '\n'); + acl_free (text); + return entries; +} diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c new file mode 100644 index 000000000..218f52ec8 --- /dev/null +++ b/lib/file-has-acl.c @@ -0,0 +1,87 @@ +/* Test whether a file has a nontrivial access control list. + + Copyright (C) 2002, 2003, 2005, 2006, 2007 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 2, 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, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Written by Paul Eggert and Andreas Gruenbacher. */ + +#include + +#include "acl.h" + +#include "acl-internal.h" + +/* 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. */ + +int +file_has_acl (char const *name, struct stat const *sb) +{ + if (! S_ISLNK (sb->st_mode)) + { +#if USE_ACL && HAVE_ACL_TRIVIAL + + /* Solaris 10, which also has NFSv4 and ZFS style ACLs. */ + return acl_trivial (name); + +#elif USE_ACL && HAVE_ACL && defined GETACLCNT + + /* Solaris 2.5 through Solaris 9, and contemporaneous versions of + HP-UX and Unixware. */ + 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. */ + 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 ACL_NOT_WELL_SUPPORTED (errno) ? 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; +} diff --git a/m4/acl.m4 b/m4/acl.m4 index c5c6e3446..6e6bd086b 100644 --- a/m4/acl.m4 +++ b/m4/acl.m4 @@ -1,6 +1,6 @@ # acl.m4 - check for access control list (ACL) primitives -# Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. +# Copyright (C) 2002, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -10,6 +10,7 @@ AC_DEFUN([AC_FUNC_ACL], [ AC_LIBOBJ([acl]) + AC_LIBOBJ([file-has-acl]) dnl Prerequisites of lib/acl.c. AC_CHECK_HEADERS(sys/acl.h) @@ -21,18 +22,33 @@ AC_DEFUN([AC_FUNC_ACL], 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) - if test "$ac_cv_header_sys_acl_h" = yes; then + acl_free acl_from_mode acl_from_text \ + acl_delete_def_file acl_extended_file) + if test $ac_cv_header_sys_acl_h = yes; then use_acl=1 - if test "$ac_cv_func_acl_get_file" = yes; then + if test $ac_cv_func_acl_get_file = yes; then # If we detect the acl_get_file bug, disable ACL support altogether. gl_ACL_GET_FILE( , [use_acl=0]) fi else use_acl=0 fi + if test $use_acl = 1 && + test $ac_cv_func_acl_get_file = yes && + test $ac_cv_func_acl_free = yes; then + AC_REPLACE_FUNCS([acl_entries]) + fi LIBS="$ac_save_LIBS" + if test $use_acl = 1; then + ac_save_LIBS="$LIBS" + AC_SEARCH_LIBS([acl_trivial], [sec], + [AC_DEFINE([HAVE_ACL_TRIVIAL], 1, + [Define to 1 if you have the `acl_trivial' function.]) + test "$ac_cv_search_acl_trivial" = "none required" || + LIB_ACL_TRIVIAL="$ac_cv_search_acl_trivial"]) + AC_SUBST([LIB_ACL_TRIVIAL]) + LIBS="$ac_save_LIBS" + fi AC_DEFINE_UNQUOTED(USE_ACL, $use_acl, [Define if you want access control list support.]) ]) diff --git a/modules/acl b/modules/acl index 969511535..3211f307a 100644 --- a/modules/acl +++ b/modules/acl @@ -4,11 +4,15 @@ Access control lists of files. (Unportable.) Files: lib/acl.h lib/acl.c +lib/acl-internal.h +lib/acl_entries.c +lib/file-has-acl.c m4/acl.m4 Depends-on: error quote +sys_stat configure.ac: AC_FUNC_ACL