/// <summary> /// Adds unspecified default entries by copying permissions from the /// corresponding access entries. /// </summary> /// <param name="aclBuilder">ArrayList<AclEntry> containing entries to build</param> private static void CopyDefaultsIfNeeded(IList <AclEntry> aclBuilder) { aclBuilder.Sort(AclEntryComparator); ScopedAclEntries scopedEntries = new ScopedAclEntries(aclBuilder); if (!scopedEntries.GetDefaultEntries().IsEmpty()) { IList <AclEntry> accessEntries = scopedEntries.GetAccessEntries(); IList <AclEntry> defaultEntries = scopedEntries.GetDefaultEntries(); IList <AclEntry> copiedEntries = Lists.NewArrayListWithCapacity(3); foreach (AclEntryType type in EnumSet.Of(AclEntryType.User, AclEntryType.Group, AclEntryType .Other)) { AclEntry defaultEntryKey = new AclEntry.Builder().SetScope(AclEntryScope.Default) .SetType(type).Build(); int defaultEntryIndex = Sharpen.Collections.BinarySearch(defaultEntries, defaultEntryKey , AclEntryComparator); if (defaultEntryIndex < 0) { AclEntry accessEntryKey = new AclEntry.Builder().SetScope(AclEntryScope.Access).SetType (type).Build(); int accessEntryIndex = Sharpen.Collections.BinarySearch(accessEntries, accessEntryKey , AclEntryComparator); if (accessEntryIndex >= 0) { copiedEntries.AddItem(new AclEntry.Builder().SetScope(AclEntryScope.Default).SetType (type).SetPermission(accessEntries[accessEntryIndex].GetPermission()).Build()); } } } // Add all copied entries when done to prevent potential issues with binary // search on a modified aclBulider during the main loop. Sharpen.Collections.AddAll(aclBuilder, copiedEntries); } }
/// <summary> /// Builds the final list of ACL entries to return by trimming, sorting and /// validating the ACL entries that have been added. /// </summary> /// <param name="aclBuilder">ArrayList<AclEntry> containing entries to build</param> /// <returns>List<AclEntry> unmodifiable, sorted list of ACL entries</returns> /// <exception cref="Org.Apache.Hadoop.Hdfs.Protocol.AclException">if validation fails /// </exception> private static IList <AclEntry> BuildAndValidateAcl(AList <AclEntry> aclBuilder) { if (aclBuilder.Count > MaxEntries) { throw new AclException("Invalid ACL: ACL has " + aclBuilder.Count + " entries, which exceeds maximum of " + MaxEntries + "."); } aclBuilder.TrimToSize(); aclBuilder.Sort(AclEntryComparator); // Full iteration to check for duplicates and invalid named entries. AclEntry prevEntry = null; foreach (AclEntry entry in aclBuilder) { if (prevEntry != null && AclEntryComparator.Compare(prevEntry, entry) == 0) { throw new AclException("Invalid ACL: multiple entries with same scope, type and name." ); } if (entry.GetName() != null && (entry.GetType() == AclEntryType.Mask || entry.GetType () == AclEntryType.Other)) { throw new AclException("Invalid ACL: this entry type must not have a name: " + entry + "."); } prevEntry = entry; } // Search for the required base access entries. If there is a default ACL, // then do the same check on the default entries. ScopedAclEntries scopedEntries = new ScopedAclEntries(aclBuilder); foreach (AclEntryType type in EnumSet.Of(AclEntryType.User, AclEntryType.Group, AclEntryType .Other)) { AclEntry accessEntryKey = new AclEntry.Builder().SetScope(AclEntryScope.Access).SetType (type).Build(); if (Sharpen.Collections.BinarySearch(scopedEntries.GetAccessEntries(), accessEntryKey , AclEntryComparator) < 0) { throw new AclException("Invalid ACL: the user, group and other entries are required." ); } if (!scopedEntries.GetDefaultEntries().IsEmpty()) { AclEntry defaultEntryKey = new AclEntry.Builder().SetScope(AclEntryScope.Default) .SetType(type).Build(); if (Sharpen.Collections.BinarySearch(scopedEntries.GetDefaultEntries(), defaultEntryKey , AclEntryComparator) < 0) { throw new AclException("Invalid default ACL: the user, group and other entries are required." ); } } } return(Sharpen.Collections.UnmodifiableList(aclBuilder)); }
/// <summary>Reads the existing ACL of an inode.</summary> /// <remarks> /// Reads the existing ACL of an inode. This method always returns the full /// logical ACL of the inode after reading relevant data from the inode's /// <see cref="Org.Apache.Hadoop.FS.Permission.FsPermission"/> /// and /// <see cref="AclFeature"/> /// . Note that every inode /// logically has an ACL, even if no ACL has been set explicitly. If the inode /// does not have an extended ACL, then the result is a minimal ACL consising of /// exactly 3 entries that correspond to the owner, group and other permissions. /// This method always reads the inode's current state and does not support /// querying by snapshot ID. This is because the method is intended to support /// ACL modification APIs, which always apply a delta on top of current state. /// </remarks> /// <param name="inode">INode to read</param> /// <returns>List<AclEntry> containing all logical inode ACL entries</returns> public static IList <AclEntry> ReadINodeLogicalAcl(INode inode) { FsPermission perm = inode.GetFsPermission(); AclFeature f = inode.GetAclFeature(); if (f == null) { return(AclUtil.GetMinimalAcl(perm)); } IList <AclEntry> existingAcl; // Split ACL entries stored in the feature into access vs. default. IList <AclEntry> featureEntries = GetEntriesFromAclFeature(f); ScopedAclEntries scoped = new ScopedAclEntries(featureEntries); IList <AclEntry> accessEntries = scoped.GetAccessEntries(); IList <AclEntry> defaultEntries = scoped.GetDefaultEntries(); // Pre-allocate list size for the explicit entries stored in the feature // plus the 3 implicit entries (owner, group and other) from the permission // bits. existingAcl = Lists.NewArrayListWithCapacity(featureEntries.Count + 3); if (!accessEntries.IsEmpty()) { // Add owner entry implied from user permission bits. existingAcl.AddItem(new AclEntry.Builder().SetScope(AclEntryScope.Access).SetType (AclEntryType.User).SetPermission(perm.GetUserAction()).Build()); // Next add all named user and group entries taken from the feature. Sharpen.Collections.AddAll(existingAcl, accessEntries); // Add mask entry implied from group permission bits. existingAcl.AddItem(new AclEntry.Builder().SetScope(AclEntryScope.Access).SetType (AclEntryType.Mask).SetPermission(perm.GetGroupAction()).Build()); // Add other entry implied from other permission bits. existingAcl.AddItem(new AclEntry.Builder().SetScope(AclEntryScope.Access).SetType (AclEntryType.Other).SetPermission(perm.GetOtherAction()).Build()); } else { // It's possible that there is a default ACL but no access ACL. In this // case, add the minimal access ACL implied by the permission bits. Sharpen.Collections.AddAll(existingAcl, AclUtil.GetMinimalAcl(perm)); } // Add all default entries after the access entries. Sharpen.Collections.AddAll(existingAcl, defaultEntries); // The above adds entries in the correct order, so no need to sort here. return(existingAcl); }
/// <exception cref="System.IO.IOException"/> protected internal override void ProcessPath(PathData item) { @out.WriteLine("# file: " + item); @out.WriteLine("# owner: " + item.stat.GetOwner()); @out.WriteLine("# group: " + item.stat.GetGroup()); FsPermission perm = item.stat.GetPermission(); if (perm.GetStickyBit()) { @out.WriteLine("# flags: --" + (perm.GetOtherAction().Implies(FsAction.Execute) ? "t" : "T")); } AclStatus aclStatus = item.fs.GetAclStatus(item.path); IList <AclEntry> entries = perm.GetAclBit() ? aclStatus.GetEntries() : Collections .EmptyList <AclEntry>(); ScopedAclEntries scopedEntries = new ScopedAclEntries(AclUtil.GetAclFromPermAndEntries (perm, entries)); PrintAclEntriesForSingleScope(aclStatus, perm, scopedEntries.GetAccessEntries()); PrintAclEntriesForSingleScope(aclStatus, perm, scopedEntries.GetDefaultEntries()); @out.WriteLine(); }
/// <summary>Updates an inode with a new ACL.</summary> /// <remarks> /// Updates an inode with a new ACL. This method takes a full logical ACL and /// stores the entries to the inode's /// <see cref="Org.Apache.Hadoop.FS.Permission.FsPermission"/> /// and /// <see cref="AclFeature"/> /// . /// </remarks> /// <param name="inode">INode to update</param> /// <param name="newAcl">List<AclEntry> containing new ACL entries</param> /// <param name="snapshotId">int latest snapshot ID of inode</param> /// <exception cref="Org.Apache.Hadoop.Hdfs.Protocol.AclException">if the ACL is invalid for the given inode /// </exception> /// <exception cref="Org.Apache.Hadoop.Hdfs.Protocol.QuotaExceededException">if quota limit is exceeded /// </exception> public static void UpdateINodeAcl(INode inode, IList <AclEntry> newAcl, int snapshotId ) { System.Diagnostics.Debug.Assert(newAcl.Count >= 3); FsPermission perm = inode.GetFsPermission(); FsPermission newPerm; if (!AclUtil.IsMinimalAcl(newAcl)) { // This is an extended ACL. Split entries into access vs. default. ScopedAclEntries scoped = new ScopedAclEntries(newAcl); IList <AclEntry> accessEntries = scoped.GetAccessEntries(); IList <AclEntry> defaultEntries = scoped.GetDefaultEntries(); // Only directories may have a default ACL. if (!defaultEntries.IsEmpty() && !inode.IsDirectory()) { throw new AclException("Invalid ACL: only directories may have a default ACL."); } // Attach entries to the feature. if (inode.GetAclFeature() != null) { inode.RemoveAclFeature(snapshotId); } inode.AddAclFeature(CreateAclFeature(accessEntries, defaultEntries), snapshotId); newPerm = CreateFsPermissionForExtendedAcl(accessEntries, perm); } else { // This is a minimal ACL. Remove the ACL feature if it previously had one. if (inode.GetAclFeature() != null) { inode.RemoveAclFeature(snapshotId); } newPerm = CreateFsPermissionForMinimalAcl(newAcl, perm); } inode.SetPermission(newPerm, snapshotId); }
/// <summary> /// If a default ACL is defined on a parent directory, then copies that default /// ACL to a newly created child file or directory. /// </summary> /// <param name="child">INode newly created child</param> public static void CopyINodeDefaultAcl(INode child) { INodeDirectory parent = child.GetParent(); AclFeature parentAclFeature = parent.GetAclFeature(); if (parentAclFeature == null || !(child.IsFile() || child.IsDirectory())) { return; } // Split parent's entries into access vs. default. IList <AclEntry> featureEntries = GetEntriesFromAclFeature(parent.GetAclFeature()); ScopedAclEntries scopedEntries = new ScopedAclEntries(featureEntries); IList <AclEntry> parentDefaultEntries = scopedEntries.GetDefaultEntries(); // The parent may have an access ACL but no default ACL. If so, exit. if (parentDefaultEntries.IsEmpty()) { return; } // Pre-allocate list size for access entries to copy from parent. IList <AclEntry> accessEntries = Lists.NewArrayListWithCapacity(parentDefaultEntries .Count); FsPermission childPerm = child.GetFsPermission(); // Copy each default ACL entry from parent to new child's access ACL. bool parentDefaultIsMinimal = AclUtil.IsMinimalAcl(parentDefaultEntries); foreach (AclEntry entry in parentDefaultEntries) { AclEntryType type = entry.GetType(); string name = entry.GetName(); AclEntry.Builder builder = new AclEntry.Builder().SetScope(AclEntryScope.Access). SetType(type).SetName(name); // The child's initial permission bits are treated as the mode parameter, // which can filter copied permission values for owner, mask and other. FsAction permission; if (type == AclEntryType.User && name == null) { permission = entry.GetPermission().And(childPerm.GetUserAction()); } else { if (type == AclEntryType.Group && parentDefaultIsMinimal) { // This only happens if the default ACL is a minimal ACL: exactly 3 // entries corresponding to owner, group and other. In this case, // filter the group permissions. permission = entry.GetPermission().And(childPerm.GetGroupAction()); } else { if (type == AclEntryType.Mask) { // Group bits from mode parameter filter permission of mask entry. permission = entry.GetPermission().And(childPerm.GetGroupAction()); } else { if (type == AclEntryType.Other) { permission = entry.GetPermission().And(childPerm.GetOtherAction()); } else { permission = entry.GetPermission(); } } } } builder.SetPermission(permission); accessEntries.AddItem(builder.Build()); } // A new directory also receives a copy of the parent's default ACL. IList <AclEntry> defaultEntries = child.IsDirectory() ? parentDefaultEntries : Sharpen.Collections .EmptyList <AclEntry>(); FsPermission newPerm; if (!AclUtil.IsMinimalAcl(accessEntries) || !defaultEntries.IsEmpty()) { // Save the new ACL to the child. child.AddAclFeature(CreateAclFeature(accessEntries, defaultEntries)); newPerm = CreateFsPermissionForExtendedAcl(accessEntries, childPerm); } else { // The child is receiving a minimal ACL. newPerm = CreateFsPermissionForMinimalAcl(accessEntries, childPerm); } child.SetPermission(newPerm); }