C # Linq для файлов, к которым пользователь имеет доступ на чтение

Как мне использовать Linq на list.Items = directoryInfo.GetFiles("\\server\share\folder\");, чтобы включить только те файлы, к которым у пользователя есть доступ на чтение?

... Пока только предложения используют try / catch или API, которые устарели в .NET 4.0? Я бы предпочел, чтобы что-нибудь прочитало ACL и посмотрело, был ли предоставлен доступ для чтения конкретному пользователю или группе, членом которой является пользователь. Я пытаюсь сделать это для упрощения управления предоставлением отчетов пользователям на веб-сайте, который не будет иметь большого трафика, поэтому логика, что «кто знает, действительно ли вы можете прочитать это, когда вы пытаетесь открыть файл», не относятся к этому делу. Я чувствую, что Microsoft действительно должна облегчить эту задачу.


person Matt    schedule 22.09.2011    source источник


Ответы (4)


Вы подвергаетесь риску состязания, если проверяете разрешение на чтение перед открытием файла.

Если вы пытаетесь прочитать все файлы в папке, к которым у вас есть доступ, лучше просто попробовать открыть каждый из них и поймать UnauthorizedAccessException.

Видеть:

person Michael Petito    schedule 22.09.2011

просто попробуйте это. должно работать. хотя

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

ИЗМЕНИТЬ, если это просто файлы, доступные только для чтения, попробуйте это

var fe = from f in new DirectoryInfo("C:\\Users\\ashley\\Downloads\\").GetFiles()
                where f.IsReadOnly==true
                select f
person Ashley John    schedule 22.09.2011
comment
Возможно, вы сможете вместо этого использовать решение из этого вопроса. - person Merlyn Morgan-Graham; 22.09.2011
comment
да ... но изложение некоторой логики внутри catch звучит не очень элегантно. Представьте, что у вас есть тысячи файлов, и ожидание возникновения исключения для получения его состояния - довольно дорогостоящая операция. - person Ashley John; 22.09.2011
comment
@Ashley: Я почти уверен, что это особые случаи (диск не существует или вы полностью заблокированы для доступа к папке). Вы можете вызвать эту функцию из запроса Linq, чтобы ваш код более высокого уровня оставался красивым. Он уже инкапсулирует истину / ложь, поэтому вам просто нужно вставить его в предложение where. Я не знаю, есть ли лучший вариант без использования p / Invoke (например, вариант Try). Также я думаю, что перечисление файлов в файловой системе уже может быть узким местом. Я полагаю, что на этом этапе исключением можно будет пренебречь. - person Merlyn Morgan-Graham; 22.09.2011

Примечание: я не тестировал, но теоретически он должен работать

Сначала определите предикат для определения доступа для чтения

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;
  }
}


Тогда это должен быть простой случай использования предложения where в запросе linq

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

Протестировано и работает, но вернет false, если файл уже используется.

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;
}
person Rob    schedule 22.09.2011
comment
Работает ли это для групп внутри групп? Как насчет явного запрета разрешений? - person Michael Petito; 22.09.2011