221

I need to test if a user can write to a folder before actually attempting to do so.

I've implemented the following method (in C# 2.0) that attempts to retrieve the security permissions for the folder using Directory.GetAccessControl() method.

private bool hasWriteAccessToFolder(string folderPath)
{
    try
    {
        // Attempt to get a list of security permissions from the folder. 
        // This will raise an exception if the path is read only or do not have access to view the permissions. 
        System.Security.AccessControl.DirectorySecurity ds = Directory.GetAccessControl(folderPath);
        return true;
    }
    catch (UnauthorizedAccessException)
    {
        return false;
    }
}

When I was googling how to test for write access nothing like this came up and it appeared very complicated to actually test permissions in Windows. I am concerned that I am over-simplifying things and that this method is not robust, although it does seem to work.

Will my method to test if the current user has write access work correctly?

Chris B
  • 5,311
  • 11
  • 45
  • 57
  • 14
    Is not having access to **view** the permissions really the same as not being allowed to write to it? – deed02392 Sep 19 '13 at 15:02

19 Answers19

91
public bool IsDirectoryWritable(string dirPath, bool throwIfFails = false)
{
    try
    {
        using (FileStream fs = File.Create(
            Path.Combine(
                dirPath, 
                Path.GetRandomFileName()
            ), 
            1,
            FileOptions.DeleteOnClose)
        )
        { }
        return true;
    }
    catch
    {
        if (throwIfFails)
            throw;
        else
            return false;
    }
}
Jon Dosmann
  • 667
  • 7
  • 20
priit
  • 937
  • 6
  • 2
  • 8
    This answer will catch all exceptions that could occur when trying to write a file, not just permission violations. – Matt Ellen Jun 17 '11 at 09:42
  • Almost good! but how to do without creating an actual file.. what if a file with the same name already exists there... nice try though :) – G.Y May 06 '13 at 17:12
  • 7
    @G.Y, `string tempFileName = Path.GetRandomFileName();`, evidently – Alexey Khoroshikh Feb 05 '14 at 09:37
  • 4
    @Matt, this answers exactly the asked question "is the directory is writable" regardless of the reason of failure, however. You rather answer to "**why** i can't write to the directory". :) – Alexey Khoroshikh Feb 05 '14 at 09:43
  • 1
    I get a false positive with this code. The File.Create() runs OK (and leaves a temp file if you change the last option) even though the executing user has no permission to write to that folder. Really really odd - spent an hour trying to figure out why but I'm stumped. – NickG Feb 10 '15 at 11:49
  • 1
    You may have access to Write the file but not delete. Check your NTFS permissions. – software is fun Mar 25 '15 at 17:04
  • 4
    From all alternatives which I have tried below (and referenced links) - this is the only one which works reliably. – TarmoPikaro Apr 21 '15 at 08:10
  • 1
    Please note that this technique changes the "last modified date" of the directory. – EylM Feb 10 '19 at 16:55
  • One issue with this approach is that the the random filename may put the path over the Path limit; thus throwing a PathTooLongException which would be caught and interpretted (incorrectly) as the directory not being writable. – Matt Smith Apr 20 '22 at 16:38
84

I appreciate that this is a little late in the day for this post, but you might find this bit of code useful.

string path = @"c:\temp";
string NtAccountName = @"MyDomain\MyUserOrGroup";

DirectoryInfo di = new DirectoryInfo(path);
DirectorySecurity acl = di.GetAccessControl(AccessControlSections.All);
AuthorizationRuleCollection rules = acl.GetAccessRules(true, true, typeof(NTAccount));

//Go through the rules returned from the DirectorySecurity
foreach (AuthorizationRule rule in rules)
{
    //If we find one that matches the identity we are looking for
    if (rule.IdentityReference.Value.Equals(NtAccountName,StringComparison.CurrentCultureIgnoreCase))
    {
        var filesystemAccessRule = (FileSystemAccessRule)rule;

        //Cast to a FileSystemAccessRule to check for access rights
        if ((filesystemAccessRule.FileSystemRights & FileSystemRights.WriteData)>0 && filesystemAccessRule.AccessControlType != AccessControlType.Deny)
        {
            Console.WriteLine(string.Format("{0} has write access to {1}", NtAccountName, path));
        }
        else
        {
            Console.WriteLine(string.Format("{0} does not have write access to {1}", NtAccountName, path));
        }
    }
}

Console.ReadLine();

Drop that into a Console app and see if it does what you need.

Duncan Howe
  • 2,965
  • 19
  • 18
  • Right on target! Helps me a lot! – smwikipedia Nov 30 '11 at 02:27
  • I get an exception on the call to `GetAccessControl` but my software is actualy capable of writing to the directory I'm looking at.. ? – Jon Cage May 10 '12 at 13:50
  • @JonCage - what exception are you getting? The first thing that leaps to mind is, ironically, a security problem. Does the account that your app is running as have permission to get the ACL information? – Duncan Howe May 16 '12 at 20:48
  • Nice work here. This didn't end up solving my issue, though. If the app is running under a user that does not have write privileges on the folder, GetAccessControl will throw an exception. But that gave me what I neeeded--a simple try/catch! – wooters Apr 09 '14 at 02:14
  • You can have write permissions on a folder without having access to look those permissions up. Also it doesn't look this will handle the case if you're a member of a group as it's checking the account name directly. – RandomEngy May 26 '15 at 00:21
  • @RandomEngy - that first point is news to me, so thank you. As for the second point, it is true that this snippet checks the account directly, but there is nothing stopping you putting this into a method and passing the variables in as parameters and then enumerating over the users group membership externally and passing those details in. – Duncan Howe May 27 '15 at 14:38
  • Does this also check for inherited permissions? – Venson Jun 16 '16 at 07:07
  • 2
    You need to add a check for FileSystemAccessRule type. If it's a Deny rule, you will incorrectly report it as writable. – tdemay Dec 29 '17 at 23:57
  • @tdemay - Good spot and thank you. I have updated the code to test the rule's AccessControlType to make sure that the "WriteData" setting isn't a deny rule – Duncan Howe Jan 02 '18 at 14:16
  • 2
    I'm trying to use this. Found another problem. If rights are only assigned to groups and not specific users this will incorrectly report they don't have write access. For example, write access granted to "Authenticated users" – tdemay Jan 02 '18 at 15:49
  • @tdemay - this was a point raised by RandomEngy (see above). It does only test access for a given identity and doesn't lookup the groups that the account is a member of. As suggested above you could simply extract this code into a method and pass the account name and directory in as arguments – Duncan Howe Jan 02 '18 at 16:29
  • doesn't work if the directory is a network share and user has rights locally, but not through the share. – tdemay Jan 11 '18 at 22:49
  • @tdemay - that is true but that is because share permissions are different to file system permissions. This is only going to deal with the file system permissions, not the sharing permissions. – Duncan Howe Jan 25 '18 at 14:52
  • 1
    this gives me `PrivilegeNotHeldException` when run with normal privileges – mrid Jun 03 '19 at 08:27
  • @duncan-howe For a general purpose code that will run anywhere, how can we know the 'domain' and 'user group' at development time? – Syed Irfan Ahmad Jul 17 '22 at 11:55
  • @SyedIrfanAhmad - you could take a look at `Environment.UserDomainName` to get the domain name. For the user group you would either have to know that in advance and input it or enumerate a collection of group names (e.g. either taken from a user account or directly from AD) – Duncan Howe Jul 19 '22 at 13:46
  • @DuncanHowe What permission need to be given to a windows account in order to be able to check ACL? ie., To be able to execute "DirectorySecurity acl = di.GetAccessControl(AccessControlSections.All)" – user1066231 Sep 11 '22 at 05:46
  • @user1066231 according to https://learn.microsoft.com/en-us/dotnet/api/system.io.file.getaccesscontrol?view=netframework-4.8 the caller would need to have the ListDirectory right on the parent directory. According to https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/icacls, this would be granting the `RD` permission. – Duncan Howe Sep 12 '22 at 09:28
  • @user1066231 Note: I haven't tested this, but that is what the MS docs say :-) – Duncan Howe Sep 12 '22 at 09:28
68

That's a perfectly valid way to check for folder access in C#. The only place it might fall down is if you need to call this in a tight loop where the overhead of an exception may be an issue.

There have been other similar questions asked previously.

Community
  • 1
  • 1
Ash
  • 60,973
  • 31
  • 151
  • 169
  • 1
    Funnily enough I had one of those other questions open in another tab but hadn't seen the answer about DirectorySecurity, teach me to read *all* the answers not just the accepted one;-) – Chris B Sep 11 '09 at 10:45
  • Won't it also fall down when you use long paths in Windows? – Alexandru Apr 20 '15 at 18:18
  • 14
    That won't tell you if you have write permission, it will only tell you if you can look up permissions on that folder or not. Also you might be able to write but not be able to look up permissions. – RandomEngy May 26 '15 at 00:15
29

I tried most of these, but they give false positives, all for the same reason.. It is not enough to test the directory for an available permission, you have to check that the logged in user is a member of a group that has that permission. To do this you get the users identity, and check if it is a member of a group that contains the FileSystemAccessRule IdentityReference. I have tested this, works flawlessly..

    /// <summary>
    /// Test a directory for create file access permissions
    /// </summary>
    /// <param name="DirectoryPath">Full path to directory </param>
    /// <param name="AccessRight">File System right tested</param>
    /// <returns>State [bool]</returns>
    public static bool DirectoryHasPermission(string DirectoryPath, FileSystemRights AccessRight)
    {
        if (string.IsNullOrEmpty(DirectoryPath)) return false;

        try
        {
            AuthorizationRuleCollection rules = Directory.GetAccessControl(DirectoryPath).GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
            WindowsIdentity identity = WindowsIdentity.GetCurrent();

            foreach (FileSystemAccessRule rule in rules)
            {
                if (identity.Groups.Contains(rule.IdentityReference))
                {
                    if ((AccessRight & rule.FileSystemRights) == AccessRight)
                    {
                        if (rule.AccessControlType == AccessControlType.Allow)
                            return true;
                    }
                }
            }
        }
        catch { }
        return false;
    }
JGU
  • 879
  • 12
  • 14
  • Thanks John, I've got false positive as well until I've using your code to check user group again the rule IdentifyReference! – Paul L Jun 22 '17 at 19:50
  • 1
    i had to add an additional check for identity.Owner == rule.IdentityReference as I had a user who given access but not in any groups, like a dedicated local account for services – grinder22 Jun 12 '18 at 20:51
  • 2
    AccessControlType deny takes precedence over allow, so to be completely thorough rules that deny the access right should be checked as well, and when checking for deny types it should be `(AccessRight & rule.FileSystemRights) > 0` because any sub access type denied that is part of `AccessRight` means you don't have *full* access to `AccessRight` – TJ Rockefeller Oct 03 '18 at 15:45
  • As grinder22 mentioned above, I needed to change; if (identity.Groups.Contains(rule.IdentityReference)) to if (identity.Groups.Contains(rule.IdentityReference) || identity.Owner.Equals(rule.IdentityReference)) as I had a user who had access but wasn't in any of the groups. – ehambright Nov 20 '19 at 17:21
  • @TJRockefeller Shouldn't we just add `if (rule.AccessControlType == AccessControlType.Deny) continue;` inside the `foreach` to prevent taking `Deny` as `Allow`? – Nicke Manarin Sep 14 '20 at 15:01
  • 1
    @NickeManarin There could be a rule that allows access, but also a different rule that denies access, and deny overrides allow, so it's not enough to just skip the deny rules. Also, if you want the access right of read and write, but there is a rule denying write access, then that will prevent full read and write access even if there is a rule that allows read and write. – TJ Rockefeller Sep 14 '20 at 18:40
15

For example for all users (Builtin\Users), this method works fine - enjoy.

public static bool HasFolderWritePermission(string destDir)
{
   if(string.IsNullOrEmpty(destDir) || !Directory.Exists(destDir)) return false;
   try
   {
      DirectorySecurity security = Directory.GetAccessControl(destDir);
      SecurityIdentifier users = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null);
      foreach(AuthorizationRule rule in security.GetAccessRules(true, true, typeof(SecurityIdentifier)))
      {
          if(rule.IdentityReference == users)
          {
             FileSystemAccessRule rights = ((FileSystemAccessRule)rule);
             if(rights.AccessControlType == AccessControlType.Allow)
             {
                    if(rights.FileSystemRights == (rights.FileSystemRights | FileSystemRights.Modify)) return true;
             }
          }
       }
       return false;
    }
    catch
    {
        return false;
    }
}
Przemysław Michalski
  • 9,627
  • 7
  • 31
  • 37
15

IMHO the only 100% reliable way to test if you can write to a directory is to actually write to it and eventually catch exceptions.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
9

Try this:

try
{
    DirectoryInfo di = new DirectoryInfo(path);
    DirectorySecurity acl = di.GetAccessControl();
    AuthorizationRuleCollection rules = acl.GetAccessRules(true, true, typeof(NTAccount));

    WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
    WindowsPrincipal principal = new WindowsPrincipal(currentUser);
    foreach (AuthorizationRule rule in rules)
    {
        FileSystemAccessRule fsAccessRule = rule as FileSystemAccessRule;
        if (fsAccessRule == null)
            continue;

        if ((fsAccessRule.FileSystemRights & FileSystemRights.WriteData) > 0)
        {
            NTAccount ntAccount = rule.IdentityReference as NTAccount;
            if (ntAccount == null)
            {
                continue;
            }

            if (principal.IsInRole(ntAccount.Value))
            {
                Console.WriteLine("Current user is in role of {0}, has write access", ntAccount.Value);
                continue;
            }
            Console.WriteLine("Current user is not in role of {0}, does not have write access", ntAccount.Value);                        
        }
    }
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("does not have write access");
}
Adi Lester
  • 24,731
  • 12
  • 95
  • 110
CsabaS
  • 91
  • 1
  • 2
  • If I'm not mistaken, this is close but not quite there -- it overlooks the fact that `fsAccessRule.AccessControlType` could be `AccessControlType.Deny`. – Jonathan Gilbert Jun 19 '17 at 21:23
  • This was working for me on my Win7 dev machine but fails on Win10 (both for a tester and my own test machine). ssds's modification (see below) appears to fix it. – winwaed Oct 28 '17 at 20:07
9

Above solutions are good but for me, I find this code simple and workable. Just create a temporary file. If the file is created, its mean user has the write access.

        public static bool HasWritePermission(string tempfilepath)
        {
            try
            {
                System.IO.File.Create(tempfilepath + "temp.txt").Close();
                System.IO.File.Delete(tempfilepath + "temp.txt");
            }
            catch (System.UnauthorizedAccessException ex)
            {

                return false;
            }

            return true;
        }
Ali Asad
  • 1,235
  • 1
  • 18
  • 33
  • 4
    Nice! One thing though is the that user might have `Create` permission but not `Delete` in which case this would return false even though the user _does_ have write permission. – Chris B Jan 30 '18 at 10:12
  • Most convenient answer for coding :) I also use this one only, however, when there are large concurrent requests then so much read/write might slow down performance so in those cases you can use accesscontrol methodology as given in other answers. – vibs2006 Jun 21 '18 at 09:44
  • 2
    Use `Path.Combine` instead such as `Path.Combine(tempfilepath, "temp.txt")`. – ΩmegaMan Dec 09 '19 at 18:17
  • 1
    It's better to use GUID for the temp file's name. – YantingChen Jan 22 '21 at 06:46
  • @ali-asad If the user or the application doesn't have delete permission in the specific folder, a temporary file will remain there in that folder. The code is ambiguous in case an exception occurs deleting the temp file – Syed Irfan Ahmad Jul 17 '22 at 11:51
8

Your code gets the DirectorySecurity for a given directory, and handles an exception (due to your not having access to the security info) correctly. However, in your sample you don't actually interrogate the returned object to see what access is allowed - and I think you need to add this in.

Vinay Sajip
  • 95,872
  • 14
  • 179
  • 191
  • +1 - I just ran into this problem where an exception was not thrown when calling GetAccessControl yet I get an unauthorized exception when attempting to write to that same directory. – Mayo Jan 20 '11 at 15:49
7

Here is a modified version of CsabaS's answer, which accounts for explicit deny access rules. The function goes through all FileSystemAccessRules for a directory, and checks if the current user is in a role which has access to a directory. If no such roles are found or the user is in a role with denied access, the function returns false. To check read rights, pass FileSystemRights.Read to the function; for write rights, pass FileSystemRights.Write. If you want to check an arbitrary user's rights and not the current one's, substitute the currentUser WindowsIdentity for the desired WindowsIdentity. I would also advise against relying on functions like this to determine if the user can safely use the directory. This answer perfectly explains why.

    public static bool UserHasDirectoryAccessRights(string path, FileSystemRights accessRights)
    {
        var isInRoleWithAccess = false;

        try
        {
            var di = new DirectoryInfo(path);
            var acl = di.GetAccessControl();
            var rules = acl.GetAccessRules(true, true, typeof(NTAccount));

            var currentUser = WindowsIdentity.GetCurrent();
            var principal = new WindowsPrincipal(currentUser);
            foreach (AuthorizationRule rule in rules)
            {
                var fsAccessRule = rule as FileSystemAccessRule;
                if (fsAccessRule == null)
                    continue;

                if ((fsAccessRule.FileSystemRights & accessRights) > 0)
                {
                    var ntAccount = rule.IdentityReference as NTAccount;
                    if (ntAccount == null)
                        continue;

                    if (principal.IsInRole(ntAccount.Value))
                    {
                        if (fsAccessRule.AccessControlType == AccessControlType.Deny)
                            return false;
                        isInRoleWithAccess = true;
                    }
                }
            }
        }
        catch (UnauthorizedAccessException)
        {
            return false;
        }
        return isInRoleWithAccess;
    }
Community
  • 1
  • 1
sdds
  • 2,021
  • 2
  • 25
  • 33
  • Csaba's code was failing for me on Windows 10 (but fine on my Win7 dev machine). The above appears to fix the problem. – winwaed Oct 28 '17 at 20:06
4

You can try following code block to check if the directory is having Write Access. It checks the FileSystemAccessRule.

string directoryPath = "C:\\XYZ"; //folderBrowserDialog.SelectedPath;
bool isWriteAccess = false;
try
{
    AuthorizationRuleCollection collection =
        Directory.GetAccessControl(directoryPath)
            .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
    foreach (FileSystemAccessRule rule in collection)
    {
        if (rule.AccessControlType == AccessControlType.Allow)
        {
            isWriteAccess = true;
            break;
        }
    }
}
catch (UnauthorizedAccessException ex)
{
    isWriteAccess = false;
}
catch (Exception ex)
{
    isWriteAccess = false;
}
if (!isWriteAccess)
{
    //handle notifications 
}
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
RockWorld
  • 1,278
  • 2
  • 11
  • 24
3

You have a potential race condition in your code--what happens if the user has permissions to write to the folder when you check, but before the user actually writes to the folder this permission is withdrawn? The write will throw an exception which you will need to catch and handle. So the initial check is pointless. You might as well just do the write and handle any exceptions. This is the standard pattern for your situation.

  • What about letting the user know that the default location they chose in their configuration dialog does not have the appropriate permissions for storing received content files? Sure at some point later (0-999 days time) when a content file is actually received you'd have to handle the exception anyway as the permission may have changed, but it's better UX to warn the user when they set their initial configuration. – Reahreic Feb 12 '21 at 18:38
3

http://www.codeproject.com/KB/files/UserFileAccessRights.aspx

Very usefull Class, check for improved version in messages bellow.

2

Simply trying to access the file in question isn't necessarily enough. The test will run with the permissions of the user running the program - Which isn't necessarily the user permissions you want to test against.

Mort
  • 144
  • 2
  • 11
1

This should be all you need, as far as I can tell you only need to catch the one exception.

private static readonly byte[] TestArray = new byte[]{
    69, 70, 71, 72
};

private static bool IsFolderAccessible(string path) {
    var temp_path = Path.Combine(path, Path.GetRandomFileName());

    try {
        using (var file = File.Create(temp_path, TestArray.Length, FileOptions.DeleteOnClose)) {
            file.Write(TestArray, 0, TestArray.Length);
        }

        return true;
    } catch (UnauthorizedAccessException ex) {
        Log.Warn($"Error accessing file {temp_path}", ex);

        return false;
    }
}
Kelly Elton
  • 4,373
  • 10
  • 53
  • 97
0

I agree with Ash, that should be fine. Alternatively you could use declarative CAS and actually prevent the program from running in the first place if they don't have access.

I believe some of the CAS features may not be present in C# 4.0 from what I've heard, not sure if that might be an issue or not.

Ian
  • 33,605
  • 26
  • 118
  • 198
0

I couldn't get GetAccessControl() to throw an exception on Windows 7 as recommended in the accepted answer.

I ended up using a variation of sdds's answer:

        try
        {
            bool writeable = false;
            WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
            DirectorySecurity security = Directory.GetAccessControl(pstrPath);
            AuthorizationRuleCollection authRules = security.GetAccessRules(true, true, typeof(SecurityIdentifier));

            foreach (FileSystemAccessRule accessRule in authRules)
            {

                if (principal.IsInRole(accessRule.IdentityReference as SecurityIdentifier))
                {
                    if ((FileSystemRights.WriteData & accessRule.FileSystemRights) == FileSystemRights.WriteData)
                    {
                        if (accessRule.AccessControlType == AccessControlType.Allow)
                        {
                            writeable = true;
                        }
                        else if (accessRule.AccessControlType == AccessControlType.Deny)
                        {
                            //Deny usually overrides any Allow
                            return false;
                        }

                    } 
                }
            }
            return writeable;
        }
        catch (UnauthorizedAccessException)
        {
            return false;
        }

Hope this helps.

Community
  • 1
  • 1
Patrick
  • 1
  • 1
0

I faced the same problem: how to verify if I can read/write in a particular directory. I ended up with the easy solution to...actually test it. Here is my simple though effective solution.

 class Program
{

    /// <summary>
    /// Tests if can read files and if any are present
    /// </summary>
    /// <param name="dirPath"></param>
    /// <returns></returns>
    private genericResponse check_canRead(string dirPath)
    {
        try
        {
            IEnumerable<string> files = Directory.EnumerateFiles(dirPath);
            if (files.Count().Equals(0))
                return new genericResponse() { status = true, idMsg = genericResponseType.NothingToRead };

            return new genericResponse() { status = true, idMsg = genericResponseType.OK };
        }
        catch (DirectoryNotFoundException ex)
        {

            return new genericResponse() { status = false, idMsg = genericResponseType.ItemNotFound };

        }
        catch (UnauthorizedAccessException ex)
        {

            return new genericResponse() { status = false, idMsg = genericResponseType.CannotRead };

        }

    }

    /// <summary>
    /// Tests if can wirte both files or Directory
    /// </summary>
    /// <param name="dirPath"></param>
    /// <returns></returns>
    private genericResponse check_canWrite(string dirPath)
    {

        try
        {
            string testDir = "__TESTDIR__";
            Directory.CreateDirectory(string.Join("/", dirPath, testDir));

            Directory.Delete(string.Join("/", dirPath, testDir));


            string testFile = "__TESTFILE__.txt";
            try
            {
                TextWriter tw = new StreamWriter(string.Join("/", dirPath, testFile), false);
                tw.WriteLine(testFile);
                tw.Close();
                File.Delete(string.Join("/", dirPath, testFile));

                return new genericResponse() { status = true, idMsg = genericResponseType.OK };
            }
            catch (UnauthorizedAccessException ex)
            {

                return new genericResponse() { status = false, idMsg = genericResponseType.CannotWriteFile };

            }


        }
        catch (UnauthorizedAccessException ex)
        {

            return new genericResponse() { status = false, idMsg = genericResponseType.CannotWriteDir };

        }
    }


}

public class genericResponse
{

    public bool status { get; set; }
    public genericResponseType idMsg { get; set; }
    public string msg { get; set; }

}

public enum genericResponseType
{

    NothingToRead = 1,
    OK = 0,
    CannotRead = -1,
    CannotWriteDir = -2,
    CannotWriteFile = -3,
    ItemNotFound = -4

}

Hope it helps !

l.raimondi
  • 389
  • 2
  • 14
0

Most of the answers here does not check for write access. It just check if the user/group can 'Read Permission' (Read the ACE list of the file/directory).

Also iterating through ACE and checking if it matches the Security Identifier does not work because the user can be a member of a group from which he might get/lose privilege. Worse than that is nested groups.

I know this is an old thread but there is a better way for any one looking now.

Provided the user has Read Permission privilege is, one can use the Authz API to check Effective access.

https://learn.microsoft.com/en-us/windows/win32/secauthz/using-authz-api

https://learn.microsoft.com/en-us/windows/win32/secauthz/checking-access-with-authz-api

Kamaal
  • 117
  • 5