void KrVfsHandler::getACL(vfile *file, QString &acl, QString &defAcl) { Q_UNUSED(file); acl.clear(); defAcl.clear(); #ifdef HAVE_POSIX_ACL QString fileName = vfs::cleanUrl(file->vfile_getUrl()).path(); #ifdef HAVE_NON_POSIX_ACL_EXTENSIONS if (acl_extended_file(fileName)) { #endif acl = getACL(fileName, ACL_TYPE_ACCESS); if (file->vfile_isDir()) defAcl = getACL(fileName, ACL_TYPE_DEFAULT); #ifdef HAVE_NON_POSIX_ACL_EXTENSIONS } #endif #endif }
int file_has_acl (char const *name, struct stat const *sb) { #if USE_ACL if (! S_ISLNK (sb->st_mode)) { # if HAVE_ACL_GET_FILE /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ int ret; if (HAVE_ACL_EXTENDED_FILE) /* Linux */ { /* 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 /* FreeBSD, MacOS X, IRIX, Tru64 */ { # 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 = acl_extended_nontrivial (acl); acl_free (acl); } else ret = -1; # else /* FreeBSD, IRIX, Tru64 */ acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS); if (acl) { int saved_errno; ret = acl_access_nontrivial (acl); saved_errno = errno; acl_free (acl); errno = saved_errno; # if HAVE_ACL_FREE_TEXT /* Tru64 */ /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always returns NULL with errno not set. There is no point in making this call. */ # else /* FreeBSD, IRIX */ /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS) and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory either both succeed or both fail; it depends on the file system. Therefore there is no point in making the second call if the first one already failed. */ 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; } # endif } else ret = -1; # endif } if (ret < 0) return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; return ret; # elif HAVE_FACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ # if defined ACL_NO_TRIVIAL /* Solaris 10 (newer version), which has additional API declared in <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial, acl_fromtext, ...). */ return acl_trivial (name); # else /* Solaris, Cygwin, general case */ /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions of Unixware. The acl() call returns the access and default ACL both at once. */ int count; { aclent_t *entries; for (;;) { count = acl (name, GETACLCNT, 0, NULL); if (count < 0) { if (errno == ENOSYS || errno == ENOTSUP) break; else return -1; } if (count == 0) break; /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin returns only 3 entries for files with no ACL. But this is safe: If there are more than 4 entries, there cannot be only the "user::", "group::", "other:", and "mask:" entries. */ if (count > 4) return 1; entries = (aclent_t *) malloc (count * sizeof (aclent_t)); if (entries == NULL) { errno = ENOMEM; return -1; } if (acl (name, GETACL, count, entries) == count) { if (acl_nontrivial (count, entries)) { free (entries); return 1; } free (entries); break; } /* Huh? The number of ACL entries changed since the last call. Repeat. */ free (entries); } } # ifdef ACE_GETACL /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 file systems (whereas the other ones are used in UFS file systems). */ { ace_t *entries; for (;;) { count = acl (name, ACE_GETACLCNT, 0, NULL); if (count < 0) { if (errno == ENOSYS || errno == EINVAL) break; else return -1; } if (count == 0) break; /* In the old (original Solaris 10) convention: If there are more than 3 entries, there cannot be only the ACE_OWNER, ACE_GROUP, ACE_OTHER entries. In the newer Solaris 10 and Solaris 11 convention: If there are more than 6 entries, there cannot be only the ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with NEW_ACE_ACCESS_DENIED_ACE_TYPE. */ if (count > 6) return 1; entries = (ace_t *) malloc (count * sizeof (ace_t)); if (entries == NULL) { errno = ENOMEM; return -1; } if (acl (name, ACE_GETACL, count, entries) == count) { if (acl_ace_nontrivial (count, entries)) { free (entries); return 1; } free (entries); break; } /* Huh? The number of ACL entries changed since the last call. Repeat. */ free (entries); } } # endif return 0; # endif # elif HAVE_GETACL /* HP-UX */ for (;;) { int count; struct acl_entry entries[NACLENTRIES]; count = getacl (name, 0, NULL); if (count < 0) { /* ENOSYS is seen on newer HP-UX versions. EOPNOTSUPP is typically seen on NFS mounts. ENOTSUP was seen on Quantum StorNext file systems (cvfs). */ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) break; else return -1; } if (count == 0) return 0; if (count > NACLENTRIES) /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); /* If there are more than 3 entries, there cannot be only the (uid,%), (%,gid), (%,%) entries. */ if (count > 3) return 1; if (getacl (name, count, entries) == count) { struct stat statbuf; if (stat (name, &statbuf) < 0) return -1; return acl_nontrivial (count, entries, &statbuf); } /* Huh? The number of ACL entries changed since the last call. Repeat. */ } # if HAVE_ACLV_H /* HP-UX >= 11.11 */ for (;;) { int count; struct acl entries[NACLVENTRIES]; count = acl ((char *) name, ACL_CNT, NACLVENTRIES, entries); if (count < 0) { /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23. EINVAL is seen on NFS in HP-UX 11.31. */ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) break; else return -1; } if (count == 0) return 0; if (count > NACLVENTRIES) /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); /* If there are more than 4 entries, there cannot be only the four base ACL entries. */ if (count > 4) return 1; if (acl ((char *) name, ACL_GET, count, entries) == count) return aclv_nontrivial (count, entries); /* Huh? The number of ACL entries changed since the last call. Repeat. */ } # endif # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */ acl_type_t type; char aclbuf[1024]; void *acl = aclbuf; size_t aclsize = sizeof (aclbuf); mode_t mode; for (;;) { /* The docs say that type being 0 is equivalent to ACL_ANY, but it is not true, in AIX 5.3. */ type.u64 = ACL_ANY; if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0) break; if (errno == ENOSYS) return 0; if (errno != ENOSPC) { if (acl != aclbuf) { int saved_errno = errno; free (acl); errno = saved_errno; } return -1; } aclsize = 2 * aclsize; if (acl != aclbuf) free (acl); acl = malloc (aclsize); if (acl == NULL) { errno = ENOMEM; return -1; } } if (type.u64 == ACL_AIXC) { int result = acl_nontrivial ((struct acl *) acl); if (acl != aclbuf) free (acl); return result; } else if (type.u64 == ACL_NFS4) { int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl); if (acl != aclbuf) free (acl); return result; } else { /* A newer type of ACL has been introduced in the system. We should better support it. */ if (acl != aclbuf) free (acl); errno = EINVAL; return -1; } # elif HAVE_STATACL /* older AIX */ union { struct acl a; char room[4096]; } u; if (statacl (name, STX_NORMAL, &u.a, sizeof (u)) < 0) return -1; return acl_nontrivial (&u.a); # elif HAVE_ACLSORT /* NonStop Kernel */ int count; struct acl entries[NACLENTRIES]; for (;;) { count = acl ((char *) name, ACL_CNT, NACLENTRIES, NULL); if (count < 0) { if (errno == ENOSYS || errno == ENOTSUP) break; else return -1; } if (count == 0) return 0; if (count > NACLENTRIES) /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); /* If there are more than 4 entries, there cannot be only the four base ACL entries. */ if (count > 4) return 1; if (acl ((char *) name, ACL_GET, count, entries) == count) return acl_nontrivial (count, entries); /* Huh? The number of ACL entries changed since the last call. Repeat. */ } # endif } #endif return 0; }