X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Facl.c;h=b40e43a174c7f3c6b046a5b0feb2db8f4eca2303;hb=34ebad3df7a99eea326f9170f2517b5d23873d1b;hp=c95a57115f354f8497fd5cdcaed77791777096ad;hpb=78950f7af37b8e264119ca2e6a4cece82c921b6d;p=gnulib.git diff --git a/lib/acl.c b/lib/acl.c index c95a57115..b40e43a17 100644 --- a/lib/acl.c +++ b/lib/acl.c @@ -40,11 +40,11 @@ chmod_or_fchmod (const char *name, int desc, mode_t mode) /* 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. + DST_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. */ + Return 0 if successful, otherwise output a diagnostic and return -1. */ int copy_acl (const char *src_name, int source_desc, const char *dst_name, @@ -87,7 +87,7 @@ copy_acl (const char *src_name, int source_desc, const char *dst_name, /* 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; + 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) { @@ -144,10 +144,38 @@ copy_acl (const char *src_name, int source_desc, const char *dst_name, acl_free (acl); } return 0; + #else - ret = chmod_or_fchmod (dst_name, dest_desc, mode); + +# if USE_ACL && defined ACL_NO_TRIVIAL + /* Solaris 10 NFSv4 ACLs. */ + acl_t *aclp = NULL; + ret = (source_desc < 0 + ? acl_get (src_name, ACL_NO_TRIVIAL, &aclp) + : facl_get (source_desc, ACL_NO_TRIVIAL, &aclp)); + if (ret != 0 && errno != ENOSYS) + { + error (0, errno, "%s", quote (src_name)); + return ret; + } +# endif + + ret = qset_acl (dst_name, dest_desc, mode); if (ret != 0) error (0, errno, _("preserving permissions for %s"), quote (dst_name)); + +# if USE_ACL && defined ACL_NO_TRIVIAL + if (ret == 0 && aclp) + { + ret = (dest_desc < 0 + ? acl_set (dst_name, aclp) + : facl_set (dest_desc, aclp)); + if (ret != 0) + error (0, errno, _("preserving permissions for %s"), quote (dst_name)); + acl_free (aclp); + } +# endif + return ret; #endif } @@ -161,7 +189,7 @@ copy_acl (const char *src_name, int source_desc, const char *dst_name, semantics. */ int -set_acl (char const *name, int desc, mode_t mode) +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. */ @@ -185,10 +213,7 @@ set_acl (char const *name, int desc, mode_t mode) { acl = acl_from_mode (mode); if (!acl) - { - error (0, errno, "%s", quote (name)); - return -1; - } + return -1; } else { @@ -206,10 +231,7 @@ set_acl (char const *name, int desc, mode_t mode) acl = acl_from_text (acl_text); if (!acl) - { - error (0, errno, "%s", quote (name)); - return -1; - } + return -1; } if (HAVE_ACL_SET_FD && desc != -1) ret = acl_set_fd (desc, acl); @@ -227,17 +249,14 @@ set_acl (char const *name, int desc, mode_t mode) else return 0; } - error (0, saved_errno, _("setting permissions for %s"), quote (name)); + errno = saved_errno; 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; - } + return -1; if (mode & (S_ISUID | S_ISGID | S_ISVTX)) { @@ -245,16 +264,57 @@ set_acl (char const *name, int desc, mode_t mode) been set. */ if (chmod_or_fchmod (name, desc, mode)) - { - error (0, errno, _("preserving permissions for %s"), quote (name)); - return -1; - } + 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; + +# if USE_ACL && defined ACL_NO_TRIVIAL + + /* Solaris 10, with NFSv4 ACLs. */ + acl_t *aclp; + char acl_text[] = "user::---,group::---,mask:---,other:---"; + + if (mode & S_IRUSR) acl_text[ 6] = 'r'; + if (mode & S_IWUSR) acl_text[ 7] = 'w'; + if (mode & S_IXUSR) acl_text[ 8] = 'x'; + if (mode & S_IRGRP) acl_text[17] = acl_text[26] = 'r'; + if (mode & S_IWGRP) acl_text[18] = acl_text[27] = 'w'; + if (mode & S_IXGRP) acl_text[19] = acl_text[28] = 'x'; + if (mode & S_IROTH) acl_text[36] = 'r'; + if (mode & S_IWOTH) acl_text[37] = 'w'; + if (mode & S_IXOTH) acl_text[38] = 'x'; + + if (acl_fromtext (acl_text, &aclp) != 0) + { + errno = ENOMEM; + return -1; + } + else + { + int acl_result = (desc < 0 ? acl_set (name, aclp) : facl_set (desc, aclp)); + int acl_errno = errno; + acl_free (aclp); + if (acl_result == 0 || acl_errno != ENOSYS) + { + errno = acl_errno; + return acl_result; + } + } +# endif + + return chmod_or_fchmod (name, desc, mode); + #endif } + +/* As with qset_acl, but also output a diagnostic on failure. */ + +int +set_acl (char const *name, int desc, mode_t mode) +{ + int r = qset_acl (name, desc, mode); + if (r != 0) + error (0, errno, _("setting permissions for %s"), quote (name)); + return r; +}