Четверг, 28.03.2024, 15:01
Мой персональный сайт Добрым людям smart & sober

Главная Регистрация Вход
Приветствую Вас, Гость · RSS
Калькулятор


Меню сайта
Календарь
«  Февраль 2011  »
ПнВтСрЧтПтСбВс
 123456
78910111213
14151617181920
21222324252627
28


Форма входа


Архив записей
Мини-чат


Категории раздела


Наш опрос
В чем заключается ваш смысл жизни
Всего ответов: 154
 
Главная » 2011 » Февраль » 12 » Расширенные атрибуты FAT16 и NTFS
19:24
Расширенные атрибуты FAT16 и NTFS

Расширенные атрибуты файлов — дополнительный набор атрибутов, поддерживаемый Windows в файловых системах NTFS, FAT16 и HPFS. Расширенные атрибуты (extended attributes, EA) поддерживаются начиная с Windows NT и во всех последующих операционных системах на ядре NT. Поддержка расширенных атрибутов была добавлена в Windows для совместимости с операционной системой OS/2, в которой они широко использовались. В Windows эти атрибуты почти не используются программным обеспечением, но, тем не менее, их поддержка не была убрана и присутствует даже в Windows 7.

Каждый расширенный атрибут имеет строку названия, максимальный размер которой 255 символов, и байт флагов атрибута. Максимальный размер данных расширенного атрибута — 64 килобайта, причём это ограничение распространяется не на один отдельный атрибут, а на все атрибуты целиком.

В NTFS расширенные атрибуты прицеплены к файлу в виде потока ::$EA. Увидеть этот поток у файла можно с помошью программы NTFS Stream Explorer. Она предназначена для работы с альтернативными файловыми потоками, но может отображать и наличие потока EA. На иллюстрации видно, что у файла test.dat нулевой длины есть поток расширенных атрибутов размером 23 байта.

Расширенные атрибуты
Буфер расширенных атрибутов

Прочитать содержимое потока ::$EA напрямую нельзя. Это приведёт к выводу такого сообщения:

E:\CODE\ea\bin>more < test.dat::$EA
Отказано в доступе.

В FAT16 для расширенных атрибутов система создаёт в корне диска системный файл «EA DATA. SF», там и хранится их содержимое. А вот в FAT32 поддержка расширенных атрибутов отсутствует, при копировании файла на эту файловую систему EA теряются.

EA DATA. SF
Файл EA DATA. SF

При копировании файла с расширенными атрибутами на раздел FAT32 информация EA молча теряется. Windows не выводит никаких сообщений о потере информации. Это отличает дополнительные атрибуты от схожих по концепции альтернативных файловых потоков, поддержка которых есть в NTFS. Например в Windows 7 при попытке скопировать с NTFS на FAT32 файл, содержащий в себе альтернативные потоки NTFS, выводится сообщение «Действительно скопировать файл без его свойств?». Но если копировать туда же файл с EA, никаких сообщений не будет.

скопировать файл без его свойств
Сообщение при потери потока

Стандартных WinAPI функций специально для работы с расширенными атрибутами нет. Отсутствуют также стандартные утилиты Windows для работы с ними. Даже утилита fsutil, которая умеет делать много интересных операций над файлами, не поможет при работе с EA. Этим объясняется то, что данная технология почти никем не используется в Windows. Чтение расширенных атрибутов возможно через использование функции BackupRead (способ описан тут, но в примере описывается чтение потоков NTFS, а не EA), или через использование NT Native API (недокументированных функций библиотеки ntdll.dll).

Я написал консольное приложение EA.EXE, способное читать, писать, удалять расширенные атрибуты и выводить список EA. Программа использует функции из ntdll для работы с EA.

Имена расширенных атрибутов

Имя расширенного атрибута состоит из ASCII-символов. Латинские буквы приводятся к верхнему регистру, регистр символов не различается при обращении к атрибуту. Набор символов имени файла не должен содержать следующие запрещённые символы: значения ASCII 0x00 - 0x1F, символы \ / : * ? " < > | , + = [ ] ;. Максимальная длина имени 255 символов.

API расширенных атрибутов

В ntdll.dll содержатся две функции, с помощью которых реализуется доступ к расширенным атрибутам. Их прототипы:


NTSYSCALLAPI
NTSTATUS
NTAPI
NtSetEaFile(
IN HANDLE FileHandle,
IN PIO_STATUS_BLOCK IoStatusBlock,
PVOID EaBuffer,
ULONG EaBufferSize
);

NTSYSCALLAPI
NTSTATUS
NTAPI
NtQueryEaFile(
IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID Buffer,
IN ULONG Length,
IN BOOLEAN ReturnSingleEntry,
IN PVOID EaList OPTIONAL,
IN ULONG EaListLength,
IN PULONG EaIndex OPTIONAL,
IN BOOLEAN RestartScan
);

Функция NtSetEaFile служит для записи информации в расширенные атрибуты, а также для удаления атрибутов. Функция NtQueryEaFile предназначена для чтения данных EA или перечисления расширенных атрибутов у файла. Эти функции работают со структурой FILE_FULL_EA_INFORMATION, имеющей следующий формат:


typedef struct _FILE_FULL_EA_INFORMATION
{
ULONG NextEntryOffset;
UCHAR Flags;
UCHAR EaNameLength;
USHORT EaValueLength;
CHAR EaName[1];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;

Поле NextEntryOffset содержит смещение следующей структуры в буфере данных. Поле нужно при использовании NtQueryEaFile, когда она возвращает в буфере сразу несколько атрибутов. Поле Flags содержит флаги атрибутов. По-умолчанию поле флагов имеет значение 0, допустимо также значение FILE_NEED_EA, равное 0x80, которое означает, что имеющий этот флаг атрибут важен для обработки данных файла.

Поля EaNameLength и EaValueLength это размеры имени атрибута и данных атрибута. EaName это указатель на начало имени атрибута. Сразу после имени атрибута начинаются данные. Общий размер структуры FILE_FULL_EA_INFORMATION не может превышать 64 кб. При наличии в буфере нескольких структур их общий размер также не может превышать этот размер.

Запись расширенного атрибута

Определим в константе EA_BUF_LEN максимальный размер буфера EA, равный 0xFFFF. Тогда максимальный размер данных атрибута MAX_EA_DATA_LEN равен размеру буфера, от которого нужно отнять 8 (заголовок структуры) и ещё отнять 2 (минимально короткое имя атрибута, 1 буква + нулевой символ). Перед записью нужно убедиться, что записываемые данные не превышают этого значения.

Файл для записи EA данных нужно открыть с флагом FILE_FLAG_BACKUP_SEMANTICS. Далее следует сформировать структуру FILE_FULL_EA_INFORMATION, правильно указать в ней размеры имени и данных, выставить флаги и скопировать в структуру строку имени и данные атрибута по правильным смещениям.

Затем вызывается функция NtSetEaFile и анализируется её возвращаемое значение NTSTATUS. В результате ошибки попытки записи расширенных атрибутов функция может вернуть следующие коды ошибок:


// Неправильное имя расширенного атрибута
#define STATUS_INVALID_EA_NAME ((NTSTATUS)0x80000013L)
// Структура EA сформирована неправильно
#define STATUS_EA_LIST_INCONSISTENT ((NTSTATUS)0x80000014L)
// Структура EA превышает максимальный размер
#define STATUS_EA_TOO_LARGE ((NTSTATUS)0xC0000050L)
// Расширенные атрибуты не поддерживаются
#define STATUS_EAS_NOT_SUPPORTED ((NTSTATUS)0xC000004FL)
// Структура EA повреждена
#define STATUS_EA_CORRUPT_ERROR ((NTSTATUS)0xC0000053L)

Код ошибки STATUS_EAS_NOT_SUPPORTED может означать не только отсутствие поддержки расширенных атрибутов у файловой системы, но и невозможность использовать EA у конкретного файла. Если у файла есть reparse данные, то есть файл является точкой повторной обработки (например, симлинком), то у такого файла расширенные атрибуты не поддерживаются. В файловой системе NTFS файл не может одновременно являться и reparse point'ом, и содержать расширенные атрибуты EA, только что-то одно.


BOOL WriteEA(LPCSTR file_name, LPCSTR ascii_caps_name,
IN PVOID buf, UINT buf_len, UCHAR flags)
{
IO_STATUS_BLOCK iosb;
CHAR ea_buf[EA_BUF_LEN];
PFILE_FULL_EA_INFORMATION ffei
= (PFILE_FULL_EA_INFORMATION) ea_buf;
HANDLE FileHandle;
NTSTATUS ntst;

if (buf_len > MAX_EA_DATA_LEN)
{
return FALSE;
}

ZeroMemory(&ea_buf, EA_BUF_LEN);
FileHandle = CreateFile(file_name, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);

if (INVALID_HANDLE_VALUE == FileHandle)
{
return FALSE;
}

ffei->EaNameLength = strnlen(ascii_caps_name, MAX_EA_NAME_LEN);
ffei->EaValueLength = buf_len;
ffei->Flags = flags;

memcpy(ffei->EaName, ascii_caps_name, ffei->EaNameLength);
memcpy(ffei->EaName + ffei->EaNameLength + 1,
buf, ffei->EaValueLength);

ntst = NtSetEaFile(FileHandle, &iosb, ffei, EA_BUF_LEN);

return NT_SUCCESS(ntst);
}

Чтение расширенного атрибута

Для чтения расширенного атрибута следует получить EA-буфер полностью и найти в буфере ту структуру, которая содержит атрибут с искомым именем (EaName). Буфер читается с помощью функции NtQueryEaFile. Если параметр ReturnSingleEntry установлен в TRUE, функция с каждым вызовом возвращает только одну структуру, если FALSE - в буфер пишутся сразу все структуры, а переход между ними осуществляется через поле NextEntryOffset.

Данные читаются из буфера по смещению EaName + EaNameLength + 1. Параметр RestartScan перезапускает выдачу атрибутов сначала (если используется ReturnSingleEntry). Параметр EaList может содержать указатель на дополнительный список структур FILE_GET_EA_INFORMATION, содержащий список EA, которые нужно получить. Тем самым можно получить в буфере не все EA, а какой-то определённый набор. Параметр EaIndex позволяет обращаться к атрибуту по индексу.

В результате ошибки попытки чтения расширенных атрибутов, функция NtQueryEaFile может вернуть следующие коды ошибок:


// Доступ запрещён
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022)
// Файл не содержит расширенных атрибутов
#define STATUS_NO_EAS_ON_FILE ((NTSTATUS)0xC0000052)
// Буфер слишком мал
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023)
// Переполнение буфера
#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005)

Код функции для чтения расширенных атрибутов:


BOOL ReadEA(LPCSTR file_name, LPCSTR ascii_caps_name,
OUT PVOID buf, OUT PUINT buf_len)
{
IO_STATUS_BLOCK iosb;
CHAR ea_buf[EA_BUF_LEN];
PFILE_FULL_EA_INFORMATION ffei
= (PFILE_FULL_EA_INFORMATION) ea_buf;
HANDLE FileHandle;
NTSTATUS ntst;

ZeroMemory(&ea_buf, EA_BUF_LEN);
FileHandle = CreateFile(file_name,
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);

if (INVALID_HANDLE_VALUE == FileHandle)
{
return FALSE;
}

while (TRUE)
{
ntst = NtQueryEaFile(FileHandle, &iosb, ffei,
EA_BUF_LEN, TRUE, NULL, NULL, NULL, FALSE);
if (!NT_SUCCESS(ntst))
{
break;
}
if (0 == _strnicmp(ffei->EaName, ascii_caps_name,
MAX_EA_NAME_LEN))
{
memcpy(buf, ffei->EaName + ffei->EaNameLength + 1,
ffei->EaValueLength);
*buf_len = ffei->EaValueLength;
return TRUE;
}
}

return FALSE;
}

Удаление расширенного атрибута

Удаление расширенного атрибута из файла реализуется через вызов NtSetEaFile, со структурой, в которой поле EaValueLength равно NULL, а EaName содержит только имя удаляемого атрибута.


// Удалить атрибут attribute из файла filename
WriteEA("filename", "attribute", NULL, 0, 0);

Исходный код

Скачать консольную программу EA.EXE для работы с расширенными атрибутами. В архиве содержится программа и её исходный код на Си.

Просмотров: 1181 | Добавил: Breger | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Copyright MyCorp © 2024