|
|
/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
grabmiapi.c
Abstract:
Code for generating matching information for files in a given directory and its subdirectories.
Author:
jdoherty created sometime in 2000
Revision History:
several people contributed (vadimb, clupu, ...)
--*/
#include "sdbp.h"
#include <time.h>
#include <shlwapi.h>
#define MAX_MISC_FILES_PER_LEVEL 10
#define MAX_LEVELS_OF_DIRECTORIES 3
static UCHAR UNICODE_MARKER[2] = { 0xFF, 0xFE }; // will hold special characters to specify
// a UNICODE File
TCHAR* g_szFilterDesc[] = { TEXT("GRABMI_FILTER_NORMAL"), TEXT("GRABMI_FILTER_PRIVACY"), TEXT("GRABMI_FILTER_DRIVERS"), TEXT("GRABMI_FILTER_VERBOSE"), TEXT("GRABMI_FILTER_SYSTEM"), TEXT("GRABMI_FILTER_THISFILEONLY"), };
TCHAR* g_szGrabmiFilterNormal[] = { TEXT(".exe"), TEXT(".icd"), TEXT("._mp"), TEXT(".msi"), TEXT(".dll") };
TCHAR* g_szGrabmiFilterSystem[] = { TEXT("ntdll.dll"), TEXT("user32.dll"), TEXT("kernel32.dll"), TEXT("gdi32.dll"), TEXT("wininet.dll"), TEXT("winsock.dll"), TEXT("advapi32.dll"), TEXT("shell32.dll"), TEXT("ole32.dll"), TEXT("advapi32.dll"), TEXT("oleaut32.dll"), TEXT("repcrt32.dll"), };
typedef struct tagRECINFO {
LPVOID lpvCallbackParameter; PFNGMIProgressCallback pfnCallback;
ULONG MaxFiles; // limit the number of files
ULONG FileCount; // count the files
BOOL bNewStorageFile;
} RECINFO, *PRECINFO;
#define GRABMI_FLAGS_MASK 0xFFFF0000
GMI_RESULT SdbpGrabMatchingInfoDir( HANDLE hStorageFile, // handle to a file we are writing
PRECINFO pinfo, // pointer to extra info
DWORD dwFilterAndFlags, // specifies the types of files to be added for matching
LPCTSTR lpszRoot, // root directory for our search (pointer to the buffer)
LPTSTR lpszOriginalExe, // never null -- pointer to the relative portion,
LPTSTR lpszRelative, // never null -- pointer to the relative portion,
int nLevel // current directory level for matching information
) /*++
Function Name: SdbpGrabMatchingInfoDir
Function Description:
This function traverses a directory and its subdirectories gathering matching information and writes it to the specified file.
Return Value:
BOOL: TRUE if Successful
History:
04/26/2001 jdoherty Created
SdbpGrabMatchingInfoDir pointer definition: c:\foo\bar\soap\relativepath\ ^- lpszRoot ^- lpszRelative
--*/ { HANDLE hSearch = INVALID_HANDLE_VALUE; // handle for FindFileFirst and FindFileNext
WIN32_FIND_DATA FindFileData; // structure containing file information
LPTSTR lpchFilePart; // points to a file part in szSearchPath
LPTSTR pchExt; // extension of current file
LPTSTR lpReplaceChar; // pointer to character to be replaced
BOOL bMiscFile; INT nch, nchBuffer, i; INT nLen; INT cbFileCounter = 0; // running count of misc files added to matching.
int cbMultiByte = 0; // The amount of MultiByte chars converting.
int cchWideChar = 0; // The amount of WideChars converted.
DWORD dwBufferSize = 4096; // initialize me with the alloc size for lpData
LPTSTR lpData = NULL; // INITIALIZE ME WITH MALLOC!!!
LPTSTR lpBuffer = NULL; // points within lpData
LPWSTR lpUnicodeBuffer = NULL; // INITIALIZE ME WITH MALLOC!!!
BOOL bThisFileOnlyDone = FALSE; DWORD dwFilter = (dwFilterAndFlags & ~GRABMI_FLAGS_MASK); DWORD dwFilterFlags = (dwFilterAndFlags & GRABMI_FLAGS_MASK); PATTRINFO pAttrInfo; // attribute information structure
DWORD dwBytesWritten = 0; DWORD dwAttributes; DWORD dwAttrCount; GMI_RESULT Result = GMI_FAILED; // these two variables control return Result
// is set as a return from callback or nested call
//
// Only want to grab information for the file(s) specified which
// should reside in the root directory specified.
//
if (nLevel != 0 && (dwFilter == GRABMI_FILTER_THISFILEONLY || dwFilter == GRABMI_FILTER_SYSTEM)) { goto eh; }
lpData = (LPTSTR)SdbAlloc(dwBufferSize * sizeof(TCHAR));
if (lpData == NULL) { DBGPRINT((sdlError, "SdbpGrabMatchingInfoDir", "Unable to allocate %d bytes.\n", dwBufferSize * sizeof(TCHAR))); goto eh; }
#ifdef WIN32A_MODE
lpUnicodeBuffer = (LPWSTR)SdbAlloc(dwBufferSize * sizeof(WCHAR));
if (lpUnicodeBuffer == NULL) { DBGPRINT((sdlError, "SdbpGrabMatchingInfoDir", "Unable to allocate %d bytes.\n", dwBufferSize * sizeof(WCHAR))); goto eh; } #endif // WIN32A_MODE
lpchFilePart = lpszRelative + _tcslen(lpszRelative);
assert(lpchFilePart == lpszRoot || *(lpchFilePart-1) == TEXT('\\'));
if (dwFilter == GRABMI_FILTER_THISFILEONLY) { _tcscpy(lpchFilePart, lpszOriginalExe); } else { _tcscpy(lpchFilePart, TEXT("*")); }
//
// Pass one. Grab all the file matching info we can.
//
hSearch = FindFirstFile(lpszRoot, &FindFileData);
if (hSearch == INVALID_HANDLE_VALUE) { DBGPRINT((sdlError, "SdbpGrabMatchingInfoDir", "FindFirstFile Failed on [%s].\n", lpszRoot)); goto eh; }
//
// Comment in hStorage file where the root of the matching information is
//
if (nLevel == 0 && pinfo->bNewStorageFile) { *lpchFilePart = TEXT('\0'); nch = _sntprintf(lpData, dwBufferSize, TEXT("<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n<DATABASE>\r\n")); if (nch < 0) { //
// lpData is too small to store information
//
DBGPRINT((sdlError, "SdbpGrabMatchingInforDir", "lpData is too small\n")); goto eh; }
#ifndef WIN32A_MODE
lpUnicodeBuffer = lpData; #else
cchWideChar = MultiByteToWideChar(CP_ACP, 0, lpData, -1, lpUnicodeBuffer, dwBufferSize);
if (cchWideChar == 0) { DBGPRINT((sdlError, "SdbpGrabMatchingInforDir", "lpUnicodeBuffer is too small for conversion\n"));
goto eh; }
#endif
WriteFile(hStorageFile, UNICODE_MARKER, 2, &dwBytesWritten, NULL);
WriteFile(hStorageFile, lpUnicodeBuffer, wcslen(lpUnicodeBuffer) * sizeof(WCHAR), &dwBytesWritten, NULL); }
if (nLevel == 0) { if (dwFilter == GRABMI_FILTER_SYSTEM) { _tcscpy (lpszOriginalExe, TEXT("SYSTEM INFO")); }
nch = _sntprintf(lpData, dwBufferSize, TEXT("<EXE NAME=\""));
if (nch < 0) { DBGPRINT((sdlError, "SdbpGrabMatchingInforDir", "lpData is to small\n")); goto eh; }
if (!SdbpSanitizeXML(lpData + nch, dwBufferSize - nch, lpszOriginalExe)) { goto eh; }
// if we are here, we need to attach a few more things
nLen = _tcslen(lpData); nch = _sntprintf(lpData + nLen, dwBufferSize - nLen, TEXT("\" FILTER=\"%s\">\r\n"), g_szFilterDesc[dwFilter]); if (nch < 0) { goto eh; } nch += nLen;
#ifndef WIN32A_MODE
lpUnicodeBuffer = lpData; #else
cchWideChar = MultiByteToWideChar(CP_ACP, 0, lpData, -1, lpUnicodeBuffer, dwBufferSize); if (cchWideChar == 0) { DBGPRINT((sdlError, "SdbpGrabMatchingInforDir", "lpUnicodeBuffer is too small for conversion\n"));
goto eh; }
#endif // WIN32A_MODE
WriteFile(hStorageFile, lpUnicodeBuffer, wcslen(lpUnicodeBuffer) * sizeof(WCHAR), &dwBytesWritten, NULL); }
switch (dwFilter) {
case GRABMI_FILTER_PRIVACY: case GRABMI_FILTER_THISFILEONLY: case GRABMI_FILTER_SYSTEM: cbFileCounter = MAX_MISC_FILES_PER_LEVEL; break; }
do { //
// Check for directories including . and ..
//
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { continue; }
//
// Make a relative path with our buffer
//
_tcscpy(lpchFilePart, FindFileData.cFileName);
//
// lpszRelative points to the relative path
// lpszRoot points to the full path
bMiscFile = FALSE;
//
// Check to see if there is version information for the specified file and whether
// it is a .exe, .icd, ._MP, .msi, or .dll. If so print the information to the file.
// Otherwise, add the information if cbFileCounter is less than MAX_MISC_FILES_PER_LEVEL.
//
pchExt = PathFindExtension(lpszRoot);
switch (dwFilter) {
case GRABMI_FILTER_NORMAL: case GRABMI_FILTER_PRIVACY: for (i = 0; i < ARRAYSIZE(g_szGrabmiFilterNormal); i++) { if (_tcsicmp(pchExt, g_szGrabmiFilterNormal[i]) == 0) { break; } } bMiscFile = (i >= ARRAYSIZE(g_szGrabmiFilterNormal)); break;
case GRABMI_FILTER_SYSTEM: for (i = 0; i < ARRAYSIZE(g_szGrabmiFilterSystem); i++) { if (_tcsicmp(FindFileData.cFileName, g_szGrabmiFilterSystem[i]) == 0) { break; } } bMiscFile = (i >= ARRAYSIZE(g_szGrabmiFilterSystem)); break;
case GRABMI_FILTER_THISFILEONLY: bMiscFile = _tcsicmp(FindFileData.cFileName, lpszOriginalExe); break;
case GRABMI_FILTER_DRIVERS: bMiscFile = _tcsicmp(pchExt, TEXT(".sys")); break;
default: break; }
if (bMiscFile) { if (cbFileCounter < MAX_MISC_FILES_PER_LEVEL) { ++cbFileCounter; } else { continue; } }
//
// List relative data here
//
lpBuffer = lpData;
if (dwFilter == GRABMI_FILTER_DRIVERS) { nch = _sntprintf(lpBuffer, dwBufferSize, TEXT(" <SYS NAME=\"")); } else { nch = _sntprintf(lpBuffer, dwBufferSize, TEXT(" <MATCHING_FILE NAME=\"")); }
if (nch < 0) { goto eh; }
if (!SdbpSanitizeXML(lpBuffer + nch, dwBufferSize - nch, lpszRelative)) { goto eh; }
nLen = _tcslen(lpBuffer); nch = _sntprintf(lpBuffer + nLen, dwBufferSize - nLen, TEXT("\" "));
if (nch < 0) { goto eh; }
//
// Now we add the length -- and we're ready
//
nch += nLen;
lpBuffer += nch; nchBuffer = nch; // amount of characters in lpBuffer already
//
// Call the attribute manager to get all the attributes for this file.
//
pAttrInfo = NULL;
if (SdbGetFileAttributes(lpszRoot, &pAttrInfo, &dwAttrCount)) {
//
// Loop through all the attributes and add the ones that are available.
//
TCHAR lpszAttr[MAX_PATH*2];
for (i = 0; (DWORD)i < dwAttrCount; ++i) {
if (SdbFormatAttribute(&pAttrInfo[i], lpBuffer, dwBufferSize - nchBuffer)) { //
// lpBuffer has XML for this attribute
//
// insert space
nch = _tcslen(lpBuffer) + 1; // for space
if (dwFilter == GRABMI_FILTER_DRIVERS) { switch (pAttrInfo[i].tAttrID) {
case TAG_BIN_PRODUCT_VERSION: case TAG_UPTO_BIN_PRODUCT_VERSION: case TAG_LINK_DATE: case TAG_UPTO_LINK_DATE: break;
default: continue; } }
if (nchBuffer + nch >= (int)dwBufferSize) { //
// lpBuffer is not large enough to hold the information
//
DBGPRINT((sdlError, "SdbGetMatchingInfoDir", "lpBuffer is too small to handle attributes for %s.\n", lpszRelative)); }
_tcscat(lpBuffer, TEXT(" "));
lpBuffer += nch;
nchBuffer += nch; } } }
nch = _sntprintf(lpBuffer, dwBufferSize, TEXT("/>\r\n"));
if (nch < 0) { //
// Buffer is too small.
//
DBGPRINT((sdlError, "SdbGrabMatchingInfoDir", "lpBuffer is too small to handle attributes for %s.\n", lpszRelative)); continue; } //
// Check to see if using unicode or not. If not, convert
// to unicode.
//
#ifndef WIN32A_MODE
lpUnicodeBuffer = lpData; #else
cchWideChar = MultiByteToWideChar(CP_ACP, 0, lpData, -1, lpUnicodeBuffer, dwBufferSize); if (cchWideChar == 0) { //
// buffer is not large enough for conversion
//
DBGPRINT((sdlError, "SdbpGrabMatchingInforDir", "lpUnicodeBuffer is not large enough for conversion\n"));
goto eh; }
#endif // WIN32A_MODE
if (pinfo->pfnCallback) { if (!pinfo->pfnCallback(pinfo->lpvCallbackParameter, lpszRoot, // give straight name
lpszRelative, // relative name
pAttrInfo, // pointer to the attributes
lpUnicodeBuffer)) { // xml output
Result = GMI_CANCELLED; } }
WriteFile(hStorageFile, lpUnicodeBuffer, wcslen(lpUnicodeBuffer) * sizeof(WCHAR), &dwBytesWritten, NULL);
if (pAttrInfo) { SdbFreeFileAttributes(pAttrInfo); pAttrInfo = NULL; // make sure we do not free it twice
}
//
// Check to see whether we have reached the file limit
//
if (pinfo->MaxFiles && ++pinfo->FileCount >= pinfo->MaxFiles && Result != GMI_CANCELLED) { Result = GMI_SUCCESS; // limit reached, grabmi cancelled
nLevel = MAX_LEVELS_OF_DIRECTORIES; // this is so that we bail out
break; }
} while (FindNextFile(hSearch, &FindFileData) && (Result != GMI_CANCELLED));
FindClose(hSearch); hSearch = INVALID_HANDLE_VALUE;
if (Result == GMI_CANCELLED) { goto CloseTags; }
if (dwFilter != GRABMI_FILTER_SYSTEM && dwFilter != GRABMI_FILTER_THISFILEONLY) { if (nLevel >= MAX_LEVELS_OF_DIRECTORIES || (dwFilterFlags & GRABMI_FILTER_NORECURSE)) { Result = GMI_SUCCESS; // not a failure, just a limiting case
goto eh; // done
}
//
// Replace the filename in szSearchFile with "*" -- hack!
//
_tcscpy(lpchFilePart, TEXT("*"));
hSearch = FindFirstFile(lpszRoot, &FindFileData);
if (INVALID_HANDLE_VALUE == hSearch) { //
// lpszRoot does not contain any matching files
//
DBGPRINT((sdlError, "SdbGrabMatchingInfoDir", "%s contains no matching files!\n", lpszRoot)); goto eh; }
//
// Now go through the subdirectories and grab that information.
//
do { if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { continue; }
if ((_tcscmp(FindFileData.cFileName, TEXT(".")) == 0) || (_tcscmp( FindFileData.cFileName, TEXT("..")) == 0)) { continue; }
//
// Form relative path here by copying lpszRelative and appending cFileName and '\\'
//
_tcscpy(lpchFilePart, FindFileData.cFileName); _tcscat(lpchFilePart, TEXT("\\"));
//
// Recusive call. Check return result for having been cancelled !!!
//
Result = SdbpGrabMatchingInfoDir(hStorageFile, pinfo, dwFilterAndFlags, lpszRoot, NULL, lpszRelative, nLevel + 1);
if (Result == GMI_CANCELLED) { //
// We are cancelled. Write out a valid database code to close
// this if we have the option set.
//
break; }
} while (FindNextFile(hSearch, &FindFileData));
}
CloseTags: //
// This is where we close the tags if instructed to do so
//
if (nLevel == 0) { wcscpy (lpUnicodeBuffer, L"</EXE>\r\n");
if (!(dwFilterFlags & GRABMI_FILTER_NOCLOSE)) { wcscat(lpUnicodeBuffer, L"</DATABASE>\r\n"); }
WriteFile(hStorageFile, lpUnicodeBuffer, wcslen(lpUnicodeBuffer) * sizeof(WCHAR), &dwBytesWritten, NULL); }
//
// Check how we got here -- was it via the cancel route ?
//
if (Result == GMI_CANCELLED) { goto eh; }
//
// Information gathered successfully.
//
Result = GMI_SUCCESS;
eh:
if (INVALID_HANDLE_VALUE != hSearch) { FindClose(hSearch); } if (lpData != NULL) { SdbFree(lpData); }
#ifdef WIN32A_MODE
if (lpUnicodeBuffer != NULL) { SdbFree(lpUnicodeBuffer); } #endif // WIN32A_MODE
return Result; }
BOOL SDBAPI SdbGrabMatchingInfo( LPCTSTR szMatchingPath, DWORD dwFilter, LPCTSTR szFile ) { return SdbGrabMatchingInfoEx(szMatchingPath, dwFilter, szFile, NULL, NULL) == GMI_SUCCESS; }
GMI_RESULT SDBAPI SdbGrabMatchingInfoEx( LPCTSTR szMatchingPath, // path to begin gathering information
DWORD dwFilterAndFlags, // specifies the types of files to be added to matching
LPCTSTR szFile, // full path to file where information will be stored
PFNGMIProgressCallback pfnCallback, LPVOID lpvCallbackParameter ) { HANDLE hStorageFile = INVALID_HANDLE_VALUE; LPTSTR lpRootDirectory = NULL; LPTSTR pchBackslash; LPTSTR lpRelative; TCHAR szOriginalExe[MAX_PATH] = {TEXT("Exe Not Specified")}; int nDirLen, nLevel = 0; DWORD dwAttributes; GMI_RESULT Result = GMI_FAILED; DWORD dwFilter = (dwFilterAndFlags & ~GRABMI_FLAGS_MASK); DWORD dwFilterFlags = (dwFilterAndFlags & GRABMI_FLAGS_MASK); RECINFO info;
//
// Check to see if dwFilter is a know value
//
if (dwFilter != GRABMI_FILTER_NORMAL && dwFilter != GRABMI_FILTER_PRIVACY && dwFilter != GRABMI_FILTER_DRIVERS && dwFilter != GRABMI_FILTER_VERBOSE && dwFilter != GRABMI_FILTER_SYSTEM && dwFilter != GRABMI_FILTER_THISFILEONLY) {
//
// Unknown filter specified.
//
DBGPRINT((sdlError, "SdbGrabMatchingInfo", "dwFilter is not a recognized filter.\n")); goto eh; }
RtlZeroMemory(&info, sizeof(info));
info.pfnCallback = pfnCallback; info.lpvCallbackParameter = lpvCallbackParameter; info.MaxFiles = (dwFilterFlags & GRABMI_FILTER_LIMITFILES) ? GRABMI_IMPOSED_FILE_LIMIT : 0; info.FileCount = 0; info.bNewStorageFile = TRUE;
lpRootDirectory = (LPTSTR)SdbAlloc(4096 * sizeof(TCHAR));
if (lpRootDirectory == NULL) { DBGPRINT((sdlError, "SdbGrabMatchingInfo", "Unable to allocate memory for lpRootDirectory.")); goto eh; }
if (dwFilter == GRABMI_FILTER_SYSTEM) { GetSystemDirectory (lpRootDirectory, MAX_PATH); _tcscat (lpRootDirectory, TEXT("\\"));
} else { dwAttributes = GetFileAttributes(szMatchingPath);
if (dwAttributes == (DWORD)-1) { DBGPRINT((sdlError, "SdbGrabMatchingInfo", "GetFileAttributes failed or %s is not a valid path", szMatchingPath)); goto eh; }
_tcscpy (lpRootDirectory, szMatchingPath); nDirLen = _tcslen(lpRootDirectory);
//
// See if location specified exists and if so determine
// whether its a file or directory
//
if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) { //
// Is this a directory ?
//
if (nDirLen > 0 && lpRootDirectory[nDirLen-1] != TEXT('\\')) { _tcscat(lpRootDirectory, TEXT("\\")); } } else { //
// A path containing a file name was passed as szMatchingPath.
// Determine what the containing dir is.
//
pchBackslash = _tcsrchr(lpRootDirectory, TEXT('\\'));
if (NULL == pchBackslash) { _tcscpy (szOriginalExe, lpRootDirectory); GetCurrentDirectory (MAX_PATH*16, lpRootDirectory); _tcscat (lpRootDirectory, TEXT("\\"));
} else { pchBackslash = CharNext(pchBackslash); _tcscpy (szOriginalExe, pchBackslash); *pchBackslash = TEXT('\0'); } } }
lpRelative = lpRootDirectory + _tcslen(lpRootDirectory);
//
// Check to see if szOriginalExe is not NULL if
// GRABMI_FILTER_THISFILEONLY was selected.
//
if (dwFilter == GRABMI_FILTER_THISFILEONLY && szOriginalExe == '\0' ) { DBGPRINT((sdlError, "SdbGrabMatchingInfo", "GRABMI_FILTER_THISFILEONLY specified but passed in a directory: %s.", lpRootDirectory)); goto eh;
} else if (dwFilterFlags & GRABMI_FILTER_APPEND) { //
// Open the file where the information will be stored.
//
hStorageFile = CreateFile(szFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (ERROR_ALREADY_EXISTS == GetLastError()) { SetFilePointer (hStorageFile, 0, NULL, FILE_END); info.bNewStorageFile = FALSE; } } else { //
// Open the file where the information will be stored.
//
hStorageFile = CreateFile(szFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); }
if (hStorageFile == INVALID_HANDLE_VALUE) { DBGPRINT((sdlError, "SdbGrabMatchingInfo", "Unable to open the storage file.")); goto eh; }
//
// Call the API which does the bulk of the work
//
Result = SdbpGrabMatchingInfoDir(hStorageFile, &info, dwFilterAndFlags, lpRootDirectory, szOriginalExe, lpRelative, nLevel);
eh:
if (hStorageFile != INVALID_HANDLE_VALUE) { CloseHandle(hStorageFile); }
if (lpRootDirectory) { SdbFree(lpRootDirectory); }
return Result; }
|