How can I determine if I have read access to a folder in C#

I am trying to see if I have read access to a folder.  I am not trying to determine write access, just read.  I have a lame way of doing this now, but I think it can be better.
rye004Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jmcgOwnerCommented:
I think the most straightforward way to do it is to attempt to read the folder and handle the error condition if you don't have access. Is that what your "lame" method does?

Other methods require making other queries of the file system and interpretation of the results...and, if it happens that access fails when you finally try it, you still have to be prepared to handle the error condition.

(The analogous question comes up when someone wants to determine whether a folder is empty before they remove it. The easiest thing to do is make the rmdir call and -- should it fail -- that's when it's time to figure out if the folder is not empty or if there's some other condition preventing the removal.)
rye004Author Commented:
Sorry, what you suggested is what I am doing.  When I run VS profiler, it takes up a lot of resources.
jmcgOwnerCommented:
Are you reading the entire folder or just enough to determine that you can read it?

Which resources are at a premium?

Does your profiling tell you what parts of the access are consuming the most? Any query to the file system to find out what you want is going to consume some resources, but if you're walking an entire file system, there may be some strategies that reduce the algorithmic complexity and prevent n-squared behavior from repetitive parsing.
PMI ACP® Project Management

Prepare for the PMI Agile Certified Practitioner (PMI-ACP)® exam, which formally recognizes your knowledge of agile principles and your skill with agile techniques.

rye004Author Commented:
Below is what I am currently using - which I think is lame.

This is taking a huge amount of my execution time.


        public static bool canReadFolderContent(string folderString)
        {
            bool returnBool = true;

            try
            {

                foreach (string tempString in Directory.GetDirectories(folderString, "*", SearchOption.TopDirectoryOnly))
                {
                    return true;
                }

            }
            catch
            {
                returnBool = false;
            }
            
            return returnBool;

        }

Open in new window

jmcgOwnerCommented:
MSDN has an article with a couple of suggestions:

How to: Iterate Through a Directory Tree (C# Programming Guide)

The first walks the folder tree using a recursive function, the second is a bit lighter weight and handles the recursive aspects with a stack.

I haven't examined these samples in great detail, but what I suspect they do is reduce the number of round trips through the code that turns a filesystem name string into a filesystem object, as well as ensuring that folder contents are read (or are attempted to be read) only once.

But perhaps you were already doing something like this in code outside of the snippet you showed us. It could be that this operation can't be reduced any further.
it_saigeDeveloperCommented:
Directorys (and files) have attributes on them, one of these is the FileSystemRights enumeration:
using System;
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;

namespace EE_Q28705514
{
	class Program
	{
		static void Main(string[] args)
		{
			DirectoryInfo directory = new DirectoryInfo(@"c:\windows\system32");
			FileInfo file = new FileInfo(@"c:\windows\system32\notepad.exe");
			Console.WriteLine("Current user has read rights for {0}: {1}", directory.FullName, directory.HasReadRights());
			Console.WriteLine("Current user has read rights for {0}: {1}", file.FullName, file.HasReadRights());
			Console.ReadLine();
		}
	}

	static class Extensions
	{
		public static bool CheckRights(this FileSystemAccessRule ace)
		{
			bool result = default(bool);
			try
			{
				result = ((int)(ace.FileSystemRights & FileSystemRights.Read) == (int)FileSystemRights.Read) || ((int)(ace.FileSystemRights & FileSystemRights.ReadData) == (int)FileSystemRights.ReadData);
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		public static bool HasReadRights(this FileInfo file)
		{
			bool result = default(bool);
			if (file.Exists)
			{
				var acls = new FileSecurity(file.FullName, AccessControlSections.Access);
				var user = WindowsIdentity.GetCurrent();
				var principal = new WindowsPrincipal(user);
				var sid = new NTAccount(user.Name).Translate(typeof(SecurityIdentifier));
				foreach (FileSystemAccessRule rule in acls.GetAccessRules(true, true, typeof(NTAccount)))
				{
					if ((user.IsInGroup(rule.IdentityReference.Translate(typeof(NTAccount)).Value) || principal.IsInRole(rule.IdentityReference.Value) || rule.IdentityReference == sid) && rule.CheckRights())
					{
						result = true;
						break;
					}
				}
			}
			return result;
		}

		public static bool HasReadRights(this DirectoryInfo directory)
		{
			bool result = default(bool);
			if (directory.Exists)
			{
				var acls = new DirectorySecurity(directory.FullName, AccessControlSections.Access);
				var user = WindowsIdentity.GetCurrent();
				var principal = new WindowsPrincipal(user);
				var sid = new NTAccount(user.Name).Translate(typeof(SecurityIdentifier));
				foreach (FileSystemAccessRule rule in acls.GetAccessRules(true, true, typeof(NTAccount)))
				{
					if ((user.IsInGroup(rule.IdentityReference.Translate(typeof(NTAccount)).Value) || principal.IsInRole(rule.IdentityReference.Value) || rule.IdentityReference == sid) && rule.CheckRights())
					{
						result = true;
						break;
					}
				}
			}
			return result;
		}

		public static bool IsInGroup(this WindowsIdentity user, string groupName)
		{
			var groups = user.Groups;
			foreach (var group in groups)
			{
				var translated = group.Translate(typeof(NTAccount));
				if (groupName.Equals(translated.Value, StringComparison.CurrentCultureIgnoreCase))
					return true;
			}
			return false;
		}
	}
}

Open in new window

Which produces the following output -Capture.JPG-saige-
it_saigeDeveloperCommented:
Now let's take it a step farther.  I have explicitly set on a file that I have no read access to it:As you can see the rights associated with reading the file data have been removed.So now let's make a change to the program for additional error trapping and to list the ACL's for the files notepad.exe and noreadaccess.txt -
using System;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text;

namespace EE_Q28705514
{
	class Program
	{
		static void Main(string[] args)
		{
			DirectoryInfo directory = new DirectoryInfo(@"c:\windows\system32");
			FileInfo file = new FileInfo(@"c:\windows\system32\notepad.exe");
			FileInfo noread = new FileInfo(@"c:\!quick\noreadaccess.txt");
			Console.WriteLine("{0}Current user has read rights for {1}: {2}", directory.ListDirectoryACLs(), directory.FullName, directory.HasReadRights());
			Console.WriteLine();
			Console.WriteLine("{0}Current user has read rights for {1}: {2}", file.ListFileACLs(), file.FullName, file.HasReadRights());
			Console.WriteLine();
			Console.WriteLine("{0}Current user has read rights for {1}: {2}", noread.ListFileACLs(), noread.FullName, noread.HasReadRights());
			Console.ReadLine();
		}
	}

	static class Extensions
	{
		static bool CheckRights(this FileSystemAccessRule ace)
		{
			bool result = default(bool);
			try
			{
				result = ((int)(ace.FileSystemRights & FileSystemRights.Read) == (int)FileSystemRights.Read) || ((int)(ace.FileSystemRights & FileSystemRights.ReadData) == (int)FileSystemRights.ReadData);
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		public static bool HasReadRights(this FileInfo file)
		{
			bool result = default(bool);
			try
			{
				if (file.Exists)
				{
					var acls = new FileSecurity(file.FullName, AccessControlSections.Access);
					var user = WindowsIdentity.GetCurrent();
					var principal = new WindowsPrincipal(user);
					var sid = new NTAccount(user.Name).Translate(typeof(SecurityIdentifier));
					result = (from FileSystemAccessRule rule in acls.GetAccessRules(true, true, typeof(NTAccount))
							where ((user.IsInGroup(rule.IdentityReference.Translate(typeof(NTAccount)).Value) ||
							principal.IsInRole(rule.IdentityReference.Value) || rule.IdentityReference == sid) && rule.CheckRights())
							select rule).Count() > 0;
				}
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		public static bool HasReadRights(this DirectoryInfo directory)
		{
			bool result = default(bool);
			try
			{
				if (directory.Exists)
				{
					var acls = new DirectorySecurity(directory.FullName, AccessControlSections.Access);
					var user = WindowsIdentity.GetCurrent();
					var principal = new WindowsPrincipal(user);
					var sid = new NTAccount(user.Name).Translate(typeof(SecurityIdentifier));
					result = (from FileSystemAccessRule rule in acls.GetAccessRules(true, true, typeof(NTAccount))
							where ((user.IsInGroup(rule.IdentityReference.Translate(typeof(NTAccount)).Value) ||
							principal.IsInRole(rule.IdentityReference.Value) || rule.IdentityReference == sid) && rule.CheckRights())
							select rule).Count() > 0;
				}
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		static bool IsInGroup(this WindowsIdentity user, string groupName)
		{
			try
			{
				return (from grp in user.Groups 
					   let translated = grp.Translate(typeof(NTAccount)) 
					   where translated.Value.Equals(groupName, StringComparison.CurrentCultureIgnoreCase) 
					   select grp).Count() > 0;
			}
			catch (Exception)
			{
				return false;
			}
		}

		public static string ListDirectoryACLs(this DirectoryInfo directory)
		{
			var sb  = new StringBuilder();
			try
			{
				if (directory.Exists)
				{
					var acls = new DirectorySecurity(directory.FullName, AccessControlSections.Access);
					var user = WindowsIdentity.GetCurrent();
					var principal = new WindowsPrincipal(user);
					var sid = new NTAccount(user.Name).Translate(typeof(SecurityIdentifier));

					sb.AppendFormat("Access Control List for Directory - {0}", directory.FullName).AppendLine();
					foreach (FileSystemAccessRule rule in acls.GetAccessRules(true, true, typeof(NTAccount)))
					{
						if ((user.IsInGroup(rule.IdentityReference.Translate(typeof(NTAccount)).Value) || principal.IsInRole(rule.IdentityReference.Value) || rule.IdentityReference == sid))
						{
							sb.AppendFormat("Account:     {0}", rule.IdentityReference.Value).AppendLine();
							sb.AppendFormat("Type:        {0}", rule.AccessControlType).AppendLine();
							sb.AppendFormat("Rights:      {0}", rule.FileSystemRights).AppendLine();
							sb.AppendFormat("Inherited:   {0}", rule.IsInherited).AppendLine();
							sb.AppendFormat("Inheritance: {0}", rule.InheritanceFlags).AppendLine();
							sb.AppendFormat("Propagation: {0}", rule.PropagationFlags).AppendLine();
							sb.AppendLine(new string('-', 25));
						}
					}
				}
			}
			catch (Exception) { /* We don't care about errors here */ ;}
			return sb.ToString();
		}

		public static string ListFileACLs(this FileInfo file)
		{
			var sb = new StringBuilder();
			try
			{
				if (file.Exists)
				{
					var acls = new FileSecurity(file.FullName, AccessControlSections.Access);
					var user = WindowsIdentity.GetCurrent();
					var principal = new WindowsPrincipal(user);
					var sid = new NTAccount(user.Name).Translate(typeof(SecurityIdentifier));

					sb.AppendFormat("Access Control List for File - {0}", file.FullName).AppendLine();

					foreach (FileSystemAccessRule rule in acls.GetAccessRules(true, true, typeof(NTAccount)))
					{
						if ((user.IsInGroup(rule.IdentityReference.Translate(typeof(NTAccount)).Value) || principal.IsInRole(rule.IdentityReference.Value) || rule.IdentityReference == sid))
						{
							sb.AppendFormat("Account:     {0}", rule.IdentityReference.Value).AppendLine();
							sb.AppendFormat("Type:        {0}", rule.AccessControlType).AppendLine();
							sb.AppendFormat("Rights:      {0}", rule.FileSystemRights).AppendLine();
							sb.AppendFormat("Inherited:   {0}", rule.IsInherited).AppendLine();
							sb.AppendFormat("Inheritance: {0}", rule.InheritanceFlags).AppendLine();
							sb.AppendFormat("Propagation: {0}", rule.PropagationFlags).AppendLine();
							sb.AppendLine(new string('-', 25));
						}
					}
				}
			}
			catch (Exception) { /* We don't care about errors here */ ;}
			return sb.ToString();
		}
	}
}

Open in new window

Now we get the following output -Capture.JPGYou can read more about the FileSystemRights enumeration here: https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.filesystemrights(v=vs.110).aspx

-saige-

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
rye004Author Commented:
Forgive me for taking so long to get back to this, especially after you spent time detailing something for me that worked.  Thank you.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.