1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
#include <wchar.h>
#include "altdstrm.h"
bool EnumerateAltDataStreams(const wchar_t* fileName, LinkedList* result, AltDataStreamEnumError* error) { memset(error->message, 0, sizeof(error->message));
HANDLE hFile = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) { GetLastErrorMessage(GetLastError(), error->message, ARRAYSIZE(error->message)); return false; }
bool hasError = false; do { LPVOID backupContext = NULL;
BOOL shouldReadNextEntry = TRUE; bool endOfFileReached = false;
while (shouldReadNextEntry) { AltDataStreamMetadata metadata; bool gotMetadata = false;
shouldReadNextEntry = ReadSingleStreamMetadata(hFile, &metadata, &backupContext, &gotMetadata, &endOfFileReached);
if (shouldReadNextEntry && gotMetadata) { wcsncpy_s(metadata.fileName, MAX_PATH, fileName, MAX_PATH); llAppend(result, &metadata, sizeof(metadata)); } }
if (!endOfFileReached) { DWORD code = GetLastError();
if (code != ERROR_HANDLE_EOF) { GetLastErrorMessage(code, error->message, ARRAYSIZE(error->message)); hasError = true; } }
{ WIN32_STREAM_ID dummy; DWORD n; BackupRead(hFile, (LPBYTE)(&dummy), 0, &n, TRUE, FALSE, &backupContext); } } while (false);
CloseHandle(hFile); return !hasError; }
BOOL ReadSingleStreamMetadata(HANDLE hFile, AltDataStreamMetadata* metadata, LPVOID* context, bool* gotMetadata, bool* endOfFileReached) { *endOfFileReached = false; *gotMetadata = false;
const size_t WIN32_STREAM_ID_SIZE = 20; const size_t WRONG_WIN32_STREAM_ID_SIZE = sizeof(WIN32_STREAM_ID); const size_t WIN32_STREAM_ID_BUFFER_SIZE = WIN32_STREAM_ID_SIZE + sizeof(wchar_t) * (MAX_PATH + 36); LPBYTE dataBuffer = (LPBYTE)malloc(WIN32_STREAM_ID_BUFFER_SIZE); memset(dataBuffer, 0, WIN32_STREAM_ID_BUFFER_SIZE);
BOOL continueReadingNextEntry = FALSE;
do { DWORD numBytesRead = 0; BOOL readSomeData = BackupRead(hFile, dataBuffer, WIN32_STREAM_ID_SIZE, &numBytesRead, FALSE, FALSE, context);
if (!readSomeData) { break; }
if (numBytesRead == 0) { *endOfFileReached = true; break; }
LARGE_INTEGER toSeek = {0};
const WIN32_STREAM_ID* streamId = (const WIN32_STREAM_ID*)dataBuffer;
if (streamId->dwStreamId == BACKUP_DATA || streamId->dwStreamId == BACKUP_ALTERNATE_DATA) { readSomeData = BackupRead(hFile, dataBuffer + WIN32_STREAM_ID_SIZE, streamId->dwStreamNameSize, &numBytesRead, FALSE, FALSE, context);
if (!readSomeData) { break; }
wcsncpy_s(metadata->streamName, MAX_PATH + 36, (LPCWSTR)(dataBuffer + WIN32_STREAM_ID_SIZE), MAX_PATH + 36); metadata->size = streamId->Size.QuadPart;
*gotMetadata = true; }
toSeek.QuadPart += streamId->Size.QuadPart;
LARGE_INTEGER sought = {0};
if (toSeek.QuadPart > 0) { BackupSeek(hFile, toSeek.LowPart, toSeek.HighPart, &sought.LowPart, (DWORD*)&sought.HighPart, context); }
if (sought.QuadPart == toSeek.QuadPart) { continueReadingNextEntry = TRUE; } } while (false);
free(dataBuffer); return continueReadingNextEntry; }
|