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.

1691 lines
40 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // General utility routines.
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "pch.hpp"
  9. #ifndef _WIN32_WCE
  10. #include <common.ver>
  11. #include <dbghelp.h>
  12. #else
  13. #include <winver.h>
  14. #define VER_VERSION_TRANSLATION 0x0000, 0x04B0
  15. #endif
  16. #include <wininet.h>
  17. #include <lmerr.h>
  18. #include "symsrv.h"
  19. #define NTDLL_APIS
  20. #include "dllimp.h"
  21. #include "cmnutil.hpp"
  22. #ifdef NT_NATIVE
  23. #include "ntnative.h"
  24. #endif
  25. #define COPYSTR_MOD
  26. #include "copystr.h"
  27. // Formatted codes are pretty small and there's usually only
  28. // one in a message.
  29. #define MAX_FORMAT_CODE_STRINGS 2
  30. #define MAX_FORMAT_CODE_BUFFER 64
  31. char g_FormatCodeBuffer[MAX_FORMAT_CODE_STRINGS][MAX_FORMAT_CODE_BUFFER];
  32. ULONG g_NextFormatCodeBuffer = MAX_FORMAT_CODE_STRINGS;
  33. // Security attributes with a NULL DACL to explicitly
  34. // allow anyone access.
  35. PSECURITY_DESCRIPTOR g_AllAccessSecDesc;
  36. SECURITY_ATTRIBUTES g_AllAccessSecAttr;
  37. PSTR
  38. FormatStatusCode(HRESULT Status)
  39. {
  40. PSTR Buf;
  41. DWORD Len = 0;
  42. g_NextFormatCodeBuffer = (g_NextFormatCodeBuffer + 1) &
  43. (MAX_FORMAT_CODE_STRINGS - 1);
  44. Buf = g_FormatCodeBuffer[g_NextFormatCodeBuffer];
  45. if ((LONG)Status & FACILITY_NT_BIT)
  46. {
  47. sprintf(Buf, "NTSTATUS 0x%08X", Status & ~FACILITY_NT_BIT);
  48. }
  49. else if (HRESULT_FACILITY(Status) == FACILITY_WIN32)
  50. {
  51. sprintf(Buf, "Win32 error %d", HRESULT_CODE(Status));
  52. }
  53. else
  54. {
  55. sprintf(Buf, "HRESULT 0x%08X", Status);
  56. }
  57. return Buf;
  58. }
  59. #ifndef NT_NATIVE
  60. // Generally there's only one status per output message so
  61. // only keep space for a small number of strings. Each string
  62. // can be verbose plus it can contain inserts which may be large
  63. // so each string buffer needs to be roomy.
  64. #define MAX_FORMAT_STATUS_STRINGS 2
  65. #define MAX_FORMAT_STATUS_BUFFER 1024
  66. char g_FormatStatusBuffer[MAX_FORMAT_STATUS_STRINGS][MAX_FORMAT_STATUS_BUFFER];
  67. ULONG g_NextFormatStatusBuffer = MAX_FORMAT_STATUS_STRINGS;
  68. PSTR
  69. FormatAnyStatus(HRESULT Status, PVOID Arguments,
  70. PBOOL IsNtStatus, PSTR* ErrorGroup)
  71. {
  72. PSTR Buf;
  73. DWORD Len = 0;
  74. PVOID Source;
  75. PSTR SourceDll;
  76. DWORD Flags;
  77. BOOL _IsNtStatus = FALSE;
  78. PSTR _ErrorGroup;
  79. BOOL FreeLib = FALSE;
  80. g_NextFormatStatusBuffer = (g_NextFormatStatusBuffer + 1) &
  81. (MAX_FORMAT_STATUS_STRINGS - 1);
  82. Buf = g_FormatStatusBuffer[g_NextFormatStatusBuffer];
  83. // By default, get error text from the system error list.
  84. Flags = FORMAT_MESSAGE_FROM_SYSTEM;
  85. // If this is an NT code and ntdll is around,
  86. // allow messages to be retrieved from it also.
  87. if ((IsNtStatus && *IsNtStatus) ||
  88. ((ULONG)Status & FACILITY_NT_BIT) ||
  89. ((ULONG)Status & 0xc0000000) == 0xc0000000)
  90. {
  91. Status &= ~FACILITY_NT_BIT;
  92. _IsNtStatus = TRUE;
  93. _ErrorGroup = "NTSTATUS";
  94. SourceDll = "ntdll.dll";
  95. }
  96. else if ((ULONG)Status >= NERR_BASE && (ULONG)Status <= MAX_NERR)
  97. {
  98. _ErrorGroup = "NetAPI";
  99. SourceDll = "netmsg.dll";
  100. }
  101. else if (((ULONG)Status >= WSABASEERR &&
  102. (ULONG)Status <= WSABASEERR + 150) ||
  103. ((ULONG)Status >= WSABASEERR + 1000 &&
  104. (ULONG)Status <= WSABASEERR + 1050))
  105. {
  106. _ErrorGroup = "WinSock";
  107. SourceDll = "wsock32.dll";
  108. }
  109. else
  110. {
  111. _ErrorGroup = ((ULONG)Status & 0x80000000) ? "HRESULT" : "Win32";
  112. SourceDll = NULL;
  113. }
  114. if (IsNtStatus)
  115. {
  116. *IsNtStatus = _IsNtStatus;
  117. }
  118. if (ErrorGroup)
  119. {
  120. *ErrorGroup = _ErrorGroup;
  121. }
  122. // Use the currently loaded DLL if possible, otherwise load it.
  123. if (SourceDll)
  124. {
  125. if (!(Source = (PVOID)GetModuleHandle(SourceDll)))
  126. {
  127. Source = (PVOID)LoadLibrary(SourceDll);
  128. FreeLib = TRUE;
  129. }
  130. if (Source)
  131. {
  132. Flags |= FORMAT_MESSAGE_FROM_HMODULE;
  133. }
  134. }
  135. else
  136. {
  137. Source = NULL;
  138. }
  139. // If the caller passed in arguments allow format inserts
  140. // to be processed.
  141. if (Arguments != NULL)
  142. {
  143. Len = FormatMessage(Flags | FORMAT_MESSAGE_ARGUMENT_ARRAY, Source,
  144. Status, 0, Buf, MAX_FORMAT_STATUS_BUFFER,
  145. (va_list*)Arguments);
  146. }
  147. // If no arguments were passed or FormatMessage failed when
  148. // used with arguments try it without format inserts.
  149. if (Len == 0)
  150. {
  151. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  152. MessageEntry = NULL;
  153. if (Source &&
  154. g_NtDllCalls.RtlFindMessage &&
  155. NT_SUCCESS(g_NtDllCalls.
  156. RtlFindMessage(Source, PtrToUlong(RT_MESSAGETABLE),
  157. 0, (ULONG)Status, &MessageEntry)) &&
  158. MessageEntry)
  159. {
  160. if (MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE)
  161. {
  162. _snprintf(Buf, MAX_FORMAT_STATUS_BUFFER,
  163. "%ws", (PWSTR)MessageEntry->Text);
  164. Buf[MAX_FORMAT_STATUS_BUFFER - 1] = 0;
  165. }
  166. else
  167. {
  168. CopyString(Buf, (PSTR)MessageEntry->Text,
  169. MAX_FORMAT_STATUS_BUFFER);
  170. }
  171. Len = strlen(Buf);
  172. }
  173. else
  174. {
  175. Len = FormatMessage(Flags | FORMAT_MESSAGE_IGNORE_INSERTS, Source,
  176. Status, 0, Buf, MAX_FORMAT_STATUS_BUFFER,
  177. NULL);
  178. }
  179. }
  180. if (Source && FreeLib)
  181. {
  182. FreeLibrary((HMODULE)Source);
  183. }
  184. if (Len > 0)
  185. {
  186. PSTR Scan;
  187. //
  188. // Eliminate unprintable characters and trim trailing spaces.
  189. //
  190. Scan = Buf;
  191. while (*Scan)
  192. {
  193. if (!isprint(*Scan))
  194. {
  195. *Scan = ' ';
  196. }
  197. Scan++;
  198. }
  199. while (Len > 0 && isspace(Buf[Len - 1]))
  200. {
  201. Buf[--Len] = 0;
  202. }
  203. }
  204. if (Len > 0)
  205. {
  206. return Buf;
  207. }
  208. else
  209. {
  210. return "<Unable to get error code text>";
  211. }
  212. }
  213. HINSTANCE g_hsrv = 0;
  214. HTTPOPENFILEHANDLE g_httpOpenFileHandle = NULL;
  215. HTTPQUERYDATAAVAILABLE g_httpQueryDataAvailable = NULL;
  216. HTTPREADFILE g_httpReadFile = NULL;
  217. HTTPCLOSEHANDLE g_httpCloseHandle;
  218. BOOL
  219. HttpOpenFileHandle(
  220. IN LPCSTR prefix,
  221. IN LPCSTR fullpath,
  222. IN DWORD options,
  223. OUT HINTERNET *hsite,
  224. OUT HINTERNET *hfile
  225. )
  226. {
  227. BOOL rc = FALSE;
  228. CHAR buf[_MAX_PATH];
  229. LPSTR site;
  230. LPSTR path;
  231. if (!g_hsrv)
  232. {
  233. g_hsrv = LoadLibrary("symsrv.dll");
  234. g_httpOpenFileHandle = (HTTPOPENFILEHANDLE)GetProcAddress(g_hsrv, "httpOpenFileHandle");
  235. if (!g_httpOpenFileHandle)
  236. {
  237. g_hsrv = (HINSTANCE)INVALID_HANDLE_VALUE;
  238. }
  239. g_httpQueryDataAvailable = (HTTPQUERYDATAAVAILABLE)GetProcAddress(g_hsrv, "httpQueryDataAvailable");
  240. if (!g_httpQueryDataAvailable)
  241. {
  242. g_hsrv = (HINSTANCE)INVALID_HANDLE_VALUE;
  243. }
  244. g_httpReadFile = (HTTPREADFILE)GetProcAddress(g_hsrv, "httpReadFile");
  245. if (!g_httpReadFile)
  246. {
  247. g_hsrv = (HINSTANCE)INVALID_HANDLE_VALUE;
  248. }
  249. g_httpCloseHandle = (HTTPCLOSEHANDLE)GetProcAddress(g_hsrv, "httpCloseHandle");
  250. if (!g_httpCloseHandle)
  251. {
  252. g_hsrv = (HINSTANCE)INVALID_HANDLE_VALUE;
  253. }
  254. }
  255. if (!g_httpOpenFileHandle)
  256. {
  257. return rc;
  258. }
  259. CopyString(buf, fullpath, DIMA(buf));
  260. if (prefix && *prefix)
  261. {
  262. if (!strstr(buf, prefix))
  263. {
  264. return rc;
  265. }
  266. site = buf;
  267. path = buf + strlen(prefix);
  268. *path++ = 0;
  269. }
  270. else
  271. {
  272. site = NULL;
  273. path = buf;
  274. }
  275. rc = g_httpOpenFileHandle(site, path, options, hsite, hfile);
  276. if (!rc)
  277. {
  278. if (GetLastError() == ERROR_INVALID_NAME)
  279. {
  280. g_hsrv = (HINSTANCE)INVALID_HANDLE_VALUE;
  281. g_httpOpenFileHandle = NULL;
  282. }
  283. }
  284. return rc;
  285. }
  286. BOOL
  287. InstallAsAeDebug(PCSTR Append)
  288. {
  289. PCSTR KeyName;
  290. HKEY Key;
  291. LONG Status;
  292. char Value[MAX_PATH * 2];
  293. Value[0] = '"';
  294. if (GetModuleFileName(NULL, Value + 1, DIMA(Value) - 1) == 0)
  295. {
  296. return FALSE;
  297. }
  298. if (!CatString(Value, "\" -p %ld -e %ld -g", DIMA(Value)))
  299. {
  300. return FALSE;
  301. }
  302. if (Append != NULL)
  303. {
  304. if (!CatString(Value, " ", DIMA(Value)) ||
  305. !CatString(Value, Append, DIMA(Value)))
  306. {
  307. return FALSE;
  308. }
  309. }
  310. // AeDebug is always under Windows NT even on Win9x.
  311. KeyName = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug";
  312. Status = RegCreateKeyEx(HKEY_LOCAL_MACHINE, KeyName,
  313. 0, NULL, 0, KEY_READ | KEY_WRITE, NULL,
  314. &Key, NULL);
  315. if (Status == ERROR_SUCCESS)
  316. {
  317. Status = RegSetValueEx(Key, "Debugger", 0, REG_SZ,
  318. (PUCHAR)Value, strlen(Value) + 1);
  319. if (Status == ERROR_SUCCESS)
  320. {
  321. Status = RegSetValueEx(Key, "Auto", 0, REG_SZ,
  322. (PUCHAR)"1", 2);
  323. }
  324. RegCloseKey(Key);
  325. }
  326. return Status == ERROR_SUCCESS;
  327. }
  328. HANDLE
  329. CreatePidEvent(ULONG Pid, ULONG CreateOrOpen)
  330. {
  331. HANDLE Event;
  332. char Name[32];
  333. sprintf(Name, "DbgEngEvent_%08X", Pid);
  334. Event = CreateEvent(NULL, FALSE, FALSE, Name);
  335. if (Event != NULL)
  336. {
  337. if (GetLastError() == ERROR_ALREADY_EXISTS)
  338. {
  339. if (CreateOrOpen == CREATE_NEW)
  340. {
  341. CloseHandle(Event);
  342. Event = NULL;
  343. }
  344. }
  345. else if (CreateOrOpen == OPEN_EXISTING)
  346. {
  347. CloseHandle(Event);
  348. Event = NULL;
  349. }
  350. }
  351. return Event;
  352. }
  353. BOOL
  354. SetPidEvent(ULONG Pid, ULONG CreateOrOpen)
  355. {
  356. BOOL Status;
  357. HANDLE Event = CreatePidEvent(Pid, CreateOrOpen);
  358. if (Event != NULL)
  359. {
  360. Status = SetEvent(Event);
  361. CloseHandle(Event);
  362. }
  363. else
  364. {
  365. Status = FALSE;
  366. }
  367. return Status;
  368. }
  369. HRESULT
  370. EnableDebugPrivilege(void)
  371. {
  372. OSVERSIONINFO OsVer;
  373. OsVer.dwOSVersionInfoSize = sizeof(OsVer);
  374. if (!GetVersionEx(&OsVer))
  375. {
  376. return WIN32_LAST_STATUS();
  377. }
  378. if (OsVer.dwPlatformId != VER_PLATFORM_WIN32_NT)
  379. {
  380. return S_OK;
  381. }
  382. #ifdef _WIN32_WCE
  383. return E_NOTIMPL;
  384. #else
  385. HRESULT Status = S_OK;
  386. HANDLE Token;
  387. PTOKEN_PRIVILEGES NewPrivileges;
  388. LUID LuidPrivilege;
  389. static s_PrivilegeEnabled = FALSE;
  390. if (s_PrivilegeEnabled)
  391. {
  392. return S_OK;
  393. }
  394. //
  395. // Make sure we have access to adjust and to get the
  396. // old token privileges
  397. //
  398. if (!OpenProcessToken(GetCurrentProcess(),
  399. TOKEN_ADJUST_PRIVILEGES,
  400. &Token))
  401. {
  402. Status = WIN32_LAST_STATUS();
  403. goto EH_Exit;
  404. }
  405. //
  406. // Initialize the privilege adjustment structure
  407. //
  408. LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &LuidPrivilege);
  409. NewPrivileges = (PTOKEN_PRIVILEGES)
  410. calloc(1, sizeof(TOKEN_PRIVILEGES) +
  411. (1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
  412. if (NewPrivileges == NULL)
  413. {
  414. Status = E_OUTOFMEMORY;
  415. goto EH_Token;
  416. }
  417. NewPrivileges->PrivilegeCount = 1;
  418. NewPrivileges->Privileges[0].Luid = LuidPrivilege;
  419. NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  420. //
  421. // Enable the privilege
  422. //
  423. if (!AdjustTokenPrivileges( Token, FALSE,
  424. NewPrivileges, 0, NULL, NULL ))
  425. {
  426. Status = WIN32_LAST_STATUS();
  427. }
  428. free(NewPrivileges);
  429. EH_Token:
  430. CloseHandle(Token);
  431. EH_Exit:
  432. if (Status == S_OK)
  433. {
  434. s_PrivilegeEnabled = TRUE;
  435. }
  436. return Status;
  437. #endif // #ifdef _WIN32_WCE
  438. }
  439. #else // #ifndef NT_NATIVE
  440. HRESULT
  441. EnableDebugPrivilege(void)
  442. {
  443. HRESULT Status = S_OK;
  444. HANDLE Token;
  445. PTOKEN_PRIVILEGES NewPrivileges;
  446. LUID LuidPrivilege;
  447. NTSTATUS NtStatus;
  448. static s_PrivilegeEnabled = FALSE;
  449. if (s_PrivilegeEnabled)
  450. {
  451. return S_OK;
  452. }
  453. //
  454. // Make sure we have access to adjust and to get the
  455. // old token privileges
  456. //
  457. if (!NT_SUCCESS(NtStatus =
  458. NtOpenProcessToken(NtCurrentProcess(),
  459. TOKEN_ADJUST_PRIVILEGES,
  460. &Token)))
  461. {
  462. Status = HRESULT_FROM_NT(NtStatus);
  463. goto EH_Exit;
  464. }
  465. //
  466. // Initialize the privilege adjustment structure
  467. //
  468. LuidPrivilege = RtlConvertUlongToLuid(SE_DEBUG_PRIVILEGE);
  469. NewPrivileges = (PTOKEN_PRIVILEGES)
  470. RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY,
  471. sizeof(TOKEN_PRIVILEGES) +
  472. (1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
  473. if (NewPrivileges == NULL)
  474. {
  475. Status = E_OUTOFMEMORY;
  476. goto EH_Token;
  477. }
  478. NewPrivileges->PrivilegeCount = 1;
  479. NewPrivileges->Privileges[0].Luid = LuidPrivilege;
  480. NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  481. //
  482. // Enable the privilege
  483. //
  484. if (!NT_SUCCESS(NtStatus =
  485. NtAdjustPrivilegesToken(Token,
  486. FALSE,
  487. NewPrivileges,
  488. 0, NULL, NULL)))
  489. {
  490. Status = HRESULT_FROM_NT(NtStatus);
  491. }
  492. free(NewPrivileges);
  493. EH_Token:
  494. NtClose(Token);
  495. EH_Exit:
  496. if (Status == S_OK)
  497. {
  498. s_PrivilegeEnabled = TRUE;
  499. }
  500. return Status;
  501. }
  502. #endif // #ifndef NT_NATIVE
  503. //
  504. // Copies the input data to the output buffer.
  505. // Handles optionality of the buffer pointer and output length
  506. // parameter. Trims the data to fit the buffer.
  507. // Returns S_FALSE if only a part of the data is copied.
  508. //
  509. HRESULT
  510. FillDataBuffer(PVOID Data, ULONG DataLen,
  511. PVOID Buffer, ULONG BufferLen, PULONG BufferUsed)
  512. {
  513. ULONG Len;
  514. HRESULT Status;
  515. if (DataLen > BufferLen && Buffer != NULL)
  516. {
  517. Len = BufferLen;
  518. Status = S_FALSE;
  519. }
  520. else
  521. {
  522. Len = DataLen;
  523. Status = S_OK;
  524. }
  525. if (Buffer != NULL && BufferLen > 0 && Data != NULL && Len > 0)
  526. {
  527. memcpy(Buffer, Data, Len);
  528. }
  529. if (BufferUsed != NULL)
  530. {
  531. *BufferUsed = DataLen;
  532. }
  533. return Status;
  534. }
  535. //
  536. // Copies the input string to the output buffer.
  537. // Handles optionality of the buffer pointer and output length
  538. // parameter. Trims the string to fit the buffer and guarantees
  539. // termination of the string in the buffer if anything fits.
  540. // Returns S_FALSE if only a partial string is copied.
  541. //
  542. // If the input string length is zero the routine strlens.
  543. //
  544. HRESULT
  545. FillStringBuffer(PCSTR String, ULONG StringLenIn,
  546. PSTR Buffer, ULONG BufferLen, PULONG StringLenOut)
  547. {
  548. ULONG Len;
  549. HRESULT Status;
  550. if (StringLenIn == 0)
  551. {
  552. if (String != NULL)
  553. {
  554. StringLenIn = strlen(String) + 1;
  555. }
  556. else
  557. {
  558. StringLenIn = 1;
  559. }
  560. }
  561. if (BufferLen == 0)
  562. {
  563. Len = 0;
  564. Status = Buffer != NULL ? S_FALSE : S_OK;
  565. }
  566. else if (StringLenIn >= BufferLen)
  567. {
  568. Len = BufferLen - 1;
  569. Status = StringLenIn > BufferLen ? S_FALSE : S_OK;
  570. }
  571. else
  572. {
  573. Len = StringLenIn - 1;
  574. Status = S_OK;
  575. }
  576. if (Buffer != NULL && BufferLen > 0)
  577. {
  578. if (String != NULL)
  579. {
  580. memcpy(Buffer, String, Len);
  581. }
  582. Buffer[Len] = 0;
  583. }
  584. if (StringLenOut != NULL)
  585. {
  586. *StringLenOut = StringLenIn;
  587. }
  588. return Status;
  589. }
  590. HRESULT
  591. AppendToStringBuffer(HRESULT Status, PCSTR String, BOOL First,
  592. PSTR* Buffer, ULONG* BufferLen, PULONG LenOut)
  593. {
  594. ULONG Len = strlen(String) + 1;
  595. BOOL ForceTerminate;
  596. if (LenOut)
  597. {
  598. // If this is the first string we need to add
  599. // on space for the terminator. For later
  600. // strings we only need to add the string
  601. // characters.
  602. *LenOut += First ? Len : Len - 1;
  603. }
  604. // If there's no buffer we can skip writeback and pointer update.
  605. if (!*Buffer || !*BufferLen)
  606. {
  607. return Status;
  608. }
  609. // Fit as much of the string into the buffer as possible.
  610. if (Len > *BufferLen)
  611. {
  612. Status = S_FALSE;
  613. Len = *BufferLen - 1;
  614. ForceTerminate = TRUE;
  615. }
  616. else
  617. {
  618. ForceTerminate = FALSE;
  619. }
  620. memcpy(*Buffer, String, Len);
  621. if (ForceTerminate)
  622. {
  623. (*Buffer)[Len] = 0;
  624. Len++;
  625. }
  626. // Update the buffer pointer to point to the terminator
  627. // for further appends. Update the size similarly.
  628. *Buffer += Len - 1;
  629. *BufferLen -= Len - 1;
  630. return Status;
  631. }
  632. HRESULT
  633. FillStringBufferW(PCWSTR String, ULONG StringLenIn,
  634. PWSTR Buffer, ULONG BufferLen, PULONG StringLenOut)
  635. {
  636. ULONG Len;
  637. HRESULT Status;
  638. if (StringLenIn == 0)
  639. {
  640. if (String != NULL)
  641. {
  642. StringLenIn = (wcslen(String) + 1) * sizeof(WCHAR);
  643. }
  644. else
  645. {
  646. StringLenIn = sizeof(WCHAR);
  647. }
  648. }
  649. // Ignore partial character storage space in the buffer.
  650. BufferLen &= ~(sizeof(WCHAR) - 1);
  651. if (BufferLen < sizeof(WCHAR))
  652. {
  653. Len = 0;
  654. Status = Buffer != NULL ? S_FALSE : S_OK;
  655. }
  656. else if (StringLenIn >= BufferLen)
  657. {
  658. Len = BufferLen - sizeof(WCHAR);
  659. Status = StringLenIn > BufferLen ? S_FALSE : S_OK;
  660. }
  661. else
  662. {
  663. Len = StringLenIn - sizeof(WCHAR);
  664. Status = S_OK;
  665. }
  666. if (Buffer != NULL && BufferLen > 0)
  667. {
  668. if (String != NULL)
  669. {
  670. memcpy(Buffer, String, Len);
  671. }
  672. Buffer[Len / sizeof(WCHAR)] = 0;
  673. }
  674. if (StringLenOut != NULL)
  675. {
  676. *StringLenOut = StringLenIn;
  677. }
  678. return Status;
  679. }
  680. HRESULT
  681. AppendToStringBufferW(HRESULT Status, PCWSTR String, BOOL First,
  682. PWSTR* Buffer, ULONG* BufferLen, PULONG LenOut)
  683. {
  684. ULONG Len = (wcslen(String) + 1) * sizeof(WCHAR);
  685. if (LenOut)
  686. {
  687. // If this is the first string we need to add
  688. // on space for the terminator. For later
  689. // strings we only need to add the string
  690. // characters.
  691. *LenOut += First ? Len : Len - sizeof(WCHAR);
  692. }
  693. // If there's no buffer we can skip writeback and pointer update.
  694. if (!*Buffer)
  695. {
  696. return Status;
  697. }
  698. ULONG RoundBufLen = *BufferLen & ~(sizeof(WCHAR) - 1);
  699. // Fit as much of the string into the buffer as possible.
  700. if (Len > RoundBufLen)
  701. {
  702. Status = S_FALSE;
  703. Len = RoundBufLen;
  704. }
  705. memcpy(*Buffer, String, Len);
  706. // Update the buffer pointer to point to the terminator
  707. // for further appends. Update the size similarly.
  708. *Buffer += Len / sizeof(WCHAR) - 1;
  709. *BufferLen -= Len - sizeof(WCHAR);
  710. return Status;
  711. }
  712. PSTR
  713. FindPathElement(PSTR Path, ULONG Element, PSTR* EltEnd)
  714. {
  715. PSTR Elt, Sep;
  716. if (Path == NULL)
  717. {
  718. return NULL;
  719. }
  720. Elt = Path;
  721. for (;;)
  722. {
  723. Sep = strchr(Elt, ';');
  724. if (Sep == NULL)
  725. {
  726. Sep = Elt + strlen(Elt);
  727. }
  728. if (Element == 0)
  729. {
  730. break;
  731. }
  732. if (*Sep == 0)
  733. {
  734. // No more elements.
  735. return NULL;
  736. }
  737. Elt = Sep + 1;
  738. Element--;
  739. }
  740. *EltEnd = Sep;
  741. return Elt;
  742. }
  743. void
  744. Win32ToNtTimeout(ULONG Win32Timeout, PLARGE_INTEGER NtTimeout)
  745. {
  746. if (Win32Timeout == INFINITE)
  747. {
  748. NtTimeout->LowPart = 0;
  749. NtTimeout->HighPart = 0x80000000;
  750. }
  751. else
  752. {
  753. NtTimeout->QuadPart = UInt32x32To64(Win32Timeout, 10000);
  754. NtTimeout->QuadPart *= -1;
  755. }
  756. }
  757. HRESULT
  758. InitializeAllAccessSecObj(void)
  759. {
  760. if (g_AllAccessSecDesc != NULL)
  761. {
  762. // Already initialized.
  763. return S_OK;
  764. }
  765. #ifdef _WIN32_WCE
  766. return S_OK;
  767. #else
  768. HRESULT Status;
  769. SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  770. PSID WorldSid;
  771. if (!AllocateAndInitializeSid(&WorldAuthority, 1,
  772. SECURITY_WORLD_RID,
  773. 0, 0, 0, 0, 0, 0, 0,
  774. &WorldSid))
  775. {
  776. Status = WIN32_LAST_STATUS();
  777. if (Status == HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED))
  778. {
  779. // This platform doesn't support security, such as Win9x.
  780. return S_OK;
  781. }
  782. goto EH_Fail;
  783. }
  784. ULONG AclSize;
  785. AclSize = sizeof(ACL) +
  786. (sizeof(ACCESS_DENIED_ACE) - sizeof(ULONG)) +
  787. (sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG)) +
  788. 2 * GetLengthSid(WorldSid);
  789. g_AllAccessSecDesc =
  790. (PSECURITY_DESCRIPTOR)malloc(SECURITY_DESCRIPTOR_MIN_LENGTH + AclSize);
  791. if (g_AllAccessSecDesc == NULL)
  792. {
  793. Status = E_OUTOFMEMORY;
  794. goto EH_Sid;
  795. }
  796. PACL Acl;
  797. Acl = (PACL)((PUCHAR)g_AllAccessSecDesc + SECURITY_DESCRIPTOR_MIN_LENGTH);
  798. if (!InitializeAcl(Acl, AclSize, ACL_REVISION) ||
  799. !AddAccessDeniedAce(Acl, ACL_REVISION, WRITE_DAC | WRITE_OWNER,
  800. WorldSid) ||
  801. !AddAccessAllowedAce(Acl, ACL_REVISION, GENERIC_ALL,
  802. WorldSid) ||
  803. !InitializeSecurityDescriptor(g_AllAccessSecDesc,
  804. SECURITY_DESCRIPTOR_REVISION) ||
  805. !SetSecurityDescriptorDacl(g_AllAccessSecDesc, TRUE, Acl, FALSE))
  806. {
  807. Status = WIN32_LAST_STATUS();
  808. goto EH_Desc;
  809. }
  810. FreeSid(WorldSid);
  811. g_AllAccessSecAttr.nLength = sizeof(g_AllAccessSecAttr);
  812. g_AllAccessSecAttr.lpSecurityDescriptor = g_AllAccessSecDesc;
  813. g_AllAccessSecAttr.bInheritHandle = FALSE;
  814. return S_OK;
  815. EH_Desc:
  816. free(g_AllAccessSecDesc);
  817. g_AllAccessSecDesc = NULL;
  818. EH_Sid:
  819. FreeSid(WorldSid);
  820. EH_Fail:
  821. return Status;
  822. #endif // #ifdef _WIN32_WCE
  823. }
  824. void
  825. DeleteAllAccessSecObj(void)
  826. {
  827. free(g_AllAccessSecDesc);
  828. g_AllAccessSecDesc = NULL;
  829. ZeroMemory(&g_AllAccessSecAttr, sizeof(g_AllAccessSecAttr));
  830. }
  831. HRESULT
  832. QueryVersionDataBuffer(PVOID VerData, PCSTR Item,
  833. PVOID Buffer, ULONG BufferSize, PULONG DataSize)
  834. {
  835. #ifndef NT_NATIVE
  836. PVOID Val;
  837. UINT ValSize;
  838. if (!::VerQueryValue(VerData, (PSTR)Item, &Val, &ValSize))
  839. {
  840. return WIN32_LAST_STATUS();
  841. }
  842. else if (!ValSize)
  843. {
  844. return HRESULT_FROM_WIN32(ERROR_NO_DATA);
  845. }
  846. return FillDataBuffer(Val, ValSize,
  847. Buffer, BufferSize, DataSize);
  848. #else // #ifndef NT_NATIVE
  849. return E_UNEXPECTED;
  850. #endif // #ifndef NT_NATIVE
  851. }
  852. PVOID
  853. GetAllFileVersionInfo(PCWSTR VerFile)
  854. {
  855. #ifndef NT_NATIVE
  856. char VerFileA[MAX_PATH];
  857. DWORD VerHandle;
  858. DWORD VerSize = ::GetFileVersionInfoSizeW((PWSTR)VerFile, &VerHandle);
  859. if (VerSize == 0)
  860. {
  861. if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED ||
  862. !WideCharToMultiByte(CP_ACP, 0, VerFile, -1,
  863. VerFileA, sizeof(VerFileA),
  864. NULL, NULL) ||
  865. !(VerSize = ::GetFileVersionInfoSizeA(VerFileA, &VerHandle)))
  866. {
  867. return NULL;
  868. }
  869. }
  870. else
  871. {
  872. VerFileA[0] = 0;
  873. }
  874. PVOID Buffer = malloc(VerSize);
  875. if (Buffer == NULL)
  876. {
  877. return NULL;
  878. }
  879. if ((VerFileA[0] &&
  880. !::GetFileVersionInfoA(VerFileA, VerHandle, VerSize, Buffer)) ||
  881. (!VerFileA[0] &&
  882. !::GetFileVersionInfoW((PWSTR)VerFile, VerHandle, VerSize, Buffer)))
  883. {
  884. free(Buffer);
  885. Buffer = NULL;
  886. }
  887. return Buffer;
  888. #else // #ifndef NT_NATIVE
  889. return NULL;
  890. #endif // #ifndef NT_NATIVE
  891. }
  892. BOOL
  893. GetFileStringFileInfo(PCWSTR VerFile, PCSTR SubItem,
  894. PSTR Buffer, ULONG BufferSize)
  895. {
  896. #ifndef NT_NATIVE
  897. BOOL Status = FALSE;
  898. PVOID AllInfo = GetAllFileVersionInfo(VerFile);
  899. if (AllInfo == NULL)
  900. {
  901. return Status;
  902. }
  903. // XXX drewb - Probably should do a more clever
  904. // enumeration of languages.
  905. char ValName[128];
  906. int PrintChars;
  907. PrintChars = _snprintf(ValName, DIMA(ValName),
  908. "\\StringFileInfo\\%04x%04x\\%s",
  909. VER_VERSION_TRANSLATION, SubItem);
  910. if (PrintChars < 0 || PrintChars == DIMA(ValName))
  911. {
  912. SetLastError(ERROR_INVALID_PARAMETER);
  913. return FALSE;
  914. }
  915. Status = SUCCEEDED(QueryVersionDataBuffer(AllInfo, ValName,
  916. Buffer, BufferSize, NULL));
  917. free(AllInfo);
  918. return Status;
  919. #else // #ifndef NT_NATIVE
  920. return FALSE;
  921. #endif // #ifndef NT_NATIVE
  922. }
  923. BOOL
  924. IsUrlPathComponent(PCSTR Path)
  925. {
  926. return
  927. strncmp(Path, "ftp://", 6) == 0 ||
  928. strncmp(Path, "http://", 7) == 0 ||
  929. strncmp(Path, "https://", 8) == 0 ||
  930. strncmp(Path, "gopher://", 9) == 0;
  931. }
  932. #ifndef NT_NATIVE
  933. BOOL
  934. PathFileExists(PCSTR PathComponent, PCSTR PathAndFile,
  935. ULONG SymOpt, FILE_IO_TYPE* IoType)
  936. {
  937. BOOL Exists = FALSE;
  938. if (IsUrlPathComponent(PathAndFile))
  939. {
  940. PathFile* File;
  941. if (OpenPathFile(PathComponent, PathAndFile, SymOpt, &File) == S_OK)
  942. {
  943. *IoType = File->m_IoType;
  944. delete File;
  945. Exists = TRUE;
  946. }
  947. }
  948. else
  949. {
  950. #ifndef _WIN32_WCE
  951. DWORD OldMode;
  952. if (SymOpt & SYMOPT_FAIL_CRITICAL_ERRORS)
  953. {
  954. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  955. }
  956. #endif
  957. *IoType = FIO_WIN32;
  958. Exists = GetFileAttributes(PathAndFile) != -1;
  959. #ifndef _WIN32_WCE
  960. if (SymOpt & SYMOPT_FAIL_CRITICAL_ERRORS)
  961. {
  962. SetErrorMode(OldMode);
  963. }
  964. #endif
  965. }
  966. return Exists;
  967. }
  968. PathFile::~PathFile(void)
  969. {
  970. }
  971. class Win32PathFile : public PathFile
  972. {
  973. public:
  974. Win32PathFile(void)
  975. : PathFile(FIO_WIN32)
  976. {
  977. m_Handle = NULL;
  978. }
  979. virtual ~Win32PathFile(void)
  980. {
  981. if (m_Handle)
  982. {
  983. CloseHandle(m_Handle);
  984. }
  985. }
  986. virtual HRESULT Open(PCSTR PathComponent, PCSTR PathAndFile,
  987. ULONG SymOpt)
  988. {
  989. HRESULT Status;
  990. #ifndef _WIN32_WCE
  991. DWORD OldMode;
  992. if (SymOpt & SYMOPT_FAIL_CRITICAL_ERRORS)
  993. {
  994. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  995. }
  996. #endif
  997. m_Handle = CreateFile(PathAndFile, GENERIC_READ, FILE_SHARE_READ,
  998. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  999. NULL);
  1000. if (m_Handle == NULL || m_Handle == INVALID_HANDLE_VALUE)
  1001. {
  1002. m_Handle = NULL;
  1003. Status = WIN32_LAST_STATUS();
  1004. }
  1005. else
  1006. {
  1007. Status = S_OK;
  1008. }
  1009. #ifndef _WIN32_WCE
  1010. if (SymOpt & SYMOPT_FAIL_CRITICAL_ERRORS)
  1011. {
  1012. SetErrorMode(OldMode);
  1013. }
  1014. #endif
  1015. return Status;
  1016. }
  1017. virtual HRESULT QueryDataAvailable(PULONG Avail)
  1018. {
  1019. LARGE_INTEGER Cur, End;
  1020. Cur.HighPart = 0;
  1021. End.HighPart = 0;
  1022. if ((Cur.LowPart =
  1023. SetFilePointer(m_Handle, 0, &Cur.HighPart, FILE_CURRENT)) ==
  1024. INVALID_SET_FILE_POINTER ||
  1025. (End.LowPart =
  1026. SetFilePointer(m_Handle, 0, &End.HighPart, FILE_END)) ==
  1027. INVALID_SET_FILE_POINTER ||
  1028. SetFilePointer(m_Handle, Cur.LowPart, &Cur.HighPart, FILE_BEGIN) ==
  1029. INVALID_SET_FILE_POINTER)
  1030. {
  1031. return WIN32_LAST_STATUS();
  1032. }
  1033. End.QuadPart -= Cur.QuadPart;
  1034. if (End.HighPart < 0)
  1035. {
  1036. // Shouldn't be possible, but check anyway.
  1037. return E_FAIL;
  1038. }
  1039. // Limit max data available to 32-bit quantity.
  1040. if (End.HighPart > 0)
  1041. {
  1042. *Avail = 0xffffffff;
  1043. }
  1044. else
  1045. {
  1046. *Avail = End.LowPart;
  1047. }
  1048. return S_OK;
  1049. }
  1050. virtual HRESULT GetLastWriteTime(PFILETIME Time)
  1051. {
  1052. // If we can't get the write time try and get
  1053. // the create time.
  1054. if (!GetFileTime(m_Handle, NULL, NULL, Time))
  1055. {
  1056. if (!GetFileTime(m_Handle, Time, NULL, NULL))
  1057. {
  1058. return WIN32_LAST_STATUS();
  1059. }
  1060. }
  1061. return S_OK;
  1062. }
  1063. virtual HRESULT Read(PVOID Buffer, ULONG BufferLen, PULONG Done)
  1064. {
  1065. if (!ReadFile(m_Handle, Buffer, BufferLen, Done, NULL))
  1066. {
  1067. return WIN32_LAST_STATUS();
  1068. }
  1069. return S_OK;
  1070. }
  1071. private:
  1072. HANDLE m_Handle;
  1073. };
  1074. class WinInetPathFile : public PathFile
  1075. {
  1076. public:
  1077. WinInetPathFile(void)
  1078. : PathFile(FIO_WININET)
  1079. {
  1080. m_SiteHandle = NULL;
  1081. m_Handle = NULL;
  1082. m_InitialDataLen = 0;
  1083. }
  1084. virtual ~WinInetPathFile(void)
  1085. {
  1086. if (m_Handle && g_httpCloseHandle)
  1087. {
  1088. g_httpCloseHandle(m_Handle);
  1089. }
  1090. }
  1091. virtual HRESULT Open(PCSTR PathComponent, PCSTR PathAndFile,
  1092. ULONG SymOpt)
  1093. {
  1094. HRESULT Status;
  1095. if (!HttpOpenFileHandle(PathComponent, PathAndFile, 0, &m_SiteHandle, &m_Handle))
  1096. {
  1097. Status = WIN32_LAST_STATUS();
  1098. goto Fail;
  1099. }
  1100. return S_OK;
  1101. Fail:
  1102. m_InitialDataLen = 0;
  1103. if (m_Handle && g_httpCloseHandle)
  1104. {
  1105. g_httpCloseHandle(m_Handle);
  1106. m_Handle = NULL;
  1107. }
  1108. return Status;
  1109. }
  1110. virtual HRESULT QueryDataAvailable(PULONG Avail)
  1111. {
  1112. if (m_InitialDataLen > 0)
  1113. {
  1114. *Avail = m_InitialDataLen;
  1115. return S_OK;
  1116. }
  1117. if (!g_httpQueryDataAvailable)
  1118. {
  1119. return ERROR_MOD_NOT_FOUND;
  1120. }
  1121. if (!g_httpQueryDataAvailable(m_Handle, Avail, 0, 0))
  1122. {
  1123. return WIN32_LAST_STATUS();
  1124. }
  1125. return S_OK;
  1126. }
  1127. virtual HRESULT GetLastWriteTime(PFILETIME Time)
  1128. {
  1129. // Don't know of a way to get this.
  1130. return E_NOTIMPL;
  1131. }
  1132. virtual HRESULT Read(PVOID Buffer, ULONG BufferLen, PULONG Done)
  1133. {
  1134. *Done = 0;
  1135. if (m_InitialDataLen > 0)
  1136. {
  1137. ULONG Len = min(BufferLen, m_InitialDataLen);
  1138. if (Len > 0)
  1139. {
  1140. memcpy(Buffer, m_InitialData, Len);
  1141. Buffer = (PVOID)((PUCHAR)Buffer + Len);
  1142. BufferLen -= Len;
  1143. *Done += Len;
  1144. m_InitialDataLen -= Len;
  1145. if (m_InitialDataLen > 0)
  1146. {
  1147. memmove(m_InitialData, m_InitialData + Len,
  1148. m_InitialDataLen);
  1149. }
  1150. }
  1151. }
  1152. if (BufferLen > 0)
  1153. {
  1154. ULONG _Done;
  1155. if (!g_httpReadFile)
  1156. {
  1157. return ERROR_MOD_NOT_FOUND;
  1158. }
  1159. if (!g_httpReadFile(m_Handle, Buffer, BufferLen, &_Done))
  1160. {
  1161. return WIN32_LAST_STATUS();
  1162. }
  1163. *Done += _Done;
  1164. }
  1165. return S_OK;
  1166. }
  1167. private:
  1168. HANDLE m_Handle, m_SiteHandle;
  1169. BYTE m_InitialData[16];
  1170. ULONG m_InitialDataLen;
  1171. };
  1172. HRESULT
  1173. OpenPathFile(PCSTR PathComponent, PCSTR PathAndFile,
  1174. ULONG SymOpt, PathFile** File)
  1175. {
  1176. HRESULT Status;
  1177. PathFile* Attempt;
  1178. if (IsUrlPathComponent(PathAndFile))
  1179. {
  1180. Attempt = new WinInetPathFile;
  1181. }
  1182. else
  1183. {
  1184. Attempt = new Win32PathFile;
  1185. }
  1186. if (Attempt == NULL)
  1187. {
  1188. Status = E_OUTOFMEMORY;
  1189. }
  1190. else
  1191. {
  1192. Status = Attempt->Open(PathComponent, PathAndFile, SymOpt);
  1193. if (Status != S_OK)
  1194. {
  1195. delete Attempt;
  1196. }
  1197. else
  1198. {
  1199. *File = Attempt;
  1200. }
  1201. }
  1202. return Status;
  1203. }
  1204. #endif // #ifndef NT_NATIVE
  1205. HRESULT
  1206. AnsiToWide(PCSTR Ansi, PWSTR* Wide)
  1207. {
  1208. #ifndef NT_NATIVE
  1209. ULONG Len = strlen(Ansi) + 1;
  1210. PWSTR WideBuf = (PWSTR)malloc(Len * sizeof(WCHAR));
  1211. if (WideBuf == NULL)
  1212. {
  1213. return E_OUTOFMEMORY;
  1214. }
  1215. if (!MultiByteToWideChar(CP_ACP, 0, Ansi, Len, WideBuf, Len))
  1216. {
  1217. free(WideBuf);
  1218. return WIN32_LAST_STATUS();
  1219. }
  1220. *Wide = WideBuf;
  1221. return S_OK;
  1222. #else // #ifndef NT_NATIVE
  1223. NTSTATUS Status;
  1224. STRING AnsiStr;
  1225. UNICODE_STRING UnicodeStr;
  1226. RtlInitString(&AnsiStr, Ansi);
  1227. Status = RtlAnsiStringToUnicodeString(&UnicodeStr, &AnsiStr, TRUE);
  1228. if (!NT_SUCCESS(Status))
  1229. {
  1230. return HRESULT_FROM_NT(Status);
  1231. }
  1232. *Wide = UnicodeStr.Buffer;
  1233. return S_OK;
  1234. #endif // #ifndef NT_NATIVE
  1235. }
  1236. void
  1237. FreeWide(PCWSTR Wide)
  1238. {
  1239. #ifndef NT_NATIVE
  1240. free((PVOID)Wide);
  1241. #else
  1242. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)Wide);
  1243. #endif
  1244. }
  1245. HRESULT
  1246. WideToAnsi(PCWSTR Wide, PSTR* Ansi)
  1247. {
  1248. #ifndef NT_NATIVE
  1249. ULONG Len = wcslen(Wide) + 1;
  1250. // Allow each Unicode character to convert into two multibyte characters.
  1251. PSTR AnsiBuf = (PSTR)malloc(Len * 2);
  1252. if (AnsiBuf == NULL)
  1253. {
  1254. return E_OUTOFMEMORY;
  1255. }
  1256. if (!WideCharToMultiByte(CP_ACP, 0, Wide, Len, AnsiBuf, Len*2, NULL, NULL))
  1257. {
  1258. free(AnsiBuf);
  1259. return WIN32_LAST_STATUS();
  1260. }
  1261. *Ansi = AnsiBuf;
  1262. return S_OK;
  1263. #else // #ifndef NT_NATIVE
  1264. NTSTATUS Status;
  1265. STRING AnsiStr;
  1266. UNICODE_STRING UnicodeStr;
  1267. RtlInitUnicodeString(&UnicodeStr, Wide);
  1268. Status = RtlUnicodeStringToAnsiString(&AnsiStr, &UnicodeStr, TRUE);
  1269. if (!NT_SUCCESS(Status))
  1270. {
  1271. return HRESULT_FROM_NT(Status);
  1272. }
  1273. *Ansi = AnsiStr.Buffer;
  1274. return S_OK;
  1275. #endif // #ifndef NT_NATIVE
  1276. }
  1277. void
  1278. FreeAnsi(PCSTR Ansi)
  1279. {
  1280. #ifndef NT_NATIVE
  1281. free((PVOID)Ansi);
  1282. #else
  1283. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)Ansi);
  1284. #endif
  1285. }
  1286. void
  1287. ImageNtHdr32To64(PIMAGE_NT_HEADERS32 Hdr32,
  1288. PIMAGE_NT_HEADERS64 Hdr64)
  1289. {
  1290. #define CP(x) Hdr64->x = Hdr32->x
  1291. #define SE64(x) Hdr64->x = (ULONG64) (LONG64) (LONG) Hdr32->x
  1292. ULONG i;
  1293. CP(Signature);
  1294. CP(FileHeader);
  1295. CP(OptionalHeader.Magic);
  1296. CP(OptionalHeader.MajorLinkerVersion);
  1297. CP(OptionalHeader.MinorLinkerVersion);
  1298. CP(OptionalHeader.SizeOfCode);
  1299. CP(OptionalHeader.SizeOfInitializedData);
  1300. CP(OptionalHeader.SizeOfUninitializedData);
  1301. CP(OptionalHeader.AddressOfEntryPoint);
  1302. CP(OptionalHeader.BaseOfCode);
  1303. SE64(OptionalHeader.ImageBase);
  1304. CP(OptionalHeader.SectionAlignment);
  1305. CP(OptionalHeader.FileAlignment);
  1306. CP(OptionalHeader.MajorOperatingSystemVersion);
  1307. CP(OptionalHeader.MinorOperatingSystemVersion);
  1308. CP(OptionalHeader.MajorImageVersion);
  1309. CP(OptionalHeader.MinorImageVersion);
  1310. CP(OptionalHeader.MajorSubsystemVersion);
  1311. CP(OptionalHeader.MinorSubsystemVersion);
  1312. CP(OptionalHeader.Win32VersionValue);
  1313. CP(OptionalHeader.SizeOfImage);
  1314. CP(OptionalHeader.SizeOfHeaders);
  1315. CP(OptionalHeader.CheckSum);
  1316. CP(OptionalHeader.Subsystem);
  1317. CP(OptionalHeader.DllCharacteristics);
  1318. // Sizes are not sign extended, just copied.
  1319. CP(OptionalHeader.SizeOfStackReserve);
  1320. CP(OptionalHeader.SizeOfStackCommit);
  1321. CP(OptionalHeader.SizeOfHeapReserve);
  1322. CP(OptionalHeader.SizeOfHeapCommit);
  1323. CP(OptionalHeader.LoaderFlags);
  1324. CP(OptionalHeader.NumberOfRvaAndSizes);
  1325. for (i = 0; i < DIMA(Hdr32->OptionalHeader.DataDirectory); i++)
  1326. {
  1327. CP(OptionalHeader.DataDirectory[i]);
  1328. }
  1329. #undef CP
  1330. #undef SE64
  1331. }
  1332. VALUE_FORMAT_DESC g_ValueFormatDesc[] =
  1333. {
  1334. "", "", 0, FALSE,
  1335. "ib", "%d", 1, TRUE, "ub", "%02x", 1, FALSE,
  1336. "iw", "%d", 2, TRUE, "uw", "%04x", 2, FALSE,
  1337. "id", "%d", 4, TRUE, "ud", "%08x", 4, FALSE,
  1338. "iq", "%I64d", 8, TRUE, "uq", "%016I64x", 8, FALSE,
  1339. "f", "%12.6g", 4, TRUE,
  1340. "d", "%22.12g", 8, TRUE,
  1341. };
  1342. void
  1343. GetValueFormatDesc(VALUE_FORMAT Format, PVALUE_FORMAT_DESC Desc)
  1344. {
  1345. *Desc = g_ValueFormatDesc[Format];
  1346. }
  1347. PSTR
  1348. ParseValueFormat(PSTR Str, VALUE_FORMAT* Format, PULONG Elts)
  1349. {
  1350. VALUE_FORMAT Try;
  1351. while (*Str == ' ' || *Str == '\t')
  1352. {
  1353. Str++;
  1354. }
  1355. *Elts = 0;
  1356. while (*Str >= '0' && *Str <= '9')
  1357. {
  1358. *Elts = (*Elts * 10) + (*Str - '0');
  1359. Str++;
  1360. }
  1361. for (Try = VALUE_INT8; Try <= VALUE_FLT64; Try = (VALUE_FORMAT)(Try + 1))
  1362. {
  1363. if (!_stricmp(Str, g_ValueFormatDesc[Try].Name))
  1364. {
  1365. *Format = Try;
  1366. return Str + strlen(g_ValueFormatDesc[Try].Name);
  1367. }
  1368. }
  1369. return NULL;
  1370. }
  1371. BOOL
  1372. FormatValue(VALUE_FORMAT Format, PUCHAR Value, ULONG ValSize, ULONG Elts,
  1373. PSTR Buffer, ULONG BufferChars)
  1374. {
  1375. PVALUE_FORMAT_DESC Desc = &g_ValueFormatDesc[Format];
  1376. ULONG i;
  1377. if (!BufferChars)
  1378. {
  1379. return FALSE;
  1380. }
  1381. if (Elts == 0)
  1382. {
  1383. Elts = ValSize / Desc->Size;
  1384. }
  1385. // Start at the top of the value so that
  1386. // individual elements come out from high to low.
  1387. Value += Elts * Desc->Size;
  1388. for (i = 0; i < Elts; i++)
  1389. {
  1390. PSTR FmtStr;
  1391. ULONG64 RawElt;
  1392. if (i > 0)
  1393. {
  1394. if (!BufferChars)
  1395. {
  1396. return FALSE;
  1397. }
  1398. *Buffer++ = ' ';
  1399. BufferChars--;
  1400. }
  1401. Value -= Desc->Size;
  1402. if (Format == VALUE_FLT32)
  1403. {
  1404. // Need to convert to double for printf.
  1405. double Tmp = *(float*)Value;
  1406. RawElt = *(PULONG64)&Tmp;
  1407. }
  1408. else
  1409. {
  1410. RawElt = 0;
  1411. memcpy(&RawElt, Value, Desc->Size);
  1412. }
  1413. if (!PrintString(Buffer, BufferChars, Desc->FmtStr, RawElt))
  1414. {
  1415. return FALSE;
  1416. }
  1417. ULONG Len = strlen(Buffer);
  1418. BufferChars -= Len;
  1419. Buffer += Len;
  1420. }
  1421. return TRUE;
  1422. }
  1423. ULONG
  1424. ProcArchToImageMachine(ULONG ProcArch)
  1425. {
  1426. switch(ProcArch)
  1427. {
  1428. case PROCESSOR_ARCHITECTURE_INTEL:
  1429. return IMAGE_FILE_MACHINE_I386;
  1430. case PROCESSOR_ARCHITECTURE_IA64:
  1431. return IMAGE_FILE_MACHINE_IA64;
  1432. case PROCESSOR_ARCHITECTURE_AMD64:
  1433. return IMAGE_FILE_MACHINE_AMD64;
  1434. case PROCESSOR_ARCHITECTURE_ARM:
  1435. return IMAGE_FILE_MACHINE_ARM;
  1436. case PROCESSOR_ARCHITECTURE_ALPHA:
  1437. return IMAGE_FILE_MACHINE_ALPHA;
  1438. case PROCESSOR_ARCHITECTURE_ALPHA64:
  1439. return IMAGE_FILE_MACHINE_AXP64;
  1440. default:
  1441. return IMAGE_FILE_MACHINE_UNKNOWN;
  1442. }
  1443. }
  1444. ULONG
  1445. ImageMachineToProcArch(ULONG ImageMachine)
  1446. {
  1447. switch(ImageMachine)
  1448. {
  1449. case IMAGE_FILE_MACHINE_I386:
  1450. return PROCESSOR_ARCHITECTURE_INTEL;
  1451. case IMAGE_FILE_MACHINE_IA64:
  1452. return PROCESSOR_ARCHITECTURE_IA64;
  1453. case IMAGE_FILE_MACHINE_AMD64:
  1454. return PROCESSOR_ARCHITECTURE_AMD64;
  1455. case IMAGE_FILE_MACHINE_ARM:
  1456. return PROCESSOR_ARCHITECTURE_ARM;
  1457. case IMAGE_FILE_MACHINE_ALPHA:
  1458. return PROCESSOR_ARCHITECTURE_ALPHA;
  1459. case IMAGE_FILE_MACHINE_AXP64:
  1460. return PROCESSOR_ARCHITECTURE_ALPHA64;
  1461. default:
  1462. return PROCESSOR_ARCHITECTURE_UNKNOWN;
  1463. }
  1464. }