You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
479 lines
14 KiB
479 lines
14 KiB
//+------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1993 - 1993
|
|
//
|
|
// File: tstgdir.cpp
|
|
//
|
|
// Contents: Recursive directory display of a storage
|
|
// document
|
|
//
|
|
// Functions: main
|
|
//
|
|
// History: 04 Nov 94 - Created by philh
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include <windows.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
#include <time.h>
|
|
|
|
|
|
|
|
static int indent = 0;
|
|
static BOOL fVerbose = FALSE;
|
|
static BOOL fDebug = FALSE;
|
|
static BOOL fRead = FALSE;
|
|
static BOOL fReadVerbose = FALSE;
|
|
static BOOL fBrief = FALSE;
|
|
|
|
#define READ_BUF_SIZE 10000
|
|
static BYTE readBuf[READ_BUF_SIZE];
|
|
|
|
static CLSID NullClsid;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
SCODE sc;
|
|
char *text;
|
|
} StatusCodeText;
|
|
|
|
static StatusCodeText scodes[] =
|
|
{
|
|
S_OK, "S_OK",
|
|
S_FALSE, "S_FALSE",
|
|
STG_E_INVALIDFUNCTION, "STG_E_INVALIDFUNCTION",
|
|
STG_E_FILENOTFOUND, "STG_E_FILENOTFOUND",
|
|
STG_E_PATHNOTFOUND, "STG_E_PATHNOTFOUND",
|
|
STG_E_TOOMANYOPENFILES, "STG_E_TOOMANYOPENFILES",
|
|
STG_E_ACCESSDENIED, "STG_E_ACCESSDENIED",
|
|
STG_E_INVALIDHANDLE, "STG_E_INVALIDHANDLE",
|
|
STG_E_INSUFFICIENTMEMORY, "STG_E_INSUFFICIENTMEMORY",
|
|
STG_E_INVALIDPOINTER, "STG_E_INVALIDPOINTER",
|
|
STG_E_NOMOREFILES, "STG_E_NOMOREFILES",
|
|
STG_E_DISKISWRITEPROTECTED, "STG_E_DISKISWRITEPROTECTED",
|
|
STG_E_SEEKERROR, "STG_E_SEEKERROR",
|
|
STG_E_WRITEFAULT, "STG_E_WRITEFAULT",
|
|
STG_E_READFAULT, "STG_E_READFAULT",
|
|
STG_E_SHAREVIOLATION, "STG_E_SHAREVIOLATION",
|
|
STG_E_LOCKVIOLATION, "STG_E_LOCKVIOLATION",
|
|
STG_E_FILEALREADYEXISTS, "STG_E_FILEALREADYEXISTS",
|
|
STG_E_INVALIDPARAMETER, "STG_E_INVALIDPARAMETER",
|
|
STG_E_MEDIUMFULL, "STG_E_MEDIUMFULL",
|
|
STG_E_ABNORMALAPIEXIT, "STG_E_ABNORMALAPIEXIT",
|
|
STG_E_INVALIDHEADER, "STG_E_INVALIDHEADER",
|
|
STG_E_INVALIDNAME, "STG_E_INVALIDNAME",
|
|
STG_E_UNKNOWN, "STG_E_UNKNOWN",
|
|
STG_E_UNIMPLEMENTEDFUNCTION, "STG_E_UNIMPLEMENTEDFUNCTION",
|
|
STG_E_INVALIDFLAG, "STG_E_INVALIDFLAG",
|
|
STG_E_INUSE, "STG_E_INUSE",
|
|
STG_E_NOTCURRENT, "STG_E_NOTCURRENT",
|
|
STG_E_REVERTED, "STG_E_REVERTED",
|
|
STG_E_CANTSAVE, "STG_E_CANTSAVE",
|
|
STG_E_OLDFORMAT, "STG_E_OLDFORMAT",
|
|
STG_E_OLDDLL, "STG_E_OLDDLL",
|
|
STG_E_SHAREREQUIRED, "STG_E_SHAREREQUIRED",
|
|
STG_E_NOTFILEBASEDSTORAGE, "STG_E_NOTFILEBASEDSTORAGE",
|
|
STG_E_EXTANTMARSHALLINGS, "STG_E_EXTANTMARSHALLINGS",
|
|
E_NOINTERFACE, "E_NOINTERFACE",
|
|
STG_S_CONVERTED, "STG_S_CONVERTED"
|
|
};
|
|
#define NSCODETEXT (sizeof(scodes)/sizeof(scodes[0]))
|
|
|
|
|
|
// Convert a HRESULT to text
|
|
static char *hResultText(HRESULT hResult)
|
|
{
|
|
static char buf[80];
|
|
int i;
|
|
|
|
for (i = 0; i<NSCODETEXT; i++)
|
|
if (scodes[i].sc == hResult)
|
|
return scodes[i].text;
|
|
sprintf(buf, "%lx", hResult);
|
|
return buf;
|
|
}
|
|
|
|
static void DirPrintf(const char * Format, ...)
|
|
{
|
|
int i = indent;
|
|
va_list pArgs;
|
|
char aBuf[256];
|
|
|
|
while (i-- > 0)
|
|
printf(" ");
|
|
|
|
va_start( pArgs, Format );
|
|
vsprintf(aBuf, Format, pArgs);
|
|
printf("%s", aBuf);
|
|
}
|
|
|
|
|
|
#pragma pack(1)
|
|
struct SplitGuid
|
|
{
|
|
DWORD dw1;
|
|
WORD w1;
|
|
WORD w2;
|
|
BYTE b[8];
|
|
};
|
|
#pragma pack()
|
|
|
|
static char *GuidText(GUID *pguid)
|
|
{
|
|
static char buf[39];
|
|
SplitGuid *psg = (SplitGuid *)pguid;
|
|
|
|
sprintf(buf, "{%08lX-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X}",
|
|
psg->dw1, psg->w1, psg->w2, psg->b[0], psg->b[1], psg->b[2],
|
|
psg->b[3], psg->b[4], psg->b[5], psg->b[6], psg->b[7]);
|
|
return buf;
|
|
}
|
|
|
|
static char *FileTimeText(FILETIME *pft)
|
|
{
|
|
static char buf[80];
|
|
FILETIME ftLocal;
|
|
struct tm ctm;
|
|
SYSTEMTIME st;
|
|
|
|
FileTimeToLocalFileTime(pft, &ftLocal);
|
|
if (FileTimeToSystemTime(&ftLocal, &st))
|
|
{
|
|
ctm.tm_sec = st.wSecond;
|
|
ctm.tm_min = st.wMinute;
|
|
ctm.tm_hour = st.wHour;
|
|
ctm.tm_mday = st.wDay;
|
|
ctm.tm_mon = st.wMonth-1;
|
|
ctm.tm_year = st.wYear-1900;
|
|
ctm.tm_wday = st.wDayOfWeek;
|
|
ctm.tm_yday = 0;
|
|
ctm.tm_isdst = 0;
|
|
strcpy(buf, asctime(&ctm));
|
|
buf[strlen(buf)-1] = 0;
|
|
}
|
|
else
|
|
sprintf(buf, "<FILETIME %08lX:%08lX>", pft->dwHighDateTime,
|
|
pft->dwLowDateTime);
|
|
return buf;
|
|
}
|
|
|
|
static void DispStatStg(STATSTG *pStatStg)
|
|
{
|
|
char *szSTGTY;
|
|
|
|
switch (pStatStg->type) {
|
|
case STGTY_STORAGE:
|
|
szSTGTY = "STGTY_STORAGE";
|
|
break;
|
|
case STGTY_STREAM:
|
|
szSTGTY = "STGTY_STREAM";
|
|
break;
|
|
case STGTY_LOCKBYTES:
|
|
szSTGTY = "STGTY_LOCKBYTES";
|
|
break;
|
|
default:
|
|
szSTGTY = "STGTY_???";
|
|
}
|
|
|
|
|
|
if (pStatStg->type == STGTY_STREAM)
|
|
DirPrintf("%S %s size:%ld\n", pStatStg->pwcsName, szSTGTY,
|
|
pStatStg->cbSize.LowPart);
|
|
else {
|
|
DirPrintf("%S %s\n", pStatStg->pwcsName, szSTGTY);
|
|
if (!fBrief && pStatStg->clsid != NullClsid)
|
|
DirPrintf("CLSID: %s\n", GuidText(&pStatStg->clsid));
|
|
}
|
|
if (fVerbose) {
|
|
DirPrintf("size: %ld,%ld Mode: %lx StateBits: %lx Locks: %ld\n",
|
|
pStatStg->cbSize.HighPart, pStatStg->cbSize.LowPart,
|
|
pStatStg->grfMode, pStatStg->grfStateBits,
|
|
pStatStg->grfLocksSupported);
|
|
if ((pStatStg->mtime.dwHighDateTime != 0) ||
|
|
(pStatStg->mtime.dwLowDateTime != 0))
|
|
DirPrintf("mtime %s\n", FileTimeText(&pStatStg->mtime));
|
|
if ((pStatStg->ctime.dwHighDateTime != 0) ||
|
|
(pStatStg->ctime.dwLowDateTime != 0))
|
|
DirPrintf("ctime %s\n", FileTimeText(&pStatStg->ctime));
|
|
if ((pStatStg->atime.dwHighDateTime != 0) ||
|
|
(pStatStg->atime.dwLowDateTime != 0))
|
|
DirPrintf("atime %s\n", FileTimeText(&pStatStg->atime));
|
|
}
|
|
}
|
|
|
|
#define CROW 16
|
|
void BinText(ULONG cbSize, BYTE *pb)
|
|
{
|
|
ULONG cb, i;
|
|
|
|
while (cbSize > 0)
|
|
{
|
|
cb = min(CROW, cbSize);
|
|
cbSize -= cb;
|
|
for (i = 0; i<cb; i++)
|
|
printf(" %02X", pb[i]);
|
|
for (i = cb; i<CROW; i++)
|
|
printf(" ");
|
|
printf(" '");
|
|
for (i = 0; i<cb; i++)
|
|
if (pb[i] >= 0x20 && pb[i] <= 0x7f)
|
|
printf("%c", pb[i]);
|
|
else
|
|
printf(".");
|
|
pb += cb;
|
|
printf("'\n");
|
|
}
|
|
}
|
|
|
|
void DispStream(IStream *pstm);
|
|
void DispStorage(IStorage *pstg);
|
|
|
|
|
|
void DispStream(IStream *pstm)
|
|
{
|
|
HRESULT hResult;
|
|
STATSTG statStg;
|
|
|
|
hResult = pstm->Stat(&statStg, STATFLAG_DEFAULT);
|
|
if (SUCCEEDED(hResult)) {
|
|
DispStatStg(&statStg);
|
|
if (statStg.pwcsName != NULL)
|
|
CoTaskMemFree(statStg.pwcsName);
|
|
} else {
|
|
DirPrintf("Stat => %lx\n", hResult);
|
|
return;
|
|
}
|
|
|
|
if (fRead) {
|
|
ULONG ulTotalRead = 0;
|
|
ULONG ulBytesRead;
|
|
int i = 0;
|
|
while (TRUE) {
|
|
ulBytesRead = 0;
|
|
hResult = pstm->Read(readBuf, READ_BUF_SIZE, &ulBytesRead);
|
|
if (FAILED(hResult)) {
|
|
DirPrintf("IStream->Read => %lx\n", hResult);
|
|
break;
|
|
}
|
|
if (fReadVerbose) {
|
|
DirPrintf("%lu bytes starting at offset: 0x%08lX\n",
|
|
ulBytesRead, ulTotalRead);
|
|
BinText(ulBytesRead, readBuf);
|
|
}
|
|
ulTotalRead += ulBytesRead;
|
|
if (ulBytesRead < READ_BUF_SIZE)
|
|
break;
|
|
i++;
|
|
if (i % 10 == 0) {
|
|
if (fReadVerbose)
|
|
DirPrintf("Read %ld bytes\n", ulTotalRead);
|
|
else
|
|
DirPrintf("Read %ld bytes\r", ulTotalRead);
|
|
}
|
|
}
|
|
DirPrintf("Read %ld bytes\n", ulTotalRead);
|
|
}
|
|
}
|
|
|
|
|
|
void DispStorage(IStorage *pstg)
|
|
{
|
|
HRESULT hResult;
|
|
DWORD grfMode;
|
|
STATSTG statStg;
|
|
CLSID readClsid;
|
|
|
|
IStorage *pstgChild;
|
|
IStream *pstmChild;
|
|
IEnumSTATSTG *penumStatStg;
|
|
|
|
hResult = pstg->Stat(&statStg, STATFLAG_DEFAULT);
|
|
if (SUCCEEDED(hResult)) {
|
|
DispStatStg(&statStg);
|
|
if (statStg.pwcsName != NULL)
|
|
CoTaskMemFree(statStg.pwcsName);
|
|
} else {
|
|
DirPrintf("Stat => %s\n", hResultText(hResult));
|
|
return;
|
|
}
|
|
|
|
hResult = ReadClassStg(pstg, &readClsid);
|
|
if (SUCCEEDED(hResult)) {
|
|
if (readClsid != statStg.clsid)
|
|
DirPrintf("ReadClassStg CLSID: %s\n", GuidText(&readClsid));
|
|
} else
|
|
DirPrintf("ReadClassStg => %s\n", hResultText(hResult));
|
|
|
|
indent += 2;
|
|
hResult = pstg->EnumElements(0, NULL, 0, &penumStatStg);
|
|
if (FAILED(hResult))
|
|
DirPrintf("EnumElements => %lx\n", hResult);
|
|
else {
|
|
while(TRUE) {
|
|
hResult = penumStatStg->Next(1, &statStg, NULL);
|
|
if (hResult == S_FALSE) break;
|
|
if (FAILED(hResult)) {
|
|
DirPrintf("EnumStatStg => %lx\n", hResult);
|
|
break;
|
|
} else {
|
|
switch (statStg.type) {
|
|
case STGTY_STORAGE:
|
|
if ((statStg.pwcsName == NULL) ||
|
|
(statStg.pwcsName[0] == L'.'))
|
|
DispStatStg(&statStg);
|
|
else {
|
|
grfMode =
|
|
STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE;
|
|
hResult = pstg->OpenStorage(
|
|
statStg.pwcsName,
|
|
NULL, // pstgPriority
|
|
grfMode,
|
|
NULL, // snbExclude
|
|
0, // dwReserved
|
|
&pstgChild);
|
|
if (FAILED(hResult)) {
|
|
DispStatStg(&statStg);
|
|
DirPrintf("OpenStorage => %lx\n", hResult);
|
|
} else {
|
|
if (fDebug) {
|
|
DirPrintf("--- Enum ---\n");
|
|
DispStatStg(&statStg);
|
|
DirPrintf("--- Enum ---\n");
|
|
}
|
|
DispStorage(pstgChild);
|
|
pstgChild->Release();
|
|
}
|
|
}
|
|
break;
|
|
case STGTY_STREAM:
|
|
if ((statStg.pwcsName == NULL) ||
|
|
(statStg.pwcsName[0] == L'.'))
|
|
DispStatStg(&statStg);
|
|
else {
|
|
grfMode =
|
|
STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE;
|
|
hResult = pstg->OpenStream(
|
|
statStg.pwcsName,
|
|
NULL, // pReserved1
|
|
grfMode,
|
|
0, // dwReserved2
|
|
&pstmChild);
|
|
if (FAILED(hResult)) {
|
|
DispStatStg(&statStg);
|
|
DirPrintf("OpenStream => %lx\n", hResult);
|
|
} else {
|
|
if (fDebug) {
|
|
DirPrintf("--- Enum ---\n");
|
|
DispStatStg(&statStg);
|
|
DirPrintf("--- Enum ---\n");
|
|
}
|
|
DispStream(pstmChild);
|
|
pstmChild->Release();
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
DispStatStg(&statStg);
|
|
}
|
|
if (statStg.pwcsName != NULL)
|
|
CoTaskMemFree(statStg.pwcsName);
|
|
}
|
|
} // while loop
|
|
penumStatStg->Release();
|
|
}
|
|
indent -= 2;
|
|
}
|
|
|
|
static void Usage(void)
|
|
{
|
|
printf("Usage: tstgdir [options] <filename>\n");
|
|
printf("Options are:\n");
|
|
printf(" -h - This message\n");
|
|
printf(" -b - Brief\n");
|
|
printf(" -d - Debug\n");
|
|
printf(" -r - Read streams (don't display)\n");
|
|
printf(" -R - Read streams (display contents)\n");
|
|
printf(" -v - Verbose\n");
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
int _cdecl main(int argc, char * argv[])
|
|
{
|
|
WCHAR wcsFile[_MAX_PATH];
|
|
HRESULT hResult;
|
|
DWORD grfMode;
|
|
IStorage *pstgRoot;
|
|
|
|
wcscpy(wcsFile, L"");
|
|
while (--argc>0)
|
|
{
|
|
if (**++argv == '-')
|
|
{
|
|
switch(argv[0][1])
|
|
{
|
|
case 'b':
|
|
fBrief = TRUE;
|
|
break;
|
|
case 'd':
|
|
fDebug = TRUE;
|
|
break;
|
|
case 'R':
|
|
fReadVerbose = TRUE;
|
|
case 'r':
|
|
fRead = TRUE;
|
|
break;
|
|
case 'v':
|
|
fVerbose = TRUE;
|
|
break;
|
|
case 'h':
|
|
default:
|
|
Usage();
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
mbstowcs(wcsFile, argv[0], strlen(argv[0]) + 1);
|
|
}
|
|
|
|
if (wcsFile[0] == L'\0') {
|
|
printf("missing filename\n");
|
|
Usage();
|
|
return -1;
|
|
}
|
|
|
|
if (fVerbose)
|
|
fBrief = FALSE;
|
|
|
|
|
|
if (FAILED(hResult = CoInitialize(NULL))) {
|
|
printf("CoInitialize => %s\n", hResultText(hResult));
|
|
return -1;
|
|
}
|
|
|
|
grfMode = STGM_DIRECT | STGM_READ | STGM_SHARE_DENY_WRITE;
|
|
hResult = StgOpenStorage(wcsFile,
|
|
NULL, //pstgPriority
|
|
grfMode,
|
|
NULL, // snbExclude
|
|
0, //dwReserved
|
|
&pstgRoot);
|
|
if (FAILED(hResult)) {
|
|
CoUninitialize();
|
|
printf("StgOpenStorage => %s\n", hResultText(hResult));
|
|
return -1;
|
|
}
|
|
|
|
DispStorage(pstgRoot);
|
|
pstgRoot->Release();
|
|
|
|
CoUninitialize();
|
|
|
|
return 0;
|
|
}
|