Файловые потоки NTFS - как много в этом слове :-)
Работа с потоками из консоли
Создание файла с потоком:
type nul > somefile.txt:Stream
Запись в поток:
echo "Something" >> somefile.txt:Stream
Чтение из потока:
more < somefile:Stream Копирование содержимого существующего файла в поток: type file1.txt >> somefile.txt:Stream
Копирование содержимого потока в файл:
more < somefile.txt:Stream >> file2.txt
Удаление потоков
Существует мнение о том, что поток можно удалить только вместе с файлом, к которому он прикреплен. Это не так. Если ты знаешь название потока, то ты всегда сможешь удалить его стандартной функцией DeleteFile.
Листинг 1. Пример создания потока.
#includeЛистинг 2. X-Stream: Программа, показывающая список потоковint main() { DWORD dwRet; HANDLE hStream = CreateFile( "testfile:stream", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, NULL, NULL ); WriteFile( hFile, "This is a stream", 17, &dwRet, NULL ); CloseHandle(hStream); return 0; }
#includeвзято отсюда http://hex.pp.ua/using-alternate-data-streams.php и отсюда http://electro-2006.narod.ru/text/stati/NTFS.html#include #include #include int _tmain( int argc, _TCHAR *argv[] ) { WIN32_STREAM_ID sid; ZeroMemory(&sid, sizeof(WIN32_STREAM_ID)); DWORD dw1,dw2,dwRead; INT numofstreams = 0; //Буфер для имени потока в формате Unicode WCHAR wszStreamName[MAX_PATH]; LPVOID lpContext = NULL; /* * Открываем файл для чтения с параметром * FILE_FLAG_BACKUP_SEMANTICS, что позволяет нам * открывать не только файлы, но и каталоги с дисками. */ HANDLE hFile = CreateFile(argv[1],GENERIC_READ,FILE_SHARE_READ, NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL); if (hFile == INVALID_HANDLE_VALUE) {printf("\nError: Could't open file, directory or disk %s\n",argv[1]); exit(0); } DWORD dwStreamHeaderSize = (LPBYTE)&sid.cStreamName - (LPBYTE)&sid + sid.dwStreamNameSize; printf("\nStreams information for %s:\n",argv[1]); while ( BackupRead(hFile, (LPBYTE) &sid, dwStreamHeaderSize, &dwRead, FALSE, TRUE, &lpContext) ) { //Если тип потока неверный, значит прерываем цикл if (sid.dwStreamId == BACKUP_INVALID) break; ZeroMemory(&wszStreamName,sizeof(wszStreamName)); //Получаем имя потока if (!BackupRead(hFile, (LPBYTE) wszStreamName, sid.dwStreamNameSize, &dwRead, FALSE, TRUE, &lpContext)) break; if (sid.dwStreamId == BACKUP_DATA || sid.dwStreamId == BACKUP_ALTERNATE_DATA) { numofstreams++; printf("\n\nStream\t\t#%u",numofstreams); switch (sid.dwStreamId) { case BACKUP_DATA: printf("\nName:\t\t::$DATA"); break; case BACKUP_ALTERNATE_DATA: printf("\nName:\t\t%S",wszStreamName); break; } printf("\nSize:\t\t%u\n",sid.Size); } //Перемещаемся к следующему потоку BackupSeek(hFile, sid.Size.LowPart, sid.Size.HighPart, &dw1, &dw2, &lpContext); //Очищаем структуру перед следующим проходом цикла ZeroMemory(&sid,sizeof(sid)); } //Очищаем lpContext, содержащий служебную информацию //для работы функции BackupRead BackupRead(hFile, NULL, NULL, &dwRead, TRUE, FALSE, &lpContext); //Закрываем файл CloseHandle(hFile); return 0; }
Comments