From c9c845c2a4a217b2b1a5c41c3a665e75032f92c9 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 8 Jun 2008 05:06:19 +0200 Subject: [PATCH] Add support for MacOS X ACLs. --- ChangeLog | 8 ++++++ lib/copy-acl.c | 68 +++++++++++++++++++++++++++++++++++++++++++++- lib/file-has-acl.c | 25 +++++++++++++++-- lib/set-mode-acl.c | 21 ++++++++++++-- 4 files changed, 117 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index edce9825dc..e9e48fa5db 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-06-07 Bruno Haible + + Add support for MacOS X ACLs. + * lib/file-has-acl.c (file_has_acl): Use ACL_TYPE_EXTENDED instead of + ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT. + * lib/set-mode-acl.c (qset_acl): Likewise. + * lib/copy-acl.c (qcopy_acl): Likewise. + 2008-06-07 Bruno Haible Fix memory leak introduced on 2008-05-22. diff --git a/lib/copy-acl.c b/lib/copy-acl.c index f0c8dc2ce3..87952f4086 100644 --- a/lib/copy-acl.c +++ b/lib/copy-acl.c @@ -42,6 +42,8 @@ qcopy_acl (const char *src_name, int source_desc, const char *dst_name, #if USE_ACL && HAVE_ACL_GET_FILE /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ +# if MODE_INSIDE_ACL + /* Linux, FreeBSD, IRIX, Tru64 */ acl_t acl; int ret; @@ -82,7 +84,7 @@ qcopy_acl (const char *src_name, int source_desc, const char *dst_name, else acl_free (acl); - if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX))) + if (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. */ @@ -110,6 +112,70 @@ qcopy_acl (const char *src_name, int source_desc, const char *dst_name, } return 0; +# else /* !MODE_INSIDE_ACL */ + /* MacOS X */ + +# if !HAVE_ACL_TYPE_EXTENDED +# error Must have ACL_TYPE_EXTENDED +# endif + + /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS) + and acl_get_file (name, ACL_TYPE_DEFAULT) + always return NULL / EINVAL. You have to use + acl_get_file (name, ACL_TYPE_EXTENDED) + or acl_get_fd (open (name, ...)) + to retrieve an ACL. + On the other hand, + acl_set_file (name, ACL_TYPE_ACCESS, acl) + and acl_set_file (name, ACL_TYPE_DEFAULT, acl) + have the same effect as + acl_set_file (name, ACL_TYPE_EXTENDED, acl): + Each of these calls sets the file's ACL. */ + + acl_t acl; + int ret; + + if (HAVE_ACL_GET_FD && source_desc != -1) + acl = acl_get_fd (source_desc); + else + acl = acl_get_file (src_name, ACL_TYPE_EXTENDED); + if (acl == NULL) + { + if (ACL_NOT_WELL_SUPPORTED (errno)) + return qset_acl (dst_name, dest_desc, mode); + else + return -2; + } + + if (HAVE_ACL_SET_FD && dest_desc != -1) + ret = acl_set_fd (dest_desc, acl); + else + ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl); + if (ret != 0) + { + int saved_errno = errno; + + if (ACL_NOT_WELL_SUPPORTED (errno) && !(acl_entries (acl) > 0)) + { + acl_free (acl); + return chmod_or_fchmod (dst_name, dest_desc, mode); + } + else + { + acl_free (acl); + chmod_or_fchmod (dst_name, dest_desc, mode); + errno = saved_errno; + return -1; + } + } + else + acl_free (acl); + + /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */ + return chmod_or_fchmod (dst_name, dest_desc, mode); + +# endif + #elif USE_ACL && defined ACL_NO_TRIVIAL /* Solaris 10 NFSv4 ACLs. */ diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index 5b1e8ff232..f3d8bfdac2 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -127,9 +127,29 @@ file_has_acl (char const *name, struct stat const *sb) int ret; if (HAVE_ACL_EXTENDED_FILE) - ret = acl_extended_file (name); + { + /* 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 { +# if HAVE_ACL_TYPE_EXTENDED /* MacOS X */ + /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS) + and acl_get_file (name, ACL_TYPE_DEFAULT) + always return NULL / EINVAL. There is no point in making + these two useless calls. The real ACL is retrieved through + acl_get_file (name, ACL_TYPE_EXTENDED). */ + acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED); + if (acl) + { + ret = (0 < acl_entries (acl)); + acl_free (acl); + } + else + ret = -1; +# else /* FreeBSD, IRIX, Tru64 */ acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS); if (acl) { @@ -153,6 +173,7 @@ file_has_acl (char const *name, struct stat const *sb) } else ret = -1; +# endif } if (ret < 0) return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; @@ -179,7 +200,7 @@ file_has_acl (char const *name, struct stat const *sb) } #endif - /* FIXME: Add support for AIX, Irix, and Tru64. Please see Samba's + /* FIXME: Add support for AIX. Please see Samba's source/lib/sysacls.c file for fix-related ideas. */ return 0; diff --git a/lib/set-mode-acl.c b/lib/set-mode-acl.c index 6780d23939..b56ce03a94 100644 --- a/lib/set-mode-acl.c +++ b/lib/set-mode-acl.c @@ -143,6 +143,23 @@ qset_acl (char const *name, int desc, mode_t mode) # else /* !MODE_INSIDE_ACL */ /* MacOS X */ +# if !HAVE_ACL_TYPE_EXTENDED +# error Must have ACL_TYPE_EXTENDED +# endif + + /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS) + and acl_get_file (name, ACL_TYPE_DEFAULT) + always return NULL / EINVAL. You have to use + acl_get_file (name, ACL_TYPE_EXTENDED) + or acl_get_fd (open (name, ...)) + to retrieve an ACL. + On the other hand, + acl_set_file (name, ACL_TYPE_ACCESS, acl) + and acl_set_file (name, ACL_TYPE_DEFAULT, acl) + have the same effect as + acl_set_file (name, ACL_TYPE_EXTENDED, acl): + Each of these calls sets the file's ACL. */ + acl_t acl; int ret; @@ -150,7 +167,7 @@ qset_acl (char const *name, int desc, mode_t mode) if (HAVE_ACL_GET_FD && desc != -1) acl = acl_get_fd (desc); else - acl = acl_get_file (name, ACL_TYPE_ACCESS); + acl = acl_get_file (name, ACL_TYPE_EXTENDED); if (acl) { acl_free (acl); @@ -161,7 +178,7 @@ qset_acl (char const *name, int desc, mode_t mode) if (HAVE_ACL_SET_FD && desc != -1) ret = acl_set_fd (desc, acl); else - ret = acl_set_file (name, ACL_TYPE_ACCESS, acl); + ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl); if (ret != 0) { int saved_errno = errno; -- 2.30.2