Расширенные атрибуты NTFS и FAT16
Расширенные атрибуты файлов — дополнительный набор атрибутов, поддерживаемый 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В FAT16 для расширенных атрибутов система создаёт в корне диска системный файл «EA DATA. SF», там и хранится их содержимое. А вот в FAT32 поддержка расширенных атрибутов отсутствует, при копировании файла на эту файловую систему EA теряются.
При копировании файла с расширенными атрибутами на раздел 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 для работы с расширенными атрибутами. В архиве содержится программа и её исходный код на Си.
Кроме того, моя программа NTFS Stream Explorer, которая имеет графический интерфейс, теперь тоже поддерживает редактирование расширенных атрибутов файлов.
Автор: амдф
Дата: 10.02.2011
Избранное
Остальное
По вопросам сотрудничества и другим вопросам по работе сайта пишите на cleogroup[собака]yandex.ru