summaryrefslogtreecommitdiffstats
path: root/private/ole32/stg/utils/chkdsk
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ole32/stg/utils/chkdsk
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ole32/stg/utils/chkdsk')
-rw-r--r--private/ole32/stg/utils/chkdsk/chkdsk.cxx374
-rw-r--r--private/ole32/stg/utils/chkdsk/chkdsk.def21
-rw-r--r--private/ole32/stg/utils/chkdsk/chkdsk.hxx116
-rw-r--r--private/ole32/stg/utils/chkdsk/depend.mk916
-rw-r--r--private/ole32/stg/utils/chkdsk/makefile106
5 files changed, 633 insertions, 0 deletions
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,&sect);
+ 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,&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 <name of docfile>\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; index<fatlen; index++)
+ {
+ pDIFat->GetFatSect(index,&sect);
+ 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,&sect);
+ }
+
+ 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; index<diflen; index++)
+ {
+ pDIFat->GetSect(index,&sect);
+ 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 <stdlib.h>
+#include <stdio.h>
+#include <msf.hxx>
+#include <filest.hxx>
+#include <header.hxx>
+#include <fat.hxx>
+#include <wchar.h>
+#include <handle.hxx>
+#include <dfmsp.hxx>
+#include <dir.hxx>
+
+#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)