Использование функций Native API для выполнения операций над файлами
Библиотека ntdll.dll содержит все необходимые функции для выполнения операций над файлами и каталогами. Во всех файловых функциях Native API требуется передавать полный путь. Существует функция, помогающая хранить значение текущего каталога, но сцеплять это значение с именем файла нужно самостоятельно.
Функции для установки и получения текущего каталога определены так:
NTSYSAPI ULONG NTAPI RtlGetCurrentDirectory_U( ULONG MaximumLength, PWSTR Buffer ); NTSYSAPI NTSTATUS NTAPI RtlSetCurrentDirectory_U( IN PUNICODE_STRING name );
Для доступа к файлам и каталогам используется NT-формат пути. Это полный путь к файлу с буквой диска и префиксом \??\. Например, путь до файла C:\boot.ini будет выглядеть как \??\C:\boot.ini. Привычный формат пути без префикса называется в терминологии Native API «DOS-путь». Для конвертации пути из формата DOS в NT существует функция:
NTSYSAPI BOOLEAN NTAPI RtlDosPathNameToNtPathName_U( IN PCWSTR DosPathName, OUT PUNICODE_STRING NtPathName, OUT PCWSTR *NtFileNamePart, OUT CURDIR *DirectoryInfo );
Целесообразно сохранять путь в DOS-формате. Его можно показывать без изменений пользователю, если он хочет увидеть текущий каталог. При каждой файловой операции придётся формировать полный NT-путь к файлу вызовом соответствующей функции, или прямой склейкой пути с префиксом.
Одна из операций, которая может понадобиться это вывод списка содержимого каталога. Чтобы его вывести, программа должна получить список файлов и каталогов текущей директории. Прежде всего, надо открыть каталог функцией NtCreateFile с опцией FILE_LIST_DIRECTORY и указанием флага FILE_DIRECTORY_FILE. Полученный хэндл скармливается функции NtQueryDirectoryFile, которой передается константа FileBothDirectoryInformation и указатель на буфер данных типа FILE_BOTH_DIR_INFORMATION. Структура этого типа позволяет узнать о файлах и каталогах все их важные параметры: имя, атрибуты, размер и время создания.
typedef struct _FILE_BOTH_DIR_INFORMATION { ULONG NextEntryOffset; ULONG FileIndex; LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; LARGE_INTEGER LastWriteTime; LARGE_INTEGER ChangeTime; LARGE_INTEGER EndOfFile; LARGE_INTEGER AllocationSize; ULONG FileAttributes; ULONG FileNameLength; ULONG EaSize; CCHAR ShortNameLength; WCHAR ShortName[12]; WCHAR FileName[1]; } FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
При вызове функции NtQueryDirectoryFile можно использовать параметр ReturnSingleEntry = TRUE, тогда за один вызов функции в буфер будет помещена только одна структура FILE_BOTH_DIR_INFORMATION, а вызвать функцию в цикле придётся столько раз, сколько файлов в каталоге. При установке того же параметра в FALSE функция будет вызвана всего один раз, а в буфере окажется массив структур. Перемещаться по нему можно, сдвигая указатель на структуру по смещению, указанному в поле NextEntryOffset. У последнего элемента массива значение этого поля будет NULL.
Функции для стандартных файловых операций, таких как чтение из файла, запись в файл и удаление файла документированы в MSDN. Их названия NtReadFile, NtWriteFile, NtDeleteFile и их использование мало чем отличается от привычных функций WinAPI. Открывать файл можно функцией NtCreateFile. Чтобы скопировать файл, нужно просто прочитать его из одного места и записать копию в другом месте. А вот переименование файла – более комплексная операция, поэтому стоит рассмотреть её более подробно.
Переименование файла
Существует функция NtSetInformationFile, которая может производить множество различных операций над файлом. Прототип функции выглядит так:
NTSYSCALLAPI NTSTATUS NTAPI NtSetInformationFile( IN HANDLE FileHandle, IN PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass );
В параметре FileInformationClass передаётся константа FileRenameInformation, означающая операцию переименования. В сочетании с этой константой, функция получает в параметре FileInformation указатель на структуру FILE_RENAME_INFORMATION.
typedef struct _FILE_RENAME_INFORMATION { BOOLEAN ReplaceIfExists; HANDLE RootDirectory; ULONG FileNameLength; WCHAR FileName[1]; } FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
Структура FILE_RENAME_INFORMATION имеет переменную длину, зависящую от длины нового имени файла. Нужно выделить для структуры достаточное количество памяти. Предположим, у тебя есть буфер NewFileName с новым именем файла и его размер в переменной FileNameSize.
PFILE_RENAME_INFORMATION FileRenameInfo; FileRenameInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILE_RENAME_INFORMATION) + FileNameSize);
После выделения памяти следует скопировать буфер NewFileName в поле структуры FileName и проинициализировать другие её поля. Поле ReplaceIfExists определяет, заменять ли существующий файл, если его имя совпадает с новым именем файла при переименовании. В параметре RootDirectory может содержаться хэндл другой директории, в которой должен оказаться файл после перемещения. Проще оставить это поле равным NULL, ведь для перемещения файла в другой каталог достаточно указать в поле FileName полный путь к новому расположению файла в NT-формате. Если осуществляется переименование файла, а не перемещение, в FileName должно быть только имя файла. После инициализации структуры остается только вызвать функцию для осуществления операции:
Status = NtSetInformationFile( FileHandle, &IoStatusBlock;, FileRenameInfo, sizeof(FILE_RENAME_INFORMATION)+ FileNameSize, FileRenameInformation );
Размер буфера FileRenameInfo нельзя считать равным sizeof(FILE_RENAME_INFORMATION), ведь в определении структуры не учтена переменная длина поля FileName. Поэтому в четвёртом параметре Length следует передать длину структуры, к которой прибавлен размер строки FileName.
Автор: амдф
Дата: 15.04.2011
Избранное
Остальное
Лента atom