EreTIk's Box » Cтатьи, исходники » Преобразование DOS-пути в NT-формат: функция RtlDosPathNameToNtPathName_U


Думаю, что многим приходилось писать программы, в которых использовались 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\. Пример печати утилиты:


D:\Test\dir00>dos2nt dir.name\file.name DOS Name : dir.name\file.name NT Name : \??\D:\Test\dir00\dir.name\file.name File Part : file.name

Если указанный путь заканчивается символом обратного слеша, то указанное имя трактуется как директория. На это указывает NULL в возвращаемом параметре имени файла FilePart. Это удобно, если учесть, что при вызове ZwCreateFile необходимо указывать во флагах признак директории\файла: FILE_DIRECTORY_FILE и FILE_NON_DIRECTORY_FILE. Пример печати утилиты:


D:\Test\dir00>dos2nt dir.name\ DOS Name : dir.name\ NT Name : \??\D:\Test\dir00\dir.name\ File Part : (null)

Если указанный путь начинается с символа обратного слеша, то путь преобразуется, как указанный от корневой директории текущего диска. Пример печати утилиты:


D:\Test\dir00>dos2nt \dir.name\file.name DOS Name : \dir.name\file.name NT Name : \??\D:\dir.name\file.name File Part : file.name

Еще одна из немаловажных "вкусностей" работы функции - преобразование прямых слешей в обратные. То есть не важно, какими млешами пользователь разделял путь при вводе, функция добросовестно приведет путь к человеческому (Windows - Style) виду. Пример печати утилиты:


D:\Test\dir00>dos2nt dir.name/file.name DOS Name : dir.name/file.name NT Name : \??\D:\Test\dir00\dir.name\file.name File Part : file.name

Еще одна из особенностей работы функции, это преобразование префикса "\\.\" в "\??\". Например, введем имя pipe'а и на выходе получим:


D:\Test\dir00>dos2nt \\.\pipe\w2003 DOS Name : \\.\pipe\w2003 NT Name : \??\pipe\w2003 File Part : w2003

Ну и последнее, на что хотелось бы обратить внимание, это то, что функция никак не реагирует на специальные символы: '?' '*' '<' '>'. Естественно, что файловая система, при обработке пути, вернет ошибку, так что нужно быть готовым к статусу STATUS_OBJECT_NAME_INVALID. Пример печати утилиты:


D:\Test\dir00>dos2nt d*r.name\f?le.name DOS Name : d*r.name\f?le.name NT Name : \??\D:\Test\dir00\d*r.name\f?le.name File Part : f?le.name

Функция присутствует на всей линейке ОС: 2000 - Seven(7). Резюмируя вышеописанное, хочется сказать, что использование этой функции может сильно упростить жизнь при работе с файловой подсистемой на nativ'ном уровне. Use and enjoy.


Тестовую утилиту с исходным кодом можно скачать здесь.


ΞρεΤΙκ