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.
989 lines
21 KiB
989 lines
21 KiB
#include "pch.h"
|
|
|
|
#include "store.hpp"
|
|
|
|
#define CF_COMPRESSED 0x1
|
|
|
|
|
|
#define TLS // __declspec( thread )
|
|
|
|
#if defined(_WIN64) && defined(_M_IA64)
|
|
#pragma section(".base", long, read, write)
|
|
extern "C"
|
|
__declspec(allocate(".base"))
|
|
extern
|
|
IMAGE_DOS_HEADER __ImageBase;
|
|
#else
|
|
extern "C"
|
|
extern
|
|
IMAGE_DOS_HEADER __ImageBase;
|
|
#endif
|
|
|
|
HINSTANCE ghSymSrv = (HINSTANCE)&__ImageBase;
|
|
UINT_PTR goptions = SSRVOPT_DWORD;
|
|
DWORD gptype = SSRVOPT_DWORD;
|
|
PSYMBOLSERVERCALLBACKPROC gcallback = NULL;
|
|
ULONG64 gcontext = 0;
|
|
HWND ghwndParent = (HWND)0;
|
|
char gproxy[MAX_PATH + 1] = "";
|
|
int gdbgout = -1;
|
|
char gdstore[MAX_PATH + 1] = "";
|
|
|
|
|
|
void
|
|
PrepOutputString(
|
|
char *in,
|
|
char *out,
|
|
int len
|
|
)
|
|
{
|
|
int i;
|
|
|
|
*out = 0;
|
|
|
|
for (i = 0; *in && i < len; i++, in++, out++) {
|
|
if (*in == '\b')
|
|
break;
|
|
*out = *in;
|
|
}
|
|
|
|
*out = 0;
|
|
}
|
|
|
|
|
|
VOID
|
|
OutputDbgString(
|
|
char *sz
|
|
)
|
|
{
|
|
char sztxt[3000];
|
|
|
|
PrepOutputString(sz, sztxt, 3000);
|
|
if (*sztxt)
|
|
OutputDebugString(sztxt);
|
|
}
|
|
|
|
|
|
__inline
|
|
BOOL
|
|
DoCallback(
|
|
DWORD action,
|
|
ULONG64 data
|
|
)
|
|
{
|
|
return gcallback(action, data, gcontext);
|
|
}
|
|
|
|
|
|
BOOL
|
|
PostEvent(
|
|
PIMAGEHLP_CBA_EVENT evt
|
|
)
|
|
{
|
|
BOOL fdbgout = false;
|
|
|
|
if (!*evt->desc)
|
|
return true;
|
|
|
|
// write to debug terminal, if called for
|
|
|
|
if (gdbgout == 1) {
|
|
fdbgout = true;
|
|
OutputDbgString(evt->desc);
|
|
}
|
|
|
|
// don't pass info-level messages, unless told to
|
|
|
|
if ((evt->severity <= sevInfo) && !(goptions & SSRVOPT_TRACE))
|
|
return true;
|
|
|
|
// If there is no callback function, send to the debug terminal.
|
|
|
|
if (!gcallback) {
|
|
if (!fdbgout)
|
|
OutputDbgString(evt->desc);
|
|
return true;
|
|
}
|
|
|
|
// Otherwise call the callback function.
|
|
|
|
return DoCallback(SSRVACTION_EVENT, (ULONG64)evt);
|
|
}
|
|
|
|
BOOL
|
|
WINAPIV
|
|
evtprint(
|
|
DWORD severity,
|
|
DWORD code,
|
|
PVOID object,
|
|
LPSTR format,
|
|
...
|
|
)
|
|
{
|
|
static char buf[1000] = "";
|
|
IMAGEHLP_CBA_EVENT evt;
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
wvsprintf(buf, format, args);
|
|
va_end(args);
|
|
if (!*buf)
|
|
return true;
|
|
|
|
evt.severity = severity;
|
|
evt.code = code;
|
|
evt.desc = buf;
|
|
evt.object = object;
|
|
|
|
return PostEvent(&evt);
|
|
}
|
|
|
|
|
|
int
|
|
_eprint(
|
|
LPSTR format,
|
|
...
|
|
)
|
|
{
|
|
static char buf[1000] = "";
|
|
va_list args;
|
|
|
|
if (!format || !*format)
|
|
return 1;
|
|
|
|
if (!(goptions & SSRVOPT_TRACE) && gdbgout != 1)
|
|
return 1;
|
|
|
|
va_start(args, format);
|
|
wvsprintf(buf, format, args);
|
|
va_end(args);
|
|
|
|
if (!evtprint(sevInfo, 0, NULL, buf))
|
|
if (gcallback)
|
|
gcallback(SSRVACTION_TRACE, (ULONG64)buf, gcontext);
|
|
|
|
return 1;
|
|
}
|
|
|
|
DBGEPRINT geprint = _eprint;
|
|
|
|
int
|
|
_dprint(
|
|
LPSTR format,
|
|
...
|
|
)
|
|
{
|
|
static char buf[1000] = "SYMSRV: ";
|
|
va_list args;
|
|
|
|
if (!format || !*format)
|
|
return 1;
|
|
|
|
if (!(goptions & SSRVOPT_TRACE) && gdbgout != 1)
|
|
return 1;
|
|
|
|
va_start(args, format);
|
|
wvsprintf(buf + 9, format, args);
|
|
va_end(args);
|
|
|
|
return _eprint(buf);
|
|
}
|
|
|
|
DBGPRINT gdprint = NULL; // _dprint;
|
|
|
|
|
|
// this one is for calling from dload.cpp
|
|
|
|
int
|
|
__dprint(
|
|
LPSTR sz
|
|
)
|
|
{
|
|
static char buf[1000] = "SYMSRV: ";
|
|
va_list args;
|
|
|
|
if (!sz || !*sz)
|
|
return 1;
|
|
|
|
CopyStrArray(buf, "SYMSRV: ");
|
|
CatStrArray(buf, sz);
|
|
|
|
if (gcallback)
|
|
gcallback(SSRVACTION_TRACE, (ULONG64)buf, gcontext);
|
|
if (!gcallback || (gdbgout == 1))
|
|
OutputDbgString(buf);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
_querycancel(
|
|
)
|
|
{
|
|
BOOL rc;
|
|
BOOL cancel = false;
|
|
|
|
if (!gcallback)
|
|
return false;
|
|
|
|
rc = gcallback(SSRVACTION_QUERYCANCEL, (ULONG64)&cancel, gcontext);
|
|
if (rc && cancel)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
QUERYCANCEL gquerycancel = _querycancel;
|
|
|
|
BOOL
|
|
SetError(
|
|
DWORD err
|
|
)
|
|
{
|
|
SetLastError(err);
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
copy(
|
|
IN PCSTR trgsite,
|
|
IN PCSTR srcsite,
|
|
IN PCSTR rpath,
|
|
IN PCSTR file,
|
|
OUT PSTR trg, // must be at least MAX_PATH elements
|
|
IN DWORD flags
|
|
)
|
|
{
|
|
BOOL rc;
|
|
DWORD type = stUNC;
|
|
CHAR epath[MAX_PATH + 1];
|
|
CHAR srcbuf[MAX_PATH + 1];
|
|
CHAR tsite[MAX_PATH + 1];
|
|
CHAR ssite[MAX_PATH + 1];
|
|
PSTR src;
|
|
Store *store;
|
|
DWORD ec;
|
|
|
|
assert(trgsite && srcsite);
|
|
|
|
// use the default downstream store, if specified
|
|
|
|
CopyStrArray(tsite, (*trgsite) ? trgsite : gdstore);
|
|
CopyStrArray(ssite, srcsite);
|
|
|
|
// get the store type of the target store
|
|
|
|
type = GetStoreType(tsite);
|
|
switch (type) {
|
|
case stUNC:
|
|
break;
|
|
case stHTTP:
|
|
case stHTTPS:
|
|
// Can't use http for the target.
|
|
// If a source is specifed, then bail.
|
|
if (*ssite)
|
|
return SetError(ERROR_INVALID_PARAMETER);
|
|
// Otherwise, just use the default downstream store for a target.
|
|
CopyStrArray(ssite, tsite);
|
|
CopyStrArray(tsite, gdstore);
|
|
break;
|
|
case stError:
|
|
return SetError(ERROR_INVALID_PARAMETER);
|
|
default:
|
|
return SetError(ERROR_INVALID_NAME); }
|
|
|
|
// MAYBE PUT A CHECK IN HERE FOR A CAB. LIKE IF THE DIRECTORY IS
|
|
// ACTUALLY A COMPRESSED FILE AND RETURN stCAB.
|
|
|
|
// generate full target path
|
|
|
|
pathcpy(trg, tsite, rpath, MAX_PATH);
|
|
pathcat(trg, file, MAX_PATH);
|
|
|
|
// if file exists, return it
|
|
|
|
ec = FileStatus(trg);
|
|
if (!ec) {
|
|
return true;
|
|
} else if (ec == ERROR_NOT_READY) {
|
|
dprint("%s - drive not ready\n", trg);
|
|
return false;
|
|
}
|
|
|
|
if (ReadFilePtr(trg, MAX_PATH)) {
|
|
ec = FileStatus(trg);
|
|
if (ec == NO_ERROR)
|
|
return true;
|
|
dprint("%s - %s\n", trg, FormatStatus(ec));
|
|
return false;
|
|
}
|
|
|
|
if (!*ssite) {
|
|
ec = FileStatus(CompressedFileName(trg));
|
|
if (ec != NO_ERROR) {
|
|
// if there is no source to copy from, then error
|
|
dprint("%s - file not found\n", trg);
|
|
return SetError(ERROR_FILE_NOT_FOUND);
|
|
}
|
|
|
|
// There is a compressed file..
|
|
// Expand it to the default store.
|
|
|
|
CopyStrArray(ssite, tsite);
|
|
CopyStrArray(tsite, gdstore);
|
|
pathcpy(trg, tsite, rpath, MAX_PATH);
|
|
pathcat(trg, file, MAX_PATH);
|
|
ec = FileStatus(trg);
|
|
if (ec == NO_ERROR)
|
|
return true;
|
|
}
|
|
|
|
if (goptions & SSRVOPT_SECURE) {
|
|
dprint("%s - file copy not allowed in secure mode\n", trg);
|
|
return SetError(ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
if (!EnsurePathExists(trg, epath, DIMA(epath))) {
|
|
dprint("%s - couldn't create target path\n", trg);
|
|
return SetError(ERROR_PATH_NOT_FOUND);
|
|
}
|
|
|
|
store = GetStore(ssite);
|
|
if (!store)
|
|
return false;
|
|
|
|
rc = store->init();
|
|
if (!rc)
|
|
return false;
|
|
|
|
rc = store->copy(rpath, file, tsite);
|
|
|
|
// test the results and set the return value
|
|
|
|
if (rc && !FileStatus(trg))
|
|
return true;
|
|
|
|
UndoPath(trg, epath);
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ping(
|
|
IN PCSTR trgsite,
|
|
IN PCSTR srcsite,
|
|
IN PCSTR rpath,
|
|
IN PCSTR file,
|
|
OUT PSTR trg,
|
|
IN DWORD flags
|
|
)
|
|
{
|
|
BOOL rc;
|
|
DWORD type = stUNC;
|
|
CHAR epath[_MAX_PATH];
|
|
CHAR srcbuf[_MAX_PATH];
|
|
PSTR src;
|
|
Store *store;
|
|
DWORD ec;
|
|
|
|
|
|
store = GetStore(srcsite);
|
|
if (!store)
|
|
return false;
|
|
|
|
rc = store->init();
|
|
if (!rc)
|
|
return false;
|
|
|
|
rc = store->ping();
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
void
|
|
CatStrDWORD(
|
|
IN OUT PSTR sz,
|
|
IN DWORD value,
|
|
IN DWORD size
|
|
)
|
|
{
|
|
CHAR buf[MAX_PATH + 256];
|
|
|
|
assert(sz);
|
|
|
|
if (!value)
|
|
return;
|
|
|
|
wsprintf(buf, "%s%x", sz, value); // SECURITY: This will take a 256 digit DWORD.
|
|
CopyString(sz, buf, size);
|
|
}
|
|
|
|
|
|
void
|
|
CatStrGUID(
|
|
IN OUT PSTR sz,
|
|
IN GUID *guid,
|
|
IN DWORD size
|
|
)
|
|
{
|
|
CHAR buf[MAX_PATH + 256];
|
|
BYTE byte;
|
|
int i;
|
|
|
|
assert(sz);
|
|
|
|
if (!guid)
|
|
return;
|
|
|
|
// append the first DWORD in the pointer
|
|
|
|
wsprintf(buf, "%08X", guid->Data1);
|
|
CatString(sz, buf, size);
|
|
|
|
// this will catch the passing of a PDWORD and avoid
|
|
// all the GUID parsing
|
|
|
|
if (!guid->Data2 && !guid->Data3) {
|
|
for (i = 0, byte = 0; i < 8; i++) {
|
|
byte |= guid->Data4[i];
|
|
if (byte)
|
|
break;
|
|
}
|
|
if (!byte)
|
|
return;
|
|
}
|
|
|
|
// go ahead and add the rest of the GUID
|
|
|
|
wsprintf(buf, "%04X", guid->Data2);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%04X", guid->Data3);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%02X", guid->Data4[0]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%02X", guid->Data4[1]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%02X", guid->Data4[2]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%02X", guid->Data4[3]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%02X", guid->Data4[4]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%02X", guid->Data4[5]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%02X", guid->Data4[6]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%02X", guid->Data4[7]);
|
|
CatString(sz, buf, size);
|
|
}
|
|
|
|
|
|
void
|
|
CatStrOldGUID(
|
|
IN OUT PSTR sz,
|
|
IN GUID *guid,
|
|
IN DWORD size
|
|
)
|
|
{
|
|
CHAR buf[MAX_PATH + 256];
|
|
BYTE byte;
|
|
int i;
|
|
|
|
assert(sz);
|
|
|
|
if (!guid)
|
|
return;
|
|
|
|
// append the first DWORD in the pointer
|
|
|
|
wsprintf(buf, "%8x", guid->Data1);
|
|
CatString(sz, buf, size);
|
|
|
|
// this will catch the passing of a PDWORD and avoid
|
|
// all the GUID parsing
|
|
|
|
if (!guid->Data2 && !guid->Data3) {
|
|
for (i = 0, byte = 0; i < 8; i++) {
|
|
byte |= guid->Data4[i];
|
|
if (byte)
|
|
break;
|
|
}
|
|
if (!byte)
|
|
return;
|
|
}
|
|
|
|
// go ahead and add the rest of the GUID
|
|
|
|
wsprintf(buf, "%4x", guid->Data2);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%4x", guid->Data3);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%2x", guid->Data4[0]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%2x", guid->Data4[1]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%2x", guid->Data4[2]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%2x", guid->Data4[3]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%2x", guid->Data4[4]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%2x", guid->Data4[5]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%2x", guid->Data4[6]);
|
|
CatString(sz, buf, size);
|
|
wsprintf(buf, "%2x", guid->Data4[7]);
|
|
CatString(sz, buf, size);
|
|
}
|
|
|
|
|
|
void
|
|
CatStrID(
|
|
IN OUT PSTR sz,
|
|
PVOID id,
|
|
DWORD paramtype,
|
|
DWORD size
|
|
)
|
|
{
|
|
switch (paramtype)
|
|
{
|
|
case SSRVOPT_DWORD:
|
|
CatStrDWORD(sz, PtrToUlong(id), size);
|
|
break;
|
|
case SSRVOPT_DWORDPTR:
|
|
CatStrDWORD(sz, *(DWORD *)id, size);
|
|
break;
|
|
case SSRVOPT_GUIDPTR:
|
|
CatStrGUID(sz, (GUID *)id, size);
|
|
break;
|
|
case SSRVOPT_OLDGUIDPTR:
|
|
CatStrOldGUID(sz, (GUID *)id, size);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// for Barb and Greg only. I'm going to get rid of these...
|
|
|
|
void
|
|
AppendHexStringWithDWORD(
|
|
IN OUT PSTR sz,
|
|
IN DWORD value
|
|
)
|
|
{
|
|
return CatStrDWORD(sz, value, MAX_PATH);
|
|
}
|
|
|
|
|
|
void
|
|
AppendHexStringWithGUID(
|
|
IN OUT PSTR sz,
|
|
IN GUID *guid
|
|
)
|
|
{
|
|
return CatStrGUID(sz, guid, MAX_PATH);
|
|
}
|
|
|
|
|
|
void
|
|
AppendHexStringWithOldGUID(
|
|
IN OUT PSTR sz,
|
|
IN GUID *guid
|
|
)
|
|
{
|
|
return CatStrOldGUID(sz, guid, MAX_PATH);
|
|
}
|
|
|
|
|
|
void
|
|
AppendHexStringWithID(
|
|
IN OUT PSTR sz,
|
|
PVOID id,
|
|
DWORD paramtype
|
|
)
|
|
{
|
|
return CatStrID(sz, id, paramtype, MAX_PATH);
|
|
}
|
|
|
|
/*
|
|
* Given a string, find the next '*' and zero it
|
|
* out to convert the current token into it's
|
|
* own string. Return the address of the next character,
|
|
* if there are any more strings to parse.
|
|
*/
|
|
|
|
|
|
PSTR
|
|
ExtractToken(
|
|
PSTR in,
|
|
PSTR out,
|
|
size_t size
|
|
)
|
|
{
|
|
PSTR p = in;
|
|
|
|
*out = 0;
|
|
|
|
if (!in || !*in)
|
|
return NULL;
|
|
|
|
for (;*p; p++) {
|
|
if (*p == '*') {
|
|
*p = 0;
|
|
p++;
|
|
break;
|
|
}
|
|
}
|
|
CopyString(out, in, size);
|
|
|
|
return (*p) ? p : NULL;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BuildRelativePath(
|
|
OUT LPSTR rpath,
|
|
IN LPCSTR filename,
|
|
IN PVOID id, // first number in directory name
|
|
IN DWORD val2, // second number in directory name
|
|
IN DWORD val3, // third number in directory name
|
|
IN DWORD size
|
|
)
|
|
{
|
|
LPSTR p;
|
|
|
|
assert(rpath);
|
|
|
|
CopyString(rpath, filename, size);
|
|
EnsureTrailingBackslash(rpath);
|
|
CatStrID(rpath, id, gptype, size);
|
|
CatStrDWORD(rpath, val2, size);
|
|
CatStrDWORD(rpath, val3, size);
|
|
|
|
for (p = rpath + strlen(rpath) - 1; p > rpath; p--) {
|
|
if (*p == '\\') {
|
|
dprint("Insufficient information querying for %s\n", filename);
|
|
SetLastError(ERROR_MORE_DATA);
|
|
return false;
|
|
}
|
|
if (*p != '0')
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SymbolServerClose()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL
|
|
TestParameters(
|
|
IN PCSTR params, // server and cache path
|
|
IN PCSTR filename, // name of file to search for
|
|
IN PVOID id, // first number in directory name
|
|
IN DWORD val2, // second number in directory name
|
|
IN DWORD val3, // third number in directory name
|
|
OUT PSTR path // return validated file path here
|
|
)
|
|
{
|
|
__try {
|
|
if (path)
|
|
*path = 0;
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return SetError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (!path || !params || !*params || !filename || !*filename || (!id && !val2 && !val3))
|
|
return SetError(ERROR_INVALID_PARAMETER);
|
|
|
|
if (strlen(filename) > 100) {
|
|
dprint("%s - filename cannot exceed 100 characters\n", filename);
|
|
return SetError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
switch (gptype)
|
|
{
|
|
case SSRVOPT_GUIDPTR:
|
|
case SSRVOPT_OLDGUIDPTR:
|
|
// this test should AV if a valid GUID pointer wasn't passed in
|
|
__try {
|
|
GUID *guid = (GUID *)id;
|
|
BYTE b;
|
|
b = guid->Data4[8];
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return SetError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
break;
|
|
case SSRVOPT_DWORDPTR:
|
|
// this test should AV if a valid DWORD pointer wasn't passed in
|
|
__try {
|
|
DWORD dword = *(DWORD *)id;
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
return SetError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SymbolServer(
|
|
IN PCSTR params, // server and cache path
|
|
IN PCSTR filename, // name of file to search for
|
|
IN PVOID id, // first number in directory name
|
|
IN DWORD val2, // second number in directory name
|
|
IN DWORD val3, // third number in directory name
|
|
OUT PSTR path // return validated file path here
|
|
)
|
|
{
|
|
CHAR *p;
|
|
CHAR tdir[MAX_PATH + 1] = "";
|
|
CHAR sdir[MAX_PATH + 1] = "";
|
|
CHAR sz[MAX_PATH * 2 + 3];
|
|
CHAR rpath[MAX_PATH + 1];
|
|
BOOL rc;
|
|
|
|
if (!TestParameters(params, filename, id, val2, val3, path))
|
|
return false;
|
|
|
|
// test environment
|
|
|
|
if (gdbgout == -1) {
|
|
if (GetEnvironmentVariable("SYMSRV_DBGOUT", sz, MAX_PATH))
|
|
gdbgout = 1;
|
|
else
|
|
gdbgout = 0;
|
|
*sz = 0;
|
|
}
|
|
|
|
// parse parameters
|
|
|
|
CopyStrArray(sz, params);
|
|
p = ExtractToken(sz, tdir, DIMA(tdir)); // 1st path is where the symbol should be
|
|
p = ExtractToken(p, sdir, DIMA(sdir)); // 2nd optional path is the server to copy from
|
|
|
|
// build the relative path to the target symbol file
|
|
|
|
if (!BuildRelativePath(rpath, filename, id, val2, val3, DIMA(rpath)))
|
|
return false;
|
|
|
|
// if no_copy option is set, just return the path to the target
|
|
|
|
if (goptions & SSRVOPT_NOCOPY) {
|
|
pathcpy(path, tdir, rpath, MAX_PATH);
|
|
pathcat(path, filename, MAX_PATH);
|
|
return true;
|
|
}
|
|
|
|
// copy from server to specified symbol path
|
|
|
|
rc = copy(tdir, sdir, rpath, filename, path, 0);
|
|
if (!rc)
|
|
*path = 0;
|
|
|
|
return rc;
|
|
}
|
|
|
|
BOOL
|
|
SymbolServerSetOptions(
|
|
UINT_PTR options,
|
|
ULONG64 data
|
|
)
|
|
{
|
|
DWORD ptype;
|
|
|
|
// set the callback function
|
|
|
|
if (options & SSRVOPT_CALLBACK) {
|
|
if (data) {
|
|
goptions |= SSRVOPT_CALLBACK;
|
|
gcallback = (PSYMBOLSERVERCALLBACKPROC)data;
|
|
} else {
|
|
goptions &= ~SSRVOPT_CALLBACK;
|
|
gcallback = NULL;
|
|
}
|
|
}
|
|
|
|
// set the callback context
|
|
|
|
if (options & SSRVOPT_SETCONTEXT)
|
|
gcontext = data;
|
|
|
|
// when this flags is set, trace output will be delivered
|
|
|
|
if (options & SSRVOPT_TRACE) {
|
|
if (data) {
|
|
goptions |= SSRVOPT_TRACE;
|
|
setdprint(_dprint);
|
|
} else {
|
|
goptions &= ~SSRVOPT_TRACE;
|
|
setdprint(NULL);
|
|
}
|
|
}
|
|
|
|
// set the parameter type for the first ID parameter
|
|
|
|
if (options & SSRVOPT_PARAMTYPE) {
|
|
switch(data) {
|
|
case SSRVOPT_DWORD:
|
|
case SSRVOPT_DWORDPTR:
|
|
case SSRVOPT_GUIDPTR:
|
|
case SSRVOPT_OLDGUIDPTR:
|
|
goptions &= ~(SSRVOPT_DWORD | SSRVOPT_DWORDPTR | SSRVOPT_GUIDPTR | SSRVOPT_OLDGUIDPTR);
|
|
goptions |= data;
|
|
gptype = (DWORD)data;
|
|
break;
|
|
default:
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// set the parameter type for the first ID paramter - OLD SYNTAX
|
|
// the if statements provide and order of precedence
|
|
|
|
ptype = 0;
|
|
if (options & SSRVOPT_DWORD)
|
|
ptype = SSRVOPT_DWORD;
|
|
if (options & SSRVOPT_DWORDPTR)
|
|
ptype = SSRVOPT_DWORDPTR;
|
|
if (options & SSRVOPT_GUIDPTR)
|
|
ptype = SSRVOPT_GUIDPTR;
|
|
if (options & SSRVOPT_OLDGUIDPTR)
|
|
ptype = SSRVOPT_OLDGUIDPTR;
|
|
if (ptype) {
|
|
goptions &= ~(SSRVOPT_DWORD | SSRVOPT_DWORDPTR | SSRVOPT_GUIDPTR | SSRVOPT_OLDGUIDPTR);
|
|
if (data) {
|
|
goptions |= ptype;
|
|
gptype = ptype;
|
|
} else if (gptype == ptype) {
|
|
// when turning off a type, reset it to DWORD
|
|
goptions |= SSRVOPT_DWORD;
|
|
gptype = SSRVOPT_DWORD;
|
|
}
|
|
}
|
|
|
|
// if this flag is set, no GUI will be displayed
|
|
|
|
if (options & SSRVOPT_UNATTENDED) {
|
|
if (data)
|
|
goptions |= SSRVOPT_UNATTENDED;
|
|
else
|
|
goptions &= ~SSRVOPT_UNATTENDED;
|
|
}
|
|
|
|
// when this is set, the existence of the returned file path is not checked
|
|
|
|
if (options & SSRVOPT_NOCOPY) {
|
|
if (data)
|
|
goptions |= SSRVOPT_NOCOPY;
|
|
else
|
|
goptions &= ~SSRVOPT_NOCOPY;
|
|
}
|
|
|
|
// this window handle is used as a parent for dialog boxes
|
|
|
|
if (options & SSRVOPT_PARENTWIN) {
|
|
SetParentWindow((HWND)data);
|
|
if (data)
|
|
goptions |= SSRVOPT_PARENTWIN;
|
|
else
|
|
goptions &= ~SSRVOPT_PARENTWIN;
|
|
}
|
|
|
|
// when running in secure mode, we don't copy files to downstream stores
|
|
|
|
if (options & SSRVOPT_SECURE) {
|
|
if (data)
|
|
goptions |= SSRVOPT_SECURE;
|
|
else
|
|
goptions &= ~SSRVOPT_SECURE;
|
|
}
|
|
|
|
// set http proxy
|
|
|
|
if (options & SSRVOPT_PROXY) {
|
|
if (data) {
|
|
goptions |= SSRVOPT_PROXY;
|
|
CopyStrArray(gproxy, (char *)data);
|
|
setproxy(gproxy);
|
|
} else {
|
|
goptions &= ~SSRVOPT_PROXY;
|
|
*gproxy = 0;
|
|
setproxy(NULL);
|
|
}
|
|
}
|
|
|
|
// set default downstream store
|
|
|
|
if (options & SSRVOPT_DOWNSTREAM_STORE) {
|
|
if (data) {
|
|
goptions |= SSRVOPT_DOWNSTREAM_STORE;
|
|
CopyStrArray(gdstore, (char *)data);
|
|
setdstore(gdstore);
|
|
} else {
|
|
goptions &= ~SSRVOPT_DOWNSTREAM_STORE;
|
|
*gdstore = 0;
|
|
setdstore(NULL);
|
|
}
|
|
}
|
|
|
|
SetStoreOptions(goptions);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
UINT_PTR
|
|
SymbolServerGetOptions(
|
|
)
|
|
{
|
|
return goptions;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SymbolServerPing(
|
|
IN PCSTR params // server and cache path
|
|
)
|
|
{
|
|
CHAR *p;
|
|
CHAR sz[MAX_PATH * 2 + 3];
|
|
CHAR tdir[MAX_PATH + 1] = "";
|
|
CHAR sdir[MAX_PATH + 1] = "";
|
|
CHAR rpath[MAX_PATH + 1];
|
|
CHAR filename[MAX_PATH + 1];
|
|
CHAR path[MAX_PATH + 1];
|
|
|
|
if (!params || !*params)
|
|
return SetError(ERROR_INVALID_PARAMETER);
|
|
|
|
// parse parameters
|
|
|
|
// parse parameters
|
|
|
|
CopyStrArray(sz, params);
|
|
p = ExtractToken(sz, tdir, DIMA(tdir)); // 1st path is where the symbol should be
|
|
p = ExtractToken(p, sdir, DIMA(sdir)); // 2nd optional path is the server to copy from
|
|
|
|
// copy from server to specified symbol path
|
|
|
|
return ping(tdir, sdir, rpath, filename, path, 0);
|
|
|
|
return true;
|
|
}
|
|
|