[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
acl: add support for MacOS X 10.5
From: |
Bruno Haible |
Subject: |
acl: add support for MacOS X 10.5 |
Date: |
Fri, 23 May 2008 01:37:38 +0200 |
User-agent: |
KMail/1.5.4 |
Hi Jim,
Here comes the reworked patch for MacOS X 10.5 support in copy_acl, used
by the 'copy-file' module. With it, now the test passes on MacOS X 10.5,
and of course still passes on Linux and FreeBSD.
The main difficulty here was to realize that in MacOS X, unlike many other
flavors of ACLs, an ACL does *not* contain the file mode (rwxrwxrwx). They
are separate. In the code I created a macro MODE_INSIDE_ACL to denote the
"normal" situation.
The consequences are that
- The qset_acl function requires a different logic when !MODE_INSIDE_ACL.
When MODE_INSIDE_ACL, one optimizes system calls by calling chmod only
when setting the ACL failed or was not enough. When !MODE_INSIDE_ACL,
one has to call chmod always.
- Similarly in copy_acl, but here the code changes are smaller.
- When !MODE_INSIDE_ACL, a trivial ACL has 0 entries, not 3 entries.
Another realization is that this piece of code in acl.c:
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';
works only on FreeBSD (and possibly IRIX). Basically, every ACL flavor comes
with its own textual representation of ACLs, and most of them expect the
syntax "other:rwx", not "other::rwx".
Also, I added a comment explaining why the conversion mode_t -> acl_t goes
through the textual representation rather than through acl_init() and
acl_create_entry().
> for future patches to my attention please use git format-patch,
> since that makes it easier for me to apply and ensure that when I review
Find it attached as attachment. Now I'll have to learn how to amend previous
commits...
OK to commit? After this, I'll turn to the other 5 platforms.
2008-05-22 Bruno Haible <address@hidden>
Make copy_acl work on MacOS X 10.5.
* lib/acl-internal.h (MODE_INSIDE_ACL): New macro.
(ACL_NOT_WELL_SUPPORTED): On MacOS X, also handle ENOENT.
* lib/acl.c (qset_acl): Add different code branch for !MODE_INSIDE_ACL.
If MODE_INSIDE_ACL, don't assume that every system has the same text
representation for ACLs as FreeBSD.
* lib/copy-acl.c (copy_acl): Add support for platforms with
!MODE_INSIDE_ACL.
* lib/file-has-acl.c (file_has_acl): Likewise.
* m4/acl.m4 (gl_FUNC_ACL): Test for some functions that are witness
of FreeBSD or MacOS X, respectively.
*** lib/acl-internal.h.orig 2008-05-23 01:08:01.000000000 +0200
--- lib/acl-internal.h 2008-05-23 00:15:58.000000000 +0200
***************
*** 84,91 ****
# define acl_from_mode(mode) (NULL)
#endif
! #define ACL_NOT_WELL_SUPPORTED(Err) \
! ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY)
/* Define a replacement for acl_entries if needed. */
#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE && !HAVE_ACL_ENTRIES
--- 84,104 ----
# define acl_from_mode(mode) (NULL)
#endif
! /* Set to 1 if a file's mode is implicit by the ACL.
! Set to 0 if a file's mode is stored independently from the ACL. */
! #if HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP /* MacOS X */
! # define MODE_INSIDE_ACL 0
! #else
! # define MODE_INSIDE_ACL 1
! #endif
!
! #if defined __APPLE__ && defined __MACH__ /* MacOS X */
! # define ACL_NOT_WELL_SUPPORTED(Err) \
! ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY
|| (Err) == ENOENT)
! #else
! # define ACL_NOT_WELL_SUPPORTED(Err) \
! ((Err) == ENOTSUP || (Err) == ENOSYS || (Err) == EINVAL || (Err) == EBUSY)
! #endif
/* Define a replacement for acl_entries if needed. */
#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE && !HAVE_ACL_ENTRIES
*** lib/acl.c.orig 2008-05-23 01:08:01.000000000 +0200
--- lib/acl.c 2008-05-23 00:52:39.000000000 +0200
***************
*** 48,79 ****
int
qset_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)
return -1;
}
! else
{
char acl_text[] = "u::---,g::---,o::---";
if (mode & S_IRUSR) acl_text[ 3] = 'r';
--- 48,89 ----
int
qset_acl (char const *name, int desc, mode_t mode)
{
! #if USE_ACL
! # if MODE_INSIDE_ACL
! # if HAVE_ACL_SET_FILE && HAVE_ACL_FREE
/* POSIX 1003.1e draft 17 (abandoned) specific version. */
+ /* Linux, FreeBSD, IRIX, Tru64 */
! /* We must also 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) /* Linux */
{
acl = acl_from_mode (mode);
if (!acl)
return -1;
}
! else /* FreeBSD, IRIX, Tru64 */
{
+ /* If we were to create the ACL using the functions acl_init(),
+ acl_create_entry(), acl_set_tag_type(), acl_set_qualifier(),
+ acl_get_permset(), acl_clear_perm[s](), acl_add_perm(), we
+ would need to create a qualifier. I don't know how to do this.
+ So create it using acl_from_text(). */
+
+ # if HAVE_ACL_DELETE_FD_NP && HAVE_ACL_DELETE_FILE_NP /* FreeBSD */
char acl_text[] = "u::---,g::---,o::---";
if (mode & S_IRUSR) acl_text[ 3] = 'r';
***************
*** 89,94 ****
--- 99,107 ----
acl = acl_from_text (acl_text);
if (!acl)
return -1;
+ # else /* Unknown flavor of POSIX-like ACLs */
+ return chmod_or_fchmod (name, desc, mode);
+ # endif
}
if (HAVE_ACL_SET_FD && desc != -1)
ret = acl_set_fd (desc, acl);
***************
*** 124,133 ****
return -1;
}
return 0;
- #else
-
- # if USE_ACL && defined ACL_NO_TRIVIAL
/* Solaris 10, with NFSv4 ACLs. */
acl_t *aclp;
char acl_text[] = "user::---,group::---,mask:---,other:---";
--- 137,144 ----
return -1;
}
return 0;
+ # elif defined ACL_NO_TRIVIAL
/* Solaris 10, with NFSv4 ACLs. */
acl_t *aclp;
char acl_text[] = "user::---,group::---,mask:---,other:---";
***************
*** 158,167 ****
return acl_result;
}
}
- # endif
return chmod_or_fchmod (name, desc, mode);
#endif
}
--- 169,234 ----
return acl_result;
}
}
return chmod_or_fchmod (name, desc, mode);
+ # else /* Unknown flavor of ACLs */
+ return chmod_or_fchmod (name, desc, mode);
+ # endif
+ # else /* !MODE_INSIDE_ACL */
+ # if HAVE_ACL_SET_FILE && HAVE_ACL_FREE
+ /* POSIX 1003.1e draft 17 (abandoned) specific version. */
+ /* MacOS X */
+
+ acl_t acl;
+ int ret;
+
+ /* Remove the ACL if the file has ACLs. */
+ if (HAVE_ACL_GET_FD && desc != -1)
+ acl = acl_get_fd (desc);
+ else
+ acl = acl_get_file (name, ACL_TYPE_ACCESS);
+ if (acl)
+ {
+ # if HAVE_ACL_COPY_EXT_NATIVE && HAVE_ACL_CREATE_ENTRY_NP /* MacOS X */
+ static const char empty_acl_text[] = "!#acl 1\n";
+ # else /* Unknown flavor of POSIX-like ACLs */
+ # error Unknown flavor of POSIX-like ACLs - add support for your platform.
+ # endif
+
+ acl = acl_from_text (empty_acl_text);
+ if (acl)
+ {
+ 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 (ACL_NOT_WELL_SUPPORTED (saved_errno))
+ {
+ if (chmod_or_fchmod (name, desc, mode) != 0)
+ saved_errno = errno;
+ else
+ return 0;
+ }
+ errno = saved_errno;
+ return -1;
+ }
+ }
+ }
+
+ return chmod_or_fchmod (name, desc, mode);
+ # else /* Unknown flavor of ACLs */
+ return chmod_or_fchmod (name, desc, mode);
+ # endif
+ # endif
+ #else /* !USE_ACL */
+ return chmod_or_fchmod (name, desc, mode);
#endif
}
*** lib/copy-acl.c.orig 2008-05-23 01:08:01.000000000 +0200
--- lib/copy-acl.c 2008-05-23 00:54:12.000000000 +0200
***************
*** 40,45 ****
--- 40,46 ----
#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
+ /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
acl_t acl;
if (HAVE_ACL_GET_FD && source_desc != -1)
***************
*** 70,81 ****
int n = acl_entries (acl);
acl_free (acl);
! /* On most hosts an ACL is trivial if n == 3, and it cannot be
! less than 3. On IRIX 6.5 it is also trivial if n == -1.
For simplicity and safety, assume the ACL is trivial if n <= 3.
Also see file-has-acl.c for some of the other possibilities;
it's not clear whether that complexity is needed here. */
! if (n <= 3)
{
if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
saved_errno = errno;
--- 71,83 ----
int n = acl_entries (acl);
acl_free (acl);
! /* On most hosts with MODE_INSIDE_ACL an ACL is trivial if n == 3,
! and it cannot be less than 3. On IRIX 6.5 it is also trivial if
! n == -1.
For simplicity and safety, assume the ACL is trivial if n <= 3.
Also see file-has-acl.c for some of the other possibilities;
it's not clear whether that complexity is needed here. */
! if (n <= 3 * MODE_INSIDE_ACL)
{
if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
saved_errno = errno;
***************
*** 97,106 ****
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)
{
--- 99,108 ----
else
acl_free (acl);
! if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX)))
{
! /* We did not call chmod so far, and either the mode and the ACL are
! separate or special bits are to be set which don't fit into ACLs. */
if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
{
*** lib/file-has-acl.c.orig 2008-05-23 01:08:01.000000000 +0200
--- lib/file-has-acl.c 2008-05-23 00:36:37.000000000 +0200
***************
*** 1,6 ****
/* 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
--- 1,6 ----
/* Test whether a file has a nontrivial access control list.
! Copyright (C) 2002-2003, 2005-2008 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
***************
*** 47,52 ****
--- 47,53 ----
#elif USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE
/* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
+ /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */
int ret;
if (HAVE_ACL_EXTENDED_FILE)
***************
*** 56,62 ****
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))
{
--- 57,63 ----
acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
if (acl)
{
! ret = (3 * MODE_INSIDE_ACL < acl_entries (acl));
acl_free (acl);
if (ret == 0 && S_ISDIR (sb->st_mode))
{
*** m4/acl.m4.orig 2008-05-23 01:08:01.000000000 +0200
--- m4/acl.m4 2008-05-23 00:16:28.000000000 +0200
***************
*** 1,5 ****
# acl.m4 - check for access control list (ACL) primitives
! # serial 3
# Copyright (C) 2002, 2004-2008 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
--- 1,5 ----
# acl.m4 - check for access control list (ACL) primitives
! # serial 4
# Copyright (C) 2002, 2004-2008 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
***************
*** 35,41 ****
AC_CHECK_FUNCS(
[acl_get_file acl_get_fd acl_set_file acl_set_fd \
acl_free acl_from_mode acl_from_text \
! acl_delete_def_file acl_extended_file])
if test $ac_cv_func_acl_get_file = yes; then
# If the acl_get_file bug is detected, disable all ACL support.
gl_ACL_GET_FILE( , [use_acl=0])
--- 35,43 ----
AC_CHECK_FUNCS(
[acl_get_file acl_get_fd acl_set_file acl_set_fd \
acl_free acl_from_mode acl_from_text \
! acl_delete_def_file acl_extended_file \
! acl_delete_fd_np acl_delete_file_np \
! acl_copy_ext_native acl_create_entry_np])
if test $ac_cv_func_acl_get_file = yes; then
# If the acl_get_file bug is detected, disable all ACL support.
gl_ACL_GET_FILE( , [use_acl=0])
0001-Make-copy_acl-work-on-MacOS-X-10.5.patch
Description: Text Data
- acl: add support for MacOS X 10.5,
Bruno Haible <=