From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ole32/stg/utils/chkdsk/chkdsk.cxx | 374 ++++++++++++++++++++++++++++++ private/ole32/stg/utils/chkdsk/chkdsk.def | 21 ++ private/ole32/stg/utils/chkdsk/chkdsk.hxx | 116 +++++++++ private/ole32/stg/utils/chkdsk/depend.mk9 | 16 ++ private/ole32/stg/utils/chkdsk/makefile | 106 +++++++++ 5 files changed, 633 insertions(+) create mode 100644 private/ole32/stg/utils/chkdsk/chkdsk.cxx create mode 100644 private/ole32/stg/utils/chkdsk/chkdsk.def create mode 100644 private/ole32/stg/utils/chkdsk/chkdsk.hxx create mode 100644 private/ole32/stg/utils/chkdsk/depend.mk9 create mode 100644 private/ole32/stg/utils/chkdsk/makefile (limited to 'private/ole32/stg/utils/chkdsk') diff --git a/private/ole32/stg/utils/chkdsk/chkdsk.cxx b/private/ole32/stg/utils/chkdsk/chkdsk.cxx new file mode 100644 index 000000000..a4e7719f5 --- /dev/null +++ b/private/ole32/stg/utils/chkdsk/chkdsk.cxx @@ -0,0 +1,374 @@ +//----------------------------------------------------------------------- +// +// File: chkdsk.cxx +// +// Contents: Sanity checking and recovery mechanism for multistream files +// +// Argument: +// +// History: 9-July-92 t-chrisy Created. +//------------------------------------------------------------------------ + +#include "chkdsk.hxx" + +// Global variables, declared as so for convenience. +CMSFHeader *pheader; +CFat *pFat; +CFat *pMiniFat; +CDirectory *pDir; +CDIFat *pDIFat; +BOOL fixdf; +CFatVector *pfvFat, *pfvMiniFat; +wchar_t pwcsDocfile[_MAX_PATH]; +DFLAGS df = DF_READWRITE | DF_DENYWRITE; + +extern SCODE DllMultiStreamFromCorruptedStream(CMStream MSTREAM_NEAR **ppms, + ILockBytes **pplstStream, + DWORD dwFlags); + +// Function Prototypes +void BuildFatTables(); +void MarkFatTables(); +void TreeWalk(CDirEntry *pde, SID sid); +BOOL GetOption(int argc, char *argv[]); +void Usage(char *pszProgName); +void DIFTable(); + +void main(int argc, char *argv[]) +{ + CFileStream *pfilestr; + CMStream MSTREAM_NEAR *pms; + SCODE scRc; + ILockBytes *pilb; + + // if fixdf returns yes, open docfile without a copy; + // otherwise, open docfile with a copy and operate on the copy. + fixdf = GetOption(argc,argv); + pfilestr = new CFileStream; + + // creating ILockBytes implementation for the given file + // Note: When a docfile is corrupted, the chkdsk utility + // calls the original CFileStream::Init. If any objects + // fail to instantiate, the approach is to call an + // alternative Init routine, which can force the instantiation + // of Directory and MiniFat objects. + + if (fixdf==TRUE) // -f specified, write allowed. + { + df &= ~0x03; + df |= DF_WRITE; + printf("Trying to open file...\n"); + scRc = pfilestr->Init(pwcsDocfile,RSF_OPEN,df); + if (FAILED(scRc)) + { + printf("Error creating ILockBytes.\n"); + exit(FAIL_CREATE_ILB); + } + } + else // open a read-only copy of filestream + { + df &= ~0x300; // clear access bits + df |= DF_DENYWRITE; + printf("Trying to open file...\n"); + scRc = pfilestr->Init(pwcsDocfile,RSF_OPEN,df); + if (FAILED(scRc)) + { + printf("Error creating ILockBytes.\n"); + exit(FAIL_CREATE_ILB); + } + else printf("Successfully created ILockBytes.\n"); + } + + scRc = pfilestr->Validate(); + if (scRc == STG_E_INVALIDHANDLE) + { + printf("Filestream signature is not valid.\n"); + exit(INVALID_DOCFILE); + } + + // CFileStream is essentially equivalent to ILockBytes. + pilb = (ILockBytes *) pfilestr; + scRc = DllMultiStreamFromStream(&pms,&pilb,0); + + if (FAILED(scRc)) + if (FAILED(scRc = DllMultiStreamFromCorruptedStream + (&pms,&pilb,0))) + { + exit(FAIL_CREATE_MULTISTREAM); + printf("Error creating a multistream.\n"); + } + + + // When an multi-stream is instantiated, the following control structures + // are automatically instantiated. + pheader = pms->GetHeader(); + pDir = pms->GetDir(); + pFat = pms->GetFat(); + pMiniFat = pms->GetMiniFat(); + pDIFat = pms->GetDIFat(); + + printf("\tBuilding fat tables...\n"); + BuildFatTables(); + printf("\tExamining the DIFat...\n"); + DIFTable(); + printf("\tExamining Fat and MiniFat chains...\n"); + MarkFatTables(); + printf("\tChecking completed.\n"); + delete(pfvFat); + delete(pfvMiniFat); + pfilestr->Release(); + printf("Memory blocks freed.\n"); +} + +void BuildFatTables() +{ + // Build two tables: one for Fat sectors, the other for Minifat sectors. + + FSINDEX FatLen,MiniFatLen; + FatLen = pheader->GetFatLength(); + MiniFatLen = pheader->GetMiniFatLength(); + pfvFat = new CFatVector(TABLE_SIZE); + pfvFat->Init(FatLen); + if (MiniFatLen == 0) + printf("No MiniFat to be checked.\n"); + else + { + pfvMiniFat = new CFatVector(TABLE_SIZE); + pfvMiniFat->Init(MiniFatLen); + } +} + +void MarkFatTables() +{ + CDirEntry *pde; + + // Walk through all the fat chains and mark the new table with the + // first SID number encountered. + + pDir->SidToEntry(SIDROOT,&pde); + TreeWalk(pde,SIDROOT); // pde points to the root entry now +} + +void TreeWalk(CDirEntry *pde, SID sid) +{ + CDirEntry *pchild, *pnext; + SID childsid, nextsid; + SCODE scRc,scRcM; + FSINDEX fitable,fioffset; + SECT sectentry, sect; + CFatSect *pfsec; + CFatVector *pfv; + CFat *pf; + ULONG uldesize; + + pDir->GetStart(sid,§); + uldesize = pde->GetSize(); + + if (uldesize >= MINISTREAMSIZE) // storage is in FAT + { + pfv = pfvFat; + pf = pFat; + } + else + { + pfv = pfvMiniFat; + pf = pMiniFat; + } + + // Check if LUID exceeds MaxLUID. If so, report the error. + if (pde->GetLuid() > pheader->GetLuid()) + printf("LUID for dir entry #%lu exceeds MAXLuid.\n",sid); + + while (sect < MAXREGSECT) + { + if (sid == SIDROOT) + break; // nothing should be in root stream + // Use fitable and fioffset to index into the fat (or minifat) + // table and mark the field with visited. + // at the same time, check for loops or crosslinks. + + //Note: 3 cases + fitable = sect / (TABLE_SIZE); + fioffset = sect % (TABLE_SIZE); + pfv->GetTable(fitable,&pfsec); // pfsec = ptr to CFatSect + sectentry = pfsec->GetSect(fioffset); + +// printf("\tsect = %lu \t \t sectentry = %lu \t stream_size = %lu\n", +// sect,sectentry, uldesize); + // Mark the FatTables as well as fixing the multistream. + // Right now, the routine only marks the FatTables. + //Note: 3 cases...but the last two cases may not + // be handled the same. + if (sectentry > MAXREGSECT) + pfsec->SetSect(fioffset,sid); + else if (sectentry == sid) + { + // discontinue the current stream chain by marking + // current SECT as ENDOFCHAIN. + pf->SetNext(sect,ENDOFCHAIN); + pfsec->SetSect(fioffset,ENDOFCHAIN); + printf("Loop detected at fat SECT %ul\n",sectentry); + } + else + { + pf->SetNext(sect,ENDOFCHAIN); + pfsec->SetSect(fioffset,ENDOFCHAIN); + printf("Crosslink detected at Fat SECT %lu with stream #%lu\n", + sect,sid); + } + // get the next sector to be examined + // !!!!! Need to use the Fat object to track down next sector + pf->GetNext(sect,§); + } + + // Recursively go down the tree + // pchild and pnext must point to the original tree for + // efficiency purposes. + + childsid = pde->GetChild(); + if (childsid != NOSTREAM) + { + pDir->SidToEntry(childsid,&pchild); + TreeWalk(pchild,childsid); + } + nextsid = pde->GetNext(); + if (nextsid != NOSTREAM) + { + pDir->SidToEntry(nextsid,&pnext); + TreeWalk(pnext,nextsid); + } + + if (fixdf==TRUE) + { + scRc = pFat->Flush(); + scRcM = pMiniFat->Flush(); + if (FAILED(scRc) || FAILED(scRcM)) + printf("Failed to write all modified FatSects out to stream.\n"); + } +} + +BOOL GetOption(int argc, char *argv[]) +{ + char *pszArg, *pszProgName; + BOOL ArgsOK = FALSE, Fix = FALSE; + pszProgName = *argv++; + + while ((pszArg = *argv++) != NULL) + { + if (*pszArg == '-' || *pszArg == '/') + { + switch (tolower(*(++pszArg))) + { + case 'f': // fix the errors. + Fix = TRUE; // open file with read-only without a copy. + break; + case 'n': // name of the docfile to be opened. + // path of the filename. + mbstowcs(pwcsDocfile,++pszArg,_MAX_PATH); + Fix = FALSE; + ArgsOK = TRUE; + break; + default: + break; + } + } + else ArgsOK = FALSE; + } + if (ArgsOK == FALSE) + { + printf("0 argument or invalid command line argument.\n"); + Usage(pszProgName); + exit(INVALID_ARG); + } + return Fix; +} + +void Usage(char *pszProgName) +{ + printf("Usage: %s\n", pszProgName); + printf(" -f fix requested by user.\n"); + printf(" -n \n"); + printf("The -n option must be specified.\n"); +} + + +void DIFTable() // August 11, 1992 +{ + // Walk through each DIF sector array to detect loops and + // crosslinks. + SCODE scRc; + BOOL FatOK = TRUE; + SECT sect, sectentry; + FSINDEX diflen, fatlen, fitable, fioffset, index, minifatlen,uldif,ulr; + CFatSect *pfsec; + + diflen = pheader->GetDifLength(); + fatlen = pheader->GetFatLength(); + minifatlen = pheader->GetMiniFatLength(); + + // testing the validity of pheader->GetDifLength + if (fatlen > CSECTFAT) // diflen > 0 + { + ulr = ( ((fatlen - CSECTFAT)%TABLE_SIZE) > 0 )? 1: 0; + uldif = CSECTFAT + (fatlen-CSECTFAT)/TABLE_SIZE + ulr; + } + else uldif = 0; + if (diflen!=uldif) + printf("DIFLEN in header is inconsistent with FatLEN.\n"); + + for (index=0; indexGetFatSect(index,§); + if (sect < MAXREGSECT) + { + fitable = sect / TABLE_SIZE; + fioffset = sect % TABLE_SIZE; + pfvFat->GetTable(fitable,&pfsec); // pfsec = ptr to CFatSect + sectentry = pfsec->GetSect(fioffset); + + if (sectentry > MAXREGSECT) + pfsec->SetSect(fioffset,SIDFAT); + else + { + printf("Crosslink! DIF index #%u points\n",index); + printf(" to the same location %u.\n", sect); + FatOK = FALSE; + } + } + pDIFat->GetFatSect(index+1,§); + } + + if (FatOK == TRUE) + printf("No errors found in DIFat.\n"); + + // Walk through the terminating cells in each sector array to check + // the correctness of chaining. + printf("\tWalking through DIFTable chain.\n"); + for (index = 0; indexGetSect(index,§); + fitable = sect/TABLE_SIZE; + fioffset = sect%TABLE_SIZE; + pfvFat->GetTable(fitable,&pfsec); // pfsec = ptr to CFatSect + sectentry = pfsec->GetSect(fioffset); + if ((sectentry!=ENDOFCHAIN) && (index == diflen-1)) + printf("ERROR! ENDOFCHAIN expected at the end of DIFat.\n."); + pDIFat->SetFatSect(fioffset,SIDDIF); + pfsec->SetSect(fioffset,SIDDIF); + } + if (fixdf==TRUE) + { + scRc = pDIFat->FlushAll(); + if (FAILED(scRc)) + printf("Failed to write all modified FatSects out to stream.\n"); + } +} + + + + + + + + + diff --git a/private/ole32/stg/utils/chkdsk/chkdsk.def b/private/ole32/stg/utils/chkdsk/chkdsk.def new file mode 100644 index 000000000..7783c57d0 --- /dev/null +++ b/private/ole32/stg/utils/chkdsk/chkdsk.def @@ -0,0 +1,21 @@ +NAME CHKDSK +#ifndef FLAT +EXETYPE WINDOWS +//STUB 'WINSTUB.EXE' + +CODE MOVABLE +DATA MULTIPLE MOVABLE + +HEAPSIZE 16384 +STACKSIZE 8192 +#else +EXETYPE NT +SUBSYSTEM WINDOWSCHAR + +CODE MOVABLE +DATA MULTIPLE MOVABLE + +HEAPSIZE 16384 +STACKSIZE 8192 +#endif + diff --git a/private/ole32/stg/utils/chkdsk/chkdsk.hxx b/private/ole32/stg/utils/chkdsk/chkdsk.hxx new file mode 100644 index 000000000..e7660618f --- /dev/null +++ b/private/ole32/stg/utils/chkdsk/chkdsk.hxx @@ -0,0 +1,116 @@ +//----------------------------------------------------------------------- +// +// File: chkdsk.cxx +// +// Contents: Sanity checking and recovery mechanism for multistream files +// +// Argument: +// +// History: August-21-92 t-chrisy Created. +//------------------------------------------------------------------------ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INVALID_DOCFILE 1 +#define FAIL_CREATE_MULTISTREAM 2 +#define INVALID_ARG 3 +#define FAIL_CREATE_ILB 4 +#define NONE 0 + +#define TABLE_SIZE (SECTORSIZE/sizeof(SECT)) + + +//+------------------------------------------------------------------------- +// +// Function: DllMultiStreamFromCorruptedStream +// +// Synopsis: Create a new multistream instance from an existing stream. +// This is used to reopen a stored multi-stream. +// +// Effects: Creates a new CMStream instance +// +// Arguments: [ppms] -- Pointer to storage for return of multistream +// [pplstStream] -- Stream to be used by multi-stream for +// reads and writes +// [dwFlags] - Startup flags +// +// Returns: STG_E_INVALIDHEADER if signature on pStream does not +// match. +// STG_E_UNKNOWN if there was a problem in setup. +// S_OK if call completed OK. +// +// Algorithm: Check the signature on the pStream and on the contents +// of the pStream. If either is a mismatch, return +// STG_E_INVALIDHEADER. +// Create a new CMStream instance and run the setup function. +// If the setup function fails, return STG_E_UNKNOWN. +// Otherwise, return S_OK. +// +// History: 17-Aug-91 PhilipLa Created. +// 26-Aug-92 t-chrisy modifed to reduce ErrJmp +// Notes: +// +//-------------------------------------------------------------------------- + +SCODE DllMultiStreamFromCorruptedStream(CMStream MSTREAM_NEAR **ppms, + ILockBytes **pplstStream, + DWORD dwFlags) +{ + SCODE sc; + CMStream MSTREAM_NEAR *temp; + + BOOL fConvert = ((dwFlags & RSF_CONVERT) != 0); + BOOL fDelay = ((dwFlags & RSF_DELAY) != 0); + BOOL fTruncate = ((dwFlags & RSF_TRUNCATE) != 0); + + msfDebugOut((DEB_ITRACE,"In DllMultiStreamFromStream\n")); + + msfMem(temp = new CMStream(pplstStream, NULL, SECTORSHIFT)); + + ULARGE_INTEGER ulSize; + (*pplstStream)->GetSize(&ulSize); + msfAssert(ULIGetHigh(ulSize) == 0); + msfDebugOut((DEB_ITRACE,"Size is: %lu\n",ULIGetLow(ulSize))); + + do + { + if ((ULIGetLow(ulSize) != 0) && (fConvert)) + { + msfChk(temp->InitConvert(fDelay)); + break; + } + + if ((ULIGetLow(ulSize) == 0) || (fTruncate)) + { + msfChk(temp->InitNew(fDelay)); + break; + } + msfChk(temp->Init()); + if (FAILED(sc)) + msfDebugOut((DEB_ITRACE,"Fail to initialize multistream.\n")); + } + while (FALSE); + + *ppms = temp; + + msfDebugOut((DEB_ITRACE,"Leaving DllMultiStreamFromStream\n")); + + if (fConvert && ULIGetLow(ulSize) && !fDelay) + return STG_I_CONVERTED; + + return S_OK; + +Err: + delete temp; + return sc; +} + + diff --git a/private/ole32/stg/utils/chkdsk/depend.mk9 b/private/ole32/stg/utils/chkdsk/depend.mk9 new file mode 100644 index 000000000..891c908d5 --- /dev/null +++ b/private/ole32/stg/utils/chkdsk/depend.mk9 @@ -0,0 +1,16 @@ +# +# Source files +# + +$(OBJDIR)\chkdsk.obj $(OBJDIR)\chkdsk.lst: chkdsk.cxx \ + $(COMMON)\H\WIN40\scode.h $(COMMON)\H\WIN40\w4crt.h \ + $(COMMON)\iH\debnot.h $(CRTINC)\malloc.h $(CRTINC)\stdarg.h \ + $(CRTINC)\stdio.h $(CRTINC)\stdlib.h $(CRTINC)\string.h \ + $(OLE)\h\dblink.hxx $(OLE)\h\dfmsp.hxx $(OLE)\h\dir.hxx \ + $(OLE)\h\error.hxx $(OLE)\h\filest.hxx $(OLE)\h\handle.hxx \ + $(OLE)\h\header.hxx $(OLE)\h\luid.hxx $(OLE)\h\msf.hxx \ + $(OLE)\h\msffunc.hxx $(OLE)\h\ole.hxx $(OLE)\h\publist.hxx \ + $(OLE)\h\vect.hxx $(OLE)\h\wchar.h $(OLE)\msf\fat.hxx \ + $(OLE2H)\dvobj.h $(OLE2H)\iid.h $(OLE2H)\moniker.h $(OLE2H)\ole2.h \ + $(OLE2H)\stdobj.h $(OLE2H)\storage.h chkdsk.hxx + diff --git a/private/ole32/stg/utils/chkdsk/makefile b/private/ole32/stg/utils/chkdsk/makefile new file mode 100644 index 000000000..25c75020e --- /dev/null +++ b/private/ole32/stg/utils/chkdsk/makefile @@ -0,0 +1,106 @@ +########################################################################## +# +# Copyright (C) 1992 - 1992, Microsoft Corporation. +# +# All rights reserved. +# +############################################################################ + +EXENAME = chkdsk + +# +# Set up include directories and roots for includes.exe +# + +CFLAGS = -DCHKDSK +CINC = $(CINC) -I$(COMMON)\h -I$(OLE)\h -I$(OLE2H) -I$(OLE)\msf +INCLUDES_ROOTS = -P$$(OLE2H)=$(OLE2H) -P$$(OLE)=$(OLE) + +# +# Default OLE2 paths +# + +!ifndef OLE2H +!if "$(OPSYS)" == "NT" +OLE2H = $(OLE)\ole2flat +!else +OLE2H = $(OLE)\ole2h +!endif +!endif +!ifndef OLE2BIN +!if "$(OPSYS)" == "NT" +OLE2BIN = $(OLE)\ole2flat +!else +OLE2BIN = $(OLE)\ole2h +!endif +!endif + +# +# Defining NO_WINMAIN suppresses linking with astartw.obj +# + +NO_WINMAIN = 1 + +# +# Copy built exes to this directory +# + +EXECOPY = $(OLETARGET)\$(OBJDIR) + +# +# Name of target. Include an extension (.dll, .lib, .exe) +# If the target is part of the release, set RELEASE to 1. +# + +TARGET = $(EXENAME).exe +RELEASE = + +# +# C compiler flags +# + +!if "$(OPSYS)" == "NT" + + +CFLAGS = -DUL64 +!endif + +# +# Source files. Remember to prefix each name with .\ +# + +CXXFILES = .\$(EXENAME).cxx + +# +# Libraries and other object files to link. +# + +LIBS = $(DFLIB)\ +!if "$(OPSYS)" != "NT" + $(OLE)\common\$(OBJDIR)\dfcommon.lib\ + $(OLE)\msf\$(OBJDIR)\msf.lib\ + $(COMMON)\ilib\$(OBJDIR)\misc.lib\ + $(OLE)\docfile\$(OBJDIR)\docfile.lib\ + $(OLE)\wclib\$(OBJDIR)\wclib.lib\ + $(RTLIBEXEQ)\ + $(OSLIBDIR)\toolhelp.lib\ + $(OLE2BIN)\stdobj.lib\ +!else + $(CAIROLIB)\ +!endif + + +OBJFILES = \ +!if "$(OPSYS)" != "NT" + $(OLE2BIN)\stdalloc.obj\ +!endif + $(OLE2BIN)\iid.obj + +# +# Set MULTIDEPEND to support multiple build targets +# + +MULTIDEPEND = 1 + +!include $(COMMON)\src\win40.mk +!include $(DEPENDFILE) -- cgit v1.2.3