Думаю, что многим приходилось писать программы, в которых использовались Zw-(Nt-) функции работы с файлами. Одним из больших неудобств, при разработке подобного софта, является обработка путей файлов и директорий, вводимых пользователем. Не всегда удобно заставлять пользователя вводить имена \??\D:\dir00\file.ext. Для решения подобного рода проблем в ntdll.dll экспортируется функция RtlDosPathNameToNtPathName_U:
NTSYSAPI BOOLEAN NTAPI RtlDosPathNameToNtPathName_U( __in PCWSTR DosFileName, __out PUNICODE_STRING NtFileName, __out_opt PWSTR *FilePart, __out_opt PVOID RelativeName );
Как можно догадаться из названия, функция служит для того, что бы преобразовывать DOS-имена файлов в nativ'ный формат. Рассмотрим отдельно параметры функции:
DosFileName: входной параметр. Константная строка, содержащая DOS-имя целевого файла или директории.
NtFileName: выходной параметр. В указанную строку функция будет выделять и заполнять NT-путь до файла или директории.
FilePart: выходной опциональный параметр. На выходе, в указатель будет занесен адрес имени файла в сформированном пути. Если этот параметр на выходе заполняется NULL, то указано только имя директории.
RelativeName: выходной опциональный параметр. На самом деле это указатель на RTL-структуру, содержащую информацию о текущей директории, но формат ее толком не известен, и самое главное, возможно, меняется от версии к версии операционной системы. Можно принять этот параметр за PVOID Reserved, который всегда должен быть NULL :)
Возвращаемое значение:
TRUE - операция преобразования пути успешно завершена. После использования, необходимо освободить буфер строки NtFileName вызовом HeapFree(GetProcessHeap(), 0, NtFileName->Buffer)
FALSE - операция преобразования пути завершилась с ошибкой.
Для тестирования этой функции я написал небольшую утилиту dos2nt. Эта консольная утилита просто вызывает функцию ntdll!RtlDosPathNameToNtPathName_U(...) со строкой, переданной ей в качестве аргумента. После успешного вызова, утилита печатает в консоль выходные параметры функции. На основе результатов тестирования утилиты можно сделать довольно интересные особенности работы функции. Примеры указаны для ситуации, в которой текущей директорией утилиты является D:\Test\dir00\. Пример печати утилиты:
Если указанный путь заканчивается символом обратного слеша, то указанное имя трактуется как директория. На это указывает NULL в возвращаемом параметре имени файла FilePart. Это удобно, если учесть, что при вызове ZwCreateFile необходимо указывать во флагах признак директории\файла: FILE_DIRECTORY_FILE и FILE_NON_DIRECTORY_FILE. Пример печати утилиты:
Если указанный путь начинается с символа обратного слеша, то путь преобразуется, как указанный от корневой директории текущего диска. Пример печати утилиты:
Еще одна из немаловажных "вкусностей" работы функции - преобразование прямых слешей в обратные. То есть не важно, какими млешами пользователь разделял путь при вводе, функция добросовестно приведет путь к человеческому (Windows - Style) виду. Пример печати утилиты:
Еще одна из особенностей работы функции, это преобразование префикса "\\.\" в "\??\". Например, введем имя pipe'а и на выходе получим:
Ну и последнее, на что хотелось бы обратить внимание, это то, что функция никак не реагирует на специальные символы: '?' '*' '<' '>'. Естественно, что файловая система, при обработке пути, вернет ошибку, так что нужно быть готовым к статусу STATUS_OBJECT_NAME_INVALID. Пример печати утилиты:
Функция присутствует на всей линейке ОС: 2000 - Seven(7). Резюмируя вышеописанное, хочется сказать, что использование этой функции может сильно упростить жизнь при работе с файловой подсистемой на nativ'ном уровне. Use and enjoy.
Тестовую утилиту с исходным кодом можно скачать здесь.
ΞρεΤΙκ