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.
857 lines
30 KiB
857 lines
30 KiB
#include "pch.h"
|
|
#pragma hdrstop
|
|
|
|
#include <tchar.h> // _tprintf
|
|
#include <initguid.h>
|
|
#include "uuid.h"
|
|
#include <ccstock.h>
|
|
|
|
#include "util.h"
|
|
#include "config.h"
|
|
#include "security.h"
|
|
|
|
const TCHAR g_szKeyPolicy[] = TEXT("Software\\Policies\\Microsoft\\Windows\\NetCache");
|
|
const TCHAR g_szKeyPrefs[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\NetCache");
|
|
const TCHAR g_szKeyCustomActions[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\NetCache\\CustomGoOfflineActions");
|
|
const TCHAR g_szValEnabled[] = TEXT("Enabled");
|
|
const TCHAR g_szValEncrypted[] = TEXT("Encrypted");
|
|
const TCHAR g_szValGoOfflineAction[] = TEXT("GoOfflineAction");
|
|
const TCHAR g_szValDefCacheSize[] = TEXT("DefCacheSize");
|
|
const TCHAR g_szValNoConfigCache[] = TEXT("NoConfigCache");
|
|
const TCHAR g_szValNoCacheViewer[] = TEXT("NoCacheViewer");
|
|
const TCHAR g_szValNoMakeAvailableOffline[] = TEXT("NoMakeAvailableOffline");
|
|
const TCHAR g_szValNoReminders[] = TEXT("NoReminders");
|
|
const TCHAR g_szValNoConfigReminders[] = TEXT("NoConfigReminders");
|
|
const TCHAR g_szValSyncAtLogoff[] = TEXT("SyncAtLogoff");
|
|
const TCHAR g_szValReminderFreqMinutes[] = TEXT("ReminderFreqMinutes");
|
|
const TCHAR g_szValInitialBalloonTimeout[] = TEXT("InitialBalloonTimeoutSeconds");
|
|
const TCHAR g_szValReminderBalloonTimeout[] = TEXT("ReminderBalloonTimeoutSeconds");
|
|
const TCHAR g_szValFirstPinWizardShown[] = TEXT("FirstPinWizardShown");
|
|
const TCHAR g_szValExpandStatusDlg[] = TEXT("ExpandStatusDlg");
|
|
const TCHAR g_szValFormatCscDb[] = TEXT("FormatDatabase");
|
|
const TCHAR g_szValEventLoggingLevel[] = TEXT("EventLoggingLevel");
|
|
const TCHAR g_szValPurgeAtLogoff[] = TEXT("PurgeAtLogoff");
|
|
const TCHAR g_szValExtExclusionList[] = TEXT("ExtExclusionList");
|
|
const TCHAR g_szValAlwaysPinSubFolders[] = TEXT("AlwaysPinSubFolders");
|
|
const TCHAR g_szNA[] = TEXT("<n/a>");
|
|
|
|
const DWORD POL_CU = 0x0001; // Current user
|
|
const DWORD POL_LM = 0x0002; // Local machine
|
|
const DWORD PREF_CU = 0x0004;
|
|
const DWORD PREF_LM = 0x0008;
|
|
const DWORD PREF_BOTH = PREF_CU | PREF_LM;
|
|
const DWORD POL_BOTH = POL_CU | POL_LM;
|
|
const DWORD REG_ALL = PREF_BOTH | POL_BOTH;
|
|
|
|
const DWORD PREF = 1;
|
|
const DWORD POLICY = 2;
|
|
|
|
|
|
LPTSTR GoOfflineActionText(
|
|
int iValue,
|
|
LPTSTR pszDest
|
|
)
|
|
{
|
|
LPCTSTR rgpsz[] = { TEXT("(Work offline)"),
|
|
TEXT("(No offline)") };
|
|
|
|
if (iValue >= 0 && iValue < ARRAYSIZE(rgpsz))
|
|
lstrcpy(pszDest, rgpsz[iValue]);
|
|
else
|
|
lstrcpy(pszDest, TEXT("<unknown>"));
|
|
|
|
return pszDest;
|
|
}
|
|
|
|
|
|
LPTSTR SyncAtLogoffText(
|
|
int iValue,
|
|
LPTSTR pszDest
|
|
)
|
|
{
|
|
LPCTSTR rgpsz[] = { TEXT("(Part sync)"),
|
|
TEXT("(Full sync)") };
|
|
|
|
if (iValue >= 0 && iValue < ARRAYSIZE(rgpsz))
|
|
lstrcpy(pszDest, rgpsz[iValue]);
|
|
else
|
|
lstrcpy(pszDest, TEXT("<unknown>"));
|
|
|
|
return pszDest;
|
|
}
|
|
|
|
|
|
LPTSTR DefCacheSizeText(
|
|
int iValue,
|
|
LPTSTR pszDest
|
|
)
|
|
{
|
|
wsprintf(pszDest, TEXT("(%2d.%02d %%)"), iValue / 100, iValue % 100);
|
|
return pszDest;
|
|
}
|
|
|
|
|
|
LPCTSTR BoolText(bool b)
|
|
{
|
|
static const LPCTSTR rgYN[] = { TEXT("No"), TEXT("Yes") };
|
|
return rgYN[int(b)];
|
|
}
|
|
|
|
|
|
|
|
LPCTSTR
|
|
RegValStr(
|
|
HKEY hkeyRoot,
|
|
LPCTSTR pszSubkey,
|
|
LPCTSTR pszValue,
|
|
LPTSTR pszDest
|
|
)
|
|
{
|
|
DWORD dwValue = 0;
|
|
DWORD cbData = sizeof(dwValue);
|
|
DWORD dwType;
|
|
|
|
DWORD dwError = SHGetValue(hkeyRoot,
|
|
pszSubkey,
|
|
pszValue,
|
|
&dwType,
|
|
(LPVOID)&dwValue,
|
|
&cbData);
|
|
|
|
if (ERROR_SUCCESS == dwError)
|
|
{
|
|
wsprintf(pszDest, TEXT("%d"), dwValue);
|
|
}
|
|
else if (ERROR_FILE_NOT_FOUND == dwError)
|
|
{
|
|
lstrcpy(pszDest, TEXT("<none>"));
|
|
}
|
|
else
|
|
{
|
|
wsprintf(pszDest, TEXT("Err %d"), dwError);
|
|
}
|
|
return pszDest;
|
|
}
|
|
|
|
|
|
LPTSTR GetOsVersionInfoText(
|
|
LPTSTR pszDest
|
|
)
|
|
{
|
|
OSVERSIONINFO osvi;
|
|
ZeroMemory(&osvi, sizeof(osvi));
|
|
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
|
|
|
*pszDest = TEXT('\0');
|
|
if (GetVersionEx(&osvi))
|
|
{
|
|
static const TCHAR szUnknown[] = TEXT("Unknown OS");
|
|
static const struct
|
|
{
|
|
DWORD dwPlatform;
|
|
DWORD dwMinorVersion;
|
|
LPCTSTR pszPlatform;
|
|
|
|
} rgPlatforms[] = {{ VER_PLATFORM_WIN32s, (DWORD)-1, TEXT("Win32s") },
|
|
{ VER_PLATFORM_WIN32_WINDOWS, 0, TEXT("Windows 95") },
|
|
{ VER_PLATFORM_WIN32_WINDOWS, 10, TEXT("Windows 98") },
|
|
{ VER_PLATFORM_WIN32_NT, (DWORD)-1, TEXT("Windows NT") }};
|
|
|
|
static const struct
|
|
{
|
|
DWORD dwOS;
|
|
LPCTSTR pszOS;
|
|
|
|
} rgOS[] = {{ OS_WIN2000TERMINAL, TEXT("Windows 2000 Terminal") },
|
|
{ OS_WIN2000PRO, TEXT("Windows 2000 Professional") },
|
|
{ OS_WIN2000ADVSERVER, TEXT("Windows 2000 Advanced Server") },
|
|
{ OS_WIN2000DATACENTER, TEXT("Windows 2000 Data Center") },
|
|
{ OS_WIN2000SERVER, TEXT("Windows 2000 Server") },
|
|
{ OS_WIN2000, TEXT("Windows 2000") },
|
|
{ OS_NT5, TEXT("Windows NT") },
|
|
{ OS_NT4, TEXT("Windows NT") },
|
|
{ OS_NT, TEXT("Windows NT") },
|
|
{ OS_MEMPHIS_GOLD, TEXT("Windows 98") },
|
|
{ OS_MEMPHIS, TEXT("Windows 98 (beta)") },
|
|
{ OS_WIN95, TEXT("Windows 95") },
|
|
{ OS_WINDOWS, TEXT("Windows") }};
|
|
|
|
|
|
LPCTSTR pszPlatform = szUnknown;
|
|
int i = 0;
|
|
|
|
//
|
|
// IsOS() is the shlwapi API for figuring out the OS type. Currently, it
|
|
// provides better granularity than GetVersionEx.
|
|
//
|
|
for (i = 0; i < ARRAYSIZE(rgOS); i++)
|
|
{
|
|
if (IsOS(rgOS[i].dwOS))
|
|
{
|
|
pszPlatform = rgOS[i].pszOS;
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// If IsOS() wasn't able to determine the platform, take the platform from
|
|
// the GetVersionEx results.
|
|
//
|
|
if (szUnknown == pszPlatform)
|
|
{
|
|
for (i = 0; i < ARRAYSIZE(rgPlatforms); i++)
|
|
{
|
|
if (rgPlatforms[i].dwPlatform == osvi.dwPlatformId)
|
|
{
|
|
if ((DWORD)-1 == rgPlatforms[i].dwMinorVersion ||
|
|
osvi.dwMinorVersion == rgPlatforms[i].dwMinorVersion)
|
|
{
|
|
pszPlatform = rgPlatforms[i].pszPlatform;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wsprintf(pszDest, TEXT("%s version %d.%d %s build %d\n\n"), pszPlatform,
|
|
osvi.dwMajorVersion,
|
|
osvi.dwMinorVersion,
|
|
osvi.szCSDVersion,
|
|
osvi.dwBuildNumber);
|
|
}
|
|
return pszDest;
|
|
}
|
|
|
|
|
|
void DumpRegStats(void)
|
|
{
|
|
TCHAR szScratch[MAX_PATH];
|
|
CConfig &config = CConfig::GetSingleton();
|
|
|
|
typedef bool (CConfig::*PBMF)(bool *bSetByPolicy) const;
|
|
typedef int (CConfig::*PIMF)(bool *bSetByPolicy) const;
|
|
typedef LPTSTR (*PDF)(int iValue, LPTSTR pszDest);
|
|
|
|
struct
|
|
{
|
|
LPCTSTR pszTitle;
|
|
DWORD dwReg;
|
|
HKEY hkeyRoot;
|
|
LPCTSTR pszSubkey;
|
|
|
|
} rgRegKeys[] = {{ TEXT("Policy (LM)"), POL_LM, HKEY_LOCAL_MACHINE, g_szKeyPolicy },
|
|
{ TEXT("Policy (CU)"), POL_CU, HKEY_CURRENT_USER, g_szKeyPolicy },
|
|
{ TEXT("Pref (LM)"), PREF_LM, HKEY_LOCAL_MACHINE, g_szKeyPrefs },
|
|
{ TEXT("Pref (CU)"), PREF_CU, HKEY_CURRENT_USER, g_szKeyPrefs }};
|
|
|
|
struct
|
|
{
|
|
LPCTSTR pszValue;
|
|
DWORD dwReg;
|
|
PBMF pfnBool;
|
|
PIMF pfnInt;
|
|
PDF pfnDesc;
|
|
|
|
} rgRegValues[] = {
|
|
{ g_szValDefCacheSize, POL_LM, NULL, (PIMF)&CConfig::DefaultCacheSize, &DefCacheSizeText },
|
|
{ g_szValEnabled, POL_LM, &CConfig::CscEnabled, NULL, NULL },
|
|
{ g_szValNoConfigCache, POL_BOTH, &CConfig::NoConfigCache, NULL, NULL },
|
|
{ g_szValNoCacheViewer, POL_BOTH, &CConfig::NoCacheViewer, NULL, NULL },
|
|
{ g_szValNoMakeAvailableOffline, POL_BOTH, &CConfig::NoMakeAvailableOffline, NULL, NULL },
|
|
{ g_szValGoOfflineAction, PREF_CU | POL_BOTH, NULL, &CConfig::GoOfflineAction, &GoOfflineActionText },
|
|
{ g_szValEventLoggingLevel, REG_ALL, NULL, &CConfig::EventLoggingLevel, NULL },
|
|
{ g_szValFirstPinWizardShown, PREF_CU, (PBMF)&CConfig::FirstPinWizardShown, NULL, NULL },
|
|
{ g_szValNoReminders, POL_BOTH | PREF_CU, &CConfig::NoReminders, NULL, NULL },
|
|
{ g_szValPurgeAtLogoff, POL_LM, &CConfig::PurgeAtLogoff, NULL, NULL },
|
|
{ g_szValSyncAtLogoff, POL_BOTH | PREF_CU, NULL, &CConfig::SyncAtLogoff, &SyncAtLogoffText },
|
|
{ g_szValInitialBalloonTimeout, POL_BOTH, NULL, &CConfig::InitialBalloonTimeoutSeconds, NULL },
|
|
{ g_szValReminderBalloonTimeout, POL_BOTH, NULL, &CConfig::ReminderBalloonTimeoutSeconds, NULL },
|
|
{ g_szValReminderFreqMinutes, POL_BOTH | PREF_CU, NULL, &CConfig::ReminderFreqMinutes, NULL },
|
|
{ g_szValAlwaysPinSubFolders, POL_LM, &CConfig::AlwaysPinSubFolders, NULL, NULL }
|
|
};
|
|
|
|
|
|
_tprintf(TEXT("Registry Information:\n\n"));
|
|
_tprintf(TEXT("%-30s%15s%15s%15s%15s%15s\n"),
|
|
TEXT("Value"),
|
|
rgRegKeys[0].pszTitle,
|
|
rgRegKeys[1].pszTitle,
|
|
rgRegKeys[2].pszTitle,
|
|
rgRegKeys[3].pszTitle,
|
|
TEXT("Result"));
|
|
|
|
for (int iVal = 0; iVal < ARRAYSIZE(rgRegValues); iVal++)
|
|
{
|
|
PBMF pfnBool = rgRegValues[iVal].pfnBool;
|
|
PIMF pfnInt = rgRegValues[iVal].pfnInt;
|
|
|
|
_tprintf(TEXT("%-30s"), rgRegValues[iVal].pszValue);
|
|
|
|
for (int iKey = 0; iKey < ARRAYSIZE(rgRegKeys); iKey++)
|
|
{
|
|
if (rgRegValues[iVal].dwReg & rgRegKeys[iKey].dwReg)
|
|
{
|
|
_tprintf(TEXT("%15s"), RegValStr(rgRegKeys[iKey].hkeyRoot,
|
|
rgRegKeys[iKey].pszSubkey,
|
|
rgRegValues[iVal].pszValue,
|
|
szScratch));
|
|
}
|
|
else
|
|
{
|
|
_tprintf(TEXT("%15s"), g_szNA);
|
|
}
|
|
}
|
|
int iValue = 0;
|
|
if (NULL != pfnBool)
|
|
iValue = (config.*pfnBool)(NULL);
|
|
else
|
|
iValue = (config.*pfnInt)(NULL);
|
|
|
|
_tprintf(TEXT("%15d"), iValue);
|
|
if (NULL != rgRegValues[iVal].pfnDesc)
|
|
_tprintf(TEXT(" %s"), (*rgRegValues[iVal].pfnDesc)(iValue, szScratch));
|
|
_tprintf(TEXT("\n"));
|
|
}
|
|
_tprintf(TEXT("\n"));
|
|
|
|
CConfig::OfflineActionIter iter = config.CreateOfflineActionIter();
|
|
CConfig::OfflineActionInfo oai;
|
|
_tprintf(TEXT("Offline action exceptions. Default is %s:\n\n"), GoOfflineActionText(config.GoOfflineAction(), szScratch));
|
|
_tprintf(TEXT("%-30s%s\n"), TEXT("Server"), TEXT("Action"));
|
|
|
|
while(S_OK == iter.Next(&oai))
|
|
{
|
|
_tprintf(TEXT("%-30s%s\n"), oai.szServer, GoOfflineActionText(oai.iAction, szScratch));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
LPTSTR GetMachineName(
|
|
LPTSTR pszDest,
|
|
UINT cchDest
|
|
)
|
|
{
|
|
ULONG cchComputer = cchDest;
|
|
GetComputerName(pszDest, &cchComputer);
|
|
return pszDest;
|
|
}
|
|
|
|
LPTSTR FormatDateTime(
|
|
const SYSTEMTIME& time,
|
|
LPTSTR pszDest,
|
|
UINT cchDest
|
|
)
|
|
{
|
|
LPTSTR pszWrite = pszDest;
|
|
|
|
GetDateFormat(LOCALE_USER_DEFAULT,
|
|
DATE_SHORTDATE,
|
|
&time,
|
|
NULL,
|
|
pszWrite,
|
|
cchDest);
|
|
|
|
lstrcat(pszWrite, TEXT(" "));
|
|
int len = lstrlen(pszWrite);
|
|
pszWrite += len;
|
|
cchDest -= len;
|
|
GetTimeFormat(LOCALE_USER_DEFAULT,
|
|
LOCALE_NOUSEROVERRIDE,
|
|
&time,
|
|
NULL,
|
|
pszWrite,
|
|
cchDest);
|
|
|
|
return pszDest;
|
|
}
|
|
|
|
|
|
LPTSTR GetCurrentDateTime(
|
|
LPTSTR pszDest,
|
|
UINT cchDest
|
|
)
|
|
{
|
|
SYSTEMTIME now;
|
|
GetLocalTime(&now);
|
|
return FormatDateTime(now, pszDest, cchDest);
|
|
}
|
|
|
|
|
|
|
|
|
|
LPTSTR
|
|
Int64ToCommaSepString(
|
|
LONGLONG n,
|
|
LPTSTR pszOut,
|
|
int cchOut
|
|
)
|
|
{
|
|
ULONG ulTemp;
|
|
UNICODE_STRING s;
|
|
NUMBERFMTW nfmtW;
|
|
LPWSTR pszFmtOutW;
|
|
int cchFmtOut;
|
|
WCHAR szTextW[30];
|
|
WCHAR szSep[5];
|
|
//
|
|
// Convert the 64-bit int to a text string.
|
|
//
|
|
s.Length = 0;
|
|
s.MaximumLength = ARRAYSIZE(szTextW);
|
|
s.Buffer = szTextW;
|
|
RtlInt64ToUnicodeString(n, 10, &s);
|
|
//
|
|
// Format the number with commas according to locale conventions.
|
|
//
|
|
nfmtW.NumDigits = 0;
|
|
nfmtW.LeadingZero = 0;
|
|
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, ARRAYSIZE(szSep));
|
|
RtlInitUnicodeString(&s, szSep);
|
|
RtlUnicodeStringToInteger(&s, 10, &ulTemp);
|
|
nfmtW.Grouping = UINT(ulTemp);
|
|
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep));
|
|
nfmtW.lpDecimalSep = nfmtW.lpThousandSep = szSep;
|
|
nfmtW.NegativeOrder = 0;
|
|
|
|
#ifndef UNICODE
|
|
//
|
|
// If ansi build we need a wide-char buffer as format destination.
|
|
//
|
|
WCHAR szNumW[30];
|
|
pszFmtOutW = szNumW;
|
|
cchFmtOut = ARRAYSIZE(szNumW);
|
|
#else
|
|
//
|
|
// If unicode build we can format directly to the destination buffer.
|
|
//
|
|
pszFmtOutW = pszOut;
|
|
cchFmtOut = cchOut;
|
|
#endif
|
|
|
|
GetNumberFormatW(LOCALE_USER_DEFAULT,
|
|
0,
|
|
szTextW,
|
|
&nfmtW,
|
|
pszFmtOutW,
|
|
cchFmtOut);
|
|
#ifndef UNICODE
|
|
//
|
|
// If ansi build, need extra step to convert formatted number string
|
|
// (wide char) back to ansi.
|
|
//
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
pszFmtOutW,
|
|
-1,
|
|
pszOut,
|
|
cchOut,
|
|
NULL,
|
|
NULL);
|
|
#endif
|
|
return pszOut;
|
|
}
|
|
|
|
|
|
void PrintFileStatusFlags(void)
|
|
{
|
|
struct
|
|
{
|
|
DWORD dwFlags;
|
|
LPCTSTR pszText;
|
|
|
|
} rgMap[] = {{ FLAG_CSC_COPY_STATUS_DATA_LOCALLY_MODIFIED, TEXT("Data locally modified") },
|
|
{ FLAG_CSC_COPY_STATUS_ATTRIB_LOCALLY_MODIFIED, TEXT("Attrib locally modified") },
|
|
{ FLAG_CSC_COPY_STATUS_TIME_LOCALLY_MODIFIED, TEXT("Time locally modified") },
|
|
{ FLAG_CSC_COPY_STATUS_STALE, TEXT("Stale") },
|
|
{ FLAG_CSC_COPY_STATUS_LOCALLY_DELETED, TEXT("Locally deleted") },
|
|
{ FLAG_CSC_COPY_STATUS_SPARSE, TEXT("Sparse") },
|
|
{ FLAG_CSC_COPY_STATUS_ORPHAN, TEXT("Orphan") },
|
|
{ FLAG_CSC_COPY_STATUS_SUSPECT, TEXT("Suspect") },
|
|
{ FLAG_CSC_COPY_STATUS_LOCALLY_CREATED, TEXT("Locally created") },
|
|
{ 0x00010000, TEXT("User has READ access") },
|
|
{ 0x00020000, TEXT("User has WRITE access") },
|
|
{ 0x00040000, TEXT("Guest has READ access") },
|
|
{ 0x00080000, TEXT("Guest has WRITE access") },
|
|
{ 0x00100000, TEXT("Other has READ access") },
|
|
{ 0x00200000, TEXT("Other has WRITE access") },
|
|
{ FLAG_CSC_COPY_STATUS_IS_FILE, TEXT("Entry is a file") },
|
|
{ FLAG_CSC_COPY_STATUS_FILE_IN_USE, TEXT("File in use") },
|
|
};
|
|
|
|
_tprintf(TEXT("\nFile status flags ------------------------\n\n"));
|
|
for (int i = 0; i < ARRAYSIZE(rgMap); i++)
|
|
{
|
|
_tprintf(TEXT("0x%08X %s\n"), rgMap[i].dwFlags, rgMap[i].pszText);
|
|
}
|
|
_tprintf(TEXT("\n\n"));
|
|
}
|
|
|
|
|
|
void PrintShareStatusFlags(void)
|
|
{
|
|
struct
|
|
{
|
|
DWORD dwFlags;
|
|
LPCTSTR pszText;
|
|
|
|
} rgMap[] = {{ FLAG_CSC_SHARE_STATUS_MANUAL_REINT, TEXT("Manual Caching") }, // 0x00000000
|
|
{ FLAG_CSC_SHARE_STATUS_MODIFIED_OFFLINE, TEXT("Modified offline") }, // 0x00000001
|
|
{ FLAG_CSC_SHARE_STATUS_AUTO_REINT, TEXT("Auto Caching") }, // 0x00000040
|
|
{ FLAG_CSC_SHARE_STATUS_VDO, TEXT("Virtually Disconnected Ops") }, // 0x00000080
|
|
{ FLAG_CSC_SHARE_STATUS_NO_CACHING, TEXT("No Caching") }, // 0x000000C0
|
|
{ FLAG_CSC_SHARE_STATUS_FINDS_IN_PROGRESS, TEXT("Finds in progress") }, // 0x00000200
|
|
{ FLAG_CSC_SHARE_STATUS_FILES_OPEN, TEXT("Open files") }, // 0x00000400
|
|
{ FLAG_CSC_SHARE_STATUS_CONNECTED, TEXT("Connected") }, // 0x00000800
|
|
{ FLAG_CSC_SHARE_MERGING, TEXT("Merging") }, // 0x40000000
|
|
{ FLAG_CSC_SHARE_STATUS_DISCONNECTED_OP, TEXT("Disconnected Op") }, // 0x80000000
|
|
};
|
|
|
|
_tprintf(TEXT("\nShare status flags -------------------\n\n"));
|
|
for (int i = 0; i < ARRAYSIZE(rgMap); i++)
|
|
{
|
|
_tprintf(TEXT("%30s0x%08X %s\n"), TEXT(""), rgMap[i].dwFlags, rgMap[i].pszText);
|
|
}
|
|
_tprintf(TEXT("\n\n"));
|
|
}
|
|
|
|
|
|
void PrintHintFlags(void)
|
|
{
|
|
struct
|
|
{
|
|
DWORD dwFlags;
|
|
LPCTSTR pszText;
|
|
|
|
} rgMap[] = {{ FLAG_CSC_HINT_PIN_USER, TEXT("Pin User") }, // 0x00000001
|
|
{ FLAG_CSC_HINT_PIN_INHERIT_USER, TEXT("Pin Inherit User") }, // 0x00000002
|
|
{ FLAG_CSC_HINT_PIN_INHERIT_SYSTEM, TEXT("Pin Inherit System") }, // 0x00000004
|
|
{ FLAG_CSC_HINT_CONSERVE_BANDWIDTH, TEXT("Conserve Bandwidth") }, // 0x00000008
|
|
{ FLAG_CSC_HINT_PIN_SYSTEM, TEXT("Pin System") }, // 0x00000010
|
|
};
|
|
|
|
_tprintf(TEXT("\nFile hint flags -------------------\n\n"));
|
|
for (int i = 0; i < ARRAYSIZE(rgMap); i++)
|
|
{
|
|
_tprintf(TEXT("0x%08X %s\n"), rgMap[i].dwFlags, rgMap[i].pszText);
|
|
}
|
|
_tprintf(TEXT("\n\n"));
|
|
}
|
|
|
|
|
|
void DumpCacheStats(void)
|
|
{
|
|
DWORD dwStatus;
|
|
WIN32_FIND_DATA fd;
|
|
TCHAR szScratch[MAX_PATH];
|
|
BOOL bEnabled = CSCIsCSCEnabled();
|
|
CSCSPACEUSAGEINFO sui;
|
|
|
|
ZeroMemory(&sui, sizeof(sui));
|
|
GetCscSpaceUsageInfo(&sui);
|
|
|
|
_tprintf(TEXT("Cache information:\n\n"));
|
|
|
|
_tprintf(TEXT("CSC enabled.........: %s\n"), BoolText(boolify(CSCIsCSCEnabled())));
|
|
_tprintf(TEXT("Volume..............: %s\n"), sui.szVolume);
|
|
_tprintf(TEXT("Bytes on volume.....: %s\n"), Int64ToCommaSepString(sui.llBytesOnVolume, szScratch, ARRAYSIZE(szScratch)));
|
|
_tprintf(TEXT("Bytes in cache......: %s\n"), Int64ToCommaSepString(sui.llBytesTotalInCache, szScratch, ARRAYSIZE(szScratch)));
|
|
_tprintf(TEXT("Bytes used in cache.: %s\n"), Int64ToCommaSepString(sui.llBytesUsedInCache, szScratch, ARRAYSIZE(szScratch)));
|
|
_tprintf(TEXT("Files in cache......: %d\n"), sui.dwNumFilesInCache);
|
|
_tprintf(TEXT("Directories in cache: %d\n\n"), sui.dwNumDirsInCache);
|
|
|
|
CCscFindHandle hFind(CacheFindFirst(NULL, &fd, &dwStatus, NULL, NULL, NULL));
|
|
if (hFind.IsValid())
|
|
{
|
|
BOOL bResult = TRUE;
|
|
CSCSHARESTATS ss;
|
|
CSCCACHESTATS cs;
|
|
CSCGETSTATSINFO si = { SSEF_NONE, SSUF_NONE, true, false };
|
|
|
|
ZeroMemory(&cs, sizeof(cs));
|
|
|
|
_tprintf(TEXT("%-30s%-12s%10s%10s%10s%10s%10s%10s%10s%10s%10s%12s\n"),
|
|
TEXT("Share"),
|
|
TEXT("Status"),
|
|
TEXT("Files"),
|
|
TEXT("Dirs"),
|
|
TEXT("Pinned"),
|
|
TEXT("Modified"),
|
|
TEXT("Sparse"),
|
|
TEXT("USER"),
|
|
TEXT("GUEST"),
|
|
TEXT("OTHER"),
|
|
TEXT("Offline?"),
|
|
TEXT("OpenFiles?"));
|
|
do
|
|
{
|
|
cs.cShares++;
|
|
if (bResult = _GetShareStatistics(fd.cFileName,
|
|
&si,
|
|
&ss))
|
|
{
|
|
_tprintf(TEXT("%-30s0x%08X %10d%10d%10d%10d%10d%10d%10d%10d%10s%12s\n"),
|
|
fd.cFileName,
|
|
dwStatus,
|
|
ss.cTotal - ss.cDirs,
|
|
ss.cDirs,
|
|
ss.cPinned,
|
|
ss.cModified,
|
|
ss.cSparse,
|
|
ss.cAccessUser,
|
|
ss.cAccessGuest,
|
|
ss.cAccessOther,
|
|
BoolText(ss.bOffline),
|
|
BoolText(ss.bOpenFiles));
|
|
|
|
cs.cTotal += ss.cTotal;
|
|
cs.cPinned += ss.cPinned;
|
|
cs.cModified += ss.cModified;
|
|
cs.cSparse += ss.cSparse;
|
|
cs.cDirs += ss.cDirs;
|
|
cs.cAccessUser += ss.cAccessUser;
|
|
cs.cAccessGuest += ss.cAccessGuest;
|
|
cs.cAccessOther += ss.cAccessOther;
|
|
cs.cSharesOffline += int(ss.bOffline);
|
|
cs.cSharesWithOpenFiles += int(ss.bOpenFiles);
|
|
}
|
|
}
|
|
while(bResult && CacheFindNext(hFind, &fd, &dwStatus, NULL, NULL, NULL));
|
|
|
|
_tprintf(TEXT("%-30s%-12s%10d%10d%10d%10d%10d%10d%10d%10d%10d%12d\n\n"),
|
|
TEXT("SUMMARY"),
|
|
TEXT(""),
|
|
cs.cTotal - cs.cDirs,
|
|
cs.cDirs,
|
|
cs.cPinned,
|
|
cs.cModified,
|
|
cs.cSparse,
|
|
cs.cAccessUser,
|
|
cs.cAccessGuest,
|
|
cs.cAccessOther,
|
|
cs.cSharesOffline,
|
|
cs.cSharesWithOpenFiles);
|
|
}
|
|
}
|
|
|
|
|
|
void DumpFileInformation(LPCTSTR pszFile)
|
|
{
|
|
TCHAR szExpanded[MAX_PATH*2];
|
|
ExpandEnvironmentStrings(pszFile, szExpanded, ARRAYSIZE(szExpanded));
|
|
|
|
HANDLE hFile = CreateFile(szExpanded,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (INVALID_HANDLE_VALUE != hFile)
|
|
{
|
|
BY_HANDLE_FILE_INFORMATION fi;
|
|
if (GetFileInformationByHandle(hFile, &fi))
|
|
{
|
|
TCHAR szScratch[80];
|
|
ULARGE_INTEGER llSize = { fi.nFileSizeLow, fi.nFileSizeHigh };
|
|
FILETIME localfiletime;
|
|
SYSTEMTIME systime;
|
|
FileTimeToLocalFileTime(&fi.ftLastWriteTime, &localfiletime);
|
|
FileTimeToSystemTime(&localfiletime, &systime);
|
|
|
|
_tprintf(TEXT("File.......: %s\n"), szExpanded);
|
|
_tprintf(TEXT("Size.......: %s bytes\n"), Int64ToCommaSepString(llSize.QuadPart, szScratch, ARRAYSIZE(szScratch)));
|
|
_tprintf(TEXT("Created....: %s\n\n"), FormatDateTime(systime, szScratch, ARRAYSIZE(szScratch)));
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
else
|
|
{
|
|
_tprintf(TEXT("ERROR %d opening %s\n\n"), GetLastError(), szExpanded);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void PrintOneEnumEntry(LPCTSTR pszPath, DWORD dwStatus, DWORD dwPinCount, DWORD dwHintFlags)
|
|
{
|
|
_tprintf(TEXT("0x%08X %d 0x%08X %s\n"), dwStatus, dwPinCount, dwHintFlags, pszPath);
|
|
}
|
|
|
|
|
|
void EnumTree(LPTSTR pszPath, LPTSTR pszPathToPrint)
|
|
{
|
|
WIN32_FIND_DATA fd;
|
|
DWORD dwStatus, dwPinCount, dwHintFlags;
|
|
|
|
CCscFindHandle hFind(CacheFindFirst(pszPath, &fd, &dwStatus, &dwPinCount, &dwHintFlags, NULL));
|
|
if (hFind.IsValid())
|
|
{
|
|
do
|
|
{
|
|
if (!PathIsDotOrDotDot(pszPath))
|
|
{
|
|
const bool bIsDir = 0 != (FILE_ATTRIBUTE_DIRECTORY & fd.dwFileAttributes);
|
|
PathCombine(pszPathToPrint, pszPath, fd.cFileName);
|
|
if (bIsDir)
|
|
{
|
|
lstrcat(pszPathToPrint, TEXT(" [DIR]"));
|
|
}
|
|
PrintOneEnumEntry(pszPathToPrint, dwStatus, dwPinCount, dwHintFlags);
|
|
if (bIsDir)
|
|
{
|
|
PathAppend(pszPath, fd.cFileName);
|
|
EnumTree(pszPath, pszPathToPrint);
|
|
}
|
|
}
|
|
}
|
|
while(CacheFindNext(hFind, &fd, &dwStatus, &dwPinCount, &dwHintFlags, NULL));
|
|
}
|
|
PathRemoveFileSpec(pszPath);
|
|
}
|
|
|
|
|
|
void EnumFiles(void)
|
|
{
|
|
WIN32_FIND_DATA fd;
|
|
DWORD dwStatus, dwPinCount, dwHintFlags;
|
|
|
|
_tprintf(TEXT("Status PinCnt Hints Name\n"));
|
|
CCscFindHandle hFind(CacheFindFirst(NULL, &fd, &dwStatus, &dwPinCount, &dwHintFlags, NULL));
|
|
if (hFind.IsValid())
|
|
{
|
|
do
|
|
{
|
|
//
|
|
// We create only one path and print-path buffer that we pass
|
|
// into the recursive EnumTree() function. This way we don't have
|
|
// a path buffer on each call stack as we recurse.
|
|
//
|
|
TCHAR szPath[MAX_PATH * 2]; // Working path buffer.
|
|
TCHAR szPathToPrint[MAX_PATH * 2]; // For printing only.
|
|
|
|
wsprintf(szPathToPrint, TEXT("%s [SHARE]"), fd.cFileName);
|
|
PrintOneEnumEntry(szPathToPrint, dwStatus, dwPinCount, dwHintFlags);
|
|
|
|
lstrcpyn(szPath, fd.cFileName, ARRAYSIZE(szPath));
|
|
EnumTree(szPath, szPathToPrint);
|
|
}
|
|
while(CacheFindNext(hFind, &fd, &dwStatus, &dwPinCount, &dwHintFlags, NULL));
|
|
}
|
|
_tprintf(TEXT("\n\n"));
|
|
}
|
|
|
|
|
|
|
|
void ShowUsage(void)
|
|
{
|
|
_tprintf(TEXT("\aUsage: cscsniff [-f] [-c] [-r] [-e] [-a]\n\n"));
|
|
_tprintf(TEXT("\t-f = Show file information.\n"));
|
|
_tprintf(TEXT("\t-c = Show cache information.\n"));
|
|
_tprintf(TEXT("\t-r = Show registry information.\n"));
|
|
_tprintf(TEXT("\t-e = Enumerate all files.\n"));
|
|
_tprintf(TEXT("\t-a = Show ALL output.\n\n"));
|
|
_tprintf(TEXT("Default is -f -c -r\n"));
|
|
}
|
|
|
|
|
|
void __cdecl main(int argc, char **argv)
|
|
{
|
|
|
|
// if (!IsCurrentUserAnAdminMember())
|
|
// {
|
|
// _tprintf(TEXT("\aYou must be an administrator on this computer to run cscsniff.\n"));
|
|
// return;
|
|
// }
|
|
|
|
const char chDash = '-';
|
|
const char chSlash = '/';
|
|
|
|
const DWORD SHOW_CACHEINFO = 0x00000001;
|
|
const DWORD SHOW_REGINFO = 0x00000002;
|
|
const DWORD SHOW_FILEINFO = 0x00000004;
|
|
const DWORD SHOW_ENUMFILES = 0x00000008;
|
|
const DWORD SHOW_DEFAULT = SHOW_CACHEINFO | SHOW_REGINFO | SHOW_FILEINFO;
|
|
const DWORD SHOW_ALL = SHOW_DEFAULT | SHOW_ENUMFILES;
|
|
|
|
DWORD dwShow = 0;
|
|
|
|
for (int i = 1; i < argc; i++)
|
|
{
|
|
if (chDash == argv[i][0] || chSlash == argv[i][0])
|
|
{
|
|
switch(argv[i][1])
|
|
{
|
|
case 'C':
|
|
case 'c':
|
|
dwShow |= SHOW_CACHEINFO;
|
|
break;
|
|
|
|
case 'R':
|
|
case 'r':
|
|
dwShow |= SHOW_REGINFO;
|
|
break;
|
|
|
|
case 'F':
|
|
case 'f':
|
|
dwShow |= SHOW_FILEINFO;
|
|
break;
|
|
|
|
case 'E':
|
|
case 'e':
|
|
dwShow |= SHOW_ENUMFILES;
|
|
break;
|
|
|
|
case 'A':
|
|
case 'a':
|
|
dwShow |= SHOW_ALL;
|
|
break;
|
|
|
|
default:
|
|
ShowUsage();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 == dwShow)
|
|
{
|
|
dwShow = SHOW_DEFAULT;
|
|
}
|
|
|
|
|
|
TCHAR szScratch[MAX_PATH];
|
|
TCHAR szComputer[MAX_COMPUTERNAME_LENGTH + 1];
|
|
TCHAR szDateTime[80];
|
|
_tprintf(TEXT("Status of CSC for %s (%s)\n\n"),
|
|
GetMachineName(szComputer, ARRAYSIZE(szComputer)),
|
|
GetCurrentDateTime(szDateTime, ARRAYSIZE(szDateTime)));
|
|
|
|
_tprintf(TEXT("Operating system: %s\n\n"), GetOsVersionInfoText(szScratch));
|
|
|
|
if (dwShow & SHOW_FILEINFO)
|
|
{
|
|
_tprintf(TEXT("Binary file information:\n\n"));
|
|
DumpFileInformation(TEXT("%systemroot%\\system32\\CSCDLL.DLL"));
|
|
DumpFileInformation(TEXT("%systemroot%\\system32\\CSCUI.DLL"));
|
|
}
|
|
|
|
if (dwShow & SHOW_CACHEINFO)
|
|
{
|
|
DumpCacheStats();
|
|
PrintShareStatusFlags();
|
|
}
|
|
if (dwShow & SHOW_ENUMFILES)
|
|
{
|
|
EnumFiles();
|
|
PrintFileStatusFlags();
|
|
PrintHintFlags();
|
|
}
|
|
|
|
if (dwShow & SHOW_REGINFO)
|
|
DumpRegStats();
|
|
}
|
|
|
|
|
|
|