--- old/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java 2020-05-20 18:10:18.445948263 -0700 +++ /dev/null 2020-03-09 18:57:19.455001459 -0700 @@ -1,413 +0,0 @@ -/* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.nio.fs; - -import java.nio.file.*; -import java.nio.file.attribute.*; -import java.util.*; -import java.io.IOException; -import jdk.internal.misc.Unsafe; - -import static sun.nio.fs.UnixConstants.*; -import static sun.nio.fs.SolarisConstants.*; -import static sun.nio.fs.SolarisNativeDispatcher.*; - - -/** - * Solaris implementation of AclFileAttributeView with native support for - * NFSv4 ACLs on ZFS. - */ - -class SolarisAclFileAttributeView - extends AbstractAclFileAttributeView -{ - private static final Unsafe unsafe = Unsafe.getUnsafe(); - - // Maximum number of entries allowed in an ACL - private static final int MAX_ACL_ENTRIES = 1024; - - /** - * typedef struct ace { - * uid_t a_who; - * uint32_t a_access_mask; - * uint16_t a_flags; - * uint16_t a_type; - * } ace_t; - */ - private static final short SIZEOF_ACE_T = 12; - private static final short OFFSETOF_UID = 0; - private static final short OFFSETOF_MASK = 4; - private static final short OFFSETOF_FLAGS = 8; - private static final short OFFSETOF_TYPE = 10; - - private final UnixPath file; - private final boolean followLinks; - - SolarisAclFileAttributeView(UnixPath file, boolean followLinks) { - this.file = file; - this.followLinks = followLinks; - } - - /** - * Permission checks to access file - */ - private void checkAccess(UnixPath file, - boolean checkRead, - boolean checkWrite) - { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - if (checkRead) - file.checkRead(); - if (checkWrite) - file.checkWrite(); - sm.checkPermission(new RuntimePermission("accessUserInformation")); - } - } - - /** - * Encode the ACL to the given buffer - */ - private static void encode(List acl, long address) { - long offset = address; - for (AclEntry ace: acl) { - int flags = 0; - - // map UserPrincipal to uid and flags - UserPrincipal who = ace.principal(); - if (!(who instanceof UnixUserPrincipals.User)) - throw new ProviderMismatchException(); - UnixUserPrincipals.User user = (UnixUserPrincipals.User)who; - int uid; - if (user.isSpecial()) { - uid = -1; - if (who == UnixUserPrincipals.SPECIAL_OWNER) - flags |= ACE_OWNER; - else if (who == UnixUserPrincipals.SPECIAL_GROUP) - flags |= (ACE_GROUP | ACE_IDENTIFIER_GROUP); - else if (who == UnixUserPrincipals.SPECIAL_EVERYONE) - flags |= ACE_EVERYONE; - else - throw new AssertionError("Unable to map special identifier"); - } else { - if (user instanceof UnixUserPrincipals.Group) { - uid = user.gid(); - flags |= ACE_IDENTIFIER_GROUP; - } else { - uid = user.uid(); - } - } - - // map ACE type - int type; - switch (ace.type()) { - case ALLOW: - type = ACE_ACCESS_ALLOWED_ACE_TYPE; - break; - case DENY: - type = ACE_ACCESS_DENIED_ACE_TYPE; - break; - case AUDIT: - type = ACE_SYSTEM_AUDIT_ACE_TYPE; - break; - case ALARM: - type = ACE_SYSTEM_ALARM_ACE_TYPE; - break; - default: - throw new AssertionError("Unable to map ACE type"); - } - - // map permissions - Set aceMask = ace.permissions(); - int mask = 0; - if (aceMask.contains(AclEntryPermission.READ_DATA)) - mask |= ACE_READ_DATA; - if (aceMask.contains(AclEntryPermission.WRITE_DATA)) - mask |= ACE_WRITE_DATA; - if (aceMask.contains(AclEntryPermission.APPEND_DATA)) - mask |= ACE_APPEND_DATA; - if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS)) - mask |= ACE_READ_NAMED_ATTRS; - if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS)) - mask |= ACE_WRITE_NAMED_ATTRS; - if (aceMask.contains(AclEntryPermission.EXECUTE)) - mask |= ACE_EXECUTE; - if (aceMask.contains(AclEntryPermission.DELETE_CHILD)) - mask |= ACE_DELETE_CHILD; - if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES)) - mask |= ACE_READ_ATTRIBUTES; - if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES)) - mask |= ACE_WRITE_ATTRIBUTES; - if (aceMask.contains(AclEntryPermission.DELETE)) - mask |= ACE_DELETE; - if (aceMask.contains(AclEntryPermission.READ_ACL)) - mask |= ACE_READ_ACL; - if (aceMask.contains(AclEntryPermission.WRITE_ACL)) - mask |= ACE_WRITE_ACL; - if (aceMask.contains(AclEntryPermission.WRITE_OWNER)) - mask |= ACE_WRITE_OWNER; - if (aceMask.contains(AclEntryPermission.SYNCHRONIZE)) - mask |= ACE_SYNCHRONIZE; - - // FIXME - it would be desirable to know here if the file is a - // directory or not. Solaris returns EINVAL if an ACE has a directory - // -only flag and the file is not a directory. - Set aceFlags = ace.flags(); - if (aceFlags.contains(AclEntryFlag.FILE_INHERIT)) - flags |= ACE_FILE_INHERIT_ACE; - if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT)) - flags |= ACE_DIRECTORY_INHERIT_ACE; - if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT)) - flags |= ACE_NO_PROPAGATE_INHERIT_ACE; - if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY)) - flags |= ACE_INHERIT_ONLY_ACE; - - unsafe.putInt(offset + OFFSETOF_UID, uid); - unsafe.putInt(offset + OFFSETOF_MASK, mask); - unsafe.putShort(offset + OFFSETOF_FLAGS, (short)flags); - unsafe.putShort(offset + OFFSETOF_TYPE, (short)type); - - offset += SIZEOF_ACE_T; - } - } - - /** - * Decode the buffer, returning an ACL - */ - private static List decode(long address, int n) { - ArrayList acl = new ArrayList<>(n); - for (int i=0; i 0) { - who = UnixUserPrincipals.SPECIAL_OWNER; - } else if ((flags & ACE_GROUP) > 0) { - who = UnixUserPrincipals.SPECIAL_GROUP; - } else if ((flags & ACE_EVERYONE) > 0) { - who = UnixUserPrincipals.SPECIAL_EVERYONE; - } else if ((flags & ACE_IDENTIFIER_GROUP) > 0) { - who = UnixUserPrincipals.fromGid(uid); - } else { - who = UnixUserPrincipals.fromUid(uid); - } - - AclEntryType aceType = null; - switch (type) { - case ACE_ACCESS_ALLOWED_ACE_TYPE: - aceType = AclEntryType.ALLOW; - break; - case ACE_ACCESS_DENIED_ACE_TYPE: - aceType = AclEntryType.DENY; - break; - case ACE_SYSTEM_AUDIT_ACE_TYPE: - aceType = AclEntryType.AUDIT; - break; - case ACE_SYSTEM_ALARM_ACE_TYPE: - aceType = AclEntryType.ALARM; - break; - default: - assert false; - } - - Set aceMask = EnumSet.noneOf(AclEntryPermission.class); - if ((mask & ACE_READ_DATA) > 0) - aceMask.add(AclEntryPermission.READ_DATA); - if ((mask & ACE_WRITE_DATA) > 0) - aceMask.add(AclEntryPermission.WRITE_DATA); - if ((mask & ACE_APPEND_DATA ) > 0) - aceMask.add(AclEntryPermission.APPEND_DATA); - if ((mask & ACE_READ_NAMED_ATTRS) > 0) - aceMask.add(AclEntryPermission.READ_NAMED_ATTRS); - if ((mask & ACE_WRITE_NAMED_ATTRS) > 0) - aceMask.add(AclEntryPermission.WRITE_NAMED_ATTRS); - if ((mask & ACE_EXECUTE) > 0) - aceMask.add(AclEntryPermission.EXECUTE); - if ((mask & ACE_DELETE_CHILD ) > 0) - aceMask.add(AclEntryPermission.DELETE_CHILD); - if ((mask & ACE_READ_ATTRIBUTES) > 0) - aceMask.add(AclEntryPermission.READ_ATTRIBUTES); - if ((mask & ACE_WRITE_ATTRIBUTES) > 0) - aceMask.add(AclEntryPermission.WRITE_ATTRIBUTES); - if ((mask & ACE_DELETE) > 0) - aceMask.add(AclEntryPermission.DELETE); - if ((mask & ACE_READ_ACL) > 0) - aceMask.add(AclEntryPermission.READ_ACL); - if ((mask & ACE_WRITE_ACL) > 0) - aceMask.add(AclEntryPermission.WRITE_ACL); - if ((mask & ACE_WRITE_OWNER) > 0) - aceMask.add(AclEntryPermission.WRITE_OWNER); - if ((mask & ACE_SYNCHRONIZE) > 0) - aceMask.add(AclEntryPermission.SYNCHRONIZE); - - Set aceFlags = EnumSet.noneOf(AclEntryFlag.class); - if ((flags & ACE_FILE_INHERIT_ACE) > 0) - aceFlags.add(AclEntryFlag.FILE_INHERIT); - if ((flags & ACE_DIRECTORY_INHERIT_ACE) > 0) - aceFlags.add(AclEntryFlag.DIRECTORY_INHERIT); - if ((flags & ACE_NO_PROPAGATE_INHERIT_ACE) > 0) - aceFlags.add(AclEntryFlag.NO_PROPAGATE_INHERIT); - if ((flags & ACE_INHERIT_ONLY_ACE) > 0) - aceFlags.add(AclEntryFlag.INHERIT_ONLY); - - // build the ACL entry and add it to the list - AclEntry ace = AclEntry.newBuilder() - .setType(aceType) - .setPrincipal(who) - .setPermissions(aceMask).setFlags(aceFlags).build(); - acl.add(ace); - } - - return acl; - } - - // Returns true if NFSv4 ACLs not enabled on file system - private static boolean isAclsEnabled(int fd) { - try { - long enabled = fpathconf(fd, _PC_ACL_ENABLED); - if (enabled == _ACL_ACE_ENABLED) - return true; - } catch (UnixException x) { - } - return false; - } - - @Override - public List getAcl() - throws IOException - { - // permission check - checkAccess(file, true, false); - - // open file (will fail if file is a link and not following links) - int fd = -1; - try { - fd = file.openForAttributeAccess(followLinks); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - try { - long address = unsafe.allocateMemory(SIZEOF_ACE_T * MAX_ACL_ENTRIES); - try { - // read ACL and decode it - int n = facl(fd, ACE_GETACL, MAX_ACL_ENTRIES, address); - assert n >= 0; - return decode(address, n); - } catch (UnixException x) { - if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) { - throw new FileSystemException(file.getPathForExceptionMessage(), - null, x.getMessage() + " (file system does not support NFSv4 ACLs)"); - } - x.rethrowAsIOException(file); - return null; // keep compiler happy - } finally { - unsafe.freeMemory(address); - } - } finally { - close(fd); - } - } - - @Override - public void setAcl(List acl) throws IOException { - // permission check - checkAccess(file, false, true); - - // open file (will fail if file is a link and not following links) - int fd = -1; - try { - fd = file.openForAttributeAccess(followLinks); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - try { - // SECURITY: need to copy list as can change during processing - acl = new ArrayList(acl); - int n = acl.size(); - - long address = unsafe.allocateMemory(SIZEOF_ACE_T * n); - try { - encode(acl, address); - facl(fd, ACE_SETACL, n, address); - } catch (UnixException x) { - if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) { - throw new FileSystemException(file.getPathForExceptionMessage(), - null, x.getMessage() + " (file system does not support NFSv4 ACLs)"); - } - if (x.errno() == EINVAL && (n < 3)) - throw new IOException("ACL must contain at least 3 entries"); - x.rethrowAsIOException(file); - } finally { - unsafe.freeMemory(address); - } - } finally { - close(fd); - } - } - - @Override - public UserPrincipal getOwner() - throws IOException - { - checkAccess(file, true, false); - - try { - UnixFileAttributes attrs = - UnixFileAttributes.get(file, followLinks); - return UnixUserPrincipals.fromUid(attrs.uid()); - } catch (UnixException x) { - x.rethrowAsIOException(file); - return null; // keep compile happy - } - } - - @Override - public void setOwner(UserPrincipal owner) throws IOException { - checkAccess(file, true, false); - - if (!(owner instanceof UnixUserPrincipals.User)) - throw new ProviderMismatchException(); - if (owner instanceof UnixUserPrincipals.Group) - throw new IOException("'owner' parameter is a group"); - int uid = ((UnixUserPrincipals.User)owner).uid(); - - try { - if (followLinks) { - lchown(file, uid, -1); - } else { - chown(file, uid, -1); - } - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - } -}