Использование System.Security.AccessControl для удаления ACE из папки ACL очень медленный, если размер целевой папки очень большой
Мне нужно удалить определенные учетные записи (например, опекуна "Все" или какую-либо глобальную группу, которая предоставляет всем доступ к папке) из ACL-списка в определенной подпапке общего ресурса. Я получаю объект DirectorySecurity, получаю и перебираю AuthorizationRuleCollection, удаляю рассматриваемый AccessRule из ACL, а затем вызываю SetAccessControl для применения изменений. Все работает нормально, если целевая папка небольшая, но если в ней много дочерних папок и файлов, для внесения изменений может потребоваться вечность (гораздо дольше, чем просто сделать это вручную). Я только хочу иметь дело с ACL на целевой папке. Есть ли способ сделать это с помощью классов.net DirectorySecurity? Или мне нужно прибегнуть к Win32 API или какому-то другому решению? Благодарю.
Вот фрагмент кода. Вызов dirInfo.SetAccessControl(dirSec) находится там, где он зависает, когда размер папки очень большой.
DirectoryInfo dirInfo = new DirectoryInfo(path);
DirectorySecurity dirSec = dirInfo.GetAccessControl();
AuthorizationRuleCollection acl = dirSec.GetAccessRules(true, true,
typeof(System.Security.Principal.NTAccount));
foreach (FileSystemAccessRule ace in acl)
{
if (groupsToRemove.Contains(ace.IdentityReference.Value))
{
dirSec.RemoveAccessRuleSpecific(ace);
dirInfo.SetAccessControl(dirSec);
}
}
2 ответа
DirectoryInfo dirInfo = new DirectoryInfo(path); DirectorySecurity dirSec = dirInfo.GetAccessControl(); AuthorizationRuleCollection acl = dirSec.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)); foreach (FileSystemAccessRule ace in acl) { if (groupsToRemove.Contains(ace.IdentityReference.Value)) { dirSec.RemoveAccessRuleSpecific(ace); dirInfo.SetAccessControl(dirSec); } }
В вашем коде вы применяете обновления к ACL при каждом взаимодействии вашего цикла, это становится очень дорогим. Вы пробовали двигаться dirInfo.SetAccessControl(dirSec);
вне foreach
? Это должно ссылаться на SetAccessControl
метод на вашем DirectoryInfo
объект один раз, применяя все изменения за один проход, например так:
foreach (FileSystemAccessRule ace in acl)
{
if (groupsToRemove.Contains(ace.IdentityReference.Value))
{
dirSec.RemoveAccessRuleSpecific(ace);
}
}
dirInfo.SetAccessControl(dirSec);
Необходимо установить флаг SE_DACL_PROTECTED, чтобы "предотвратить применение ACE, заданных в DACL родительского контейнера, и любых объектов над родительским контейнером в иерархии каталогов, к объекту DACL". Это, скорее всего, ускорит вашу работу, потому что не придется применять все дочерние объекты. Также из MSDN,
Помните, что для установки SE_DACL_PROTECTED должен присутствовать флаг SE_DACL_PRESENT, а для установки SE_SACL_PROTECTED должен присутствовать SE_SACL_PRESENT.
Затем вы должны использовать свойство IADsSecurityDescriptor.Control, чтобы контролировать, наследуются ли DACL и SACL объектом от его родительского контейнера.
Дополнительная информация доступна на MSDN для интерфейса IADsSecurityDescriptor.