Something went wrong. Try again.
Reactos
Something went wrong. Try again.
8.5 kB · 303 lines
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304/* * PROJECT: ReactOS Automatic Testing Utility * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) * PURPOSE: Class implementing a journaled test list for the Crash Recovery feature * COPYRIGHT: Copyright 2009 Colin Finck (colin@reactos.org) */
#include "precomp.h"
static const char szJournalHeader[] = "RAT_J-V1";static const WCHAR szJournalFileName[] = L"rosautotest.journal";
/** * Constructs a CJournaledTestList object for an associated CTest-derived object. * * @param Test * Pointer to a CTest-derived object, for which this test list shall serve. */CJournaledTestList::CJournaledTestList(CTest* Test) : CTestList(Test){ WCHAR JournalFile[MAX_PATH];
m_hJournal = INVALID_HANDLE_VALUE;
/* Build the path to the journal file */ if(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, JournalFile) != S_OK) FATAL("SHGetFolderPathW failed\n");
m_JournalFile = JournalFile; m_JournalFile += L"\\rosautotest\\";
/* Create the directory if necessary */ if(GetFileAttributesW(m_JournalFile.c_str()) == INVALID_FILE_ATTRIBUTES) CreateDirectoryW(m_JournalFile.c_str(), NULL);
m_JournalFile += szJournalFileName;
/* Check if the journal already exists */ if(GetFileAttributesW(m_JournalFile.c_str()) == INVALID_FILE_ATTRIBUTES) WriteInitialJournalFile(); else LoadJournalFile();}
/** * Destructs a CJournaledTestList object. */CJournaledTestList::~CJournaledTestList(){ if(m_hJournal != INVALID_HANDLE_VALUE) CloseHandle(m_hJournal);}
/** * Opens the journal file through the CreateFileW API using the m_hJournal handle. * * @param DesiredAccess * dwDesiredAccess parameter passed to CreateFileW * * @param CreateNew * true if the journal file shall be created, false if an existing one shall be opened */voidCJournaledTestList::OpenJournal(DWORD DesiredAccess, bool CreateNew){ m_hJournal = CreateFileW( m_JournalFile.c_str(), DesiredAccess, 0, NULL, (CreateNew ? CREATE_ALWAYS : OPEN_EXISTING), FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL );
if(m_hJournal == INVALID_HANDLE_VALUE) FATAL("CreateFileW failed\n");}
/** * Serializes a std::string and writes it into the opened journal file. * * @param String * The std::string to serialize * * @see UnserializeFromBuffer */voidCJournaledTestList::SerializeIntoJournal(const string& String){ DWORD BytesWritten; WriteFile(m_hJournal, String.c_str(), (ULONG)String.size() + 1, &BytesWritten, NULL); FlushFileBuffers(m_hJournal);}
/** * Serializes a std::wstring and writes it into the opened journal file. * * @param String * The std::wstring to serialize * * @see UnserializeFromBuffer */voidCJournaledTestList::SerializeIntoJournal(const wstring& String){ DWORD BytesWritten; WriteFile(m_hJournal, String.c_str(), ((ULONG)String.size() + 1) * sizeof(WCHAR), &BytesWritten, NULL); FlushFileBuffers(m_hJournal);}
/** * Unserializes the next std::string from the journal buffer. * The passed buffer pointer will point at the next element afterwards. * * @param Buffer * Pointer to a pointer to a char array containing the journal buffer * * @param Output * The std::string to unserialize the value into. */voidCJournaledTestList::UnserializeFromBuffer(char** Buffer, string& Output){ Output = string(*Buffer); *Buffer += Output.size() + 1;}
/** * Unserializes the next std::wstring from the journal buffer. * The passed buffer pointer will point at the next element afterwards. * * @param Buffer * Pointer to a pointer to a char array containing the journal buffer * * @param Output * The std::wstring to unserialize the value into. */voidCJournaledTestList::UnserializeFromBuffer(char** Buffer, wstring& Output){ Output = wstring((PWSTR)*Buffer); *Buffer += (Output.size() + 1) * sizeof(WCHAR);}
/** * Gets all tests to be run and writes an initial journal file with this information. */voidCJournaledTestList::WriteInitialJournalFile(){ char TerminatingNull = 0; CTestInfo* TestInfo; DWORD BytesWritten;
StringOut("Writing initial journal file...\n\n");
m_ListIterator = 0;
/* Store all command lines in the m_List vector */ while((TestInfo = m_Test->GetNextTestInfo()) != 0) { m_List.push_back(*TestInfo); delete TestInfo; }
/* Serialize the vector and the iterator into a file */ OpenJournal(GENERIC_WRITE, true);
WriteFile(m_hJournal, szJournalHeader, sizeof(szJournalHeader), &BytesWritten, NULL); WriteFile(m_hJournal, &m_ListIterator, sizeof(m_ListIterator), &BytesWritten, NULL);
for(size_t i = 0; i < m_List.size(); i++) { SerializeIntoJournal(m_List[i].CommandLine); SerializeIntoJournal(m_List[i].Module); SerializeIntoJournal(m_List[i].Test); }
WriteFile(m_hJournal, &TerminatingNull, sizeof(TerminatingNull), &BytesWritten, NULL); FlushFileBuffers(m_hJournal);
CloseHandle(m_hJournal); m_hJournal = INVALID_HANDLE_VALUE;
/* m_ListIterator will be incremented before its first use */ m_ListIterator = (size_t)-1;}
/** * Loads the existing journal file and sets all members to the values saved in that file. */voidCJournaledTestList::LoadJournalFile(){ char* Buffer; char* pBuffer; char FileHeader[sizeof(szJournalHeader)]; DWORD BytesRead; DWORD RemainingSize;
StringOut("Loading journal file...\n\n");
OpenJournal(GENERIC_READ); RemainingSize = GetFileSize(m_hJournal, NULL);
/* Verify the header of the journal file */ ReadFile(m_hJournal, FileHeader, sizeof(szJournalHeader), &BytesRead, NULL); RemainingSize -= BytesRead;
if(BytesRead != sizeof(szJournalHeader)) EXCEPTION("Journal file contains no header!\n");
if(strcmp(FileHeader, szJournalHeader)) EXCEPTION("Journal file has an unsupported header!\n");
/* Read the iterator */ ReadFile(m_hJournal, &m_ListIterator, sizeof(m_ListIterator), &BytesRead, NULL); RemainingSize -= BytesRead;
if(BytesRead != sizeof(m_ListIterator)) EXCEPTION("Journal file contains no m_ListIterator member!\n");
/* Read the rest of the file into a buffer */ Buffer = new char[RemainingSize]; pBuffer = Buffer; ReadFile(m_hJournal, Buffer, RemainingSize, &BytesRead, NULL);
CloseHandle(m_hJournal); m_hJournal = NULL;
/* Now recreate the m_List vector out of that information */ while(*pBuffer) { CTestInfo TestInfo;
UnserializeFromBuffer(&pBuffer, TestInfo.CommandLine); UnserializeFromBuffer(&pBuffer, TestInfo.Module); UnserializeFromBuffer(&pBuffer, TestInfo.Test);
m_List.push_back(TestInfo); }
delete[] Buffer;}
/** * Writes the current m_ListIterator value into the journal. */voidCJournaledTestList::UpdateJournal(){ DWORD BytesWritten;
OpenJournal(GENERIC_WRITE);
/* Skip the header */ SetFilePointer(m_hJournal, sizeof(szJournalHeader), NULL, FILE_CURRENT);
WriteFile(m_hJournal, &m_ListIterator, sizeof(m_ListIterator), &BytesWritten, NULL); FlushFileBuffers(m_hJournal);
CloseHandle(m_hJournal); m_hJournal = NULL;}
/** * Interface to other classes for receiving information about the next test to be run. * * @return * A pointer to a CTestInfo object, which contains all available information about the next test. * The caller needs to free that object. */CTestInfo*CJournaledTestList::GetNextTestInfo(){ CTestInfo* TestInfo;
/* Always jump to the next test here. - If we're at the beginning of a new test list, the iterator will be set to 0. - If we started with a loaded one, we assume that the test m_ListIterator is currently set to crashed, so we move to the next test. */ ++m_ListIterator;
/* Check whether the iterator would already exceed the number of stored elements */ if(m_ListIterator == m_List.size()) { /* Delete the journal and return no pointer */ DeleteFileW(m_JournalFile.c_str());
TestInfo = NULL; } else { /* Update the journal with the current iterator and return the test information */ UpdateJournal();
TestInfo = new CTestInfo(m_List[m_ListIterator]); }
return TestInfo;}