Здравствуйте!
Помогите, пожалуйста, найти грамотное решение вот такой задачки.
Есть файловый фильтр, осуществляющий фильтрацию
IRP_MJ_CREATE.
Этот фильтр на основе тех или иных критериев должен сделать одно из следующего:
Разрешить операцию, т.е. просто переслать запрос ниже.
Запретить операцию, т.е. завершить запрос с соответствующим статусом.
Спросить у пользователя "что делать с этим запросом?".
Вот сейчас думаю как грамотно реализовать третий пункт?
Придумалось пока вот что:
1. Драйвер создаёт именованное событие через
IoCreateNotificationEvent() с именем что-то типа
\??\EventName. Юзермодное приложение открывает это событие через
OpenEvent().
2. Драйвер создаёт внутренний список (очередь
FIFO)
pending-запросов.
3. Для всех поступающих
IRP, соответствующих определённым критериям, драйвер делает следующее:
3.1. Создаёт примерно такую структуру:
typedef struct _REQUEST_ENTRY
{
KEVENT Event;
PIRP Irp;
ULONG UserAction;
}
REQUEST_ENTRY, *PREQUEST_ENTRY;
3.2. Ставит её во внутреннюю очередь.
3.3. Ставит глобальное событие
\??\EventName в состояние
signaled.
3.4. Входит в ожидание события
REQUEST_ENTRY.
Event через
KeWaitForSingleObject().
4. Приложение получает уведомление о событии
\??\EventName через
WaitForSingleObject().
5. По получении уведомления приложение шлёт что-то типа
IOCTL_QUERY_REQUEST_DATA драйверу.
6. Драйвер заполняет буфер приложения данными по первому запросу в очереди (в том числе передаёт и указатель на
IRP) и завершает запрос
IOCTL_QUERY_REQUEST_DATA.
7. Приложение отображает пользователю окно с данными запроса (например, имя файла) и пользователь жмёт, например, либо "
Разрешить" либо "
Запретить".
8. Приложение шлёт драйверу что-то типа
IOCTL_RESOLVE_REQUEST вот с такой примерно структурой:
typedef struct _RESOLVE_ENTRY
{
PIRP Irp;
ULONG UserAction;
}
RESOLVE_ENTRY, *PRESOLVE_ENTRY;
9. Драйвер по получении
IOCTL_RESOLVE_REQUEST делает следующее:
9.1. Прочёсывает всю свою внутреннюю очередь и ищет в ней указанный
IRP по указателю
RESOLVE_ENTRY.
Irp.
9.2. Если нашёл — ставит поле
REQUEST_ENTRY.
UserAction в значение
RESOLVE_ENTRY.
UserAction.
9.3. Ставит событие
REQUEST_ENTRY.
Event в состояние
signaled.
10. Далее запрос
IRP_MJ_CREATE, который заснул в ожидании события
REQUEST_ENTRY.
Event, просыпается и происходит следующее:
10.1. Считывается значения поля
REQUEST_ENTRY.
UserAction и запоминается в локальной переменной.
10.2.
REQUEST_ENTRY удаляется из внутреней очереди и уничтожается.
10.3. Выполняется выбранное пользователем действие.
Вот так, что-то вроде того
.
Просьба к гуру: прокомментируйте, пожалуйста, мои мысли.
Насколько приведённый алгоритм грамотен?
Какие могут быть подводные камни?
Как можно сделать безопаснее / красивее / эффективнее?
Спасибо!