//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 2000. // // File: Main.cpp // // Contents: Main wrapper file for SRDiag, this will call into cab.cpp, // chglog.cpp, getreg.cpp, rpenum.cpp for getting changlog, // restore points, registry information. This file also contains // routines for getting file information, restore Guid, and generic // logging imposed by cab.cpp // // Objects: // // Coupling: // // Notes: // // History: 9/21/00 SHeffner Created // 10/5/00 SHeffner Moved file specific gathering to the header file. // //---------------------------------------------------------------------------- //+--------------------------------------------------------------------------- // // Common Includes // //---------------------------------------------------------------------------- #include #include #include #include #include #include #include #include "srrpcapi.h" //+--------------------------------------------------------------------------- // // Function proto typing for rpenum.cpp, getreg.cpp, Chglog.cpp // //---------------------------------------------------------------------------- bool GetSRRegistry(char *szFilename, WCHAR *szPath, bool bRecurse); void GetChgLog(char *szLogfile); void RPEnumDrive(HFCI hc, char *szLogFile); //+--------------------------------------------------------------------------- // // Global Variables used within main, and through cab.cpp // //---------------------------------------------------------------------------- FILE *fLogStream = NULL; //For the Log, and Log2 routines extern char g_szCabFileLocation[_MAX_PATH]; //This is actually defined in cab.cpp extern char g_szCabFileName[_MAX_PATH]; //This is actually defined in cab.cpp void __cdecl main(int argc, char *argv[]) { HFCI hc = NULL; int i=0; bool bResult=false; char szString[_MAX_PATH], szRestoreDirPath[_MAX_PATH]; char *szTest[1], *szArgCmd[200]; //Process any commandline arguments memset(szArgCmd, 0, sizeof(char)*200); //Clean up before relying on this DS. ArgParse(argc, argv, szArgCmd); //Open up the log file, and start logging all activity strcpy(szString, getenv("TEMP")); strcat(szString, "\\SRDIAG.LOG"); fLogStream = fopen(szString, "w"); //Create a cab, if we fail then just skip, // else gather all of the relevant files required. if (NULL != (hc = create_cab()) ) { //First add in any files that were specified on the command line, but first figuring out // how many were really specified for(i=0;i<200;i++) if(NULL == szArgCmd[i]) break; bResult = test_fci(hc, i, szArgCmd, ""); //Get the Temp Location, ensure we have a new file, then // get the registry keys, and dump into our text file strcpy(szString, getenv("TEMP")); strcat(szString, "\\SR-Reg.txt"); DeleteFileA(szString); i = 0; while (NULL != *wszRegKeys[i][0]) { if(0 == wcscmp(wszRegKeys[i][1], TEXT("0"))) GetSRRegistry(szString, wszRegKeys[i][0], false); else GetSRRegistry(szString, wszRegKeys[i][0], true); i++; } //Add the log to the Cab, and clean up szTest[0] = szString; bResult = test_fci(hc, 1, szTest, ""); DeleteFileA(szString); //Add files Bases on WinDir relative root i = 0; while (NULL != *szWindirFileCollection[i]) { strcpy(szString, getenv("WINDIR")); strcat(szString, szWindirFileCollection[i]); szTest[0] = szString; bResult = test_fci(hc, 1, szTest, ""); i++; } //Get the restore directory on the system drive, and then Add in critial files GetRestoreGuid(szString); sprintf(szRestoreDirPath, "%s\\System Volume Information\\_Restore%s\\", getenv("SYSTEMDRIVE"), szString ); //Add files Bases on System Volume Information relative root i = 0; while (NULL != *szSysVolFileCollection[i]) { strcpy(szString, szRestoreDirPath); strcat(szString, szSysVolFileCollection[i]); szTest[0] = szString; bResult = test_fci(hc, 1, szTest, ""); i++; } //Get the Restore point enumeration, and then cab the file strcpy(szString, getenv("TEMP")); strcat(szString, "\\SR-RP.LOG"); RPEnumDrive(hc, szString); szTest[0] = szString; bResult = test_fci(hc, 1, szTest, ""); DeleteFileA(szString); //Get the ChangeLog enumeration, and then cab and delete the file //first we need to switch the log, then gather the log SRSwitchLog(); strcpy(szString, getenv("TEMP")); strcat(szString, "\\SR-CHGLog.LOG"); GetChgLog(szString); szTest[0] = szString; bResult = test_fci(hc, 1, szTest, ""); DeleteFileA(szString); //Get the fileversion info for each of the Files strcpy(szString, getenv("TEMP")); strcat(szString, "\\SR-FileList.LOG"); SRGetFileInfo(szString); szTest[0] = szString; bResult = test_fci(hc, 1, szTest, ""); DeleteFileA(szString); //Close out logging, and add the log to the cab // (THIS SHOULD BE THE LAST THING WE ARE DOING!!) fclose(fLogStream); fLogStream = NULL; strcpy(szString, getenv("TEMP")); strcat(szString, "\\SRDIAG.LOG"); szTest[0] = szString; bResult = test_fci(hc, 1, szTest, ""); DeleteFileA(szString); } //Completes cab file under construction if (flush_cab(hc)) { Log("Cabbing Process was Sucessful"); } else { Log("Cabbing Process has failed"); } } //+--------------------------------------------------------------------------- // // Function: Log // // Synopsis: Will print a String to both our log file, and also the console // // Arguments: [szString] -- Simple ANSI string to log // // Returns: void // // History: 9/21/00 SHeffner Created // // //---------------------------------------------------------------------------- void Log(char *szString) { if( NULL != fLogStream) fprintf(fLogStream, "%s\n", szString); puts(szString); } //+--------------------------------------------------------------------------- // // Function: Log2 // // Synopsis: Takes two strings, and will print them back to back to both the // log file, and also to the console // // Arguments: [szString] -- Simple ANSI string to log // [szString2] -- Simple ANSI string to log // // Returns: void // // History: 9/21/00 SHeffner Created // // //---------------------------------------------------------------------------- void Log2(char *szString, char *szString2) { if( NULL != fLogStream) fprintf(fLogStream,"%s %s\n", szString, szString2); printf("%s %s\n", szString, szString2); } //+--------------------------------------------------------------------------- // // Function: GetRestoreGuid // // Synopsis: Will retrieve from the registry what the GUID is for the current // Restore directory, and return this in the string pointer passed // to the function. // // Arguments: [szString] -- Simple ANSI string to receive the string // // Returns: void // // History: 9/21/00 SHeffner Created // // //---------------------------------------------------------------------------- void GetRestoreGuid(char *szString) { long lResult; HKEY mHkey; DWORD dwType, dwLength; lResult = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SystemRestore\\Cfg", 0, KEY_READ, &mHkey); dwLength = _MAX_PATH +1; lResult = RegQueryValueExA(mHkey, "MachineGuid", NULL, &dwType, (unsigned char *)szString, &dwLength); } //+--------------------------------------------------------------------------- // // Function: SRGetFileInfo // // Synopsis: This is the wrapper function for InfoPerFile, where I will assemble // the file path for each of the relevant files that we need to get // file statistics. // // Arguments: [szLogFile] -- The path to the file that I will log this information to. // // Returns: void // // History: 9/21/00 SHeffner Created // // //---------------------------------------------------------------------------- void SRGetFileInfo(char *szLogFile) { int iCount; WCHAR szString[_MAX_PATH]; //Initialize counter, and walk through the filelist that we have iCount = 0; while(NULL != *wszFileVersionList[iCount]) { //Assemble the path, since I just have the relative path from windir wcscpy(szString, _wgetenv(L"WINDIR")); wcscat(szString, wszFileVersionList[iCount]); //Call function to do the work since we have full path, and log file name InfoPerFile(szLogFile, szString); iCount++; } } //+--------------------------------------------------------------------------- // // Function: InfoPerFile // // Synopsis: This function takes the log file path, and the filename, and then // will put out the relevant information from the file to be logged. // // // Arguments: [szLogFile] -- The path to the file that I will log this information to. // [szFileName] -- The full path, and name of the file to get the information for. // // Returns: void // // History: 9/21/00 SHeffner Created // // //---------------------------------------------------------------------------- void InfoPerFile(char *szLogFile, WCHAR *szFileName) { BY_HANDLE_FILE_INFORMATION finfo; SYSTEMTIME st; HANDLE handle; FILE *fStream; WCHAR szString[_MAX_PATH]; VOID *pBuffer; VS_FIXEDFILEINFO FixedFileInfo; UINT uLen; DWORD dSize, dResult, i; struct LANGANDCODEPAGE { WORD wLanguage; WORD wCodePage; } *lpTranslate; WCHAR *szMonth[] = { L"January", L"Feburary", L"March", L"April", L"May", L"June", L"July", L"August", L"September", L"October", L"November", L"December" }; WCHAR *szDay[] = {L"Sunday", L"Monday", L"Tuesday", L"Wednesday", L"Thursday", L"Friday", L"Saturday" }; if ( NULL == *szFileName) return; //Open up our log file, and log the file we are processing fStream = fopen(szLogFile, "a"); if( NULL == fStream) return; //if we have an invalid handle just return back. fprintf(fStream, "\n%S\n", szFileName); //Open up the file so that we can get the information from the handle // If we are unable to do this we will just log the generic not able to find file. if( INVALID_HANDLE_VALUE != (handle = CreateFile(szFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL)) ) { if (FALSE != GetFileInformationByHandle(handle, &finfo)) { //FileCreation FileTimeToSystemTime( &finfo.ftCreationTime, &st); fprintf(fStream, "\tCreation Date=%S %S %lu, %lu %lu:%lu:%lu\n", szDay[st.wDayOfWeek],szMonth[st.wMonth-1],st.wDay,st.wYear,st.wHour,st.wMinute,st.wSecond); //FileLastAccess FileTimeToSystemTime( &finfo.ftLastAccessTime, &st); fprintf(fStream, "\tLast Access Date=%S %S %lu, %lu %lu:%lu:%lu\n", szDay[st.wDayOfWeek],szMonth[st.wMonth-1],st.wDay,st.wYear,st.wHour,st.wMinute,st.wSecond); //FileLastWrite FileTimeToSystemTime( &finfo.ftLastWriteTime, &st); fprintf(fStream, "\tLast Write Date=%S %S %lu, %lu %lu:%lu:%lu\n", szDay[st.wDayOfWeek],szMonth[st.wMonth-1],st.wDay,st.wYear,st.wHour,st.wMinute,st.wSecond); //File Attributes wcscpy(szString, finfo.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE ? L"ARCHIVE " : L""); wcscat(szString, finfo.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED ? L"COMPRESSED " : L""); wcscat(szString, finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? L"DIRECTORY " : L""); wcscat(szString, finfo.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED ? L"ENCRYPTED " : L""); wcscat(szString, finfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ? L"HIDDEN " : L""); wcscat(szString, finfo.dwFileAttributes & FILE_ATTRIBUTE_NORMAL ? L"NORMAL " : L""); wcscat(szString, finfo.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE ? L"OFFLINE " : L""); wcscat(szString, finfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? L"READONLY " : L""); wcscat(szString, finfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ? L"REPARSE_POINT " : L""); wcscat(szString, finfo.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE ? L"SPARSE_FILE " : L""); wcscat(szString, finfo.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM ? L"SYSTEM " : L""); wcscat(szString, finfo.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY ? L"TEMPORARY " : L""); fprintf(fStream, "\tAttributes=%S\n", szString); //Get the VolumeSerialNumber, FileSize, and Number of Links fprintf(fStream, "\tVolumeSerialNumber=%lu\n", finfo.dwVolumeSerialNumber); fprintf(fStream, "\tFileSize=%lu%lu\n", finfo.nFileSizeHigh, finfo.nFileSizeLow); fprintf(fStream, "\tNumberOfLinks=%lu\n", finfo.nNumberOfLinks); if( 0 != (dSize = GetFileVersionInfoSize(szFileName, &dResult)) ) { if( NULL != (pBuffer = malloc(dSize)) ) { GetFileVersionInfo(szFileName, dResult, dSize, (LPVOID) pBuffer); // Read the list of languages and code pages. VerQueryValue(pBuffer, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &uLen); // Read the Version info for each language and code page. for( i=0; i < (uLen/sizeof(struct LANGANDCODEPAGE)); i++ ) { char *lpBuffer; DWORD dwBytes, dwCount = 0; fprintf(fStream, "\tLanguage=%x%x\n", lpTranslate[i].wLanguage, lpTranslate[i].wCodePage); while (NULL != *wszVersionResource[dwCount] ) { //Generate the string, for getting the resource based on the language, then // retrieve this, and then put it to the log file. wsprintf( szString, L"\\StringFileInfo\\%04x%04x\\%s", lpTranslate[i].wLanguage, lpTranslate[i].wCodePage, wszVersionResource[dwCount]); VerQueryValue(pBuffer, szString, (LPVOID *) &lpBuffer, &uLen); if( 0 != uLen ) fprintf(fStream, "\t%S=%S\n", wszVersionResource[dwCount], lpBuffer); dwCount++; } //While loop end, for each resource } //for loop end for each language //Clean up the allocated memory free(pBuffer); } //If check for getting memory } //If check for getting the fileversioninfosize } //if check for GetFileInformationByHandle on the file CloseHandle(handle); } //if check on can I open this file //Cleanup fclose(fStream); } //+--------------------------------------------------------------------------- // // Function: ArgParse // // Synopsis: This function simply looks for the key word parameters, and will build // an array pointing to each of the files that we want to include in the cab // in addition to the normal files. // // // Arguments: [argc] -- Count of the number of arguments // [argv] -- Array of the arguments. // // Returns: void // // History: 9/21/00 SHeffner Created // // //---------------------------------------------------------------------------- void ArgParse(int argc, char *argv[], char *szArgCmd[]) { int iCount, iWalk; //If no command line specified then just do the normal cabbing, with core files if(1 == argc) return; //walk through each of the arguments, and check to see if its a help, file, cabname, cabloc, or a ? for(iCount = 1; iCount < argc; iCount++) { if( 0 == _strnicoll(&argv[iCount][1], "?", strlen("?")) ) Usage(); if( 0 == _strnicoll(&argv[iCount][1], "help", strlen("help")) ) Usage(); if( 0 == _strnicoll(&argv[iCount][1], "cabname", strlen("cabname")) ) strcpy(g_szCabFileName, (strstr(argv[iCount], ":") + 1)); if( 0 == _strnicoll(&argv[iCount][1], "cabloc", strlen("cabloc")) ) strcpy(g_szCabFileLocation, (strstr(argv[iCount], ":") + 1)); if( 0 == _strnicoll(&argv[iCount][1], "file", strlen("file")) ) { //find the first spot where I can put the pointer to this filename for( iWalk=0; iWalk < 200; iWalk++) { if( NULL == szArgCmd[iWalk] ) { szArgCmd[iWalk] = strstr(argv[iCount], ":") + 1; break; } } //end for loop, walking through DS } //end of if for is this an added file } //end of for loop walking through all of the arguments } //+--------------------------------------------------------------------------- // // Function: Usage // // Synopsis: Displaies the command line usage // // // Arguments: // // Returns: void // // History: 9/21/00 SHeffner Created // // //---------------------------------------------------------------------------- void Usage() { printf("Usage: SrDiag [/Cabname:test.cab] [/Cabloc:\"c:\\temp\\\"] [/file:\"c:\\boot.ini\"]\n"); printf(" /cabloc is pointing to the location to store the cab, this should have a \\ on the end\n"); printf(" /cabname is the full name of the cab file that you wish to use. \n"); printf(" /file is the name and path of a file that you wish to add to the cab, this can be used many times\n"); exit(0); }