Leaked source code of windows server 2003
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.
 
 
 
 
 
 

888 lines
25 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1998
//
// File: turlcache.cpp
//
// Contents: Test to display and delete Cryptnet Url cache entries
//
// See Usage() for a list of test options.
//
//
// Functions: main
//
// History: 02-Feb-02 philh created
//--------------------------------------------------------------------------
#include <windows.h>
#include <assert.h>
#include "wincrypt.h"
#include "crypthlp.h"
#include "cryptnet.h"
#include "certtest.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <time.h>
BOOL fExactMatch = FALSE;
BOOL fOneMatch = FALSE; // at least one match
BOOL fNoMatch = FALSE; // no matches
typedef struct _TEST_DELETE_ARG {
LPCWSTR pwszUrlSubString; // NULL implies delete all
DWORD cUrlCacheEntry;
LPWSTR *rgpwszUrl;
LPWSTR *rgpwszMetaDataFileName;
LPWSTR *rgpwszContentFileName;
} TEST_DELETE_ARG, *PTEST_DELETE_ARG;
typedef struct _TEST_DISPLAY_ARG {
LPCWSTR pwszUrlSubString; // NULL implies display all
DWORD dwDisplayFlags;
BOOL fContent;
BOOL fRawBytes;
DWORD cUrl;
} TEST_DISPLAY_ARG, *PTEST_DISPLAY_ARG;
typedef struct _TEST_SET_SYNC_TIME_ARG {
LPCWSTR pwszUrlSubString;
BOOL fVerbose;
FILETIME LastSyncTime;
DWORD cUrl;
} TEST_SET_SYNC_TIME_ARG, *PTEST_SET_SYNC_TIME_ARG;
static void Usage(void)
{
printf("Usage: turlcache [options] [<Url SubString>]\n");
printf("\n");
printf("Options are:\n");
printf(" -d - Delete Url Cache Entry\n");
printf(" -dALL - Delete All Url Cache Entries\n");
printf(" -c - Display Url Cache Content\n");
printf(" -r - Display Url Cache Raw Bytes\n");
printf(" -e - Exact match\n");
printf(" -1 - At least one match without an error\n");
printf(" -0 - No matches without an error\n");
printf(" -h - This message\n");
printf(" -b - Brief\n");
printf(" -v - Verbose\n");
printf(" -S<number> - SyncTime delta seconds\n");
printf("\n");
}
BOOL
TestIsUrlMatch(
LPCWSTR pwszCacheUrl,
LPCWSTR pwszUrlSubString // already in lower case
)
{
BOOL fResult = FALSE;
LPWSTR pwszLowerCaseCacheUrl = NULL;
if (NULL == pwszUrlSubString)
return TRUE;
if (fExactMatch) {
if (0 == wcscmp(pwszCacheUrl, pwszUrlSubString))
return TRUE;
else
return FALSE;
}
// Do case insensitive substring in string matching
pwszLowerCaseCacheUrl = (LPWSTR) TestAlloc(
(wcslen(pwszCacheUrl) + 1) * sizeof(WCHAR));
if (pwszLowerCaseCacheUrl) {
wcscpy(pwszLowerCaseCacheUrl, pwszCacheUrl);
_wcslwr(pwszLowerCaseCacheUrl);
if (wcsstr(pwszLowerCaseCacheUrl, pwszUrlSubString))
fResult = TRUE;
TestFree(pwszLowerCaseCacheUrl);
}
return fResult;
}
BOOL
WINAPI
TestDeleteUrlCacheEntryCallback(
IN const CRYPTNET_URL_CACHE_ENTRY *pUrlCacheEntry,
IN DWORD dwFlags,
IN LPVOID pvReserved,
IN LPVOID pvArg
)
{
BOOL fResult;
PTEST_DELETE_ARG pArg = (PTEST_DELETE_ARG) pvArg;
DWORD cbUrl;
LPWSTR pwszUrl = NULL;
LPWSTR *ppwszUrl = NULL;
DWORD cbMetaDataFileName;
LPWSTR pwszMetaDataFileName = NULL;
LPWSTR *ppwszMetaDataFileName = NULL;
DWORD cbContentFileName;
LPWSTR pwszContentFileName = NULL;
LPWSTR *ppwszContentFileName = NULL;
DWORD cUrlCacheEntry;
if (!TestIsUrlMatch(pUrlCacheEntry->pwszUrl, pArg->pwszUrlSubString))
return TRUE;
cbUrl = (wcslen(pUrlCacheEntry->pwszUrl) + 1) * sizeof(WCHAR);
cbMetaDataFileName =
(wcslen(pUrlCacheEntry->pwszMetaDataFileName) + 1) * sizeof(WCHAR);
cbContentFileName =
(wcslen(pUrlCacheEntry->pwszContentFileName) + 1) * sizeof(WCHAR);
pwszUrl = (LPWSTR) TestAlloc(cbUrl);
pwszMetaDataFileName = (LPWSTR) TestAlloc(cbMetaDataFileName);
pwszContentFileName = (LPWSTR) TestAlloc(cbContentFileName);
if (NULL == pwszUrl ||
NULL == pwszMetaDataFileName ||
NULL == pwszContentFileName)
goto ErrorReturn;
cUrlCacheEntry = pArg->cUrlCacheEntry;
ppwszUrl = (LPWSTR *) TestRealloc(
pArg->rgpwszUrl, sizeof(LPWSTR) * (cUrlCacheEntry + 1));
if (NULL == ppwszUrl)
goto ErrorReturn;
pArg->rgpwszUrl = ppwszUrl;
ppwszMetaDataFileName = (LPWSTR *) TestRealloc(
pArg->rgpwszMetaDataFileName, sizeof(LPWSTR) * (cUrlCacheEntry + 1));
if (NULL == ppwszMetaDataFileName)
goto ErrorReturn;
pArg->rgpwszMetaDataFileName = ppwszMetaDataFileName;
ppwszContentFileName = (LPWSTR *) TestRealloc(
pArg->rgpwszContentFileName, sizeof(LPWSTR) * (cUrlCacheEntry + 1));
if (NULL == ppwszContentFileName)
goto ErrorReturn;
pArg->rgpwszContentFileName = ppwszContentFileName;
memcpy(pwszUrl, pUrlCacheEntry->pwszUrl, cbUrl);
ppwszUrl[cUrlCacheEntry] = pwszUrl;
memcpy(pwszMetaDataFileName, pUrlCacheEntry->pwszMetaDataFileName,
cbMetaDataFileName);
ppwszMetaDataFileName[cUrlCacheEntry] = pwszMetaDataFileName;
memcpy(pwszContentFileName, pUrlCacheEntry->pwszContentFileName,
cbContentFileName);
ppwszContentFileName[cUrlCacheEntry] = pwszContentFileName;
pArg->cUrlCacheEntry = cUrlCacheEntry + 1;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
TestFree(pwszUrl);
TestFree(pwszMetaDataFileName);
TestFree(pwszContentFileName);
fResult = FALSE;
goto CommonReturn;
}
BOOL TestDeleteUrlCacheEntry(
IN LPCWSTR pwszUrlSubString, // NULL implies delete all
IN BOOL fVerbose
)
{
BOOL fResult;
TEST_DELETE_ARG TestArg;
DWORD i;
DWORD cDeleted = 0;
memset(&TestArg, 0, sizeof(TestArg));
TestArg.pwszUrlSubString = pwszUrlSubString;
fResult = I_CryptNetEnumUrlCacheEntry(
0, // dwFlags
NULL, // pvReserved
&TestArg,
TestDeleteUrlCacheEntryCallback
);
if (!fResult)
PrintLastError("I_CryptNetEnumUrlCacheEntry(Delete)");
for (i = 0; i < TestArg.cUrlCacheEntry; i++) {
BOOL fDelete = TRUE;
if (!DeleteFileW(TestArg.rgpwszContentFileName[i])) {
fDelete = FALSE;
printf("Failed Content DeleteFile(%S) for Url: %S\n",
TestArg.rgpwszContentFileName[i],
TestArg.rgpwszUrl[i]
);
PrintLastError("DeleteFilew(Content)");
}
if (!DeleteFileW(TestArg.rgpwszMetaDataFileName[i])) {
fDelete = FALSE;
printf("Failed MetaData DeleteFile(%S) for Url: %S\n",
TestArg.rgpwszMetaDataFileName[i],
TestArg.rgpwszUrl[i]
);
PrintLastError("DeleteFilew(MetaData)");
}
if (fDelete) {
if (fVerbose)
printf("Successful Delete for Url: %S\n",
TestArg.rgpwszUrl[i]);
cDeleted++;
}
TestFree(TestArg.rgpwszUrl[i]);
TestFree(TestArg.rgpwszContentFileName[i]);
TestFree(TestArg.rgpwszMetaDataFileName[i]);
}
TestFree(TestArg.rgpwszUrl);
TestFree(TestArg.rgpwszContentFileName);
TestFree(TestArg.rgpwszMetaDataFileName);
printf("\nDeleted %d Url Cache Entries\n", cDeleted);
if (fOneMatch && 0 == cDeleted) {
printf("Delete failed => no matched entries\n");
fResult = FALSE;
}
if (fNoMatch && 0 != cDeleted) {
printf("Delete failed => expected no matched entries\n");
fResult = FALSE;
}
return fResult;
}
//+-------------------------------------------------------------------------
// Allocate and read an encoded DER blob from a file
//--------------------------------------------------------------------------
BOOL ReadDERFromFile(
LPCWSTR pwszFileName,
PBYTE *ppbDER,
PDWORD pcbDER
)
{
BOOL fRet;
HANDLE hFile = INVALID_HANDLE_VALUE;
PBYTE pbDER = NULL;
DWORD cbDER;
DWORD cbRead;
if( INVALID_HANDLE_VALUE == (hFile = CreateFileW( pwszFileName, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL))) {
printf( "can't open %S\n", pwszFileName);
goto ErrorReturn;
}
cbDER = GetFileSize( hFile, NULL);
if (cbDER == 0) {
printf( "empty file %S\n", pwszFileName);
goto ErrorReturn;
}
if (NULL == (pbDER = (PBYTE)TestAlloc(cbDER))) {
printf( "can't alloc %d bytes\n", cbDER);
goto ErrorReturn;
}
if (!ReadFile( hFile, pbDER, cbDER, &cbRead, NULL) ||
(cbRead != cbDER)) {
printf( "can't read %S\n", pwszFileName);
goto ErrorReturn;
}
*ppbDER = pbDER;
*pcbDER = cbDER;
fRet = TRUE;
CommonReturn:
if (INVALID_HANDLE_VALUE != hFile)
CloseHandle(hFile);
return fRet;
ErrorReturn:
if (pbDER)
TestFree(pbDER);
*ppbDER = NULL;
*pcbDER = 0;
fRet = FALSE;
goto CommonReturn;
}
//+-------------------------------------------------------------------------
// Write an encoded DER blob to a file
//--------------------------------------------------------------------------
BOOL WriteDERToFile(
LPCWSTR pwszFileName,
PBYTE pbDER,
DWORD cbDER
)
{
BOOL fResult;
// Write the Encoded Blob to the file
HANDLE hFile;
hFile = CreateFileW(pwszFileName,
GENERIC_WRITE,
0, // fdwShareMode
NULL, // lpsa
CREATE_ALWAYS,
FILE_ATTRIBUTE_SYSTEM,
0); // TemplateFile
if (INVALID_HANDLE_VALUE == hFile) {
fResult = FALSE;
PrintLastError("WriteDERToFile::CreateFile");
} else {
DWORD dwBytesWritten;
if (!(fResult = WriteFile(
hFile,
pbDER,
cbDER,
&dwBytesWritten,
NULL // lpOverlapped
)))
PrintLastError("WriteDERToFile::WriteFile");
CloseHandle(hFile);
}
return fResult;
}
HCERTSTORE TestCreateStoreFromUrlCacheContent(
IN DWORD cBlob,
IN DWORD *pcbBlob,
IN PBYTE pbContent
)
{
BOOL fResult = TRUE;
HCERTSTORE hStore = NULL;
DWORD cCount;
int iQueryResult;
DWORD dwQueryErr = 0;
PBYTE pb;
if ( ( hStore = CertOpenStore(
CERT_STORE_PROV_MEMORY,
0,
NULL,
0,
NULL
) ) == NULL )
{
PrintLastError("CertOpenStore(Memory)");
return NULL;
}
// 0 => no CryptQueryObject()
// 1 => 1 successful CryptQueryObject()
// -1 => all CryptQueryObject()'s failed
iQueryResult = 0;
for ( cCount = 0, pb = pbContent;
( fResult == TRUE ) && ( cCount < cBlob );
pb += pcbBlob[cCount], cCount++ )
{
CERT_BLOB Blob;
HCERTSTORE hChildStore = NULL;
// Skip empty blobs. I have seen empty LDAP attributes containing
// a single byte set to 0.
if (0 == pcbBlob[cCount] ||
(1 == pcbBlob[cCount] && 0 == pb[0]))
{
continue;
}
Blob.pbData = pb;
Blob.cbData = pcbBlob[cCount];
if (CryptQueryObject(
CERT_QUERY_OBJECT_BLOB,
(LPVOID) &Blob,
CERT_QUERY_CONTENT_FLAG_CERT |
CERT_QUERY_CONTENT_FLAG_CTL |
CERT_QUERY_CONTENT_FLAG_CRL |
CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT |
CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL |
CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL |
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
CERT_QUERY_CONTENT_FLAG_CERT_PAIR,
CERT_QUERY_FORMAT_FLAG_ALL,
0,
NULL,
NULL,
NULL,
&hChildStore,
NULL,
NULL
))
{
fResult = I_CertUpdateStore( hStore, hChildStore, 0, NULL );
CertCloseStore( hChildStore, 0 );
iQueryResult = 1;
}
else if (iQueryResult == 0)
{
iQueryResult = -1;
dwQueryErr = GetLastError();
}
}
if ( fResult == TRUE && iQueryResult < 0)
{
fResult = FALSE;
SetLastError(dwQueryErr);
}
if (!fResult)
{
PrintLastError("TestCreateStoreFromUrlCacheContent");
CertCloseStore( hStore, 0 );
hStore = NULL;
}
return hStore;
}
LPCSTR FileTimeTextWithoutMilliseconds(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;
}
BOOL
WINAPI
TestDisplayUrlCacheEntryCallback(
IN const CRYPTNET_URL_CACHE_ENTRY *pUrlCacheEntry,
IN DWORD dwFlags,
IN LPVOID pvReserved,
IN LPVOID pvArg
)
{
PTEST_DISPLAY_ARG pArg = (PTEST_DISPLAY_ARG) pvArg;
DWORD cbBlob;
DWORD i;
PBYTE pbContent = NULL;
DWORD cbContent;
BOOL fDetails;
if (pArg->fRawBytes || pArg->fContent ||
(pArg->dwDisplayFlags & DISPLAY_VERBOSE_FLAG))
fDetails = TRUE;
else
fDetails = FALSE;
if (!TestIsUrlMatch(pUrlCacheEntry->pwszUrl, pArg->pwszUrlSubString))
return TRUE;
cbBlob = 0;
for (i = 0; i < pUrlCacheEntry->cBlob; i++)
cbBlob += pUrlCacheEntry->pcbBlob[i];
if (fDetails) {
printf("\n");
printf(
"=========================================================================\n");
}
printf("%s %9d %S\n",
FileTimeTextWithoutMilliseconds((FILETIME *) &pUrlCacheEntry->LastSyncTime),
cbBlob,
pUrlCacheEntry->pwszUrl
);
if (fDetails) {
printf(
"=========================================================================\n");
if (pArg->dwDisplayFlags & DISPLAY_VERBOSE_FLAG) {
printf("MetaDataFileName: %S\n",
pUrlCacheEntry->pwszMetaDataFileName);
printf("ContentFileName : %S\n",
pUrlCacheEntry->pwszContentFileName);
}
if (!ReadDERFromFile(
pUrlCacheEntry->pwszContentFileName,
&pbContent,
&cbContent
))
goto ErrorReturn;
if (cbBlob != cbContent) {
printf("Invalid content length: %d, expected: %d\n",
cbContent, cbBlob);
if (cbBlob > cbContent)
goto ErrorReturn;
}
if (pArg->fRawBytes) {
PBYTE pb = pbContent;
for (i = 0; i < pUrlCacheEntry->cBlob; i++) {
printf("---- Blob[%d] ----\n", i);
PrintBytes(" ", pb, pUrlCacheEntry->pcbBlob[i]);
pb += pUrlCacheEntry->pcbBlob[i];
}
}
if (pArg->fContent) {
HCERTSTORE hStore;
hStore = TestCreateStoreFromUrlCacheContent(
pUrlCacheEntry->cBlob,
pUrlCacheEntry->pcbBlob,
pbContent
);
if (hStore) {
DisplayStore(hStore, pArg->dwDisplayFlags);
CertCloseStore(hStore, 0);
}
}
}
CommonReturn:
TestFree(pbContent);
pArg->cUrl++;
return TRUE;
ErrorReturn:
goto CommonReturn;
}
BOOL TestDisplayUrlCacheEntry(
IN LPCWSTR pwszUrlSubString, // NULL implies display all
IN DWORD dwDisplayFlags,
IN BOOL fContent,
IN BOOL fRawBytes
)
{
BOOL fResult;
TEST_DISPLAY_ARG TestArg;
memset(&TestArg, 0, sizeof(TestArg));
TestArg.pwszUrlSubString = pwszUrlSubString;
TestArg.dwDisplayFlags = dwDisplayFlags;
TestArg.fContent = fContent;
TestArg.fRawBytes = fRawBytes;
fResult = I_CryptNetEnumUrlCacheEntry(
0, // dwFlags
NULL, // pvReserved
&TestArg,
TestDisplayUrlCacheEntryCallback
);
if (!fResult)
PrintLastError("I_CryptNetEnumUrlCacheEntry(Display)");
printf("\nDisplayed %d Url Cache Entries\n", TestArg.cUrl);
if (fOneMatch && 0 == TestArg.cUrl) {
printf("Display failed => no matched entries\n");
fResult = FALSE;
}
if (fNoMatch && 0 != TestArg.cUrl) {
printf("Display failed => expected no matched entries\n");
fResult = FALSE;
}
return fResult;
}
#if 0
from \nt\ds\security\cryptoapi\pki\rpor\rporprov.h
typedef struct _SCHEME_CACHE_META_DATA_HEADER {
DWORD cbSize;
DWORD dwMagic;
DWORD cBlob;
DWORD cbUrl;
FILETIME LastSyncTime;
} SCHEME_CACHE_META_DATA_HEADER, *PSCHEME_CACHE_META_DATA_HEADER;
#endif
#define TEST_LAST_SYNC_TIME_META_DATA_OFFSET (sizeof(DWORD) * 4)
#define TEST_MIN_META_DATA_SIZE \
(TEST_LAST_SYNC_TIME_META_DATA_OFFSET + sizeof(FILETIME))
BOOL
WINAPI
TestSetSyncTimeCallback(
IN const CRYPTNET_URL_CACHE_ENTRY *pUrlCacheEntry,
IN DWORD dwFlags,
IN LPVOID pvReserved,
IN LPVOID pvArg
)
{
BOOL fResult;
BYTE *pbMetaData = NULL;
DWORD cbMetaData;
PTEST_SET_SYNC_TIME_ARG pArg = (PTEST_SET_SYNC_TIME_ARG) pvArg;
if (!TestIsUrlMatch(pUrlCacheEntry->pwszUrl, pArg->pwszUrlSubString))
return TRUE;
printf("SetSyncTime for: %S\n", pUrlCacheEntry->pwszUrl);
if (pArg->fVerbose)
printf("MetaDataFileName: %S\n", pUrlCacheEntry->pwszMetaDataFileName);
if (!ReadDERFromFile(
pUrlCacheEntry->pwszMetaDataFileName,
&pbMetaData,
&cbMetaData
))
goto ErrorReturn;
if (TEST_MIN_META_DATA_SIZE > cbMetaData) {
printf("Invalid meta data file length: %d, expected at least: %d\n",
cbMetaData, TEST_MIN_META_DATA_SIZE);
goto ErrorReturn;
}
memcpy(pbMetaData + TEST_LAST_SYNC_TIME_META_DATA_OFFSET,
&pArg->LastSyncTime, sizeof(FILETIME));
if (!WriteDERToFile(
pUrlCacheEntry->pwszMetaDataFileName,
pbMetaData,
cbMetaData
))
goto ErrorReturn;
pArg->cUrl++;
CommonReturn:
TestFree(pbMetaData);
return TRUE;
ErrorReturn:
goto CommonReturn;
}
BOOL TestSetSyncTime(
IN LPCWSTR pwszUrlSubString, // NULL implies delete all
IN BOOL fVerbose,
IN LONG lDeltaSeconds
)
{
BOOL fResult;
TEST_SET_SYNC_TIME_ARG TestArg;
FILETIME CurrentTime;
memset(&TestArg, 0, sizeof(TestArg));
TestArg.pwszUrlSubString = pwszUrlSubString;
TestArg.fVerbose = fVerbose;
GetSystemTimeAsFileTime(&CurrentTime);
if (lDeltaSeconds >= 0)
I_CryptIncrementFileTimeBySeconds(
&CurrentTime,
(DWORD) lDeltaSeconds,
&TestArg.LastSyncTime
);
else
I_CryptDecrementFileTimeBySeconds(
&CurrentTime,
(DWORD) -lDeltaSeconds,
&TestArg.LastSyncTime
);
fResult = I_CryptNetEnumUrlCacheEntry(
0, // dwFlags
NULL, // pvReserved
&TestArg,
TestSetSyncTimeCallback
);
if (!fResult)
PrintLastError("I_CryptNetEnumUrlCacheEntry(SetSyncTime)");
printf("\nSetSyncTime for %d Url Cache Entries\n", TestArg.cUrl);
if (fOneMatch && 0 == TestArg.cUrl) {
printf("SetSyncTime failed => no matched entries\n");
fResult = FALSE;
}
if (fNoMatch && 0 != TestArg.cUrl) {
printf("SetSyncTime failed => expected no matched entries\n");
fResult = FALSE;
}
return fResult;
}
int _cdecl main(int argc, char * argv[])
{
int status;
LPWSTR pwszUrlSubString = NULL;
BOOL fVerbose = FALSE;
DWORD dwDisplayFlags = 0;
BOOL fContent = FALSE;
BOOL fRawBytes = FALSE;
BOOL fDelete = FALSE;
BOOL fDeleteAll = FALSE;
BOOL fSyncTime = FALSE;
LONG lSyncTimeDeltaSeconds = 0;
while (--argc>0) {
if (**++argv == '-')
{
{
switch(argv[0][1])
{
case 'd':
fDelete = TRUE;
if (argv[0][2]) {
if (0 != _stricmp(argv[0]+2, "ALL")) {
printf("Need to specify -dALL\n");
goto BadUsage;
}
fDeleteAll = TRUE;
}
break;
case 'b':
dwDisplayFlags |= DISPLAY_BRIEF_FLAG;
break;
case 'v':
fVerbose = TRUE;
dwDisplayFlags |= DISPLAY_VERBOSE_FLAG;
break;
case 'c':
fContent = TRUE;
break;
case 'r':
fRawBytes = TRUE;
break;
case 'e':
fExactMatch = TRUE;
break;
case '1':
fOneMatch = TRUE;
break;
case '0':
fNoMatch = TRUE;
break;
case 'S':
fSyncTime = TRUE;
lSyncTimeDeltaSeconds = strtol(argv[0]+2, NULL, 0);
break;
case 'h':
default:
goto BadUsage;
}
}
} else {
if (pwszUrlSubString) {
printf("Multiple Url Subtrings:: %S %s\n",
pwszUrlSubString, argv[0]);
goto BadUsage;
}
pwszUrlSubString = AllocAndSzToWsz(argv[0]);
}
}
printf("command line: %s\n", GetCommandLine());
if (!fExactMatch && pwszUrlSubString)
_wcslwr(pwszUrlSubString);
if (fDelete) {
if (!fDeleteAll && NULL == pwszUrlSubString) {
printf("Missing Url Substring for Delete\n");
goto BadUsage;
}
if (!TestDeleteUrlCacheEntry(
fDeleteAll ? NULL : pwszUrlSubString, // NULL implies delete all
fVerbose
))
goto ErrorReturn;
} else if (fSyncTime) {
if (NULL == pwszUrlSubString) {
printf("Missing Url Substring for SetSyncTime\n");
goto BadUsage;
}
if (!TestSetSyncTime(
pwszUrlSubString,
fVerbose,
lSyncTimeDeltaSeconds
))
goto ErrorReturn;
} else {
if (!TestDisplayUrlCacheEntry(
pwszUrlSubString, // NULL implies display all
dwDisplayFlags,
fContent,
fRawBytes
))
goto ErrorReturn;
}
printf("Passed\n");
status = 0;
CommonReturn:
TestFree(pwszUrlSubString);
return status;
ErrorReturn:
status = -1;
printf("Failed\n");
goto CommonReturn;
BadUsage:
Usage();
goto ErrorReturn;
}