#ifndef WIN32 #define RC_INVOKED #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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); }