001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.fs.permission; 019 020import java.util.List; 021 022import org.apache.hadoop.classification.InterfaceAudience; 023import org.apache.hadoop.classification.InterfaceStability; 024 025import com.google.common.base.Objects; 026import com.google.common.base.Preconditions; 027import com.google.common.collect.Lists; 028 029/** 030 * An AclStatus contains the ACL information of a specific file. AclStatus 031 * instances are immutable. Use a {@link Builder} to create a new instance. 032 */ 033@InterfaceAudience.Public 034@InterfaceStability.Stable 035public class AclStatus { 036 private final String owner; 037 private final String group; 038 private final boolean stickyBit; 039 private final List<AclEntry> entries; 040 private final FsPermission permission; 041 042 /** 043 * Returns the file owner. 044 * 045 * @return String file owner 046 */ 047 public String getOwner() { 048 return owner; 049 } 050 051 /** 052 * Returns the file group. 053 * 054 * @return String file group 055 */ 056 public String getGroup() { 057 return group; 058 } 059 060 /** 061 * Returns the sticky bit. 062 * 063 * @return boolean sticky bit 064 */ 065 public boolean isStickyBit() { 066 return stickyBit; 067 } 068 069 /** 070 * Returns the list of all ACL entries, ordered by their natural ordering. 071 * 072 * @return List<AclEntry> unmodifiable ordered list of all ACL entries 073 */ 074 public List<AclEntry> getEntries() { 075 return entries; 076 } 077 078 /** 079 * Returns the permission set for the path 080 * @return {@link FsPermission} for the path 081 */ 082 public FsPermission getPermission() { 083 return permission; 084 } 085 086 @Override 087 public boolean equals(Object o) { 088 if (o == null) { 089 return false; 090 } 091 if (getClass() != o.getClass()) { 092 return false; 093 } 094 AclStatus other = (AclStatus)o; 095 return Objects.equal(owner, other.owner) 096 && Objects.equal(group, other.group) 097 && stickyBit == other.stickyBit 098 && Objects.equal(entries, other.entries); 099 } 100 101 @Override 102 public int hashCode() { 103 return Objects.hashCode(owner, group, stickyBit, entries); 104 } 105 106 @Override 107 public String toString() { 108 return new StringBuilder() 109 .append("owner: ").append(owner) 110 .append(", group: ").append(group) 111 .append(", acl: {") 112 .append("entries: ").append(entries) 113 .append(", stickyBit: ").append(stickyBit) 114 .append('}') 115 .toString(); 116 } 117 118 /** 119 * Builder for creating new Acl instances. 120 */ 121 public static class Builder { 122 private String owner; 123 private String group; 124 private boolean stickyBit; 125 private List<AclEntry> entries = Lists.newArrayList(); 126 private FsPermission permission = null; 127 128 /** 129 * Sets the file owner. 130 * 131 * @param owner String file owner 132 * @return Builder this builder, for call chaining 133 */ 134 public Builder owner(String owner) { 135 this.owner = owner; 136 return this; 137 } 138 139 /** 140 * Sets the file group. 141 * 142 * @param group String file group 143 * @return Builder this builder, for call chaining 144 */ 145 public Builder group(String group) { 146 this.group = group; 147 return this; 148 } 149 150 /** 151 * Adds an ACL entry. 152 * 153 * @param e AclEntry entry to add 154 * @return Builder this builder, for call chaining 155 */ 156 public Builder addEntry(AclEntry e) { 157 this.entries.add(e); 158 return this; 159 } 160 161 /** 162 * Adds a list of ACL entries. 163 * 164 * @param entries AclEntry entries to add 165 * @return Builder this builder, for call chaining 166 */ 167 public Builder addEntries(Iterable<AclEntry> entries) { 168 for (AclEntry e : entries) 169 this.entries.add(e); 170 return this; 171 } 172 173 /** 174 * Sets sticky bit. If this method is not called, then the builder assumes 175 * false. 176 * 177 * @param stickyBit 178 * boolean sticky bit 179 * @return Builder this builder, for call chaining 180 */ 181 public Builder stickyBit(boolean stickyBit) { 182 this.stickyBit = stickyBit; 183 return this; 184 } 185 186 /** 187 * Sets the permission for the file. 188 * @param permission 189 */ 190 public Builder setPermission(FsPermission permission) { 191 this.permission = permission; 192 return this; 193 } 194 195 /** 196 * Builds a new AclStatus populated with the set properties. 197 * 198 * @return AclStatus new AclStatus 199 */ 200 public AclStatus build() { 201 return new AclStatus(owner, group, stickyBit, entries, permission); 202 } 203 } 204 205 /** 206 * Private constructor. 207 * 208 * @param file Path file associated to this ACL 209 * @param owner String file owner 210 * @param group String file group 211 * @param stickyBit the sticky bit 212 * @param entries the ACL entries 213 * @param permission permission of the path 214 */ 215 private AclStatus(String owner, String group, boolean stickyBit, 216 Iterable<AclEntry> entries, FsPermission permission) { 217 this.owner = owner; 218 this.group = group; 219 this.stickyBit = stickyBit; 220 this.entries = Lists.newArrayList(entries); 221 this.permission = permission; 222 } 223 224 /** 225 * Get the effective permission for the AclEntry 226 * @param entry AclEntry to get the effective action 227 */ 228 public FsAction getEffectivePermission(AclEntry entry) { 229 return getEffectivePermission(entry, permission); 230 } 231 232 /** 233 * Get the effective permission for the AclEntry. <br> 234 * Recommended to use this API ONLY if client communicates with the old 235 * NameNode, needs to pass the Permission for the path to get effective 236 * permission, else use {@link AclStatus#getEffectivePermission(AclEntry)}. 237 * @param entry AclEntry to get the effective action 238 * @param permArg Permission for the path. However if the client is NOT 239 * communicating with old namenode, then this argument will not have 240 * any preference. 241 * @return Returns the effective permission for the entry. 242 * @throws IllegalArgumentException If the client communicating with old 243 * namenode and permission is not passed as an argument. 244 */ 245 public FsAction getEffectivePermission(AclEntry entry, FsPermission permArg) 246 throws IllegalArgumentException { 247 // At least one permission bits should be available. 248 Preconditions.checkArgument(this.permission != null || permArg != null, 249 "Permission bits are not available to calculate effective permission"); 250 if (this.permission != null) { 251 // permission bits from server response will have the priority for 252 // accuracy. 253 permArg = this.permission; 254 } 255 if ((entry.getName() != null || entry.getType() == AclEntryType.GROUP)) { 256 if (entry.getScope() == AclEntryScope.ACCESS) { 257 FsAction entryPerm = entry.getPermission(); 258 return entryPerm.and(permArg.getGroupAction()); 259 } else { 260 Preconditions.checkArgument(this.entries.contains(entry) 261 && this.entries.size() >= 3, 262 "Passed default ACL entry not found in the list of ACLs"); 263 // default mask entry for effective permission calculation will be the 264 // penultimate entry. This can be mask entry in case of extended ACLs. 265 // In case of minimal ACL, this is the owner group entry, and we end up 266 // intersecting group FsAction with itself, which is a no-op. 267 FsAction defaultMask = this.entries.get(this.entries.size() - 2) 268 .getPermission(); 269 FsAction entryPerm = entry.getPermission(); 270 return entryPerm.and(defaultMask); 271 } 272 } else { 273 return entry.getPermission(); 274 } 275 } 276}