Всем доброго времени суток, пишу драйвер фильтра файловых систем, возникла необходимость отлавливать переименование файлов, ловлю всё как написано в DDK: IRP_MJ_SET_INFORMATION и получаю структуру FILE_RENAME_INFORMATION, а в ней FileName всегда имеет вид: \??\C:\... Ну, или любая другая буква вместо C. Вопрос, что такое "\??\" ? Это тоже самое что и "\DosDevices" ? И ещё, почему-то из всех типов переименований в винде (их всего 3) у меня всегда вылазит Fully Qualified Rename даже тогда когда я делаю Simple Rename, вопрос, как заставить винду переименовывать по типу Simple Rename или Relative Rename ? Хочется протестировать весь код даже и тот который выполняется крайне редко...
Clerk, а как превратить этот путь опять в DosName ? Функции RtlNtPathNameToDosPathName_U() нету. Руками ? Если да, то какие ещё префиксы возможны кроме \??\ и \DosDevices\ ?
Да. В Windows XP есть каталог Global?? с глобальными объектами. для совместимости оставлена ссылка \?? (он так раньше назывался) и \DosDevices.
Great, а, так это "\Global??", теперь ясно. Тогда такой вопрос, выходит что в качестве префикса имени может выступать вообще любой каталог ? Как же мне тогда действовать, у меня такая задача получить нормальное человеческое имя файла из поля FileName структуры FILE_RENAME_INFORMATION, что мне делать ? Пока я понимаю так: 1. Проверить начало строки на соотвествие с "\??\", "\Global??\" и "\DosDevice\", если одна из этих строк есть, то далее следует полное имя файла 2. Если нет, то проверяем начало строки на соотвествие шаблону "[Drive Letter]:", если соответсвует, то это полный путь 3. В противном случае в FileName какая-то ерунда (Рассматривается пока-что только Fully Qualified Rename) и что делать не понятно
что значит "человеческое имя"? С точки зрения ядра, путь \??\C:\boot.ini, к примеру, вполне нормальный. Нет, может быть много символьных ссылок. Слышал про subst и DefineDosDevice? Так вот, путь к файлу может выглядеть в виде \??\mysuperdrive\directory\file.txt, при учете, что создана ссылка mysuperdrive на C: Единственный уникальный путь, который файл может иметь в OS Windows NT-based, это \Device\HarddiskVolume2\windows\explorer.exe - то есть путь к устройству диска относительно корня каталога объектов (\Device\HarddiskVolume2 это DEVICE_OBJECT партиции на диске), а дальше - относительный путь (относительно корня диска). Поэтому все ссылки нужно приводить к этому пути, могу даже дать функцию, которая это делает. Сам писал, аж полчаса убил)) Она разрешает все символьные ссылки в пути к файлу: Код (Text): BOOLEAN QuerySymbolicLink( IN PUNICODE_STRING LinkName, OUT PUNICODE_STRING Destination, OUT PULONG Returned ) { HANDLE hLink; NTSTATUS Status; OBJECT_ATTRIBUTES Oa; ULONG RetLength; InitializeObjectAttributes( &Oa, LinkName, OBJ_KERNEL_HANDLE, 0, 0 ); Status = ZwOpenSymbolicLinkObject( &hLink, GENERIC_READ, &Oa ); if( !NT_SUCCESS(Status) ) { return FALSE; } Status = ZwQuerySymbolicLinkObject( hLink, Destination, &RetLength ); if( !NT_SUCCESS(Status) ) { ZwClose( hLink ); return FALSE; } if( Returned ) *Returned = RetLength; ZwClose( hLink ); return TRUE; } VOID ResolveSymLinks( IN PUNICODE_STRING InputPath, OUT PUNICODE_STRING pOutputPath ) { UNICODE_STRING OutputPath = {0}; UNICODE_STRING Queried = {0}; UNICODE_STRING temp = {0}; for( PWSTR ip = InputPath->Buffer; ip < (InputPath->Buffer + InputPath->Length/2); ip++ ) { if( *ip == L'\\' ) { // // Separator. Query symlink for the left part. // ULONG Pos = ((ULONG_PTR)ip-(ULONG_PTR)InputPath->Buffer); temp = *InputPath; temp.Length = (USHORT) Pos; if( !Queried.Buffer ) { Queried.MaximumLength = 512; Queried.Buffer = (PWSTR) ExAllocatePool(PagedPool, Queried.MaximumLength); } if( QuerySymbolicLink( &temp, &Queried, NULL ) ) { // // Symlink okay. Replace. // PWSTR Temp = OutputPath.Buffer; OutputPath.MaximumLength = (USHORT)(Queried.Length+(InputPath->Length-Pos)+2); OutputPath.Buffer = (PWSTR) ExAllocatePool(PagedPool, OutputPath.MaximumLength); OutputPath.Length = 0; RtlAppendUnicodeStringToString( &OutputPath, &Queried ); RtlAppendUnicodeToString( &OutputPath, ip ); if( Temp ) ExFreePool( Temp ); InputPath = &OutputPath; ip = InputPath->Buffer; continue; } } } *pOutputPath = *InputPath; if( Queried.Buffer ) ExFreePool( Queried.Buffer ); } ResolveSymLinks возвращает UNICODE_STRING с резолвнутыми символьными ссылками (место выделено в пуле), либо исходную строку (НЕ копию), поэтому перед ExFreePool нужно проверить, что Resolved.Buffer!=Input.Buffer Пример разрешения \SystemRoot ниже. Дело в том, SystemRoot -ссылка, которая указывает на другую ссылку, которая уже ссылается на реальный диск. (\SystemRoot => \Device\Harddisk0\Partition2 => \Device\HarddiskVolume2) Код (Text): UNICODE_STRING SystemRootPath, SystemRoot; RtlInitUnicodeString( &SystemRootPath, L"\\SystemRoot\\" ); ResolveSymLinks( &SystemRootPath, &SystemRoot ); KdPrint(("SystemRoot is: %S\n", SystemRoot.Buffer)); if( SystemRoot.Buffer != SystemRootPath.Buffer ) ExFreePool( SystemRoot.Buffer ); Если указывается только каталог, то заключительный слеш обязятелен, иначе если имя файла - нет. Именно это тебе и нужно - имена обоих файлов (входного и шаблонного) нужно преобразовать к "нормальному" пути без символьных ссылок и тогда уже сравнивать.
Great, спасибо, всё понятно. А ещё ведь может быть длинное имя типа: \\?\.... т.е надо ещё и проверять на наличие строки "\\?\", правда я не знаю передаются ли такие строки в ядро или винда сама "\\?\" убирает, я вот тестил, а "\\?\" не встречал ни разу, он вообще может появиться ?
\\?\ такого быть не может. скорее всего, ты имеешь в виду передаваемое \\.\ в CreateFileA/W, а это означает пространство имен локального компьютера, то есть другими словами преобразовывается сразу в \??\ Так что в ядре пути, которые ты будешь встречать, отсчитываются от корня каталога объектов. важно понимать, что каталог объектов содержит только объекты устройств, драйверов и т.п., в нем нет файлов. То есть когда передается имя файла \Device\HarddiskVolume2\Windows\explorer.exe, то NtCreateFile начинает парсить имя. Она доходит до HarddiskVolume2, видит, что это объект "устройство" и вызывает драйвер для этого устройства (драйвер файловой системы, точнее), передавая ему дальнейший "хвост" пути (\Windows\explorer.exe). Драйвер файловой системы по запросу IRP_MJ_CREATE уже производит поиск файла, а так же решает, что же с ним делать - удовлетворять запрос не открытие, или же завершать в ошибкой, если у пользователя не хватает привилегий.
в предыдущем посте я, в принципе, немного слукавил насчет преобразования \\.\ => \?? есть локальные каталоги для публичных объектов, которые лежат в \Sessions\x\DosDevices\y, и обычно используются они. Там, например, хранятся сетевые диски (например Z: => \Device\LanmanRedirector\;Z;000.....\192.168.0.1\MyDrive), "просабстенные" командой subst и другие локальный для текущего пользователя диски (например, диск, создаваемый TrueCrypt: W: => \Device\TrueCryptVolumeW)
Great, под "\\?\" я имел ввиду длинные имена, т.е имена > MAX_PATH символов, если я хочу создать файл с длинным именем я не могу просто сделать CreateFile("C:\....",...), я должен делать CreateFile("\\?\C:\...",...). Я понял почему "\\?\" быть не может, потому все имена файлов преобразуются в имена объектов. Спасибо, всё понятно. Тема в общем-то закрыта, хотя Остаётся для меня загадкой до сих пор...
Аа, понял. Ну это тот же глобальный каталог объектов по сути. Либо из сессионс либо из \?? Напомни, что такое simple rename/fully qualified rename/relative rename.. чтото не помню. тогда мб отвечу
Simpe rename - файл просто переименовывается не меняя местоположения на диске, допустим я переименоваываю C:\Windows\test.txt в C:\Windows\test2.txt Relative rename - файл переносится, но имя его не меняется, допустим C:\Windows\test.txt в C:\test.txt Fully Qualified Rename - переименование и перенос. Пример - C:\Windows\test.txt в C:\test2.txt Соответсвенно ОСь по разному обрабатывает эти ситуации, из DDK: Так вот, анализируя RootDirectory и FileName у меня всегда получается Fully Qualified Rename, даже когда я переименовываю C:\Windows\test.txt в C:\Windows\test2.txt Вот я и хочу понять, DDK врёт или я что-то не так делаю...
Sheph Нет не врет, просто симпле редко встречается, оболочки типа фара-експлорера работают с полными именами
z0mailbox, я и в винде переименовывал (в эксплорере) и прогу писал, которая MoveFile вызывает по разному, всё равно одно и тоже. Clerk, да
Sheph Я столкнулся с симпле при ренеймах файлов в шареном каталоге с ремоутной машины То есть внутри SRV.SYS Больше нигде вжывую не видел
Вроде нет обратной функции. Надо перебирать локальные диски, вызывать QueryDosDevice, сравнивать со строкой. В Notify функциях встречал вообще без префиксов - \WINDOWS\...., \Program Files\.....