Source code of Windows XP (NT5)
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.

1045 lines
24 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // General utility routines.
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000-2001.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "pch.hpp"
  9. #include <common.ver>
  10. #include <wininet.h>
  11. #include <dbghelp.h>
  12. #include "cmnutil.hpp"
  13. #ifdef NT_NATIVE
  14. #include "ntnative.h"
  15. #endif
  16. // Formatted codes are pretty small and there's usually only
  17. // one in a message.
  18. #define MAX_FORMAT_CODE_STRINGS 2
  19. #define MAX_FORMAT_CODE_BUFFER 64
  20. char g_FormatCodeBuffer[MAX_FORMAT_CODE_STRINGS][MAX_FORMAT_CODE_BUFFER];
  21. ULONG g_NextFormatCodeBuffer = MAX_FORMAT_CODE_STRINGS;
  22. // Security attributes with a NULL DACL to explicitly
  23. // allow anyone access.
  24. PSECURITY_DESCRIPTOR g_AllAccessSecDesc;
  25. SECURITY_ATTRIBUTES g_AllAccessSecAttr;
  26. PSTR
  27. FormatStatusCode(HRESULT Status)
  28. {
  29. PSTR Buf;
  30. DWORD Len = 0;
  31. g_NextFormatCodeBuffer = (g_NextFormatCodeBuffer + 1) &
  32. (MAX_FORMAT_CODE_STRINGS - 1);
  33. Buf = g_FormatCodeBuffer[g_NextFormatCodeBuffer];
  34. if (Status & FACILITY_NT_BIT)
  35. {
  36. sprintf(Buf, "NTSTATUS 0x%08X", Status & ~FACILITY_NT_BIT);
  37. }
  38. else if (HRESULT_FACILITY(Status) == FACILITY_WIN32)
  39. {
  40. sprintf(Buf, "Win32 error %d", HRESULT_CODE(Status));
  41. }
  42. else
  43. {
  44. sprintf(Buf, "HRESULT 0x%08X", Status);
  45. }
  46. return Buf;
  47. }
  48. #ifndef NT_NATIVE
  49. // Generally there's only one status per output message so
  50. // only keep space for a small number of strings. Each string
  51. // can be verbose plus it can contain inserts which may be large
  52. // so each string buffer needs to be roomy.
  53. #define MAX_FORMAT_STATUS_STRINGS 2
  54. #define MAX_FORMAT_STATUS_BUFFER 512
  55. char g_FormatStatusBuffer[MAX_FORMAT_STATUS_STRINGS][MAX_FORMAT_STATUS_BUFFER];
  56. ULONG g_NextFormatStatusBuffer = MAX_FORMAT_STATUS_STRINGS;
  57. PSTR
  58. FormatStatusArgs(HRESULT Status, PVOID Arguments)
  59. {
  60. PSTR Buf;
  61. DWORD Len = 0;
  62. g_NextFormatStatusBuffer = (g_NextFormatStatusBuffer + 1) &
  63. (MAX_FORMAT_STATUS_STRINGS - 1);
  64. Buf = g_FormatStatusBuffer[g_NextFormatStatusBuffer];
  65. // If the caller passed in arguments allow format inserts
  66. // to be processed.
  67. if (Arguments != NULL)
  68. {
  69. Len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
  70. FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, Status,
  71. 0, Buf, MAX_FORMAT_STATUS_BUFFER,
  72. (va_list*)Arguments);
  73. }
  74. // If no arguments were passed or FormatMessage failed when
  75. // used with arguments try it without format inserts.
  76. if (Len == 0)
  77. {
  78. Len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
  79. FORMAT_MESSAGE_IGNORE_INSERTS, NULL, Status,
  80. 0, Buf, MAX_FORMAT_STATUS_BUFFER, NULL);
  81. }
  82. if (Len > 0)
  83. {
  84. while (Len > 0 && isspace(Buf[Len - 1]))
  85. {
  86. Buf[--Len] = 0;
  87. }
  88. }
  89. if (Len > 0)
  90. {
  91. return Buf;
  92. }
  93. else
  94. {
  95. return "<Unable to get error code text>";
  96. }
  97. }
  98. BOOL
  99. InstallAsAeDebug(PCSTR Append)
  100. {
  101. PCSTR KeyName;
  102. HKEY Key;
  103. LONG Status;
  104. OSVERSIONINFO OsVer;
  105. char Value[MAX_PATH * 2];
  106. OsVer.dwOSVersionInfoSize = sizeof(OsVer);
  107. if (!GetVersionEx(&OsVer))
  108. {
  109. return FALSE;
  110. }
  111. if (GetModuleFileName(NULL, Value, sizeof(Value) - 16) == 0)
  112. {
  113. return FALSE;
  114. }
  115. strcat(Value, " -p %ld -e %ld -g");
  116. if (Append != NULL)
  117. {
  118. if (strlen(Value) + strlen(Append) + 2 > sizeof(Value))
  119. {
  120. return FALSE;
  121. }
  122. strcat(Value, " ");
  123. strcat(Value, Append);
  124. }
  125. KeyName = OsVer.dwPlatformId == VER_PLATFORM_WIN32_NT ?
  126. "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" :
  127. "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AeDebug";
  128. Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyName,
  129. 0, KEY_READ | KEY_WRITE, &Key);
  130. if (Status == ERROR_SUCCESS)
  131. {
  132. Status = RegSetValueEx(Key, "Debugger", 0, REG_SZ,
  133. (PUCHAR)Value, strlen(Value) + 1);
  134. RegCloseKey(Key);
  135. }
  136. return Status == ERROR_SUCCESS;
  137. }
  138. HANDLE
  139. CreatePidEvent(ULONG Pid, ULONG CreateOrOpen)
  140. {
  141. HANDLE Event;
  142. char Name[32];
  143. sprintf(Name, "DbgEngEvent_%08X", Pid);
  144. Event = CreateEvent(NULL, FALSE, FALSE, Name);
  145. if (Event != NULL)
  146. {
  147. if (GetLastError() == ERROR_ALREADY_EXISTS)
  148. {
  149. if (CreateOrOpen == CREATE_NEW)
  150. {
  151. CloseHandle(Event);
  152. Event = NULL;
  153. }
  154. }
  155. else if (CreateOrOpen == OPEN_EXISTING)
  156. {
  157. CloseHandle(Event);
  158. Event = NULL;
  159. }
  160. }
  161. return Event;
  162. }
  163. BOOL
  164. SetPidEvent(ULONG Pid, ULONG CreateOrOpen)
  165. {
  166. BOOL Status;
  167. HANDLE Event = CreatePidEvent(Pid, CreateOrOpen);
  168. if (Event != NULL)
  169. {
  170. Status = SetEvent(Event);
  171. CloseHandle(Event);
  172. }
  173. else
  174. {
  175. Status = FALSE;
  176. }
  177. return Status;
  178. }
  179. HRESULT
  180. EnableDebugPrivilege(void)
  181. {
  182. OSVERSIONINFO OsVer;
  183. OsVer.dwOSVersionInfoSize = sizeof(OsVer);
  184. if (!GetVersionEx(&OsVer))
  185. {
  186. return WIN32_LAST_STATUS();
  187. }
  188. if (OsVer.dwPlatformId != VER_PLATFORM_WIN32_NT)
  189. {
  190. return S_OK;
  191. }
  192. HRESULT Status = S_OK;
  193. HANDLE Token;
  194. PTOKEN_PRIVILEGES NewPrivileges;
  195. BYTE OldPriv[1024];
  196. ULONG cbNeeded;
  197. LUID LuidPrivilege;
  198. static s_PrivilegeEnabled = FALSE;
  199. if (s_PrivilegeEnabled)
  200. {
  201. return S_OK;
  202. }
  203. //
  204. // Make sure we have access to adjust and to get the
  205. // old token privileges
  206. //
  207. if (!OpenProcessToken(GetCurrentProcess(),
  208. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  209. &Token))
  210. {
  211. Status = WIN32_LAST_STATUS();
  212. goto EH_Exit;
  213. }
  214. cbNeeded = 0;
  215. //
  216. // Initialize the privilege adjustment structure
  217. //
  218. LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &LuidPrivilege);
  219. NewPrivileges = (PTOKEN_PRIVILEGES)
  220. calloc(1, sizeof(TOKEN_PRIVILEGES) +
  221. (1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
  222. if (NewPrivileges == NULL)
  223. {
  224. Status = E_OUTOFMEMORY;
  225. goto EH_Token;
  226. }
  227. NewPrivileges->PrivilegeCount = 1;
  228. NewPrivileges->Privileges[0].Luid = LuidPrivilege;
  229. NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  230. //
  231. // Enable the privilege
  232. //
  233. if (!AdjustTokenPrivileges( Token,
  234. FALSE,
  235. NewPrivileges,
  236. sizeof(OldPriv),
  237. (PTOKEN_PRIVILEGES)OldPriv,
  238. &cbNeeded ))
  239. {
  240. //
  241. // If the stack was too small to hold the privileges
  242. // then allocate off the heap
  243. //
  244. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  245. {
  246. PBYTE pbOldPriv;
  247. BOOL Adjusted;
  248. pbOldPriv = (PUCHAR)calloc(1, cbNeeded);
  249. if (pbOldPriv == NULL)
  250. {
  251. Status = E_OUTOFMEMORY;
  252. goto EH_NewPriv;
  253. }
  254. Adjusted = AdjustTokenPrivileges( Token,
  255. FALSE,
  256. NewPrivileges,
  257. cbNeeded,
  258. (PTOKEN_PRIVILEGES)pbOldPriv,
  259. &cbNeeded );
  260. free(pbOldPriv);
  261. if (!Adjusted)
  262. {
  263. Status = WIN32_LAST_STATUS();
  264. }
  265. }
  266. }
  267. EH_NewPriv:
  268. free(NewPrivileges);
  269. EH_Token:
  270. CloseHandle(Token);
  271. EH_Exit:
  272. if (Status == S_OK)
  273. {
  274. s_PrivilegeEnabled = TRUE;
  275. }
  276. return Status;
  277. }
  278. #else // #ifndef NT_NATIVE
  279. HRESULT
  280. EnableDebugPrivilege(void)
  281. {
  282. HRESULT Status = S_OK;
  283. HANDLE Token;
  284. PTOKEN_PRIVILEGES NewPrivileges;
  285. BYTE OldPriv[1024];
  286. ULONG cbNeeded;
  287. LUID LuidPrivilege;
  288. NTSTATUS NtStatus;
  289. static s_PrivilegeEnabled = FALSE;
  290. if (s_PrivilegeEnabled)
  291. {
  292. return S_OK;
  293. }
  294. //
  295. // Make sure we have access to adjust and to get the
  296. // old token privileges
  297. //
  298. if (!NT_SUCCESS(NtStatus =
  299. NtOpenProcessToken(NtCurrentProcess(),
  300. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  301. &Token)))
  302. {
  303. Status = HRESULT_FROM_NT(NtStatus);
  304. goto EH_Exit;
  305. }
  306. cbNeeded = 0;
  307. //
  308. // Initialize the privilege adjustment structure
  309. //
  310. LuidPrivilege = RtlConvertUlongToLuid(SE_DEBUG_PRIVILEGE);
  311. NewPrivileges = (PTOKEN_PRIVILEGES)
  312. RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY,
  313. sizeof(TOKEN_PRIVILEGES) +
  314. (1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
  315. if (NewPrivileges == NULL)
  316. {
  317. Status = E_OUTOFMEMORY;
  318. goto EH_Token;
  319. }
  320. NewPrivileges->PrivilegeCount = 1;
  321. NewPrivileges->Privileges[0].Luid = LuidPrivilege;
  322. NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  323. //
  324. // Enable the privilege
  325. //
  326. if (!NT_SUCCESS(NtStatus =
  327. NtAdjustPrivilegesToken(Token,
  328. FALSE,
  329. NewPrivileges,
  330. sizeof(OldPriv),
  331. (PTOKEN_PRIVILEGES)OldPriv,
  332. &cbNeeded)))
  333. {
  334. //
  335. // If the stack was too small to hold the privileges
  336. // then allocate off the heap
  337. //
  338. if (NtStatus == STATUS_BUFFER_OVERFLOW)
  339. {
  340. PBYTE pbOldPriv;
  341. pbOldPriv = (PUCHAR)RtlAllocateHeap(RtlProcessHeap(),
  342. HEAP_ZERO_MEMORY, cbNeeded);
  343. if (pbOldPriv == NULL)
  344. {
  345. Status = E_OUTOFMEMORY;
  346. goto EH_NewPriv;
  347. }
  348. NtStatus = NtAdjustPrivilegesToken(Token,
  349. FALSE,
  350. NewPrivileges,
  351. cbNeeded,
  352. (PTOKEN_PRIVILEGES)pbOldPriv,
  353. &cbNeeded);
  354. free(pbOldPriv);
  355. if (!NT_SUCCESS(NtStatus))
  356. {
  357. Status = HRESULT_FROM_NT(NtStatus);
  358. }
  359. }
  360. }
  361. EH_NewPriv:
  362. free(NewPrivileges);
  363. EH_Token:
  364. NtClose(Token);
  365. EH_Exit:
  366. if (Status == S_OK)
  367. {
  368. s_PrivilegeEnabled = TRUE;
  369. }
  370. return Status;
  371. }
  372. #endif // #ifndef NT_NATIVE
  373. //
  374. // Copies the input data to the output buffer.
  375. // Handles optionality of the buffer pointer and output length
  376. // parameter. Trims the data to fit the buffer.
  377. // Returns S_FALSE if only a part of the data is copied.
  378. //
  379. HRESULT
  380. FillDataBuffer(PVOID Data, ULONG DataLen,
  381. PVOID Buffer, ULONG BufferLen, PULONG BufferUsed)
  382. {
  383. ULONG Len;
  384. HRESULT Status;
  385. if (DataLen > BufferLen && Buffer != NULL)
  386. {
  387. Len = BufferLen;
  388. Status = S_FALSE;
  389. }
  390. else
  391. {
  392. Len = DataLen;
  393. Status = S_OK;
  394. }
  395. if (Buffer != NULL && BufferLen > 0 && Data != NULL && Len > 0)
  396. {
  397. memcpy(Buffer, Data, Len);
  398. }
  399. if (BufferUsed != NULL)
  400. {
  401. *BufferUsed = DataLen;
  402. }
  403. return Status;
  404. }
  405. //
  406. // Copies the input string to the output buffer.
  407. // Handles optionality of the buffer pointer and output length
  408. // parameter. Trims the string to fit the buffer and guarantees
  409. // termination of the string in the buffer if anything fits.
  410. // Returns S_FALSE if only a partial string is copied.
  411. //
  412. // If the input string length is zero the routine strlens.
  413. //
  414. HRESULT
  415. FillStringBuffer(PCSTR String, ULONG StringLenIn,
  416. PSTR Buffer, ULONG BufferLen, PULONG StringLenOut)
  417. {
  418. ULONG Len;
  419. HRESULT Status;
  420. if (StringLenIn == 0)
  421. {
  422. if (String != NULL)
  423. {
  424. StringLenIn = strlen(String) + 1;
  425. }
  426. else
  427. {
  428. StringLenIn = 1;
  429. }
  430. }
  431. if (BufferLen == 0)
  432. {
  433. Len = 0;
  434. Status = Buffer != NULL ? S_FALSE : S_OK;
  435. }
  436. else if (StringLenIn >= BufferLen)
  437. {
  438. Len = BufferLen - 1;
  439. Status = StringLenIn > BufferLen ? S_FALSE : S_OK;
  440. }
  441. else
  442. {
  443. Len = StringLenIn - 1;
  444. Status = S_OK;
  445. }
  446. if (Buffer != NULL && BufferLen > 0)
  447. {
  448. if (String != NULL)
  449. {
  450. memcpy(Buffer, String, Len);
  451. }
  452. Buffer[Len] = 0;
  453. }
  454. if (StringLenOut != NULL)
  455. {
  456. *StringLenOut = StringLenIn;
  457. }
  458. return Status;
  459. }
  460. HRESULT
  461. AppendToStringBuffer(HRESULT Status, PCSTR String, BOOL First,
  462. PSTR* Buffer, ULONG* BufferLen, PULONG LenOut)
  463. {
  464. ULONG Len = strlen(String) + 1;
  465. if (LenOut)
  466. {
  467. // If this is the first string we need to add
  468. // on space for the terminator. For later
  469. // strings we only need to add the string
  470. // characters.
  471. *LenOut += First ? Len : Len - 1;
  472. }
  473. // If there's no buffer we can skip writeback and pointer update.
  474. if (!*Buffer)
  475. {
  476. return Status;
  477. }
  478. // Fit as much of the string into the buffer as possible.
  479. if (Len > *BufferLen)
  480. {
  481. Status = S_FALSE;
  482. Len = *BufferLen;
  483. }
  484. memcpy(*Buffer, String, Len);
  485. // Update the buffer pointer to point to the terminator
  486. // for further appends. Update the size similarly.
  487. *Buffer += Len - 1;
  488. *BufferLen -= Len - 1;
  489. return Status;
  490. }
  491. void
  492. Win32ToNtTimeout(ULONG Win32Timeout, PLARGE_INTEGER NtTimeout)
  493. {
  494. if (Win32Timeout == INFINITE)
  495. {
  496. NtTimeout->LowPart = 0;
  497. NtTimeout->HighPart = 0x80000000;
  498. }
  499. else
  500. {
  501. NtTimeout->QuadPart = UInt32x32To64(Win32Timeout, 10000);
  502. NtTimeout->QuadPart *= -1;
  503. }
  504. }
  505. HRESULT
  506. InitializeAllAccessSecObj(void)
  507. {
  508. if (g_AllAccessSecDesc != NULL)
  509. {
  510. // Already initialized.
  511. return S_OK;
  512. }
  513. g_AllAccessSecDesc =
  514. (PSECURITY_DESCRIPTOR)malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
  515. if (g_AllAccessSecDesc == NULL)
  516. {
  517. return E_OUTOFMEMORY;
  518. }
  519. if (!InitializeSecurityDescriptor(g_AllAccessSecDesc,
  520. SECURITY_DESCRIPTOR_REVISION) ||
  521. !SetSecurityDescriptorDacl(g_AllAccessSecDesc, TRUE, NULL, FALSE))
  522. {
  523. free(g_AllAccessSecDesc);
  524. g_AllAccessSecDesc = NULL;
  525. return WIN32_LAST_STATUS();
  526. }
  527. g_AllAccessSecAttr.nLength = sizeof(g_AllAccessSecAttr);
  528. g_AllAccessSecAttr.lpSecurityDescriptor = g_AllAccessSecDesc;
  529. g_AllAccessSecAttr.bInheritHandle = FALSE;
  530. return S_OK;
  531. }
  532. void
  533. DeleteAllAccessSecObj(void)
  534. {
  535. free(g_AllAccessSecDesc);
  536. g_AllAccessSecDesc = NULL;
  537. ZeroMemory(&g_AllAccessSecAttr, sizeof(g_AllAccessSecAttr));
  538. }
  539. HRESULT
  540. QueryVersionDataBuffer(PVOID VerData, PCSTR Item,
  541. PVOID Buffer, ULONG BufferSize, PULONG DataSize)
  542. {
  543. #ifndef NT_NATIVE
  544. PVOID Val;
  545. UINT ValSize;
  546. if (::VerQueryValue(VerData, (PSTR)Item, &Val, &ValSize))
  547. {
  548. return FillDataBuffer(Val, ValSize,
  549. Buffer, BufferSize, DataSize);
  550. }
  551. else
  552. {
  553. return WIN32_LAST_STATUS();
  554. }
  555. #else // #ifndef NT_NATIVE
  556. return E_UNEXPECTED;
  557. #endif // #ifndef NT_NATIVE
  558. }
  559. PVOID
  560. GetAllFileVersionInfo(PSTR VerFile)
  561. {
  562. #ifndef NT_NATIVE
  563. DWORD VerHandle;
  564. DWORD VerSize = ::GetFileVersionInfoSize(VerFile, &VerHandle);
  565. if (VerSize == 0)
  566. {
  567. return NULL;
  568. }
  569. PVOID Buffer = malloc(VerSize);
  570. if (Buffer == NULL)
  571. {
  572. return NULL;
  573. }
  574. if (!::GetFileVersionInfo(VerFile, VerHandle, VerSize, Buffer))
  575. {
  576. free(Buffer);
  577. Buffer = NULL;
  578. }
  579. return Buffer;
  580. #else // #ifndef NT_NATIVE
  581. return NULL;
  582. #endif // #ifndef NT_NATIVE
  583. }
  584. BOOL
  585. GetFileStringFileInfo(PSTR VerFile, PCSTR SubItem,
  586. PSTR Buffer, ULONG BufferSize)
  587. {
  588. #ifndef NT_NATIVE
  589. BOOL Status = FALSE;
  590. PVOID AllInfo = GetAllFileVersionInfo(VerFile);
  591. if (AllInfo == NULL)
  592. {
  593. return Status;
  594. }
  595. // XXX drewb - Probably should do a more clever
  596. // enumeration of languages.
  597. char ValName[64];
  598. sprintf(ValName, "\\StringFileInfo\\%04x%04x\\%s",
  599. VER_VERSION_TRANSLATION, SubItem);
  600. Status = SUCCEEDED(QueryVersionDataBuffer(AllInfo, ValName,
  601. Buffer, BufferSize, NULL));
  602. free(AllInfo);
  603. return Status;
  604. #else // #ifndef NT_NATIVE
  605. return FALSE;
  606. #endif // #ifndef NT_NATIVE
  607. }
  608. BOOL
  609. IsUrlPathComponent(PCSTR Path)
  610. {
  611. return
  612. strncmp(Path, "ftp://", 6) == 0 ||
  613. strncmp(Path, "http://", 7) == 0 ||
  614. strncmp(Path, "https://", 8) == 0 ||
  615. strncmp(Path, "gopher://", 9) == 0;
  616. }
  617. #ifndef NT_NATIVE
  618. BOOL
  619. PathFileExists(PCSTR Path, ULONG SymOpt, FILE_IO_TYPE* IoType)
  620. {
  621. BOOL Exists = FALSE;
  622. if (IsUrlPathComponent(Path))
  623. {
  624. PathFile* File;
  625. if (OpenPathFile(Path, SymOpt, &File) == S_OK)
  626. {
  627. *IoType = File->m_IoType;
  628. delete File;
  629. Exists = TRUE;
  630. }
  631. }
  632. else
  633. {
  634. DWORD OldMode;
  635. if (SymOpt & SYMOPT_FAIL_CRITICAL_ERRORS)
  636. {
  637. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  638. }
  639. *IoType = FIO_WIN32;
  640. Exists = GetFileAttributes(Path) != -1;
  641. if (SymOpt & SYMOPT_FAIL_CRITICAL_ERRORS)
  642. {
  643. SetErrorMode(OldMode);
  644. }
  645. }
  646. return Exists;
  647. }
  648. PathFile::~PathFile(void)
  649. {
  650. }
  651. class Win32PathFile : public PathFile
  652. {
  653. public:
  654. Win32PathFile(void)
  655. : PathFile(FIO_WIN32)
  656. {
  657. m_Handle = NULL;
  658. }
  659. virtual ~Win32PathFile(void)
  660. {
  661. if (m_Handle)
  662. {
  663. CloseHandle(m_Handle);
  664. }
  665. }
  666. virtual HRESULT Open(PCSTR Path, ULONG SymOpt)
  667. {
  668. DWORD OldMode;
  669. HRESULT Status;
  670. if (SymOpt & SYMOPT_FAIL_CRITICAL_ERRORS)
  671. {
  672. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  673. }
  674. m_Handle = CreateFile(Path, GENERIC_READ, FILE_SHARE_READ,
  675. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  676. NULL);
  677. if (m_Handle == NULL || m_Handle == INVALID_HANDLE_VALUE)
  678. {
  679. m_Handle = NULL;
  680. Status = WIN32_LAST_STATUS();
  681. }
  682. else
  683. {
  684. Status = S_OK;
  685. }
  686. if (SymOpt & SYMOPT_FAIL_CRITICAL_ERRORS)
  687. {
  688. SetErrorMode(OldMode);
  689. }
  690. return Status;
  691. }
  692. virtual HRESULT QueryDataAvailable(PULONG Avail)
  693. {
  694. LARGE_INTEGER Cur, End;
  695. Cur.HighPart = 0;
  696. End.HighPart = 0;
  697. if ((Cur.LowPart =
  698. SetFilePointer(m_Handle, 0, &Cur.HighPart, FILE_CURRENT)) ==
  699. INVALID_SET_FILE_POINTER ||
  700. (End.LowPart =
  701. SetFilePointer(m_Handle, 0, &End.HighPart, FILE_END)) ==
  702. INVALID_SET_FILE_POINTER ||
  703. SetFilePointer(m_Handle, Cur.LowPart, &Cur.HighPart, FILE_BEGIN) ==
  704. INVALID_SET_FILE_POINTER)
  705. {
  706. return WIN32_LAST_STATUS();
  707. }
  708. End.QuadPart -= Cur.QuadPart;
  709. if (End.HighPart < 0)
  710. {
  711. // Shouldn't be possible, but check anyway.
  712. return E_FAIL;
  713. }
  714. // Limit max data available to 32-bit quantity.
  715. if (End.HighPart > 0)
  716. {
  717. *Avail = 0xffffffff;
  718. }
  719. else
  720. {
  721. *Avail = End.LowPart;
  722. }
  723. return S_OK;
  724. }
  725. virtual HRESULT GetLastWriteTime(PFILETIME Time)
  726. {
  727. // If we can't get the write time try and get
  728. // the create time.
  729. if (!GetFileTime(m_Handle, NULL, NULL, Time))
  730. {
  731. if (!GetFileTime(m_Handle, Time, NULL, NULL))
  732. {
  733. return WIN32_LAST_STATUS();
  734. }
  735. }
  736. return S_OK;
  737. }
  738. virtual HRESULT Read(PVOID Buffer, ULONG BufferLen, PULONG Done)
  739. {
  740. if (!ReadFile(m_Handle, Buffer, BufferLen, Done, NULL))
  741. {
  742. return WIN32_LAST_STATUS();
  743. }
  744. return S_OK;
  745. }
  746. private:
  747. HANDLE m_Handle;
  748. };
  749. class WinInetPathFile : public PathFile
  750. {
  751. public:
  752. WinInetPathFile(void)
  753. : PathFile(FIO_WININET)
  754. {
  755. m_InetHandle = NULL;
  756. m_Handle = NULL;
  757. m_InitialDataLen = 0;
  758. }
  759. virtual ~WinInetPathFile(void)
  760. {
  761. if (m_Handle)
  762. {
  763. InternetCloseHandle(m_Handle);
  764. }
  765. if (m_InetHandle)
  766. {
  767. InternetCloseHandle(m_InetHandle);
  768. }
  769. }
  770. virtual HRESULT Open(PCSTR Path, ULONG SymOpt)
  771. {
  772. HRESULT Status;
  773. m_InetHandle = InternetOpen("DebugEngine",
  774. INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL,
  775. 0);
  776. if (m_InetHandle == NULL)
  777. {
  778. return WIN32_LAST_STATUS();
  779. }
  780. m_Handle = InternetOpenUrl(m_InetHandle, Path, NULL, 0,
  781. INTERNET_FLAG_NO_UI |
  782. INTERNET_FLAG_NO_AUTO_REDIRECT, 0);
  783. if (m_Handle == NULL)
  784. {
  785. Status = WIN32_LAST_STATUS();
  786. goto Fail;
  787. }
  788. // Servers can return 404 - Not Found pages in
  789. // response to missing URLs so read the first
  790. // piece of data and fail if it's HTML.
  791. if (!InternetReadFile(m_Handle, m_InitialData,
  792. sizeof(m_InitialData), &m_InitialDataLen))
  793. {
  794. Status = WIN32_LAST_STATUS();
  795. goto Fail;
  796. }
  797. if (m_InitialDataLen >= 14 &&
  798. memcmp(m_InitialData, "<!DOCTYPE HTML", 14) == 0)
  799. {
  800. Status = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  801. goto Fail;
  802. }
  803. return S_OK;
  804. Fail:
  805. m_InitialDataLen = 0;
  806. if (m_Handle)
  807. {
  808. InternetCloseHandle(m_Handle);
  809. m_Handle = NULL;
  810. }
  811. if (m_InetHandle)
  812. {
  813. InternetCloseHandle(m_InetHandle);
  814. m_InetHandle = NULL;
  815. }
  816. return Status;
  817. }
  818. virtual HRESULT QueryDataAvailable(PULONG Avail)
  819. {
  820. if (m_InitialDataLen > 0)
  821. {
  822. *Avail = m_InitialDataLen;
  823. return S_OK;
  824. }
  825. if (!InternetQueryDataAvailable(m_Handle, Avail, 0, 0))
  826. {
  827. return WIN32_LAST_STATUS();
  828. }
  829. return S_OK;
  830. }
  831. virtual HRESULT GetLastWriteTime(PFILETIME Time)
  832. {
  833. // Don't know of a way to get this.
  834. return E_NOTIMPL;
  835. }
  836. virtual HRESULT Read(PVOID Buffer, ULONG BufferLen, PULONG Done)
  837. {
  838. *Done = 0;
  839. if (m_InitialDataLen > 0)
  840. {
  841. ULONG Len = min(BufferLen, m_InitialDataLen);
  842. if (Len > 0)
  843. {
  844. memcpy(Buffer, m_InitialData, Len);
  845. Buffer = (PVOID)((PUCHAR)Buffer + Len);
  846. BufferLen -= Len;
  847. *Done += Len;
  848. m_InitialDataLen -= Len;
  849. if (m_InitialDataLen > 0)
  850. {
  851. memmove(m_InitialData, m_InitialData + Len,
  852. m_InitialDataLen);
  853. }
  854. }
  855. }
  856. if (BufferLen > 0)
  857. {
  858. ULONG _Done;
  859. if (!InternetReadFile(m_Handle, Buffer, BufferLen, &_Done))
  860. {
  861. return WIN32_LAST_STATUS();
  862. }
  863. *Done += _Done;
  864. }
  865. return S_OK;
  866. }
  867. private:
  868. HANDLE m_Handle, m_InetHandle;
  869. BYTE m_InitialData[16];
  870. ULONG m_InitialDataLen;
  871. };
  872. HRESULT
  873. OpenPathFile(PCSTR Path, ULONG SymOpt, PathFile** File)
  874. {
  875. HRESULT Status;
  876. PathFile* Attempt;
  877. if (IsUrlPathComponent(Path))
  878. {
  879. Attempt = new WinInetPathFile;
  880. }
  881. else
  882. {
  883. Attempt = new Win32PathFile;
  884. }
  885. if (Attempt == NULL)
  886. {
  887. Status = E_OUTOFMEMORY;
  888. }
  889. else
  890. {
  891. Status = Attempt->Open(Path, SymOpt);
  892. if (Status != S_OK)
  893. {
  894. delete Attempt;
  895. }
  896. else
  897. {
  898. *File = Attempt;
  899. }
  900. }
  901. return Status;
  902. }
  903. #endif // #ifndef NT_NATIVE