|
|
#ifndef WIN32
#define RC_INVOKED
#endif
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include <malloc.h>
#include <errno.h>
#include <ctype.h>
#include <signal.h>
#include <string.h>
#include <time.h>
#include <conio.h>
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <imagehlp.h>
#define READ_BUFFER_SIZE (16 * 1024 * sizeof(DWORD)) // 64k blocks
#define CHECK_NAME "\\chkfile.chk"
LPSTR atolx( LPSTR psz, LPDWORD pul);
DWORD ParseCheckFile ( VOID );
HANDLE PortFindFirstFile( LPSTR FindPattern, BOOL fNormal, LPSTR FindName, LPDWORD FindSize);
BOOL PortFindNextFile( HANDLE hFind, BOOL fNormal, LPSTR FindName, LPDWORD FindSize);
VOID PortFindClose( HANDLE hFind );
UINT ProcessCheckFile(LPINT pcfiles); VOID Usage(VOID); VOID __cdecl crerror(LPSTR pszfmt, ...); LPSTR *ProcessParameters(INT *pargc, LPSTR argv[]); LPSTR ProcessArgBuf(LPSTR pszargs); BOOL OpenCheckFile(VOID); BOOL ProcessEntry(LPSTR pszFullPath, LPSTR pszRelPath); BOOL FindEntry(LPSTR pszRelPath, PULONG pSum); DWORD MissingEntries(VOID); VOID ReadCheckHeader(FILE *pf); VOID RecursiveCheckHeader(void); VOID WriteCheckHeader(FILE *pf); LPSTR iscomment(LPSTR psz); LPSTR ismatch(LPSTR psz, LPSTR pszcompact); LPSTR iscomment(LPSTR psz); LPSTR AddDirectory(LPSTR psz); BOOL AddEntry(LPSTR psz, BOOL frequired); BOOL AddComponent(LPSTR pszdir, LPSTR pszpat, BOOL fdir, BOOL frequired); LPSTR ReadDirectory(LPSTR pszdir);
#define CHECKSTRLEN(psz, cbmax) \
if (strlen(psz) > cbmax) { \ crerror("String overflow at line %u (%s)", __LINE__, psz); \ exit(4); \ }
#define DEFAULTROOT "nt"
//
// Defined parsed check file entry structure and table storage.
//
typedef struct _CHECK_FILE_ENTRY { struct _CHECK_FILE_ENTRY *Next; DWORD Sum; WORD Length; CHAR *Name; } CHECK_FILE_ENTRY, *PCHECK_FILE_ENTRY;
#define CHECK_ENTRY_TABLE_SIZE 4096
CHECK_FILE_ENTRY CheckEntryTable[CHECK_ENTRY_TABLE_SIZE];
//
// Define root of parsed check file list.
//
CHECK_FILE_ENTRY CheckEntryRoot;
struct component_s { struct component_s *pcmNext; // next in linked list
BOOL fDir; // TRUE if directory
BOOL fFound; // TRUE if found
BOOL fRequired; // TRUE if must exist
CHAR achPat[1]; // path component (subdir or pattern)
};
struct checkpath_s { struct checkpath_s *pcpNext; // next in linked list
struct component_s *pcmPat; // subdirectories and file patterns
CHAR achDir[1]; // root relative directory path
};
struct checkpath_s *pcpPaths = NULL;
DWORD cbCheck; LPSTR pszCheckFileName = NULL; // input/output check file path
LPSTR pszLogFileName = NULL; // error log file path
FILE *pfCheck = NULL; // input/output check stdio file pointer
FILE *pfLog; // error log file pointer
LPSTR pszCheck = NULL; // input check file contents
LPSTR RootOfTree = DEFAULTROOT; BOOL fInProgress = FALSE; UINT cbProgress = 0;
BOOL fAll = FALSE; BOOL fCommand = FALSE; BOOL fGenerateCheck = FALSE; BOOL fNoArgs = FALSE; BOOL fRecurse = FALSE; BOOL fPrintMissing = TRUE; BOOL fPrintExtra = TRUE; DWORD fCdCheck;
CHAR OutputLine[512]; DWORD ReadBuffer[READ_BUFFER_SIZE / sizeof(DWORD) + 1];
//
// this table must be in alphabetical order !!!
//
LPSTR pszDefaultDir = "#directory start\n" #if defined(i386)
"*.\n" "*.com\n" #endif
#if defined(MIPS) || defined(_ALPHA_)
"*.dll\n" "*.exe\n" #endif
#if defined(PPC)
"*.exe\n" #endif
"?\\*.*\n" "?\\dump\\ optional\n" "?\\dump\\*.* optional\n" "?\\idw\\ optional\n" "?\\idw\\*.* optional\n" "?\\idw\\setup\\ optional\n" "?\\idw\\setup\\*.* optional\n" "?\\km\\ optional\n" "?\\km\\*.* optional\n" "?\\km\\symbols\\ optional\n" "?\\km\\symbols\\dll\\ optional\n" "?\\km\\symbols\\dll\\*.* optional\n" "?\\km\\symbols\\sys\\ optional\n" "?\\km\\symbols\\sys\\*.* optional\n" "?\\km\\system32\\ optional\n" "?\\km\\system32\\*.* optional\n" "?\\km\\system32\\drivers\\ optional\n" "?\\km\\system32\\drivers\\*.* optional\n" "?\\mstools\\ optional\n" "?\\mstools\\*.* optional\n" "?\\nws\\ optional\n" "?\\nws\\*.* optional\n" "?\\symbols\\*.* optional\n" "?\\symbols\\acm\\*.* optional\n" "?\\symbols\\com\\*.* optional\n" "?\\symbols\\cpl\\*.* optional\n" "?\\symbols\\dll\\*.* optional\n" "?\\symbols\\drv\\*.* optional\n" "?\\symbols\\exe\\*.* optional\n" "?\\symbols\\scr\\*.* optional\n" "?\\symbols\\sys\\*.* optional\n" "?\\system\\*.*\n" "?\\system32\\*.*\n" "?\\system32\\config\\*.*\n" "?\\system32\\dhcp\\*.* optional\n" "?\\system32\\drivers\\*.*\n" "?\\system32\\drivers\\etc\\*.*\n" #ifdef i386
"?\\system32\\os2\\ optional\n" "?\\system32\\os2\\dll\\ optional\n" "?\\system32\\os2\\dll\\*.* optional\n" #endif
"?\\system32\\ras\\*.* optional\n" "?\\system32\\spool\\ optional\n" "?\\system32\\spool\\drivers\\ optional\n" "?\\system32\\spool\\prtprocs\\ optional\n" #ifdef MIPS
"?\\system32\\spool\\prtprocs\\w32mips\\ optional\n" "?\\system32\\spool\\prtprocs\\w32mips\\*.dll optional\n" #endif
#ifdef _ALPHA_
"?\\system32\\spool\\prtprocs\\w32alpha\\ optional\n" "?\\system32\\spool\\prtprocs\\w32alpha\\*.dll optional\n" #endif
#ifdef i386
"?\\system32\\spool\\prtprocs\\w32x86\\ optional\n" "?\\system32\\spool\\prtprocs\\w32x86\\*.dll optional\n" #endif
#ifdef PPC
"?\\system32\\spool\\prtprocs\\w32ppc\\ optional\n" "?\\system32\\spool\\prtprocs\\w32ppc\\*.dll optional\n" #endif
"?\\system32\\wins\\*.* optional\n" "?\\ui\\ optional\n" "?\\ui\\*.* optional\n" "?\\ui\\dump\\ optional\n" "?\\ui\\dump\\*.* optional\n" "?\\ui\\symbols\\ optional\n" "?\\ui\\symbols\\cpl\\ optional\n" "?\\ui\\symbols\\cpl\\*.* optional\n" "?\\ui\\symbols\\dll\\ optional\n" "?\\ui\\symbols\\dll\\*.* optional\n" "?\\ui\\symbols\\exe\\ optional\n" "?\\ui\\symbols\\exe\\*.* optional\n" "?\\ui\\system32\\ optional\n" "?\\ui\\system32\\*.* optional\n" #ifdef i386
"?\\wdl\\ optional\n" "?\\wdl\\video\\ optional\n" "?\\wdl\\video\\avga\\ optional\n" "?\\wdl\\video\\avga\\*.* optional\n" #endif
"#directory end\n" "";
VOID CdCheck() { #if 0
LPSTR line=NULL; LPSTR psz; CHAR partialname[256]; CHAR fullname[256]; char flatname[256]; DWORD ChkFileSum,ChkFileSize; LPSTR FilePart; DWORD ActualSize, ActualSum; FILE *pf = NULL;
//
// We are checking the CD. Read the entire checkfile
// and cross check each entry against contents of the
// CD
//
line = pszCheck; for ( line = pszCheck; line != NULL ; line = strchr(line, '\n')) { if (line >= pszCheck + cbCheck - 1) { line = pszCheck; } if (*line == '\n') { line++; } if (*line == '\0') { break; } if (*line == '\n') { continue; // skip used entries & empty lines
} psz = line; while (*psz == ' ' || *psz == '\t') { psz++; // skip leading whitespace
} if (*psz == '\n') { continue; // skip empty line
}
//
// psz points to name sum size
//
sscanf(psz,"%s %x %x",partialname,&ChkFileSum,&ChkFileSize); GetFullPathName(partialname,sizeof(fullname),fullname,&FilePart);
strcpy(flatname,RootOfTree); strcat(flatname,"\\"); strcat(flatname,FilePart);
pf = fopen(flatname, "rb"); if (pf == NULL) { strcpy(flatname,RootOfTree); strcpy(flatname+2,"\\mstools\\bin"); strcat(flatname,RootOfTree+2); strcat(flatname,"\\"); strcat(flatname,FilePart);
pf = fopen(flatname, "rb"); if (pf == NULL) { if ( strstr(partialname,"idw\\") ) { goto nextone; } if ( strstr(partialname,"dump\\") ) { goto nextone; } crerror("Cannot open file(%d): %s", errno, FilePart); goto nextone; } } ActualSize = _filelength(_fileno(pf)); if (ActualSize == 0xffffffff) { crerror("Cannot determine size of file: %s %d", FilePart, errno); fclose(pf); goto nextone; } if (ActualSize != ChkFileSize) { crerror("Size differs (actual %lx, expected %lx): %s", ActualSize, ChkFileSize, FilePart); fclose(pf); goto nextone; } // ActualSum = CheckSumFile(pf, flatname, flatname, &ActualSize);
if (ActualSum != ChkFileSum) { crerror("Sum differs (actual %lx, expected %lx): %s", ActualSum, ChkFileSum, FilePart); } nextone:; } #endif /* 0 */
}
INT __cdecl main( INT argc, LPSTR argv[] )
{
UINT rc;
pfLog = stderr;
//
// Initialize check file entry root list entry.
//
CheckEntryRoot.Next = NULL; argv = ProcessParameters(&argc, argv); if (fCommand) { pfCheck = stdout; rc = 0; while (argc > 1) { argc--; argv++; _strlwr(*argv); if (!ProcessEntry(*argv, *argv)) { rc++; } }
} else { long l; time_t t = time(NULL); INT cfiles;
// If we are generating a check file, then generate it.
// Otherwise just check the release.
rc = ProcessCheckFile(&cfiles);
l = (long)(time(NULL) - t); printf("\n%3u files: %lu:%02lu\n", cfiles, l/60, l % 60); }
exit(rc); return rc; }
LPSTR pszUsage = "usage: checkrel [-?] display this message\n" " [-a] process all files\n" " [-c] command line contains file names to sum\n" " [-f chkfile] input/output check file override\n" " [-g] generate check file\n" " [-l logfile] stderr log file\n" " [-n] suppress check file arguments\n" " [-r pathname] root path override\n" " [-R] recursive file check\n" " [-m] master cdrom check\n" " [-i] don't warn about missing files\n" " [-x] don't warn about extra files\n" "";
VOID Usage(VOID) { fprintf(stderr, pszUsage); exit(1); }
VOID __cdecl crerror( LPSTR pszfmt, ... )
{
va_list argptr;
va_start(argptr, pszfmt); if (fInProgress && pfLog == stderr) { printf("\r%*s\r", cbProgress, ""); // clear line
fflush(stdout); fInProgress = FALSE; } fprintf(pfLog, "CheckRel: "); vfprintf(pfLog, pszfmt, argptr); fprintf(pfLog, "\n"); }
LPSTR * ProcessParameters(INT *pargc, LPSTR argv[]) { CHAR cswitch, c, *p;
while (*pargc > 1) { --(*pargc); p = *++argv; if ((cswitch = *p) == '/' || cswitch == '-') { while (c = *++p) { switch (c) { case '?': Usage();
case 'm': fCdCheck++; break; case 'a': fAll++; break; case 'c': fCommand++; break; case 'g': fGenerateCheck++; break; case 'n': fNoArgs++; break; case 'i': fPrintMissing = FALSE; break; case 'x': fPrintExtra = FALSE; break; case 'R': fRecurse++; break;
case 'f': if (p[1] == '\0' && --(*pargc)) { ++argv; if (pszCheckFileName == NULL) { pszCheckFileName = *argv; break; } crerror("Check file specified twice: -f %s -f %s", pszCheckFileName, *argv); Usage(); } Usage();
case 'l': if (p[1] == '\0' && --(*pargc)) { ++argv; if (pszLogFileName == NULL) { pfLog = fopen(*argv, "wt"); if (pfLog == NULL) { pfLog = stderr; crerror("Cannot open %s (%d)", *argv, errno); exit(2); } pszLogFileName = *argv; break; } crerror("Log file specified twice: -l %s -l %s", pszLogFileName, *argv); Usage(); } Usage();
case 'r': if (p[1] == '\0' && --(*pargc)) { ++argv; RootOfTree = _strdup(*argv); if (RootOfTree == NULL) { crerror("Out of memory for tree root"); exit(2); } break; }
Usage();
default: crerror("Invalid switch: -%c", c); Usage(); } } } else if (fCommand) { (*pargc)++; argv--; break; } else { crerror("Extra argument: %s", p); Usage(); } }
if (fCommand || fRecurse) { fGenerateCheck = TRUE; fAll = TRUE; }
return(argv); }
LPSTR ProcessArgBuf(LPSTR pszargs) { UINT i; INT argc; LPSTR pb; LPSTR psz; LPSTR *ppsz; LPSTR argv[20]; CHAR achbuf[512];
ppsz = argv; *ppsz++ = "Check File"; psz = achbuf; if ((pb = strchr(pszargs, '\n')) != NULL) { pb++; while (*pszargs == ' ' || *pszargs == '\t') { pszargs++; // skip leading white space
} if (*pszargs == '-') { for (;;) { i = strcspn(pszargs, " \t\n"); *ppsz++ = psz; if (ppsz - argv + 1 >= sizeof(argv)/sizeof(argv[0])) { crerror("Too many file args (%d)", ppsz - argv); exit(2); } if (psz - achbuf + i + 2 >= sizeof(achbuf)) { crerror("Too many file arg chars (%d)", sizeof(achbuf)); exit(2); } strncpy(psz, pszargs, i); psz += i; *psz++ = '\0'; if (pszargs[i] == '\n') { break; } pszargs += i + 1; while (*pszargs == ' ' || *pszargs == '\t') { pszargs++; // skip leading white space
} } *ppsz = NULL; argc = (INT)(ppsz - argv); if (!fNoArgs) { if (fGenerateCheck) { printf("Check file arguments:"); for (ppsz = &argv[1]; *ppsz != NULL; ppsz++) { printf(" %s", *ppsz); } printf("\n"); } ProcessParameters(&argc, argv); } } else { pb = NULL; } } return(pb); }
UINT ProcessCheckFile( LPINT pcfiles )
{
HANDLE hFind; DWORD FindSize; UINT cbFindPattern; LPSTR FindPattern; LPSTR pszRelPath; LPSTR pszFile; struct checkpath_s *pcp; struct component_s *pcm; CHAR FindName[MAX_PATH]; INT i;
*pcfiles = 0; if (!OpenCheckFile()) { return(1); }
cbFindPattern = MAX_PATH + strlen(".") + 1; FindPattern = malloc(cbFindPattern + 1); if (FindPattern == NULL) { crerror("Process: memory allocation (%d bytes) failed", cbFindPattern + 1); return(1); }
//
// Set address of relative path.
//
pszRelPath = &FindPattern[strlen(".") + 1]; i = 0; for (pcp = pcpPaths; pcp != NULL; pcp = pcp->pcpNext) { i = (i & ~31) + 32;
//
// Build the initial find pattern.
//
sprintf(FindPattern, "%s\\%s%s", ".", pcp->achDir, *pcp->achDir ? "\\" : "");
CHECKSTRLEN(FindPattern, cbFindPattern);
//
// Point past directory in find pattern.
//
pszFile = &FindPattern[strlen(FindPattern)]; for (pcm = pcp->pcmPat; pcm != NULL; pcm = pcm->pcmNext) { i++; if (pcm->fDir) { continue; // process only file patterns
}
if (!fAll && *pcm->achPat == '\0') { continue; // skip entry if no search pattern
}
// Complete FindPattern: "c:\nt\system32\*.exe"
if (fAll) strcpy(pszFile, "*.*");
else if (pcm->achPat) strcpy(pszFile, pcm->achPat);
else *pcm->achPat = '\0';
CHECKSTRLEN(FindPattern, cbFindPattern);
hFind = PortFindFirstFile(FindPattern, TRUE, FindName, &FindSize);
if (hFind == INVALID_HANDLE_VALUE) { if (pcm->fRequired) { crerror("Missing files: %s", pszRelPath); }
} else { do {
// append file name to FindPattern: "c:\nt\driver\foo.sys"
_strlwr(FindName); strcpy(pszFile, FindName); CHECKSTRLEN(FindPattern, cbFindPattern); if (fAll && strcmp(FindPattern, pszCheckFileName) == 0) { continue; }
*pcfiles += 1; if (!ProcessEntry(FindPattern, pszRelPath)) { crerror("ProcessEntry failed"); return(1); } } while (PortFindNextFile(hFind, TRUE, FindName, &FindSize)); PortFindClose(hFind); }
// if ignoring the supplied extensions, skip redundant patterns
if (fAll) { break; } }
strcpy(pszFile, "*.*"); // search for all directories
CHECKSTRLEN(FindPattern, cbFindPattern);
for (pcm = pcp->pcmPat; pcm != NULL; pcm = pcm->pcmNext) { if (pcm->fDir) { // process only directories
pcm->fFound = FALSE; } }
hFind = PortFindFirstFile(FindPattern, FALSE, FindName, &FindSize); *pszFile = '\0';
if (hFind != INVALID_HANDLE_VALUE) { do { if (strcmp(FindName, ".") == 0 || strcmp(FindName, "..") == 0) { continue; } _strlwr(FindName); for (pcm = pcp->pcmPat; pcm != NULL; pcm = pcm->pcmNext) { if (pcm->fDir && strcmp(FindName, pcm->achPat) == 0) { pcm->fFound = TRUE; break; } }
if (pcm == NULL && fPrintExtra) { crerror("Extra directory: %s%s", pszRelPath, FindName); }
} while (PortFindNextFile(hFind, FALSE, FindName, &FindSize)); PortFindClose(hFind); }
for (pcm = pcp->pcmPat; pcm != NULL; pcm = pcm->pcmNext) { if (pcm->fDir && !pcm->fFound && fPrintMissing) { crerror("Missing directory: %s%s", pszRelPath, pcm->achPat); } } }
if (!fGenerateCheck && MissingEntries()) { return(1); }
if (fInProgress) { printf("\n"); fInProgress = FALSE; }
return(0); }
BOOL OpenCheckFile( VOID )
{
UINT cbCheckName;
// If the check file name wasn't given, then construct it.
if (pszCheckFileName == NULL) { cbCheckName = strlen(".") + 1 + strlen(CHECK_NAME); pszCheckFileName = malloc(cbCheckName + 1); if (pszCheckFileName == NULL) { crerror("Open: Out of memory (%d bytes)", cbCheckName + 1); exit(2); } sprintf(pszCheckFileName, "%s\\%s", ".", CHECK_NAME); }
if (fRecurse) { RecursiveCheckHeader();
} else if (fGenerateCheck) { ReadCheckHeader(NULL); }
pfCheck = fopen(pszCheckFileName, fGenerateCheck||fRecurse? "wt" : "rt");
if (pfCheck == NULL) { crerror("Cannot open %s (%d)", pszCheckFileName, errno); return(FALSE); } if (fGenerateCheck) { WriteCheckHeader(pfCheck);
} else { ReadCheckHeader(pfCheck); if (fCdCheck) { CdCheck(); return FALSE; } }
return(TRUE); }
VOID ReadCheckHeader( FILE *pf )
{ DWORD cb; UINT cbread, cbactual; LPSTR pb;
if (pf == NULL) { cbCheck = strlen(pszDefaultDir) + 1; pszCheck = pszDefaultDir;
} else { cbCheck = _filelength(_fileno(pfCheck)) + 1; if ((DWORD) (size_t) cbCheck != cbCheck) { crerror("Open: check file too large (%ld bytes)", cbCheck); exit(2); }
pszCheck = malloc((size_t) cbCheck); if (pszCheck == NULL) { crerror("Open: memory allocation (%ld bytes) failed", cbCheck); exit(2); }
pb = pszCheck; cb = cbCheck - 1; while (cb) { cbread = (cb >= READ_BUFFER_SIZE)? READ_BUFFER_SIZE : (UINT) cb; cbactual = fread(pb, 1, cbread, pfCheck); if (cbread > cbactual) { cb -= cbread - cbactual; cbCheck -= cbread - cbactual; } pb += cbactual; cb -= cbactual; } *pb = '\0'; }
while ((pb = iscomment(pszCheck)) != NULL || (pb = ProcessArgBuf(pszCheck)) != NULL) { pszCheck = pb; // skip comment or parm line
}
if ((pb = ReadDirectory(pszCheck)) != NULL) { pszCheck = pb; // skip directory lines
} else if (ReadDirectory(pszDefaultDir) == NULL) { crerror("Bad internal data structure directory format"); exit(1); }
}
LPSTR ReadDirectory( LPSTR pszdir )
{ LPSTR pb;
if ((pb = ismatch(pszdir, "#directorystart")) == NULL) { return(NULL); }
pszdir = pb; // skip "start" line
while ((pb = ismatch(pszdir, "#directoryend")) == NULL) { if ((pb = iscomment(pszdir)) == NULL && (pb = AddDirectory(pszdir)) == NULL) { return(NULL); }
pszdir = pb; }
return(pb); }
LPSTR iscomment( LPSTR psz )
{
while (*psz == ' ' || *psz == '\t') { psz++; } if (*psz == '\n' || *psz == '/' && psz[1] == '/') { psz += strcspn(psz, "\n"); if (*psz == '\n') { psz++; } return(psz); // return start of next line
} return(NULL); // not a comment
}
LPSTR ismatch( LPSTR psz, LPSTR pszcompact )
{ while (*psz) { if (*psz == ' ' || *psz == '\t') { psz++; continue; } if (*psz != *pszcompact) { break; } psz++; pszcompact++; } if (*psz != '\n' || *pszcompact != '\0') { return(NULL); } return(psz + 1); }
LPSTR AddDirectory( LPSTR psz )
{
LPSTR pb; BOOL frequired; INT i, ch;
if ((pb = strchr(psz, '\n')) == NULL) { crerror("Directory data error"); return(NULL); }
while (*psz == ' ' || *psz == '\t') { psz++; }
frequired = TRUE; i = strcspn(psz, " \t\n"); ch = psz[i]; psz[i] = '\0'; if (ch != '\n') { frequired = !ismatch(psz + i + 1, "optional"); }
if (!AddEntry(psz, frequired)) { psz[i] = (char)ch; return(NULL); }
return(pb + 1); }
BOOL AddEntry(LPSTR psz, BOOL frequired )
{
BOOL f, fdir, freq1; INT i; CHAR chsep; CHAR achdir[MAX_PATH]; CHAR FullPath[MAX_PATH];
//
// If the leading character is ?, then prepend the name of the NT tree
// to the directory name.
//
if (*psz == '?') { strcpy(&FullPath[0], RootOfTree); strcat(&FullPath[0], psz + 1); psz = &FullPath[0]; }
achdir[0] = '\0'; do { i = strcspn(psz, "\\"); chsep = psz[i]; psz[i] = '\0'; fdir = freq1 = TRUE; if (chsep == '\0' || psz[i + 1] == '\0') { if (chsep == '\0') { fdir = FALSE; // at end & no trailing pathsep
} freq1 = frequired; // at end.
} f = AddComponent(achdir, psz, fdir, freq1); if (achdir[0] != '\0') { strcat(achdir, "\\"); } strcat(achdir, psz); psz[i] = chsep; if (!f) { return(FALSE); } psz += i + 1; } while(chsep != '\0' && *psz != '\0'); return(TRUE); }
//struct component_s {
// struct component_s *pcmNext; // next in linked list
// BOOL fDir; // TRUE if directory
// BOOL fRequired; // TRUE if must exist
// CHAR achPat[1]; // path component (subdir or pattern)
//};
//
//struct checkpath_s {
// struct checkpath_s *pcpNext; // next in linked list
// struct component_s *pcmPat; // subdirectories and file patterns
// CHAR achDir[1]; // root relative directory path
//};
BOOL AddComponent( LPSTR pszdir, LPSTR pszpat, BOOL fdir, BOOL frequired )
{ struct checkpath_s *pcp; struct checkpath_s *pcplast; struct component_s *pcm; struct component_s *pcmlast; INT r; INT t = 0;
pcplast = NULL; for (pcp = pcpPaths; pcp != NULL; pcp = pcp->pcpNext) { pcplast = pcp; if ((r = strcmp(pszdir, pcp->achDir)) <= 0) { break; } } if (pcp == NULL || r) { pcp = malloc(sizeof(*pcp) + strlen(pszdir)); if (pcp == NULL) { crerror("AddComponent: out of memory"); exit(2); } if (pcplast == NULL) { t |= 1; pcp->pcpNext = NULL; pcpPaths = pcp; } else { t |= 2; pcp->pcpNext = pcplast->pcpNext; pcplast->pcpNext = pcp; } pcp->pcmPat = NULL; strcpy(pcp->achDir, pszdir); }
pcmlast = NULL; if (pszpat != NULL) { for (pcm = pcp->pcmPat; pcm != NULL; pcm = pcm->pcmNext) { pcmlast = pcm; if ((r = strcmp(pszpat, pcm->achPat)) <= 0) { break; } } }
if (pcm == NULL || r) { if (pszpat != NULL) pcm = malloc(sizeof(*pcm) + strlen(pszpat)); else pcm = malloc(sizeof(*pcm)); if (pcm == NULL) { crerror("AddComponent: out of memory"); exit(2); } if (pcmlast == NULL) { t |= 4; pcm->pcmNext = NULL; pcp->pcmPat = pcm; } else { t |= 8; pcm->pcmNext = pcmlast->pcmNext; pcmlast->pcmNext = pcm; } pcm->fDir = fdir; pcm->fFound = FALSE; pcm->fRequired = frequired; if (pszpat == NULL) *pcm->achPat = '\000'; else strcpy(pcm->achPat, pszpat); } if (!frequired) { pcm->fRequired = frequired; } return(TRUE); }
VOID WriteCheckHeader(FILE *pf) { struct checkpath_s *pcp; struct component_s *pcm; INT ccol; CHAR achpath[MAX_PATH]; CHAR *psz; CHAR SavedChar;
if (fAll) { fprintf(pf, "-%s\n\n", fAll? "a" : ""); } fprintf(pf, "#directory start\n"); for (pcp = pcpPaths; pcp != NULL; pcp = pcp->pcpNext) { for (pcm = pcp->pcmPat; pcm != NULL; pcm = pcm->pcmNext) { sprintf(achpath, "%s%s%s%s", pcp->achDir, *pcp->achDir? "\\" : "", pcm->achPat, pcm->fDir? "\\" : "");
psz = strchr(achpath, '\\'); if (psz == NULL) { fprintf(pf, achpath);
} else { psz -= 1; SavedChar = *psz; *psz = '?'; fprintf(pf, psz); *psz = SavedChar; }
if (!pcm->fRequired) { ccol = strlen(achpath); fprintf(pf, " optional"); } fprintf(pf, "\n"); } } fprintf(pf, "#directory end\n\n"); }
BOOL ProcessEntry( LPSTR pszFullPath, LPSTR pszRelPath )
{
ULONG CheckSum; ULONG HeaderSum; ULONG FileSum; FILE *pf = NULL; UINT cbLine; CHAR *psz; ULONG Status;
if (!fGenerateCheck) { if (!FindEntry(pszRelPath, &FileSum)) { if (fPrintExtra) { crerror("Extra file: %s", pszRelPath); } return TRUE; } }
//
// Compute checksum of file.
//
Status = MapFileAndCheckSum(pszFullPath, &HeaderSum, &CheckSum); if (Status != CHECKSUM_SUCCESS) { crerror("Cannot open or map file %s", pszFullPath); return TRUE; }
if (fGenerateCheck) { cbLine = sprintf(OutputLine, "%s %lx\n", pszRelPath, CheckSum);
CHECKSTRLEN(OutputLine, sizeof(OutputLine));
psz = strchr(OutputLine, '\\'); if (fCommand || psz == NULL) { fwrite(OutputLine, 1, cbLine, pfCheck);
} else { psz -= 1; *psz = '?'; fwrite(psz, 1, (size_t)(cbLine - (psz - OutputLine)), pfCheck); } }
if (!fGenerateCheck) { if (CheckSum != FileSum) { crerror("Sum differs (actual %lx, expected %lx): %s", CheckSum, FileSum, pszRelPath); } } return TRUE; }
BOOL FindEntry( LPSTR pszRelPath, PULONG FileSum )
{
PCHECK_FILE_ENTRY LastEntry; WORD Length; PCHECK_FILE_ENTRY NextEntry;
//
// If this is the first trip through this code, then reset to the
// beginning of the check file.
//
if (CheckEntryRoot.Next == NULL) { if (ParseCheckFile() == 0) { return FALSE; } }
//
// Compute the length of the specified file name and loop through
// check file list for a matching entry.
//
Length = (WORD)strlen(pszRelPath); LastEntry = &CheckEntryRoot; NextEntry = LastEntry->Next; do {
//
// If the length and the file name match, then remove the entry from
// the list and return the file size and check sum value.
//
if (NextEntry->Length == Length) { if (strncmp(pszRelPath, NextEntry->Name, Length) == 0) { LastEntry->Next = NextEntry->Next; *FileSum = NextEntry->Sum; return TRUE; } }
LastEntry = NextEntry; NextEntry = NextEntry->Next; } while (NextEntry != NULL);
//
// The specified file is not in the check file.
//
return FALSE; }
DWORD MissingEntries( VOID )
{
DWORD Count = 0; PCHECK_FILE_ENTRY NextEntry;
//
// Scan through the check file list and display an error message for
// each missing file.
//
if (fPrintMissing) { NextEntry = CheckEntryRoot.Next; while (NextEntry != NULL) { crerror("Missing file: %s", NextEntry->Name); Count += 1; NextEntry = NextEntry->Next; } }
return Count; }
DWORD ParseCheckFile( VOID )
{
DWORD Count = 0; LPSTR pszline; LPSTR psz; PCHECK_FILE_ENTRY LastEntry; WORD Length; PCHECK_FILE_ENTRY NextEntry; WORD SizeOfRoot; DWORD Sum;
//
// If the check file contains no entries, then return.
//
if (*pszCheck != '\n') { return Count; }
//
// Scan through the check file and parse each file name, checksum, and
// size field.
//
SizeOfRoot = (WORD)strlen(RootOfTree); LastEntry = &CheckEntryRoot; for (pszline = pszCheck; pszline != NULL; pszline = strchr(pszline, '\n')) {
//
// Skip over the new line and search for the blank separator between
// the file name and the checksum.
//
pszline += 1; psz = strchr(pszline, ' ');
//
// If there is no blank separator, then the end of the check file has
// been reached.
//
if (psz == NULL) { return Count; }
//
// Compute the length and checksum of the file entry.
//
Length = (short)(psz - pszline); psz = atolx(psz + 1, &Sum);
//
// Allocate a check file entry for the specified file and insert it
// at the end of the check file entry list.
//
Count += 1; if (Count > CHECK_ENTRY_TABLE_SIZE) { crerror("Checkrel: Check Entry Table Overflow"); return 0; }
NextEntry = &CheckEntryTable[Count - 1]; NextEntry->Next = NULL; NextEntry->Sum = Sum;
//
// Form the file name from the NT root name and the specified path.
//
pszline[Length] = '\0'; if (*pszline == '?') { pszline += 1; NextEntry->Name = (CHAR *)malloc(SizeOfRoot + Length); if (NextEntry->Name == NULL) { crerror("Checkrel: failure to allocate check file entry"); return Count; }
strcpy(NextEntry->Name, RootOfTree); strcat(NextEntry->Name, pszline); Length += SizeOfRoot - 1;
} else { NextEntry->Name = pszline; }
NextEntry->Length = Length; LastEntry->Next = NextEntry; LastEntry = NextEntry; pszline = psz; }
return Count; }
LPSTR atolx( LPSTR psz, LPDWORD pul)
{
DWORD ul; char ch;
ul = 0; while (isxdigit(*psz)) { ch = *psz++; if (isdigit(ch)) { ch += 0 - '0';
} else if (islower(ch)) { ch += 10 - 'a';
} else { ch += 10 - 'A'; }
ul = (ul << 4) + ch; }
*pul = ul; return(psz); }
VOID RecursiveCheckHeader() { HANDLE hFind; DWORD FindSize; UINT cbFindPattern; LPSTR FindPattern; LPSTR pszRelPath; LPSTR pszFile; struct checkpath_s *pcp; struct component_s *pcm; CHAR FindName[MAX_PATH]; INT i;
cbFindPattern = strlen(".") + MAX_PATH; FindPattern = malloc(cbFindPattern + 1); if (FindPattern == NULL) { crerror("Process: memory allocation (%d bytes) failed", cbFindPattern + 1); return; }
// Set relative path pointer into FindPattern: "driver\elnkii.sys"
pszRelPath = &FindPattern[strlen(RootOfTree) + 1]; AddComponent(".", NULL, TRUE, TRUE);
i = 0; for (pcp = pcpPaths; pcp != NULL; pcp = pcp->pcpNext) { i = (i & ~31) + 32;
// Build Initial FindPattern directory path: "c:\nt\"
sprintf(FindPattern, "%s\\%s%s", ".", pcp->achDir, *pcp->achDir? "\\" : "");
CHECKSTRLEN(FindPattern, cbFindPattern);
// point past directory in FindPattern: "c:\nt\system32\"
pszFile = &FindPattern[strlen(FindPattern)];
strcpy(pszFile, "*.*"); // search for all directories
CHECKSTRLEN(FindPattern, cbFindPattern); hFind = PortFindFirstFile(FindPattern, FALSE, FindName, &FindSize); *pszFile = '\0';
if (hFind != INVALID_HANDLE_VALUE) { do { if (strcmp(FindName, ".") == 0 || strcmp(FindName, "..") == 0) { continue; } _strlwr(FindName); for (pcm = pcp->pcmPat; pcm != NULL; pcm = pcm->pcmNext) { if (pcm->fDir && strcmp(FindName, pcm->achPat) == 0) { pcm->fFound = TRUE; break; } } if (pcm == NULL) { AddComponent(FindName, NULL, TRUE, TRUE); } } while (PortFindNextFile(hFind, FALSE, FindName, &FindSize)); PortFindClose(hFind); } } if (fInProgress) { printf("\n"); fInProgress = FALSE; } return; }
#define ATTRMATCH(fnormal, attr) \
(!fNormal ^ ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0))
HANDLE PortFindFirstFile(LPSTR FindPattern, BOOL fNormal, LPSTR FindName, LPDWORD FindSize) { HANDLE hFind; WIN32_FIND_DATA wfd;
hFind = FindFirstFile(FindPattern, &wfd); if (hFind != INVALID_HANDLE_VALUE) { if (!ATTRMATCH(fNormal, wfd.dwFileAttributes)) { if (!PortFindNextFile(hFind, fNormal, FindName, FindSize)) { FindClose(hFind); return(INVALID_HANDLE_VALUE); } } else { strcpy(FindName, wfd.cFileName); *FindSize = wfd.nFileSizeLow; } } return(hFind); }
BOOL PortFindNextFile(HANDLE hFind, BOOL fNormal, LPSTR FindName, LPDWORD FindSize) { BOOL b; WIN32_FIND_DATA wfd;
do { b = FindNextFile(hFind, &wfd); } while (b && !ATTRMATCH(fNormal, wfd.dwFileAttributes)); if (b) { strcpy(FindName, wfd.cFileName); *FindSize = wfd.nFileSizeLow; } return(b); }
VOID PortFindClose(HANDLE hFind) { FindClose(hFind); }
|