Matt
Matt

Reputation: 41

C# Linq for files user has read access to

How would I use Linq on list.Items = directoryInfo.GetFiles("\\server\share\folder\"); to include only the files the user has read access to?

... So far only suggestions are using try/catches, or APIs that are obsolete in .NET 4.0? I'd prefer something to read the ACL's and see if the specific user or a group the user is a member of has been granted read access. I'm trying to do this for simplified management of granting reports to users on a website that won't be high traffic, so the logic that "who knows if you can actually read it when you try to open the file" doesn't pertain to this case. I sense that Microsoft should really make this task easier.

Upvotes: 4

Views: 1309

Answers (4)

Rob
Rob

Reputation: 27377

Tested and working, but will return false if the file is in use

void Main()
{
    var directoryInfo = new DirectoryInfo(@"C:\");
    var currentUser = WindowsIdentity.GetCurrent();
    var files = directoryInfo.GetFiles(".").Where(f => CanRead(currentUser, f.FullName));
}

private bool CanRead(WindowsIdentity user, string filePath)
{
    if(!File.Exists(filePath))
        return false;

    try
    {
        var fileSecurity = File.GetAccessControl(filePath, AccessControlSections.Access); 
        foreach(FileSystemAccessRule fsRule in fileSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier)))
        {
            foreach(var usrGroup in user.Groups)
            {
                if(fsRule.IdentityReference.Value == usrGroup.Value)
                    return true;
            }
        }
    } catch (InvalidOperationException) {
        //File is in use
        return false;
    }

    return false;
}

Upvotes: 0

Ashley John
Ashley John

Reputation: 2453

just try this out .should work .haven't tested though

  var fw = from f in new DirectoryInfo("C:\\Users\\User\\Downloads\\").GetFiles()
                where SecurityManager.IsGranted(new FileIOPermission
 (FileIOPermissionAccess.Write, f.FullName))
                select f;

EDIT if it is just read only files then try this

var fe = from f in new DirectoryInfo("C:\\Users\\ashley\\Downloads\\").GetFiles()
                where f.IsReadOnly==true
                select f

Upvotes: 1

Michael Petito
Michael Petito

Reputation: 13171

You run the risk of a race condition if you check for read permission prior to opening the file.

If you're attempting to read all of the files you have access to in a folder, better to just try opening each one and catch the UnauthorizedAccessException.

See:

Upvotes: 1

Jordaan Mylonas
Jordaan Mylonas

Reputation: 1271

Note: I haven't tested it, but in theory it should work

First, define a predicate to determine read access

bool CanRead(FileInfo file)
{
  try {
    file.GetAccessControl();
    //Read and write access;
    return true;
  }
  catch (UnauthorizedAccessException uae)
  {
    if (uae.Message.Contains("read-only"))
    {
      //read-only access
      return true;
    }
    return false;
  }
}


Then, it should be a simple case of using a where clause in a linq query

from file in directoryInfo.GetFiles("\\server\share\folder\") 
  where HaveAccess(f) == true
    select f;

Upvotes: 0

Related Questions