views:

1733

answers:

4

In my .NET 2.0 application, I need to check if sufficient permissions exist to create and write to files to a directory. To this end I have the following function that attempts to create a file and write a single byte to it, deleting itself afterwards to test that permissions do exist.

I figured the best way to check was to actually try and do it, catching any exceptions that occur, but I'm not particularly happy about the general Exception catch, so is there a better, or perhaps a more accepted way of doing this?

Any comments or suggestions welcome.

Thanks.

private const string TEMP_FILE = "\\tempFile.tmp";

/// <summary>
/// Checks the ability to create and write to a file in the supplied directory.
/// </summary>
/// <param name="directory">String representing the directory path to check.</param>
/// <returns>True if successful; otherwise false.</returns>
private static bool CheckDirectoryAccess(string directory)
{
    bool success = false;
    string fullPath = directory + TEMP_FILE;

    if (Directory.Exists(directory))
    {
        try
        {
            // Attempt to create a temporary file.
            using (FileStream fs = new FileStream(fullPath, FileMode.CreateNew, FileAccess.Write))
            {
                fs.WriteByte(0xff);
            }

            // Delete temporary file if it was successfully created.
            if (File.Exists(fullPath))
            {
                File.Delete(fullPath);
                success = true;
            }
        }
        catch (Exception)
        {
            success = false;
        }
    }
+4  A: 

Directory.GetAcessControl(path) does what you are asking for.

public static bool HasWritePermissionOnDir(string path)
{
    var writeAllow = false;
    var writeDeny = false;
    var accessControlList = Directory.GetAccessControl(path);
    var accessRules = accessControlList.GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));

    foreach (FileSystemAccessRule rule in accessRules)
    {
        if ((FileSystemRights.Write & rule.FileSystemRights) != FileSystemRights.Write) continue;

        if (rule.AccessControlType == AccessControlType.Allow)
            writeAllow = true;
        else if (rule.AccessControlType == AccessControlType.Deny)
            writeDeny = true;
    }

    return writeAllow && !writeDeny;
}

(FileSystemRights.Write & rights) == FileSystemRights.Write is using something called "Flags" btw which if you don't know what it is you should really read up on :)

Richard
That will, of course, throw an exception if you can't actually get the ACL on the directory.
blowdart
What does it check for? That directory has Write permissions, but for which user? :)
aloneguid
+1  A: 

Hi there.

Try working with this C# snippet I just crafted:

using System;
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string directory = @"C:\downloads";

            DirectoryInfo di = new DirectoryInfo(directory);

            DirectorySecurity ds = di.GetAccessControl();

            foreach (AccessRule rule in ds.GetAccessRules(true, true, typeof(NTAccount)))
            {
                Console.WriteLine("Identity = {0}; Access = {1}", rule.IdentityReference.Value, rule.AccessControlType);
            }
        }
    }
}

And here's a reference you could also look at. My code might give you an idea as to how you could check for permissions before attempting to write to a directory.

Cheers. Jas.

Jason Evans
A: 

IMO, you need to work with such directories as usual, but instead of checking permissions before use, provide the correct way to handle UnauthorizedAccessException and react accordingly. This method is easier and much more error prone.

arbiter
+6  A: 

The answers by Richard and Jason are sort of in the right direction. However what you should be doing is computing the effective permissions for the user identity running your code. None of the examples above correctly account for group membership for example.

I'm pretty sure Keith Brown had some code to do this in his wiki version (offline at this time) of The .NET Developers Guide to Windows Security. This is also discussed in reasonable detail in his Programming Windows Security book.

Computing effective permissions is not for the faint hearted and your code to attempt creating a file and catching the security exception thrown is probably the path of least resistance.

Kev
It is also the only reliable method as otherwise someone could change the permission between checking and actually trying save (unlikely, but possible).
KeeperOfTheSoul
Thanks for this. So the only change I should do to my code is to catch a security exception instead of the general 'Exception'?
Andy
@Andy - yes, it's the path of least resistance unless you want to write the code to compute effective permissions.
Kev