Уважаемые мастера! Написал несколько процедур для организации списка файлов. Ниже привожу исходный код: fileslist.h Код (Text): #define MAX_PATH 260 typedef struct _FNAME_STRUCTURE { LIST_ENTRY ListEntry; WCHAR FileName[MAX_PATH]; ULONG Length; } FNAME_STRUCTURE, *PFNAME_STRUCTURE; typedef struct _FILES_LIST { PPAGED_LOOKASIDE_LIST pPagedLookasideList; LIST_ENTRY ListHead; ULONG Count; } FILES_LIST, *PFILES_LIST; // Создание нового списка файлов PFILES_LIST NewFilesList(void); void FreeFilesList(PFILES_LIST FilesList); void AddFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength); BOOLEAN DelFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength); void DelEntry(IN PFILES_LIST FilesList); BOOLEAN IsAddedFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength); и fileslist.cpp Код (Text): #include "StdAfx.h" // Создание нового списка файлов PFILES_LIST NewFilesList(void) { PFILES_LIST FilesList = (PFILES_LIST)ExAllocatePool(NonPagedPool, sizeof(FILES_LIST)); FilesList->Count = 0; FilesList->pPagedLookasideList = (PPAGED_LOOKASIDE_LIST)ExAllocatePool(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST)); ExInitializePagedLookasideList(FilesList->pPagedLookasideList, NULL, NULL, 0, sizeof(FNAME_STRUCTURE), 0, 0); InitializeListHead(&FilesList->ListHead); return FilesList; } void FreeFilesList(PFILES_LIST FilesList){ // Удаляем все элементы списка while (TRUE){ DelEntry(FilesList); if (IsListEmpty(&FilesList->ListHead)) break; } // Удаляем сам ассоциативный список ExDeletePagedLookasideList(FilesList->pPagedLookasideList); //освобождаем неподкачиваемую память, занятую под структуру PAGED_LOOKASIDE_LIST. ExFreePool(FilesList->pPagedLookasideList); //освобождаем сам список NEWFILES_LIST ExFreePool(FilesList); return; } //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // AddFilesList //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: void AddFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength) { //получаем указатель на новый блок памяти и сохраняем его в added PFNAME_STRUCTURE NewItem = (PFNAME_STRUCTURE)ExAllocateFromPagedLookasideList(FilesList->pPagedLookasideList); if (NewItem != NULL){ RtlZeroMemory(NewItem, sizeof(FNAME_STRUCTURE)); // Добавить в голову списка InsertHeadList(&FilesList->ListHead, &NewItem->ListEntry); if (NameLength > sizeof(NewItem->FileName)) NameLength = sizeof(NewItem->FileName); RtlCopyMemory(&NewItem->FileName, FileName, NameLength * sizeof(WCHAR)); FilesList->Count++; NewItem->Length = NameLength; DPRINT("FILES_LIST: + File %ws added. Length: %d", NewItem->FileName, NewItem->Length); }else{ DPRINT("FILES_LIST: Very bad. Couldn't allocate from lookaside list"); } return; } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // DelEntry //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: void DelEntry(IN PFILES_LIST FilesList) // Удалить с конца один элемент { if (!IsListEmpty(&FilesList->ListHead)){ PLIST_ENTRY tmplistentry = RemoveHeadList(&FilesList->ListHead); PFNAME_STRUCTURE fname_struc = CONTAINING_RECORD(tmplistentry, FNAME_STRUCTURE, ListEntry); DPRINT("FILES_LIST: - File %ws deleted", fname_struc->FileName); ExFreeToPagedLookasideList(FilesList->pPagedLookasideList, fname_struc); }else{ DPRINT("FILES_LIST: An attempt was made to remove entry from empty lookaside list"); } return; } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // DelFilesList //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: BOOLEAN DelFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength) // Удалить с конца один элемент { if (!IsListEmpty(&FilesList->ListHead)){ PFNAME_STRUCTURE fname_struc = (PFNAME_STRUCTURE)(FilesList->ListHead.Flink); while(TRUE){ if (&fname_struc->ListEntry == &FilesList->ListHead) break; if (fname_struc->Length == NameLength) // Если совпадает длина символа if (_wcsnicmp(fname_struc->FileName, FileName, NameLength) == 0) // Если совпадает имя файла { DPRINT("DelFilesList: - File %ws deleted", fname_struc->FileName); RemoveEntryList(&fname_struc->ListEntry); ExFreeToPagedLookasideList(FilesList->pPagedLookasideList, fname_struc); return TRUE; } fname_struc = (PFNAME_STRUCTURE)fname_struc->ListEntry.Flink; // Переходим к следуюзему списку } }else{ DPRINT("FILES_LIST: An attempt was made to remove entry from empty lookaside list"); } return FALSE; } //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // IsAddedFilesList //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: BOOLEAN IsAddedFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength) { // Если список пустой - то отменяем нафиг if (IsListEmpty(&FilesList->ListHead)) return FALSE; // Указатель на первый элемент PFNAME_STRUCTURE fname_struc = (PFNAME_STRUCTURE)(FilesList->ListHead.Flink); while(TRUE){ if (&fname_struc->ListEntry == &FilesList->ListHead) break; if (fname_struc->Length == NameLength) // Если совпадает длина символа if (_wcsnicmp(fname_struc->FileName, FileName, NameLength) == 0) // Если совпадает имя файла return TRUE; fname_struc = (PFNAME_STRUCTURE)fname_struc->ListEntry.Flink; // Переходим к следуюзему списку } return FALSE; } Работает все отлично, но как я понял, для надежности надо делать блокировки. Например чтобы во время выполнения функции IsAddedFilesList удалялся элемент ничего не зависло. Подскажите пожалуйста, все ли я правильно сделал и где нужно добавить чтобы драйвер не падал в синий экран. Использую этот код для хранения списка скрываемых файлов путем перехвата NTQueryDerectoryFile
Я не смотрел правильная ли у тебя работа со списками, но советую сипользовать ERESOURCE, если речь идет о ядре, а не найтив приложении. ExInitializeResourceLite, ExDeleteResourceLite ExAcquireResourceExclusiveLite захват на запись ExAcquireResourceSharedLite на чтение ExReleaseResourceLite освобождение короче эти функции реализовывают RWlock, что это такое - поищи в гугле.
Вот начал смореть сорцы и первое, за что зацепился взгляд. Объясните, как при таких разношерстных структурах Код (Text): typedef struct _FNAME_STRUCTURE { LIST_ENTRY ListEntry; WCHAR FileName[MAX_PATH]; ULONG Length; } FNAME_STRUCTURE, *PFNAME_STRUCTURE; typedef struct _FILES_LIST { PPAGED_LOOKASIDE_LIST pPagedLookasideList; LIST_ENTRY ListHead; ULONG Count; } FILES_LIST, *PFILES_LIST; возможно вообще срабатывание break'a вот здесь Код (Text): //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // DelFilesList //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: BOOLEAN DelFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength) // Удалить с конца один элемент { if (!IsListEmpty(&FilesList->ListHead)){ PFNAME_STRUCTURE fname_struc = (PFNAME_STRUCTURE)(FilesList->ListHead.Flink); while(TRUE){ if (&fname_struc->ListEntry == &FilesList->ListHead) break; // здесь больше код не стал глядеть, ибо по-сути все ясно.
mathio Все работает. Делал по статье four-f, я так понял FilesList->ListHead - голова списка структур FNAME_STRUCTURE FilesList->ListHead.flink - это первая запись в списке FilesList->ListHead.blink - это последняя запись в списке &fname_struc->ListEntry == &FilesList->ListHead Здесь я проверяю, прошел ли круг, т.е. текущая структура fname_struc->ListEntry находится ли она между первым и последним элементом, т.е. равна ли она ListHead. Это я просто два указателя сравниваю.
Вы меня не поняли. Я имею ввиду то, что если fname_struc - есть указатель на валидную структуру типа FNAME_STRUCTURE, а FilesList - есть указатель на валидную структуру типа FILES_LIST, то адреса их элементов с типом LIST_ENTRY никак не могут быть равны друг другу, хотя бы потому, что в структуре FNAME_STRUCTURE элемент типа LIST_ENTRY находится по нулевому смещению, а в структуре типа FILES_LIST элемент, имеющий тип LIST_ENTRY, находится по смещению отличному от нуля. Прояснилось?
FILES_LIST - это просто что-то вроде объекта. Где поля: PPAGED_LOOKASIDE_LIST pPagedLookasideList - так и не понял зачем, вроде для выделения памяти под элементы списка LIST_ENTRY ListHead - указатель на первый и последний элемент списка файлов ULONG Count - количество элементов в списке FNAME_STRUCTURE - это уже сам элемент списка файлов. Содержит имя файла, количество символов (для более быстрого поиска) и указатель на предыдущий/следующую структуру. В общем запутался я сам уже, код ведь полностью работает.
ya Большое спасибо. Я сделал так: если функция которая только читает данные из списка, например IsAddedFilesList Тогда вначале вызвать ExAcquireResourceSharedLite(&FilesList->Resource, TRUE); А перед завершением ExReleaseResourceLite(&FilesList->Resource); Ну а если же функция которая изменяет данные, то в начале соответственно вызываю ExAcquireResourceExclusiveLite(&FilesList->Resource, TRUE); А в конце освобождаю этот ресурс. Я все правильно понял? Т.е. в этом случае читать данные смогут сколько угодно потоков паралельно, но как только начнется запись в них - никто читать не сможет. Да, запись также не начнется - пока все потоки не завершат чтение.
Код (Text): typedef struct _FNAME_STRUCTURE { LIST_ENTRY ListEntry; WCHAR FileName[MAX_PATH]; ULONG Length; } FNAME_STRUCTURE, *PFNAME_STRUCTURE; typedef struct _FILES_LIST { PPAGED_LOOKASIDE_LIST pPagedLookasideList; LIST_ENTRY ListHead; ULONG Count; } FILES_LIST, *PFILES_LIST; Код не смотрел - только структуры - бросилось в глаза следующее: 1. Длина имени файла в 99,99% случаев значительно меньше MAX_PATH, т.е. бОшьшая часть памяти будет расходоваться впустую. 2. Использовать LookasideList имеет смысл только там где скорость очень критична. В данном случае это, видимо, не так. Но проблема даже не в этом, а в том, что поиск, в данном случае, можно вести только путем тупого обхода списка и сравнения строк, что невероятно медленно. Так что используй или не используй LookasideList - ничего не измениться. Всё равно будет тормозно и чем длиннее список, тем больше тормоза. 3. Я бы не плодил новые структуры, а использовал готовые, например, FILE_NAME_INFORMATION. Вобщем, советую глянуть IFSKit\src\filesys\filter\filespy\filter\fspyHash.c начиная с комментария "FileName cache routines", где имена файлов хешируются, что значительно эффективнее как по скорости работы, так и по расходу памяти.
Таки прав Дмитрий, лучше искать сравнивая хеши, чем строки + списки хорошо, можно использовать бинарные деревья скажем, функции для работы с ними реализованы даже в Rtlxxx, но не могу уточнить в какой версии винды они уже есть. Для полной совместимости лучше реализовать свои функции, если деревья сложно - можно использовать хеш таблицы с заголовком списка в узлах каждой, или еще какие-то другие виды асд