Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java
32288 views
/*1* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.fs;2627import java.nio.file.*;28import java.nio.file.attribute.*;29import java.util.*;30import java.io.IOException;31import sun.misc.Unsafe;3233import static sun.nio.fs.UnixConstants.*;34import static sun.nio.fs.SolarisConstants.*;35import static sun.nio.fs.SolarisNativeDispatcher.*;363738/**39* Solaris implementation of AclFileAttributeView with native support for40* NFSv4 ACLs on ZFS.41*/4243class SolarisAclFileAttributeView44extends AbstractAclFileAttributeView45{46private static final Unsafe unsafe = Unsafe.getUnsafe();4748// Maximum number of entries allowed in an ACL49private static final int MAX_ACL_ENTRIES = 1024;5051/**52* typedef struct ace {53* uid_t a_who;54* uint32_t a_access_mask;55* uint16_t a_flags;56* uint16_t a_type;57* } ace_t;58*/59private static final short SIZEOF_ACE_T = 12;60private static final short OFFSETOF_UID = 0;61private static final short OFFSETOF_MASK = 4;62private static final short OFFSETOF_FLAGS = 8;63private static final short OFFSETOF_TYPE = 10;6465private final UnixPath file;66private final boolean followLinks;6768SolarisAclFileAttributeView(UnixPath file, boolean followLinks) {69this.file = file;70this.followLinks = followLinks;71}7273/**74* Permission checks to access file75*/76private void checkAccess(UnixPath file,77boolean checkRead,78boolean checkWrite)79{80SecurityManager sm = System.getSecurityManager();81if (sm != null) {82if (checkRead)83file.checkRead();84if (checkWrite)85file.checkWrite();86sm.checkPermission(new RuntimePermission("accessUserInformation"));87}88}8990/**91* Encode the ACL to the given buffer92*/93private static void encode(List<AclEntry> acl, long address) {94long offset = address;95for (AclEntry ace: acl) {96int flags = 0;9798// map UserPrincipal to uid and flags99UserPrincipal who = ace.principal();100if (!(who instanceof UnixUserPrincipals.User))101throw new ProviderMismatchException();102UnixUserPrincipals.User user = (UnixUserPrincipals.User)who;103int uid;104if (user.isSpecial()) {105uid = -1;106if (who == UnixUserPrincipals.SPECIAL_OWNER)107flags |= ACE_OWNER;108else if (who == UnixUserPrincipals.SPECIAL_GROUP)109flags |= (ACE_GROUP | ACE_IDENTIFIER_GROUP);110else if (who == UnixUserPrincipals.SPECIAL_EVERYONE)111flags |= ACE_EVERYONE;112else113throw new AssertionError("Unable to map special identifier");114} else {115if (user instanceof UnixUserPrincipals.Group) {116uid = user.gid();117flags |= ACE_IDENTIFIER_GROUP;118} else {119uid = user.uid();120}121}122123// map ACE type124int type;125switch (ace.type()) {126case ALLOW:127type = ACE_ACCESS_ALLOWED_ACE_TYPE;128break;129case DENY:130type = ACE_ACCESS_DENIED_ACE_TYPE;131break;132case AUDIT:133type = ACE_SYSTEM_AUDIT_ACE_TYPE;134break;135case ALARM:136type = ACE_SYSTEM_ALARM_ACE_TYPE;137break;138default:139throw new AssertionError("Unable to map ACE type");140}141142// map permissions143Set<AclEntryPermission> aceMask = ace.permissions();144int mask = 0;145if (aceMask.contains(AclEntryPermission.READ_DATA))146mask |= ACE_READ_DATA;147if (aceMask.contains(AclEntryPermission.WRITE_DATA))148mask |= ACE_WRITE_DATA;149if (aceMask.contains(AclEntryPermission.APPEND_DATA))150mask |= ACE_APPEND_DATA;151if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS))152mask |= ACE_READ_NAMED_ATTRS;153if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS))154mask |= ACE_WRITE_NAMED_ATTRS;155if (aceMask.contains(AclEntryPermission.EXECUTE))156mask |= ACE_EXECUTE;157if (aceMask.contains(AclEntryPermission.DELETE_CHILD))158mask |= ACE_DELETE_CHILD;159if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES))160mask |= ACE_READ_ATTRIBUTES;161if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES))162mask |= ACE_WRITE_ATTRIBUTES;163if (aceMask.contains(AclEntryPermission.DELETE))164mask |= ACE_DELETE;165if (aceMask.contains(AclEntryPermission.READ_ACL))166mask |= ACE_READ_ACL;167if (aceMask.contains(AclEntryPermission.WRITE_ACL))168mask |= ACE_WRITE_ACL;169if (aceMask.contains(AclEntryPermission.WRITE_OWNER))170mask |= ACE_WRITE_OWNER;171if (aceMask.contains(AclEntryPermission.SYNCHRONIZE))172mask |= ACE_SYNCHRONIZE;173174// FIXME - it would be desirable to know here if the file is a175// directory or not. Solaris returns EINVAL if an ACE has a directory176// -only flag and the file is not a directory.177Set<AclEntryFlag> aceFlags = ace.flags();178if (aceFlags.contains(AclEntryFlag.FILE_INHERIT))179flags |= ACE_FILE_INHERIT_ACE;180if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT))181flags |= ACE_DIRECTORY_INHERIT_ACE;182if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT))183flags |= ACE_NO_PROPAGATE_INHERIT_ACE;184if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY))185flags |= ACE_INHERIT_ONLY_ACE;186187unsafe.putInt(offset + OFFSETOF_UID, uid);188unsafe.putInt(offset + OFFSETOF_MASK, mask);189unsafe.putShort(offset + OFFSETOF_FLAGS, (short)flags);190unsafe.putShort(offset + OFFSETOF_TYPE, (short)type);191192offset += SIZEOF_ACE_T;193}194}195196/**197* Decode the buffer, returning an ACL198*/199private static List<AclEntry> decode(long address, int n) {200ArrayList<AclEntry> acl = new ArrayList<>(n);201for (int i=0; i<n; i++) {202long offset = address + i*SIZEOF_ACE_T;203204int uid = unsafe.getInt(offset + OFFSETOF_UID);205int mask = unsafe.getInt(offset + OFFSETOF_MASK);206int flags = (int)unsafe.getShort(offset + OFFSETOF_FLAGS);207int type = (int)unsafe.getShort(offset + OFFSETOF_TYPE);208209// map uid and flags to UserPrincipal210UnixUserPrincipals.User who = null;211if ((flags & ACE_OWNER) > 0) {212who = UnixUserPrincipals.SPECIAL_OWNER;213} else if ((flags & ACE_GROUP) > 0) {214who = UnixUserPrincipals.SPECIAL_GROUP;215} else if ((flags & ACE_EVERYONE) > 0) {216who = UnixUserPrincipals.SPECIAL_EVERYONE;217} else if ((flags & ACE_IDENTIFIER_GROUP) > 0) {218who = UnixUserPrincipals.fromGid(uid);219} else {220who = UnixUserPrincipals.fromUid(uid);221}222223AclEntryType aceType = null;224switch (type) {225case ACE_ACCESS_ALLOWED_ACE_TYPE:226aceType = AclEntryType.ALLOW;227break;228case ACE_ACCESS_DENIED_ACE_TYPE:229aceType = AclEntryType.DENY;230break;231case ACE_SYSTEM_AUDIT_ACE_TYPE:232aceType = AclEntryType.AUDIT;233break;234case ACE_SYSTEM_ALARM_ACE_TYPE:235aceType = AclEntryType.ALARM;236break;237default:238assert false;239}240241Set<AclEntryPermission> aceMask = EnumSet.noneOf(AclEntryPermission.class);242if ((mask & ACE_READ_DATA) > 0)243aceMask.add(AclEntryPermission.READ_DATA);244if ((mask & ACE_WRITE_DATA) > 0)245aceMask.add(AclEntryPermission.WRITE_DATA);246if ((mask & ACE_APPEND_DATA ) > 0)247aceMask.add(AclEntryPermission.APPEND_DATA);248if ((mask & ACE_READ_NAMED_ATTRS) > 0)249aceMask.add(AclEntryPermission.READ_NAMED_ATTRS);250if ((mask & ACE_WRITE_NAMED_ATTRS) > 0)251aceMask.add(AclEntryPermission.WRITE_NAMED_ATTRS);252if ((mask & ACE_EXECUTE) > 0)253aceMask.add(AclEntryPermission.EXECUTE);254if ((mask & ACE_DELETE_CHILD ) > 0)255aceMask.add(AclEntryPermission.DELETE_CHILD);256if ((mask & ACE_READ_ATTRIBUTES) > 0)257aceMask.add(AclEntryPermission.READ_ATTRIBUTES);258if ((mask & ACE_WRITE_ATTRIBUTES) > 0)259aceMask.add(AclEntryPermission.WRITE_ATTRIBUTES);260if ((mask & ACE_DELETE) > 0)261aceMask.add(AclEntryPermission.DELETE);262if ((mask & ACE_READ_ACL) > 0)263aceMask.add(AclEntryPermission.READ_ACL);264if ((mask & ACE_WRITE_ACL) > 0)265aceMask.add(AclEntryPermission.WRITE_ACL);266if ((mask & ACE_WRITE_OWNER) > 0)267aceMask.add(AclEntryPermission.WRITE_OWNER);268if ((mask & ACE_SYNCHRONIZE) > 0)269aceMask.add(AclEntryPermission.SYNCHRONIZE);270271Set<AclEntryFlag> aceFlags = EnumSet.noneOf(AclEntryFlag.class);272if ((flags & ACE_FILE_INHERIT_ACE) > 0)273aceFlags.add(AclEntryFlag.FILE_INHERIT);274if ((flags & ACE_DIRECTORY_INHERIT_ACE) > 0)275aceFlags.add(AclEntryFlag.DIRECTORY_INHERIT);276if ((flags & ACE_NO_PROPAGATE_INHERIT_ACE) > 0)277aceFlags.add(AclEntryFlag.NO_PROPAGATE_INHERIT);278if ((flags & ACE_INHERIT_ONLY_ACE) > 0)279aceFlags.add(AclEntryFlag.INHERIT_ONLY);280281// build the ACL entry and add it to the list282AclEntry ace = AclEntry.newBuilder()283.setType(aceType)284.setPrincipal(who)285.setPermissions(aceMask).setFlags(aceFlags).build();286acl.add(ace);287}288289return acl;290}291292// Retrns true if NFSv4 ACLs not enabled on file system293private static boolean isAclsEnabled(int fd) {294try {295long enabled = fpathconf(fd, _PC_ACL_ENABLED);296if (enabled == _ACL_ACE_ENABLED)297return true;298} catch (UnixException x) {299}300return false;301}302303@Override304public List<AclEntry> getAcl()305throws IOException306{307// permission check308checkAccess(file, true, false);309310// open file (will fail if file is a link and not following links)311int fd = file.openForAttributeAccess(followLinks);312try {313long address = unsafe.allocateMemory(SIZEOF_ACE_T * MAX_ACL_ENTRIES);314try {315// read ACL and decode it316int n = facl(fd, ACE_GETACL, MAX_ACL_ENTRIES, address);317assert n >= 0;318return decode(address, n);319} catch (UnixException x) {320if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {321throw new FileSystemException(file.getPathForExceptionMessage(),322null, x.getMessage() + " (file system does not support NFSv4 ACLs)");323}324x.rethrowAsIOException(file);325return null; // keep compiler happy326} finally {327unsafe.freeMemory(address);328}329} finally {330close(fd);331}332}333334@Override335public void setAcl(List<AclEntry> acl) throws IOException {336// permission check337checkAccess(file, false, true);338339// open file (will fail if file is a link and not following links)340int fd = file.openForAttributeAccess(followLinks);341try {342// SECURITY: need to copy list as can change during processing343acl = new ArrayList<AclEntry>(acl);344int n = acl.size();345346long address = unsafe.allocateMemory(SIZEOF_ACE_T * n);347try {348encode(acl, address);349facl(fd, ACE_SETACL, n, address);350} catch (UnixException x) {351if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {352throw new FileSystemException(file.getPathForExceptionMessage(),353null, x.getMessage() + " (file system does not support NFSv4 ACLs)");354}355if (x.errno() == EINVAL && (n < 3))356throw new IOException("ACL must contain at least 3 entries");357x.rethrowAsIOException(file);358} finally {359unsafe.freeMemory(address);360}361} finally {362close(fd);363}364}365366@Override367public UserPrincipal getOwner()368throws IOException369{370checkAccess(file, true, false);371372try {373UnixFileAttributes attrs =374UnixFileAttributes.get(file, followLinks);375return UnixUserPrincipals.fromUid(attrs.uid());376} catch (UnixException x) {377x.rethrowAsIOException(file);378return null; // keep compile happy379}380}381382@Override383public void setOwner(UserPrincipal owner) throws IOException {384checkAccess(file, true, false);385386if (!(owner instanceof UnixUserPrincipals.User))387throw new ProviderMismatchException();388if (owner instanceof UnixUserPrincipals.Group)389throw new IOException("'owner' parameter is a group");390int uid = ((UnixUserPrincipals.User)owner).uid();391392try {393if (followLinks) {394lchown(file, uid, -1);395} else {396chown(file, uid, -1);397}398} catch (UnixException x) {399x.rethrowAsIOException(file);400}401}402}403404405