Break the ACL classes into files (dotnet/corefx#41454)
authorJeremy Kuhne <jkuhne@microsoft.com>
Tue, 15 Oct 2019 04:01:25 +0000 (21:01 -0700)
committerDan Moseley <danmose@microsoft.com>
Tue, 15 Oct 2019 04:01:25 +0000 (21:01 -0700)
* Break the ACL classes into files

* Fix NetFX build

Commit migrated from https://github.com/dotnet/corefx/commit/226f57b4f2bf91822604aa73338070c601d7a0fe

src/libraries/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj
src/libraries/System.IO.FileSystem.AccessControl/src/System/IO/FileSystemAclExtensions.cs
src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/DirectorySecurity.cs [new file with mode: 0644]
src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSecurity.cs
src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSystemAccessRule.cs [new file with mode: 0644]
src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSystemAuditRule.cs [new file with mode: 0644]
src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSystemRights.cs [new file with mode: 0644]
src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSystemSecurity.cs [new file with mode: 0644]

index d8041d3..2724830 100644 (file)
     </Compile>
     <Compile Include="System\Security\AccessControl\FileSecurity.cs" />
     <Compile Include="System\Security\AccessControl\DirectoryObjectSecurity.cs" />
+    <Compile Include="System\Security\AccessControl\DirectorySecurity.cs" />
+    <Compile Include="System\Security\AccessControl\FileSystemAccessRule.cs" />
+    <Compile Include="System\Security\AccessControl\FileSystemAuditRule.cs" />
+    <Compile Include="System\Security\AccessControl\FileSystemRights.cs" />
+    <Compile Include="System\Security\AccessControl\FileSystemSecurity.cs" />
     <Compile Include="System\IO\FileSystemAclExtensions.cs" />
     <Compile Include="$(CommonPath)\System\NotImplemented.cs">
       <Link>Common\Interop\Windows\mincore\NotImplemented.cs</Link>
index d6c59b3..3f0a3a7 100644 (file)
@@ -56,7 +56,7 @@ namespace System.IO
             {
                 throw new ObjectDisposedException(null, SR.ObjectDisposed_FileClosed);
             }
-            return new FileSecurity(handle, fileStream.Name, AccessControlSections.Access | AccessControlSections.Owner | AccessControlSections.Group);
+            return new FileSecurity(handle, AccessControlSections.Access | AccessControlSections.Owner | AccessControlSections.Group);
         }
 
         public static void SetAccessControl(this FileStream fileStream, FileSecurity fileSecurity)
diff --git a/src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/DirectorySecurity.cs b/src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/DirectorySecurity.cs
new file mode 100644 (file)
index 0000000..48bb9f8
--- /dev/null
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+
+namespace System.Security.AccessControl
+{
+    public sealed class DirectorySecurity : FileSystemSecurity
+    {
+        public DirectorySecurity()
+            : base(true)
+        {
+        }
+
+        public DirectorySecurity(string name, AccessControlSections includeSections)
+            : base(true, name, includeSections, true)
+        {
+            Path.GetFullPath(name);
+        }
+    }
+}
index 0503cf7..e2389c2 100644 (file)
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-/*============================================================
-**
-**
-**
-** Purpose: Managed ACL wrapper for files & directories.
-**
-**
-===========================================================*/
-
-using Microsoft.Win32.SafeHandles;
-using Microsoft.Win32;
-using System.Collections;
 using System.IO;
-using System.Runtime.InteropServices;
-using System.Runtime.Versioning;
-using System.Security.AccessControl;
-using System.Security.Principal;
-using System;
+using Microsoft.Win32.SafeHandles;
 
 namespace System.Security.AccessControl
 {
-    // Constants from winnt.h - search for FILE_WRITE_DATA, etc.
-    [Flags]
-    public enum FileSystemRights
-    {
-        // No None field - An ACE with the value 0 cannot grant nor deny.
-        ReadData = 0x000001,
-        ListDirectory = ReadData,     // For directories
-        WriteData = 0x000002,
-        CreateFiles = WriteData,    // For directories
-        AppendData = 0x000004,
-        CreateDirectories = AppendData,   // For directories
-        ReadExtendedAttributes = 0x000008,
-        WriteExtendedAttributes = 0x000010,
-        ExecuteFile = 0x000020,     // For files
-        Traverse = ExecuteFile,  // For directories
-        // DeleteSubdirectoriesAndFiles only makes sense on directories, but
-        // the shell explicitly sets it for files in its UI.  So we'll include
-        // it in FullControl.
-        DeleteSubdirectoriesAndFiles = 0x000040,
-        ReadAttributes = 0x000080,
-        WriteAttributes = 0x000100,
-        Delete = 0x010000,
-        ReadPermissions = 0x020000,
-        ChangePermissions = 0x040000,
-        TakeOwnership = 0x080000,
-        // From the Core File Services team, CreateFile always requires
-        // SYNCHRONIZE access.  Very tricksy, CreateFile is.
-        Synchronize = 0x100000,  // Can we wait on the handle?
-        FullControl = 0x1F01FF,
-
-        // These map to what Explorer sets, and are what most users want.
-        // However, an ACL editor will also want to set the Synchronize
-        // bit when allowing access, and exclude the synchronize bit when
-        // denying access.
-        Read = ReadData | ReadExtendedAttributes | ReadAttributes | ReadPermissions,
-        ReadAndExecute = Read | ExecuteFile,
-        Write = WriteData | AppendData | WriteExtendedAttributes | WriteAttributes,
-        Modify = ReadAndExecute | Write | Delete,
-    }
-
-
-    public sealed class FileSystemAccessRule : AccessRule
-    {
-        #region Constructors
-
-        //
-        // Constructor for creating access rules for file objects
-        //
-
-        public FileSystemAccessRule(
-            IdentityReference identity,
-            FileSystemRights fileSystemRights,
-            AccessControlType type)
-            : this(
-                identity,
-                AccessMaskFromRights(fileSystemRights, type),
-                false,
-                InheritanceFlags.None,
-                PropagationFlags.None,
-                type)
-        {
-        }
-
-        public FileSystemAccessRule(
-            string identity,
-            FileSystemRights fileSystemRights,
-            AccessControlType type)
-            : this(
-                new NTAccount(identity),
-                AccessMaskFromRights(fileSystemRights, type),
-                false,
-                InheritanceFlags.None,
-                PropagationFlags.None,
-                type)
-        {
-        }
-
-        //
-        // Constructor for creating access rules for folder objects
-        //
-
-        public FileSystemAccessRule(
-            IdentityReference identity,
-            FileSystemRights fileSystemRights,
-            InheritanceFlags inheritanceFlags,
-            PropagationFlags propagationFlags,
-            AccessControlType type)
-            : this(
-                identity,
-                AccessMaskFromRights(fileSystemRights, type),
-                false,
-                inheritanceFlags,
-                propagationFlags,
-                type)
-        {
-        }
-
-        public FileSystemAccessRule(
-            string identity,
-            FileSystemRights fileSystemRights,
-            InheritanceFlags inheritanceFlags,
-            PropagationFlags propagationFlags,
-            AccessControlType type)
-            : this(
-                new NTAccount(identity),
-                AccessMaskFromRights(fileSystemRights, type),
-                false,
-                inheritanceFlags,
-                propagationFlags,
-                type)
-        {
-        }
-
-        //
-        // Internal constructor to be called by public constructors
-        // and the access rule factory methods of {File|Folder}Security
-        //
-
-        internal FileSystemAccessRule(
-            IdentityReference identity,
-            int accessMask,
-            bool isInherited,
-            InheritanceFlags inheritanceFlags,
-            PropagationFlags propagationFlags,
-            AccessControlType type)
-            : base(
-                identity,
-                accessMask,
-                isInherited,
-                inheritanceFlags,
-                propagationFlags,
-                type)
-        {
-        }
-
-        #endregion
-
-        #region Public properties
-
-        public FileSystemRights FileSystemRights
-        {
-            get { return RightsFromAccessMask(base.AccessMask); }
-        }
-
-        #endregion
-
-        #region Access mask to rights translation
-
-        // ACL's on files have a SYNCHRONIZE bit, and CreateFile ALWAYS
-        // asks for it.  So for allows, let's always include this bit,
-        // and for denies, let's never include this bit unless we're denying
-        // full control.  This is the right thing for users, even if it does
-        // make the model look asymmetrical from a purist point of view.
-        internal static int AccessMaskFromRights(FileSystemRights fileSystemRights, AccessControlType controlType)
-        {
-            if (fileSystemRights < (FileSystemRights)0 || fileSystemRights > FileSystemRights.FullControl)
-                throw new ArgumentOutOfRangeException(nameof(fileSystemRights), SR.Format(SR.Argument_InvalidEnumValue, fileSystemRights, nameof(AccessControl.FileSystemRights)));
-
-            if (controlType == AccessControlType.Allow)
-            {
-                fileSystemRights |= FileSystemRights.Synchronize;
-            }
-            else if (controlType == AccessControlType.Deny)
-            {
-                if (fileSystemRights != FileSystemRights.FullControl &&
-                    fileSystemRights != (FileSystemRights.FullControl & ~FileSystemRights.DeleteSubdirectoriesAndFiles))
-                    fileSystemRights &= ~FileSystemRights.Synchronize;
-            }
-
-            return (int)fileSystemRights;
-        }
-
-        internal static FileSystemRights RightsFromAccessMask(int accessMask)
-        {
-            return (FileSystemRights)accessMask;
-        }
-        #endregion
-    }
-
-
-    public sealed class FileSystemAuditRule : AuditRule
-    {
-        #region Constructors
-
-        public FileSystemAuditRule(
-            IdentityReference identity,
-            FileSystemRights fileSystemRights,
-            AuditFlags flags)
-            : this(
-                identity,
-                fileSystemRights,
-                InheritanceFlags.None,
-                PropagationFlags.None,
-                flags)
-        {
-        }
-
-        public FileSystemAuditRule(
-            IdentityReference identity,
-            FileSystemRights fileSystemRights,
-            InheritanceFlags inheritanceFlags,
-            PropagationFlags propagationFlags,
-            AuditFlags flags)
-            : this(
-                identity,
-                AccessMaskFromRights(fileSystemRights),
-                false,
-                inheritanceFlags,
-                propagationFlags,
-                flags)
-        {
-        }
-
-        public FileSystemAuditRule(
-            string identity,
-            FileSystemRights fileSystemRights,
-            AuditFlags flags)
-            : this(
-                new NTAccount(identity),
-                fileSystemRights,
-                InheritanceFlags.None,
-                PropagationFlags.None,
-                flags)
-        {
-        }
-
-        public FileSystemAuditRule(
-            string identity,
-            FileSystemRights fileSystemRights,
-            InheritanceFlags inheritanceFlags,
-            PropagationFlags propagationFlags,
-            AuditFlags flags)
-            : this(
-                new NTAccount(identity),
-                AccessMaskFromRights(fileSystemRights),
-                false,
-                inheritanceFlags,
-                propagationFlags,
-                flags)
-        {
-        }
-
-        internal FileSystemAuditRule(
-            IdentityReference identity,
-            int accessMask,
-            bool isInherited,
-            InheritanceFlags inheritanceFlags,
-            PropagationFlags propagationFlags,
-            AuditFlags flags)
-            : base(
-                identity,
-                accessMask,
-                isInherited,
-                inheritanceFlags,
-                propagationFlags,
-                flags)
-        {
-        }
-
-        #endregion
-
-        #region Private methods
-
-        private static int AccessMaskFromRights(FileSystemRights fileSystemRights)
-        {
-            if (fileSystemRights < (FileSystemRights)0 || fileSystemRights > FileSystemRights.FullControl)
-                throw new ArgumentOutOfRangeException(nameof(fileSystemRights), SR.Format(SR.Argument_InvalidEnumValue, fileSystemRights, nameof(AccessControl.FileSystemRights)));
-
-            return (int)fileSystemRights;
-        }
-
-        #endregion
-
-        #region Public properties
-
-        public FileSystemRights FileSystemRights
-        {
-            get { return FileSystemAccessRule.RightsFromAccessMask(base.AccessMask); }
-        }
-        #endregion
-    }
-
-
-    public abstract class FileSystemSecurity : NativeObjectSecurity
-    {
-        #region Member variables
-
-        private const ResourceType s_ResourceType = ResourceType.FileObject;
-
-        #endregion
-
-        internal FileSystemSecurity(bool isContainer)
-            : base(isContainer, s_ResourceType, _HandleErrorCode, isContainer)
-        {
-        }
-
-        internal FileSystemSecurity(bool isContainer, string name, AccessControlSections includeSections, bool isDirectory)
-            : base(isContainer, s_ResourceType, name, includeSections, _HandleErrorCode, isDirectory)
-        {
-        }
-
-        internal FileSystemSecurity(bool isContainer, SafeFileHandle handle, AccessControlSections includeSections, bool isDirectory)
-            : base(isContainer, s_ResourceType, handle, includeSections, _HandleErrorCode, isDirectory)
-        {
-        }
-
-        private static Exception _HandleErrorCode(int errorCode, string name, SafeHandle handle, object context)
-        {
-            System.Exception exception = null;
-
-            switch (errorCode)
-            {
-                case Interop.Errors.ERROR_INVALID_NAME:
-                    exception = new ArgumentException(SR.Argument_InvalidName, nameof(name));
-                    break;
-
-                case Interop.Errors.ERROR_INVALID_HANDLE:
-                    exception = new ArgumentException(SR.AccessControl_InvalidHandle);
-                    break;
-
-                case Interop.Errors.ERROR_FILE_NOT_FOUND:
-                    if ((context != null) && (context is bool) && ((bool)context))
-                    { // DirectorySecurity
-                        if ((name != null) && (name.Length != 0))
-                            exception = new DirectoryNotFoundException(name);
-                        else
-                            exception = new DirectoryNotFoundException();
-                    }
-                    else
-                    {
-                        if ((name != null) && (name.Length != 0))
-                            exception = new FileNotFoundException(name);
-                        else
-                            exception = new FileNotFoundException();
-                    }
-                    break;
-
-                default:
-                    break;
-            }
-
-            return exception;
-        }
-
-        #region Factories
-
-        public sealed override AccessRule AccessRuleFactory(
-            IdentityReference identityReference,
-            int accessMask,
-            bool isInherited,
-            InheritanceFlags inheritanceFlags,
-            PropagationFlags propagationFlags,
-            AccessControlType type)
-        {
-            return new FileSystemAccessRule(
-                identityReference,
-                accessMask,
-                isInherited,
-                inheritanceFlags,
-                propagationFlags,
-                type);
-        }
-
-        public sealed override AuditRule AuditRuleFactory(
-            IdentityReference identityReference,
-            int accessMask,
-            bool isInherited,
-            InheritanceFlags inheritanceFlags,
-            PropagationFlags propagationFlags,
-            AuditFlags flags)
-        {
-            return new FileSystemAuditRule(
-                identityReference,
-                accessMask,
-                isInherited,
-                inheritanceFlags,
-                propagationFlags,
-                flags);
-        }
-
-        #endregion
-
-        #region Internal Methods
-
-        internal AccessControlSections GetAccessControlSectionsFromChanges()
-        {
-            AccessControlSections persistRules = AccessControlSections.None;
-            if (AccessRulesModified)
-                persistRules = AccessControlSections.Access;
-            if (AuditRulesModified)
-                persistRules |= AccessControlSections.Audit;
-            if (OwnerModified)
-                persistRules |= AccessControlSections.Owner;
-            if (GroupModified)
-                persistRules |= AccessControlSections.Group;
-            return persistRules;
-        }
-
-        internal void Persist(string fullPath)
-        {
-            WriteLock();
-
-            try
-            {
-                AccessControlSections persistRules = GetAccessControlSectionsFromChanges();
-                base.Persist(fullPath, persistRules);
-                OwnerModified = GroupModified = AuditRulesModified = AccessRulesModified = false;
-            }
-            finally
-            {
-                WriteUnlock();
-            }
-        }
-
-        internal void Persist(SafeFileHandle handle, string fullPath)
-        {
-            WriteLock();
-
-            try
-            {
-                AccessControlSections persistRules = GetAccessControlSectionsFromChanges();
-                base.Persist(handle, persistRules);
-                OwnerModified = GroupModified = AuditRulesModified = AccessRulesModified = false;
-            }
-            finally
-            {
-                WriteUnlock();
-            }
-        }
-
-        #endregion
-
-        #region Public Methods
-
-        public void AddAccessRule(FileSystemAccessRule rule)
-        {
-            base.AddAccessRule(rule);
-            //PersistIfPossible();
-        }
-
-        public void SetAccessRule(FileSystemAccessRule rule)
-        {
-            base.SetAccessRule(rule);
-        }
-
-        public void ResetAccessRule(FileSystemAccessRule rule)
-        {
-            base.ResetAccessRule(rule);
-        }
-
-        public bool RemoveAccessRule(FileSystemAccessRule rule)
-        {
-            if (rule == null)
-                throw new ArgumentNullException(nameof(rule));
-
-            // If the rule to be removed matches what is there currently then
-            // remove it unaltered. That is, don't mask off the Synchronize bit.
-            // This is to avoid dangling synchronize bit
-
-            AuthorizationRuleCollection rules = GetAccessRules(true, true, rule.IdentityReference.GetType());
-
-            for (int i = 0; i < rules.Count; i++)
-            {
-                FileSystemAccessRule fsrule = rules[i] as FileSystemAccessRule;
-
-                if ((fsrule != null) && (fsrule.FileSystemRights == rule.FileSystemRights)
-                    && (fsrule.IdentityReference == rule.IdentityReference)
-                    && (fsrule.AccessControlType == rule.AccessControlType))
-                {
-                    return base.RemoveAccessRule(rule);
-                }
-            }
-
-            // Mask off the synchronize bit (that is automatically added for Allow)
-            // before removing the ACL. The logic here should be same as Deny and hence
-            // fake a call to AccessMaskFromRights as though the ACL is for Deny
-
-            FileSystemAccessRule ruleNew = new FileSystemAccessRule(
-                                                    rule.IdentityReference,
-                                                    FileSystemAccessRule.AccessMaskFromRights(rule.FileSystemRights, AccessControlType.Deny),
-                                                    rule.IsInherited,
-                                                    rule.InheritanceFlags,
-                                                    rule.PropagationFlags,
-                                                    rule.AccessControlType);
-
-            return base.RemoveAccessRule(ruleNew);
-        }
-
-        public void RemoveAccessRuleAll(FileSystemAccessRule rule)
-        {
-            // We don't need to worry about the synchronize bit here
-            // AccessMask is ignored anyways in a RemoveAll call
-
-            base.RemoveAccessRuleAll(rule);
-        }
-
-        public void RemoveAccessRuleSpecific(FileSystemAccessRule rule)
-        {
-            if (rule == null)
-                throw new ArgumentNullException(nameof(rule));
-
-            // If the rule to be removed matches what is there currently then
-            // remove it unaltered. That is, don't mask off the Synchronize bit
-            // This is to avoid dangling synchronize bit
-
-            AuthorizationRuleCollection rules = GetAccessRules(true, true, rule.IdentityReference.GetType());
-
-            for (int i = 0; i < rules.Count; i++)
-            {
-                FileSystemAccessRule fsrule = rules[i] as FileSystemAccessRule;
-
-                if ((fsrule != null) && (fsrule.FileSystemRights == rule.FileSystemRights)
-                    && (fsrule.IdentityReference == rule.IdentityReference)
-                    && (fsrule.AccessControlType == rule.AccessControlType))
-                {
-                    base.RemoveAccessRuleSpecific(rule);
-                    return;
-                }
-            }
-
-            // Mask off the synchronize bit (that is automatically added for Allow)
-            // before removing the ACL. The logic here should be same as Deny and hence
-            // fake a call to AccessMaskFromRights as though the ACL is for Deny
-
-            FileSystemAccessRule ruleNew = new FileSystemAccessRule(
-                                                    rule.IdentityReference,
-                                                    FileSystemAccessRule.AccessMaskFromRights(rule.FileSystemRights, AccessControlType.Deny),
-                                                    rule.IsInherited,
-                                                    rule.InheritanceFlags,
-                                                    rule.PropagationFlags,
-                                                    rule.AccessControlType);
-
-            base.RemoveAccessRuleSpecific(ruleNew);
-        }
-
-        public void AddAuditRule(FileSystemAuditRule rule)
-        {
-            base.AddAuditRule(rule);
-        }
-
-        public void SetAuditRule(FileSystemAuditRule rule)
-        {
-            base.SetAuditRule(rule);
-        }
-
-        public bool RemoveAuditRule(FileSystemAuditRule rule)
-        {
-            return base.RemoveAuditRule(rule);
-        }
-
-        public void RemoveAuditRuleAll(FileSystemAuditRule rule)
-        {
-            base.RemoveAuditRuleAll(rule);
-        }
-
-        public void RemoveAuditRuleSpecific(FileSystemAuditRule rule)
-        {
-            base.RemoveAuditRuleSpecific(rule);
-        }
-        #endregion
-
-        #region some overrides
-        public override Type AccessRightType
-        {
-            get { return typeof(System.Security.AccessControl.FileSystemRights); }
-        }
-
-        public override Type AccessRuleType
-        {
-            get { return typeof(System.Security.AccessControl.FileSystemAccessRule); }
-        }
-
-        public override Type AuditRuleType
-        {
-            get { return typeof(System.Security.AccessControl.FileSystemAuditRule); }
-        }
-        #endregion
-    }
-
-
     public sealed class FileSecurity : FileSystemSecurity
     {
-        #region Constructors
-
         public FileSecurity()
             : base(false)
         {
@@ -615,35 +17,12 @@ namespace System.Security.AccessControl
         public FileSecurity(string fileName, AccessControlSections includeSections)
             : base(false, fileName, includeSections, false)
         {
-            string fullPath = Path.GetFullPath(fileName);
+            Path.GetFullPath(fileName);
         }
 
-        // Warning!  Be exceedingly careful with this constructor.  Do not make
-        // it public.  We don't want to get into a situation where someone can
-        // pass in the string foo.txt and a handle to bar.exe, and we do a
-        // demand on the wrong file name.
-        internal FileSecurity(SafeFileHandle handle, string fullPath, AccessControlSections includeSections)
+        internal FileSecurity(SafeFileHandle handle, AccessControlSections includeSections)
             : base(false, handle, includeSections, false)
         {
         }
-        #endregion
-    }
-
-
-    public sealed class DirectorySecurity : FileSystemSecurity
-    {
-        #region Constructors
-
-        public DirectorySecurity()
-            : base(true)
-        {
-        }
-
-        public DirectorySecurity(string name, AccessControlSections includeSections)
-            : base(true, name, includeSections, true)
-        {
-            string fullPath = Path.GetFullPath(name);
-        }
-        #endregion
     }
 }
diff --git a/src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSystemAccessRule.cs b/src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSystemAccessRule.cs
new file mode 100644 (file)
index 0000000..15ed6be
--- /dev/null
@@ -0,0 +1,135 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Security.Principal;
+
+namespace System.Security.AccessControl
+{
+    public sealed class FileSystemAccessRule : AccessRule
+    {
+        //
+        // Constructor for creating access rules for file objects
+        //
+
+        public FileSystemAccessRule(
+            IdentityReference identity,
+            FileSystemRights fileSystemRights,
+            AccessControlType type)
+            : this(
+                identity,
+                AccessMaskFromRights(fileSystemRights, type),
+                false,
+                InheritanceFlags.None,
+                PropagationFlags.None,
+                type)
+        {
+        }
+
+        public FileSystemAccessRule(
+            string identity,
+            FileSystemRights fileSystemRights,
+            AccessControlType type)
+            : this(
+                new NTAccount(identity),
+                AccessMaskFromRights(fileSystemRights, type),
+                false,
+                InheritanceFlags.None,
+                PropagationFlags.None,
+                type)
+        {
+        }
+
+        //
+        // Constructor for creating access rules for folder objects
+        //
+
+        public FileSystemAccessRule(
+            IdentityReference identity,
+            FileSystemRights fileSystemRights,
+            InheritanceFlags inheritanceFlags,
+            PropagationFlags propagationFlags,
+            AccessControlType type)
+            : this(
+                identity,
+                AccessMaskFromRights(fileSystemRights, type),
+                false,
+                inheritanceFlags,
+                propagationFlags,
+                type)
+        {
+        }
+
+        public FileSystemAccessRule(
+            string identity,
+            FileSystemRights fileSystemRights,
+            InheritanceFlags inheritanceFlags,
+            PropagationFlags propagationFlags,
+            AccessControlType type)
+            : this(
+                new NTAccount(identity),
+                AccessMaskFromRights(fileSystemRights, type),
+                false,
+                inheritanceFlags,
+                propagationFlags,
+                type)
+        {
+        }
+
+        //
+        // Internal constructor to be called by public constructors
+        // and the access rule factory methods of {File|Folder}Security
+        //
+
+        internal FileSystemAccessRule(
+            IdentityReference identity,
+            int accessMask,
+            bool isInherited,
+            InheritanceFlags inheritanceFlags,
+            PropagationFlags propagationFlags,
+            AccessControlType type)
+            : base(
+                identity,
+                accessMask,
+                isInherited,
+                inheritanceFlags,
+                propagationFlags,
+                type)
+        {
+        }
+
+        public FileSystemRights FileSystemRights
+        {
+            get { return RightsFromAccessMask(AccessMask); }
+        }
+
+        // ACL's on files have a SYNCHRONIZE bit, and CreateFile ALWAYS
+        // asks for it.  So for allows, let's always include this bit,
+        // and for denies, let's never include this bit unless we're denying
+        // full control.  This is the right thing for users, even if it does
+        // make the model look asymmetrical from a purist point of view.
+        internal static int AccessMaskFromRights(FileSystemRights fileSystemRights, AccessControlType controlType)
+        {
+            if (fileSystemRights < 0 || fileSystemRights > FileSystemRights.FullControl)
+                throw new ArgumentOutOfRangeException(nameof(fileSystemRights), SR.Format(SR.Argument_InvalidEnumValue, fileSystemRights, nameof(AccessControl.FileSystemRights)));
+
+            if (controlType == AccessControlType.Allow)
+            {
+                fileSystemRights |= FileSystemRights.Synchronize;
+            }
+            else if (controlType == AccessControlType.Deny)
+            {
+                if (fileSystemRights != FileSystemRights.FullControl &&
+                    fileSystemRights != (FileSystemRights.FullControl & ~FileSystemRights.DeleteSubdirectoriesAndFiles))
+                    fileSystemRights &= ~FileSystemRights.Synchronize;
+            }
+
+            return (int)fileSystemRights;
+        }
+
+        internal static FileSystemRights RightsFromAccessMask(int accessMask)
+        {
+            return (FileSystemRights)accessMask;
+        }
+    }
+}
diff --git a/src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSystemAuditRule.cs b/src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSystemAuditRule.cs
new file mode 100644 (file)
index 0000000..c7e34b0
--- /dev/null
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Security.Principal;
+
+namespace System.Security.AccessControl
+{
+    public sealed class FileSystemAuditRule : AuditRule
+    {
+        public FileSystemAuditRule(
+            IdentityReference identity,
+            FileSystemRights fileSystemRights,
+            AuditFlags flags)
+            : this(
+                identity,
+                fileSystemRights,
+                InheritanceFlags.None,
+                PropagationFlags.None,
+                flags)
+        {
+        }
+
+        public FileSystemAuditRule(
+            IdentityReference identity,
+            FileSystemRights fileSystemRights,
+            InheritanceFlags inheritanceFlags,
+            PropagationFlags propagationFlags,
+            AuditFlags flags)
+            : this(
+                identity,
+                AccessMaskFromRights(fileSystemRights),
+                false,
+                inheritanceFlags,
+                propagationFlags,
+                flags)
+        {
+        }
+
+        public FileSystemAuditRule(
+            string identity,
+            FileSystemRights fileSystemRights,
+            AuditFlags flags)
+            : this(
+                new NTAccount(identity),
+                fileSystemRights,
+                InheritanceFlags.None,
+                PropagationFlags.None,
+                flags)
+        {
+        }
+
+        public FileSystemAuditRule(
+            string identity,
+            FileSystemRights fileSystemRights,
+            InheritanceFlags inheritanceFlags,
+            PropagationFlags propagationFlags,
+            AuditFlags flags)
+            : this(
+                new NTAccount(identity),
+                AccessMaskFromRights(fileSystemRights),
+                false,
+                inheritanceFlags,
+                propagationFlags,
+                flags)
+        {
+        }
+
+        internal FileSystemAuditRule(
+            IdentityReference identity,
+            int accessMask,
+            bool isInherited,
+            InheritanceFlags inheritanceFlags,
+            PropagationFlags propagationFlags,
+            AuditFlags flags)
+            : base(
+                identity,
+                accessMask,
+                isInherited,
+                inheritanceFlags,
+                propagationFlags,
+                flags)
+        {
+        }
+
+        private static int AccessMaskFromRights(FileSystemRights fileSystemRights)
+        {
+            if (fileSystemRights < 0 || fileSystemRights > FileSystemRights.FullControl)
+                throw new ArgumentOutOfRangeException(nameof(fileSystemRights), SR.Format(SR.Argument_InvalidEnumValue, fileSystemRights, nameof(AccessControl.FileSystemRights)));
+
+            return (int)fileSystemRights;
+        }
+
+        public FileSystemRights FileSystemRights
+        {
+            get { return FileSystemAccessRule.RightsFromAccessMask(AccessMask); }
+        }
+    }
+}
diff --git a/src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSystemRights.cs b/src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSystemRights.cs
new file mode 100644 (file)
index 0000000..8f248fd
--- /dev/null
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.AccessControl
+{
+    // Constants from winnt.h - search for FILE_WRITE_DATA, etc.
+    [Flags]
+    public enum FileSystemRights
+    {
+        // No None field - An ACE with the value 0 cannot grant nor deny.
+        ReadData = 0x000001,
+        ListDirectory = ReadData,     // For directories
+        WriteData = 0x000002,
+        CreateFiles = WriteData,    // For directories
+        AppendData = 0x000004,
+        CreateDirectories = AppendData,   // For directories
+        ReadExtendedAttributes = 0x000008,
+        WriteExtendedAttributes = 0x000010,
+        ExecuteFile = 0x000020,     // For files
+        Traverse = ExecuteFile,  // For directories
+        // DeleteSubdirectoriesAndFiles only makes sense on directories, but
+        // the shell explicitly sets it for files in its UI.  So we'll include
+        // it in FullControl.
+        DeleteSubdirectoriesAndFiles = 0x000040,
+        ReadAttributes = 0x000080,
+        WriteAttributes = 0x000100,
+        Delete = 0x010000,
+        ReadPermissions = 0x020000,
+        ChangePermissions = 0x040000,
+        TakeOwnership = 0x080000,
+        // From the Core File Services team, CreateFile always requires
+        // SYNCHRONIZE access.  Very tricksy, CreateFile is.
+        Synchronize = 0x100000,  // Can we wait on the handle?
+        FullControl = 0x1F01FF,
+
+        // These map to what Explorer sets, and are what most users want.
+        // However, an ACL editor will also want to set the Synchronize
+        // bit when allowing access, and exclude the synchronize bit when
+        // denying access.
+        Read = ReadData | ReadExtendedAttributes | ReadAttributes | ReadPermissions,
+        ReadAndExecute = Read | ExecuteFile,
+        Write = WriteData | AppendData | WriteExtendedAttributes | WriteAttributes,
+        Modify = ReadAndExecute | Write | Delete,
+    }
+}
diff --git a/src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSystemSecurity.cs b/src/libraries/System.IO.FileSystem.AccessControl/src/System/Security/AccessControl/FileSystemSecurity.cs
new file mode 100644 (file)
index 0000000..ef253d2
--- /dev/null
@@ -0,0 +1,291 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Security.Principal;
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Security.AccessControl
+{
+    public abstract class FileSystemSecurity : NativeObjectSecurity
+    {
+        private const ResourceType s_ResourceType = ResourceType.FileObject;
+
+        internal FileSystemSecurity(bool isContainer)
+            : base(isContainer, s_ResourceType, _HandleErrorCode, isContainer)
+        {
+        }
+
+        internal FileSystemSecurity(bool isContainer, string name, AccessControlSections includeSections, bool isDirectory)
+            : base(isContainer, s_ResourceType, name, includeSections, _HandleErrorCode, isDirectory)
+        {
+        }
+
+        internal FileSystemSecurity(bool isContainer, SafeFileHandle handle, AccessControlSections includeSections, bool isDirectory)
+            : base(isContainer, s_ResourceType, handle, includeSections, _HandleErrorCode, isDirectory)
+        {
+        }
+
+        private static Exception _HandleErrorCode(int errorCode, string name, SafeHandle handle, object context)
+        {
+            Exception exception = null;
+
+            switch (errorCode)
+            {
+                case Interop.Errors.ERROR_INVALID_NAME:
+                    exception = new ArgumentException(SR.Argument_InvalidName, nameof(name));
+                    break;
+
+                case Interop.Errors.ERROR_INVALID_HANDLE:
+                    exception = new ArgumentException(SR.AccessControl_InvalidHandle);
+                    break;
+
+                case Interop.Errors.ERROR_FILE_NOT_FOUND:
+                    if ((context != null) && (context is bool) && ((bool)context))
+                    {
+                        // DirectorySecurity
+                        if ((name != null) && (name.Length != 0))
+                            exception = new DirectoryNotFoundException(name);
+                        else
+                            exception = new DirectoryNotFoundException();
+                    }
+                    else
+                    {
+                        if ((name != null) && (name.Length != 0))
+                            exception = new FileNotFoundException(name);
+                        else
+                            exception = new FileNotFoundException();
+                    }
+                    break;
+
+                default:
+                    break;
+            }
+
+            return exception;
+        }
+
+        public sealed override AccessRule AccessRuleFactory(
+            IdentityReference identityReference,
+            int accessMask,
+            bool isInherited,
+            InheritanceFlags inheritanceFlags,
+            PropagationFlags propagationFlags,
+            AccessControlType type)
+        {
+            return new FileSystemAccessRule(
+                identityReference,
+                accessMask,
+                isInherited,
+                inheritanceFlags,
+                propagationFlags,
+                type);
+        }
+
+        public sealed override AuditRule AuditRuleFactory(
+            IdentityReference identityReference,
+            int accessMask,
+            bool isInherited,
+            InheritanceFlags inheritanceFlags,
+            PropagationFlags propagationFlags,
+            AuditFlags flags)
+        {
+            return new FileSystemAuditRule(
+                identityReference,
+                accessMask,
+                isInherited,
+                inheritanceFlags,
+                propagationFlags,
+                flags);
+        }
+
+        internal AccessControlSections GetAccessControlSectionsFromChanges()
+        {
+            AccessControlSections persistRules = AccessControlSections.None;
+            if (AccessRulesModified)
+                persistRules = AccessControlSections.Access;
+            if (AuditRulesModified)
+                persistRules |= AccessControlSections.Audit;
+            if (OwnerModified)
+                persistRules |= AccessControlSections.Owner;
+            if (GroupModified)
+                persistRules |= AccessControlSections.Group;
+            return persistRules;
+        }
+
+        internal void Persist(string fullPath)
+        {
+            WriteLock();
+
+            try
+            {
+                AccessControlSections persistRules = GetAccessControlSectionsFromChanges();
+                base.Persist(fullPath, persistRules);
+                OwnerModified = GroupModified = AuditRulesModified = AccessRulesModified = false;
+            }
+            finally
+            {
+                WriteUnlock();
+            }
+        }
+
+        internal void Persist(SafeFileHandle handle, string fullPath)
+        {
+            WriteLock();
+
+            try
+            {
+                AccessControlSections persistRules = GetAccessControlSectionsFromChanges();
+                Persist(handle, persistRules);
+                OwnerModified = GroupModified = AuditRulesModified = AccessRulesModified = false;
+            }
+            finally
+            {
+                WriteUnlock();
+            }
+        }
+
+        public void AddAccessRule(FileSystemAccessRule rule)
+        {
+            base.AddAccessRule(rule);
+            // PersistIfPossible();
+        }
+
+        public void SetAccessRule(FileSystemAccessRule rule)
+        {
+            base.SetAccessRule(rule);
+        }
+
+        public void ResetAccessRule(FileSystemAccessRule rule)
+        {
+            base.ResetAccessRule(rule);
+        }
+
+        public bool RemoveAccessRule(FileSystemAccessRule rule)
+        {
+            if (rule == null)
+                throw new ArgumentNullException(nameof(rule));
+
+            // If the rule to be removed matches what is there currently then
+            // remove it unaltered. That is, don't mask off the Synchronize bit.
+            // This is to avoid dangling synchronize bit
+
+            AuthorizationRuleCollection rules = GetAccessRules(true, true, rule.IdentityReference.GetType());
+
+            for (int i = 0; i < rules.Count; i++)
+            {
+                FileSystemAccessRule fsrule = rules[i] as FileSystemAccessRule;
+
+                if ((fsrule != null) && (fsrule.FileSystemRights == rule.FileSystemRights)
+                    && (fsrule.IdentityReference == rule.IdentityReference)
+                    && (fsrule.AccessControlType == rule.AccessControlType))
+                {
+                    return base.RemoveAccessRule(rule);
+                }
+            }
+
+            // Mask off the synchronize bit (that is automatically added for Allow)
+            // before removing the ACL. The logic here should be same as Deny and hence
+            // fake a call to AccessMaskFromRights as though the ACL is for Deny
+
+            FileSystemAccessRule ruleNew = new FileSystemAccessRule(
+                                                    rule.IdentityReference,
+                                                    FileSystemAccessRule.AccessMaskFromRights(rule.FileSystemRights, AccessControlType.Deny),
+                                                    rule.IsInherited,
+                                                    rule.InheritanceFlags,
+                                                    rule.PropagationFlags,
+                                                    rule.AccessControlType);
+
+            return base.RemoveAccessRule(ruleNew);
+        }
+
+        public void RemoveAccessRuleAll(FileSystemAccessRule rule)
+        {
+            // We don't need to worry about the synchronize bit here
+            // AccessMask is ignored anyways in a RemoveAll call
+
+            base.RemoveAccessRuleAll(rule);
+        }
+
+        public void RemoveAccessRuleSpecific(FileSystemAccessRule rule)
+        {
+            if (rule == null)
+                throw new ArgumentNullException(nameof(rule));
+
+            // If the rule to be removed matches what is there currently then
+            // remove it unaltered. That is, don't mask off the Synchronize bit
+            // This is to avoid dangling synchronize bit
+
+            AuthorizationRuleCollection rules = GetAccessRules(true, true, rule.IdentityReference.GetType());
+
+            for (int i = 0; i < rules.Count; i++)
+            {
+                FileSystemAccessRule fsrule = rules[i] as FileSystemAccessRule;
+
+                if ((fsrule != null) && (fsrule.FileSystemRights == rule.FileSystemRights)
+                    && (fsrule.IdentityReference == rule.IdentityReference)
+                    && (fsrule.AccessControlType == rule.AccessControlType))
+                {
+                    base.RemoveAccessRuleSpecific(rule);
+                    return;
+                }
+            }
+
+            // Mask off the synchronize bit (that is automatically added for Allow)
+            // before removing the ACL. The logic here should be same as Deny and hence
+            // fake a call to AccessMaskFromRights as though the ACL is for Deny
+
+            FileSystemAccessRule ruleNew = new FileSystemAccessRule(
+                                                    rule.IdentityReference,
+                                                    FileSystemAccessRule.AccessMaskFromRights(rule.FileSystemRights, AccessControlType.Deny),
+                                                    rule.IsInherited,
+                                                    rule.InheritanceFlags,
+                                                    rule.PropagationFlags,
+                                                    rule.AccessControlType);
+
+            base.RemoveAccessRuleSpecific(ruleNew);
+        }
+
+        public void AddAuditRule(FileSystemAuditRule rule)
+        {
+            base.AddAuditRule(rule);
+        }
+
+        public void SetAuditRule(FileSystemAuditRule rule)
+        {
+            base.SetAuditRule(rule);
+        }
+
+        public bool RemoveAuditRule(FileSystemAuditRule rule)
+        {
+            return base.RemoveAuditRule(rule);
+        }
+
+        public void RemoveAuditRuleAll(FileSystemAuditRule rule)
+        {
+            base.RemoveAuditRuleAll(rule);
+        }
+
+        public void RemoveAuditRuleSpecific(FileSystemAuditRule rule)
+        {
+            base.RemoveAuditRuleSpecific(rule);
+        }
+
+        public override Type AccessRightType
+        {
+            get { return typeof(FileSystemRights); }
+        }
+
+        public override Type AccessRuleType
+        {
+            get { return typeof(FileSystemAccessRule); }
+        }
+
+        public override Type AuditRuleType
+        {
+            get { return typeof(FileSystemAuditRule); }
+        }
+    }
+}