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.

3713 lines
88 KiB

  1. /*++
  2. Copyright (c) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. misc.cxx
  5. Abstract:
  6. This module contains the miscellaneous UL routines.
  7. Author:
  8. Keith Moore (keithmo) 10-Jun-1998
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. ULONG HttpChars[256];
  13. USHORT FastPopChars[256];
  14. USHORT DummyPopChars[256];
  15. //
  16. // Private prototypes.
  17. //
  18. NTSTATUS
  19. UlpRestartDeviceControl(
  20. IN PDEVICE_OBJECT pDeviceObject,
  21. IN PIRP pIrp,
  22. IN PVOID pContext
  23. );
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text( PAGE, UlOpenRegistry )
  26. #pragma alloc_text( PAGE, UlReadLongParameter )
  27. #pragma alloc_text( PAGE, UlReadLongLongParameter )
  28. #pragma alloc_text( PAGE, UlReadGenericParameter )
  29. #pragma alloc_text( PAGE, UlIssueDeviceControl )
  30. #endif // ALLOC_PRAGMA
  31. #if 0
  32. NOT PAGEABLE -- UlBuildDeviceControlIrp
  33. NOT PAGEABLE -- UlULongLongToAscii
  34. NOT PAGEABLE -- UlpRestartDeviceControl
  35. NOT PAGEABLE -- UlAllocateReceiveBufferPool
  36. NOT PAGEABLE -- UlFreeReceiveBufferPool
  37. NOT PAGEABLE -- UlAllocateIrpContextPool
  38. NOT PAGEABLE -- UlFreeIrpContextPool
  39. NOT PAGEABLE -- UlAllocateRequestBufferPool
  40. NOT PAGEABLE -- UlFreeRequestBufferPool
  41. NOT PAGEABLE -- UlAllocateInternalRequestPool
  42. NOT PAGEABLE -- UlFreeInternalRequestPool
  43. NOT PAGEABLE -- UlAllocateChunkTrackerPool
  44. NOT PAGEABLE -- UlFreeChunkTrackerPool
  45. NOT PAGEABLE -- UlAllocateFullTrackerPool
  46. NOT PAGEABLE -- UlFreeFullTrackerPool
  47. NOT PAGEABLE -- UlAllocateResponseBufferPool
  48. NOT PAGEABLE -- UlFreeResponseBufferPool
  49. NOT PAGEABLE -- UlAllocateLogBufferPool
  50. NOT PAGEABLE -- UlFreeLogBufferPool
  51. NOT PAGEABLE -- UlInvokeCompletionRoutine
  52. NOT PAGEABLE -- UlUlInterlockedIncrement64
  53. NOT PAGEABLE -- UlUlInterlockedDecrement64
  54. NOT PAGEABLE -- UlUlInterlockedAdd64
  55. NOT PAGEABLE -- UlUlInterlockedExchange64
  56. NOT PAGEABLE -- TwoDigitsToUnicode
  57. NOT PAGEABLE -- TimeFieldsToHttpDate
  58. NOT PAGEABLE -- AsciiToShort
  59. NOT PAGEABLE -- TwoAsciisToShort
  60. NOT PAGEABLE -- NumericToAsciiMonth
  61. NOT PAGEABLE -- StringTimeToSystemTime
  62. #endif
  63. //
  64. // Public functions.
  65. //
  66. /***************************************************************************++
  67. Routine Description:
  68. Opens a handle to the UL's Parameters registry key.
  69. Arguments:
  70. BaseName - Supplies the name of the parent registry key containing
  71. the Parameters key.
  72. ParametersHandle - Returns a handle to the Parameters key.
  73. Return Value:
  74. NTSTATUS - Completion status.
  75. --***************************************************************************/
  76. NTSTATUS
  77. UlOpenRegistry(
  78. IN PUNICODE_STRING BaseName,
  79. OUT PHANDLE ParametersHandle
  80. )
  81. {
  82. HANDLE configHandle;
  83. NTSTATUS status;
  84. PWSTR parametersString = REGISTRY_PARAMETERS;
  85. UNICODE_STRING parametersKeyName;
  86. OBJECT_ATTRIBUTES objectAttributes;
  87. ULONG disposition;
  88. //
  89. // Sanity check.
  90. //
  91. PAGED_CODE();
  92. //
  93. // Open the registry for the initial string.
  94. //
  95. InitializeObjectAttributes(
  96. &objectAttributes, // ObjectAttributes
  97. BaseName, // ObjectName
  98. OBJ_CASE_INSENSITIVE | // Attributes
  99. UL_KERNEL_HANDLE,
  100. NULL, // RootDirectory
  101. NULL // SecurityDescriptor
  102. );
  103. UlAttachToSystemProcess();
  104. status = ZwOpenKey( &configHandle, KEY_READ, &objectAttributes );
  105. if (!NT_SUCCESS(status))
  106. {
  107. UlDetachFromSystemProcess();
  108. return STATUS_UNSUCCESSFUL;
  109. }
  110. //
  111. // Now open the parameters key.
  112. //
  113. RtlInitUnicodeString( &parametersKeyName, parametersString );
  114. InitializeObjectAttributes(
  115. &objectAttributes, // ObjectAttributes
  116. &parametersKeyName, // ObjectName
  117. OBJ_CASE_INSENSITIVE, // Attributes
  118. configHandle, // RootDirectory
  119. NULL // SecurityDescriptor
  120. );
  121. status = ZwOpenKey( ParametersHandle, KEY_READ, &objectAttributes );
  122. if (!NT_SUCCESS(status))
  123. {
  124. ZwClose( configHandle );
  125. UlDetachFromSystemProcess();
  126. return status;
  127. }
  128. //
  129. // All keys successfully opened or created.
  130. //
  131. ZwClose( configHandle );
  132. UlDetachFromSystemProcess();
  133. return STATUS_SUCCESS;
  134. } // UlOpenRegistry
  135. /***************************************************************************++
  136. Routine Description:
  137. Reads a single (LONG/ULONG) value from the registry.
  138. Arguments:
  139. ParametersHandle - Supplies an open registry handle.
  140. ValueName - Supplies the name of the value to read.
  141. DefaultValue - Supplies the default value.
  142. Return Value:
  143. LONG - The value read from the registry or the default if the
  144. registry data was unavailable or incorrect.
  145. --***************************************************************************/
  146. LONG
  147. UlReadLongParameter(
  148. IN HANDLE ParametersHandle,
  149. IN PWCHAR ValueName,
  150. IN LONG DefaultValue
  151. )
  152. {
  153. PKEY_VALUE_PARTIAL_INFORMATION information;
  154. UNICODE_STRING valueKeyName;
  155. ULONG informationLength;
  156. LONG returnValue;
  157. NTSTATUS status;
  158. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(LONG)];
  159. //
  160. // Sanity check.
  161. //
  162. PAGED_CODE();
  163. //
  164. // Build the value name, read it from the registry.
  165. //
  166. RtlInitUnicodeString(
  167. &valueKeyName,
  168. ValueName
  169. );
  170. information = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  171. status = ZwQueryValueKey(
  172. ParametersHandle,
  173. &valueKeyName,
  174. KeyValuePartialInformation,
  175. (PVOID)information,
  176. sizeof(buffer),
  177. &informationLength
  178. );
  179. //
  180. // If the read succeeded, the type is DWORD and the length is
  181. // sane, use it. Otherwise, use the default.
  182. //
  183. if (status == STATUS_SUCCESS &&
  184. information->Type == REG_DWORD &&
  185. information->DataLength == sizeof(returnValue))
  186. {
  187. RtlMoveMemory( &returnValue, information->Data, sizeof(returnValue) );
  188. } else {
  189. returnValue = DefaultValue;
  190. }
  191. return returnValue;
  192. } // UlReadLongParameter
  193. /***************************************************************************++
  194. Routine Description:
  195. Reads a single (LONGLONG/ULONGLONG) value from the registry.
  196. Arguments:
  197. ParametersHandle - Supplies an open registry handle.
  198. ValueName - Supplies the name of the value to read.
  199. DefaultValue - Supplies the default value.
  200. Return Value:
  201. LONGLONG - The value read from the registry or the default if the
  202. registry data was unavailable or incorrect.
  203. --***************************************************************************/
  204. LONGLONG
  205. UlReadLongLongParameter(
  206. IN HANDLE ParametersHandle,
  207. IN PWCHAR ValueName,
  208. IN LONGLONG DefaultValue
  209. )
  210. {
  211. PKEY_VALUE_PARTIAL_INFORMATION information;
  212. UNICODE_STRING valueKeyName;
  213. ULONG informationLength;
  214. LONGLONG returnValue;
  215. NTSTATUS status;
  216. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(LONGLONG)];
  217. //
  218. // Sanity check.
  219. //
  220. PAGED_CODE();
  221. //
  222. // Build the value name, read it from the registry.
  223. //
  224. RtlInitUnicodeString(
  225. &valueKeyName,
  226. ValueName
  227. );
  228. information = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  229. status = ZwQueryValueKey(
  230. ParametersHandle,
  231. &valueKeyName,
  232. KeyValuePartialInformation,
  233. (PVOID)information,
  234. sizeof(buffer),
  235. &informationLength
  236. );
  237. //
  238. // If the read succeeded, the type is DWORD and the length is
  239. // sane, use it. Otherwise, use the default.
  240. //
  241. if (status == STATUS_SUCCESS &&
  242. information->Type == REG_QWORD &&
  243. information->DataLength == sizeof(returnValue))
  244. {
  245. RtlMoveMemory( &returnValue, information->Data, sizeof(returnValue) );
  246. } else {
  247. returnValue = DefaultValue;
  248. }
  249. return returnValue;
  250. } // UlReadLongLongParameter
  251. /***************************************************************************++
  252. Routine Description:
  253. Reads a single free-form value from the registry.
  254. Arguments:
  255. ParametersHandle - Supplies an open registry handle.
  256. ValueName - Supplies the name of the value to read.
  257. Value - Receives the value read from the registry.
  258. Return Value:
  259. NTSTATUS - Completion status.
  260. --***************************************************************************/
  261. NTSTATUS
  262. UlReadGenericParameter(
  263. IN HANDLE ParametersHandle,
  264. IN PWCHAR ValueName,
  265. OUT PKEY_VALUE_PARTIAL_INFORMATION * Value
  266. )
  267. {
  268. KEY_VALUE_PARTIAL_INFORMATION partialInfo;
  269. UNICODE_STRING valueKeyName;
  270. ULONG informationLength;
  271. NTSTATUS status;
  272. PKEY_VALUE_PARTIAL_INFORMATION newValue;
  273. ULONG dataLength;
  274. //
  275. // Sanity check.
  276. //
  277. PAGED_CODE();
  278. //
  279. // Build the value name, then perform an initial read. The read
  280. // should fail with buffer overflow, but that's OK. We just want
  281. // to get the length of the data.
  282. //
  283. RtlInitUnicodeString( &valueKeyName, ValueName );
  284. status = ZwQueryValueKey(
  285. ParametersHandle,
  286. &valueKeyName,
  287. KeyValuePartialInformation,
  288. (PVOID)&partialInfo,
  289. sizeof(partialInfo),
  290. &informationLength
  291. );
  292. if (NT_ERROR(status))
  293. {
  294. return status;
  295. }
  296. //
  297. // Determine the data length. Ensure that strings and multi-sz get
  298. // properly terminated.
  299. //
  300. dataLength = partialInfo.DataLength - 1;
  301. if (partialInfo.Type == REG_SZ || partialInfo.Type == REG_EXPAND_SZ)
  302. {
  303. dataLength += 1;
  304. }
  305. if (partialInfo.Type == REG_MULTI_SZ)
  306. {
  307. dataLength += 2;
  308. }
  309. //
  310. // Allocate the buffer.
  311. //
  312. newValue = UL_ALLOCATE_STRUCT_WITH_SPACE(
  313. PagedPool,
  314. KEY_VALUE_PARTIAL_INFORMATION,
  315. dataLength,
  316. UL_REGISTRY_DATA_POOL_TAG
  317. );
  318. if (newValue == NULL)
  319. {
  320. return STATUS_INSUFFICIENT_RESOURCES;
  321. }
  322. //
  323. // update the actually allocated length for later use
  324. //
  325. dataLength += sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  326. RtlZeroMemory( newValue, dataLength );
  327. //
  328. // Perform the actual read.
  329. //
  330. status = ZwQueryValueKey(
  331. ParametersHandle,
  332. &valueKeyName,
  333. KeyValuePartialInformation,
  334. (PVOID)(newValue),
  335. dataLength,
  336. &informationLength
  337. );
  338. if (NT_SUCCESS(status))
  339. {
  340. *Value = newValue;
  341. }
  342. else
  343. {
  344. UL_FREE_POOL( newValue, UL_REGISTRY_DATA_POOL_TAG );
  345. }
  346. return status;
  347. } // UlReadGenericParameter
  348. /***************************************************************************++
  349. Routine Description:
  350. Builds a properly formatted device control IRP.
  351. Arguments:
  352. Irp - Supplies the IRP to format.
  353. IoControlCode - Supplies the device IO control code.
  354. InputBuffer - Supplies the input buffer.
  355. InputBufferLength - Supplies the length of InputBuffer.
  356. OutputBuffer - Supplies the output buffer.
  357. OutputBufferLength - Supplies the length of OutputBuffer.
  358. MdlAddress - Supplies a MDL to attach to the IRP. This is assumed to
  359. be a non-paged MDL.
  360. FileObject - Supplies the file object for the target driver.
  361. DeviceObject - Supplies the correct device object for the target
  362. driver.
  363. IoStatusBlock - Receives the final completion status of the request.
  364. CompletionRoutine - Supplies a pointer to a completion routine to
  365. call after the request completes. This will only be called if
  366. this routine returns STATUS_PENDING.
  367. CompletionContext - Supplies an uninterpreted context value passed
  368. to the completion routine.
  369. TargetThread - Optionally supplies a target thread for the IRP. If
  370. this value is NULL, then the current thread is used.
  371. --***************************************************************************/
  372. VOID
  373. UlBuildDeviceControlIrp(
  374. IN OUT PIRP Irp,
  375. IN ULONG IoControlCode,
  376. IN PVOID InputBuffer OPTIONAL,
  377. IN ULONG InputBufferLength,
  378. IN PVOID OutputBuffer OPTIONAL,
  379. IN ULONG OutputBufferLength,
  380. IN PMDL MdlAddress,
  381. IN PFILE_OBJECT FileObject,
  382. IN PDEVICE_OBJECT DeviceObject,
  383. IN PIO_STATUS_BLOCK IoStatusBlock,
  384. IN PIO_COMPLETION_ROUTINE CompletionRoutine,
  385. IN PVOID CompletionContext,
  386. IN PETHREAD TargetThread OPTIONAL
  387. )
  388. {
  389. PIO_STACK_LOCATION irpSp;
  390. //
  391. // Sanity check.
  392. //
  393. ASSERT( Irp != NULL );
  394. ASSERT( FileObject != NULL );
  395. ASSERT( DeviceObject != NULL );
  396. //
  397. // Fill in the service independent parameters in the IRP.
  398. //
  399. Irp->Flags = 0;
  400. Irp->RequestorMode = KernelMode;
  401. Irp->PendingReturned = FALSE;
  402. Irp->UserIosb = IoStatusBlock;
  403. Irp->UserEvent = NULL;
  404. Irp->AssociatedIrp.SystemBuffer = InputBuffer ? InputBuffer : OutputBuffer;
  405. Irp->UserBuffer = OutputBuffer;
  406. Irp->MdlAddress = MdlAddress;
  407. Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  408. Irp->Tail.Overlay.Thread = TargetThread ? TargetThread : PsGetCurrentThread();
  409. Irp->Tail.Overlay.OriginalFileObject = FileObject;
  410. Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  411. //
  412. // Put the file object pointer in the stack location.
  413. //
  414. irpSp = IoGetNextIrpStackLocation( Irp );
  415. irpSp->FileObject = FileObject;
  416. irpSp->DeviceObject = DeviceObject;
  417. //
  418. // Fill in the service dependent parameters in the IRP stack.
  419. //
  420. irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
  421. irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
  422. irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
  423. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
  424. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  425. irpSp->MinorFunction = 0;
  426. //
  427. // Set the completion routine appropriately.
  428. //
  429. if (CompletionRoutine == NULL)
  430. {
  431. IoSetCompletionRoutine(
  432. Irp,
  433. NULL,
  434. NULL,
  435. FALSE,
  436. FALSE,
  437. FALSE
  438. );
  439. }
  440. else
  441. {
  442. IoSetCompletionRoutine(
  443. Irp,
  444. CompletionRoutine,
  445. CompletionContext,
  446. TRUE,
  447. TRUE,
  448. TRUE
  449. );
  450. }
  451. } // UlBuildDeviceControlIrp
  452. /***************************************************************************++
  453. Routine Description:
  454. Converts the given ULONGLLONG to an ASCII representation and stores it
  455. in the given string.
  456. Arguments:
  457. String - Receives the ASCII representation of the ULONGLONG.
  458. Value - Supplies the ULONGLONG to convert.
  459. Return Value:
  460. PSTR - Pointer to the next character in String *after* the converted
  461. ULONGLONG.
  462. --***************************************************************************/
  463. PSTR
  464. UlULongLongToAscii(
  465. IN PSTR String,
  466. IN ULONGLONG Value
  467. )
  468. {
  469. PSTR p1;
  470. PSTR p2;
  471. CHAR ch;
  472. ULONG digit;
  473. //
  474. // Special case 0 to make the rest of the routine simpler.
  475. //
  476. if (Value == 0)
  477. {
  478. *String++ = '0';
  479. }
  480. else
  481. {
  482. //
  483. // Convert the ULONG. Note that this will result in the string
  484. // being backwards in memory.
  485. //
  486. p1 = String;
  487. p2 = String;
  488. while (Value != 0)
  489. {
  490. digit = (ULONG)( Value % 10 );
  491. Value = Value / 10;
  492. *p1++ = '0' + (CHAR)digit;
  493. }
  494. //
  495. // Reverse the string.
  496. //
  497. String = p1;
  498. p1--;
  499. while (p1 > p2)
  500. {
  501. ch = *p1;
  502. *p1 = *p2;
  503. *p2 = ch;
  504. p2++;
  505. p1--;
  506. }
  507. }
  508. *String = '\0';
  509. return String;
  510. } // UlULongLongToAscii
  511. NTSTATUS
  512. _RtlIntegerToUnicode(
  513. IN ULONG Value,
  514. IN ULONG Base OPTIONAL,
  515. IN LONG BufferLength,
  516. OUT PWSTR String
  517. )
  518. {
  519. PWSTR p1;
  520. PWSTR p2;
  521. WCHAR ch;
  522. ULONG digit;
  523. //
  524. // Special case 0 to make the rest of the routine simpler.
  525. //
  526. if (Value == 0)
  527. {
  528. *String++ = L'0';
  529. }
  530. else
  531. {
  532. //
  533. // Convert the ULONG. Note that this will result in the string
  534. // being backwards in memory.
  535. //
  536. p1 = String;
  537. p2 = String;
  538. while (Value != 0)
  539. {
  540. digit = (ULONG)( Value % 10 );
  541. Value = Value / 10;
  542. *p1++ = L'0' + (WCHAR)digit;
  543. }
  544. //
  545. // Reverse the string.
  546. //
  547. String = p1;
  548. p1--;
  549. while (p1 > p2)
  550. {
  551. ch = *p1;
  552. *p1 = *p2;
  553. *p2 = ch;
  554. p2++;
  555. p1--;
  556. }
  557. }
  558. *String = L'\0';
  559. return STATUS_SUCCESS;
  560. } // _RtlIntegerToUnicode
  561. /***************************************************************************++
  562. Routine Description:
  563. Converts an ansi string to an integer. fails if any non-digit characters
  564. appears in the string. fails on negative numbers, and assumes no preceding
  565. spaces.
  566. Arguments:
  567. PUCHAR pString the string to convert
  568. ULONG Base the base, must be 10 or 16
  569. PULONG pValue the return value of the converted integer
  570. Return Value:
  571. NTSTATUS - Completion status.
  572. --***************************************************************************/
  573. NTSTATUS
  574. UlAnsiToULongLong(
  575. PUCHAR pString,
  576. ULONG Base,
  577. PULONGLONG pValue
  578. )
  579. {
  580. ULONGLONG Value;
  581. ULONGLONG NewValue;
  582. if (Base != 10 && Base != 16)
  583. RETURN(STATUS_INVALID_PARAMETER);
  584. //
  585. // No preceding space, we already skipped it
  586. //
  587. ASSERT(IS_HTTP_LWS(pString[0]) == FALSE);
  588. Value = 0;
  589. while (pString[0] != ANSI_NULL)
  590. {
  591. if (
  592. (Base == 10 && IS_HTTP_DIGIT(pString[0]) == FALSE) ||
  593. (Base == 16 && IS_HTTP_HEX(pString[0]) == FALSE)
  594. )
  595. {
  596. //
  597. // Not valid , bad!
  598. //
  599. RETURN(STATUS_INVALID_PARAMETER);
  600. }
  601. if (Base == 16)
  602. {
  603. if (IS_HTTP_ALPHA(pString[0]))
  604. {
  605. NewValue = 16 * Value + (UPCASE_CHAR(pString[0]) - 'A' + 10);
  606. }
  607. else
  608. {
  609. NewValue = 16 * Value + (pString[0] - '0');
  610. }
  611. }
  612. else
  613. {
  614. NewValue = 10 * Value + (pString[0] - '0');
  615. }
  616. if (NewValue < Value)
  617. {
  618. //
  619. // Very bad... we overflew
  620. //
  621. RETURN(STATUS_SECTION_TOO_BIG);
  622. }
  623. Value = NewValue;
  624. pString += 1;
  625. }
  626. *pValue = Value;
  627. return STATUS_SUCCESS;
  628. } // UlAnsiToULongLong
  629. /***************************************************************************++
  630. Routine Description:
  631. Converts a unicode string to an integer. fails if any non-digit characters
  632. appear in the string. fails on negative numbers, and assumes no preceding
  633. spaces.
  634. Arguments:
  635. PWCHAR pString the string to convert
  636. ULONG Base the base, must be 10 or 16
  637. PULONG pValue the return value of the converted integer
  638. Return Value:
  639. NTSTATUS - Completion status.
  640. --***************************************************************************/
  641. NTSTATUS
  642. UlUnicodeToULongLong(
  643. PWCHAR pString,
  644. ULONG Base,
  645. PULONGLONG pValue
  646. )
  647. {
  648. ULONGLONG Value;
  649. ULONGLONG NewValue;
  650. if (Base != 10 && Base != 16)
  651. RETURN(STATUS_INVALID_PARAMETER);
  652. //
  653. // No preceding space, we already skipped it
  654. //
  655. ASSERT(pString[0] < 128 && IS_HTTP_LWS(pString[0]) == FALSE);
  656. Value = 0;
  657. while (pString[0] != UNICODE_NULL)
  658. {
  659. if ((Base == 10 &&
  660. (pString[0] >= 128 || IS_HTTP_DIGIT(pString[0]) == FALSE)) ||
  661. (Base == 16 &&
  662. (pString[0] >= 128 || IS_HTTP_HEX(pString[0]) == FALSE)))
  663. {
  664. //
  665. // Not valid , bad!
  666. //
  667. RETURN(STATUS_INVALID_PARAMETER);
  668. }
  669. if (Base == 16)
  670. {
  671. if (IS_HTTP_ALPHA(pString[0]))
  672. {
  673. NewValue = 16 * Value + (pString[0] - L'A' + 10);
  674. }
  675. else
  676. {
  677. NewValue = 16 * Value + (pString[0] - L'0');
  678. }
  679. }
  680. else
  681. {
  682. NewValue = 10 * Value + (pString[0] - L'0');
  683. }
  684. if (NewValue < Value)
  685. {
  686. //
  687. // Very bad... we overflew
  688. //
  689. RETURN(STATUS_INVALID_PARAMETER);
  690. }
  691. Value = NewValue;
  692. pString += 1;
  693. }
  694. *pValue = Value;
  695. return STATUS_SUCCESS;
  696. } // UlUnicodeToULongLong
  697. /***************************************************************************++
  698. Routine Description:
  699. Synchronously issues a device control request to the TDI provider.
  700. Arguments:
  701. pTdiObject - Supplies a pointer to the TDI object.
  702. pIrpParameters - Supplies a pointer to the IRP parameters.
  703. IrpParametersLength - Supplies the length of pIrpParameters.
  704. pMdlBuffer - Optionally supplies a pointer to a buffer to be mapped
  705. into a MDL and placed in the MdlAddress field of the IRP.
  706. MdlBufferLength - Optionally supplies the length of pMdlBuffer.
  707. MinorFunction - Supplies the minor function code of the request.
  708. Return Value:
  709. NTSTATUS - Completion status.
  710. --***************************************************************************/
  711. NTSTATUS
  712. UlIssueDeviceControl(
  713. IN PUX_TDI_OBJECT pTdiObject,
  714. IN PVOID pIrpParameters,
  715. IN ULONG IrpParametersLength,
  716. IN PVOID pMdlBuffer OPTIONAL,
  717. IN ULONG MdlBufferLength OPTIONAL,
  718. IN UCHAR MinorFunction
  719. )
  720. {
  721. NTSTATUS status;
  722. PIRP pIrp;
  723. PIO_STACK_LOCATION pIrpSp;
  724. UL_STATUS_BLOCK ulStatus;
  725. PMDL pMdl;
  726. //
  727. // Sanity check.
  728. //
  729. PAGED_CODE();
  730. //
  731. // Initialize the event that will signal I/O completion.
  732. //
  733. UlInitializeStatusBlock( &ulStatus );
  734. //
  735. // Set the file object event to the non-signaled state.
  736. //
  737. KeResetEvent( &pTdiObject->pFileObject->Event );
  738. //
  739. // Allocate an IRP for the request.
  740. //
  741. pIrp = UlAllocateIrp(
  742. pTdiObject->pDeviceObject->StackSize, // StackSize
  743. FALSE // ChargeQuota
  744. );
  745. if (pIrp == NULL)
  746. {
  747. return STATUS_INSUFFICIENT_RESOURCES;
  748. }
  749. //
  750. // Establish the service independent parameters.
  751. //
  752. pIrp->Flags = IRP_SYNCHRONOUS_API;
  753. pIrp->RequestorMode = KernelMode;
  754. pIrp->PendingReturned = FALSE;
  755. pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  756. pIrp->Tail.Overlay.OriginalFileObject = pTdiObject->pFileObject;
  757. //
  758. // If we have a MDL buffer, allocate a new MDL and map the
  759. // buffer into it.
  760. //
  761. if (pMdlBuffer != NULL)
  762. {
  763. pMdl = UlAllocateMdl(
  764. pMdlBuffer, // VirtualAddress
  765. MdlBufferLength, // Length
  766. FALSE, // SecondaryBuffer
  767. FALSE, // ChargeQuota
  768. pIrp // Irp
  769. );
  770. if (pMdl == NULL)
  771. {
  772. UlFreeIrp( pIrp );
  773. return STATUS_INSUFFICIENT_RESOURCES;
  774. }
  775. MmBuildMdlForNonPagedPool( pMdl );
  776. }
  777. else
  778. {
  779. pIrp->MdlAddress = NULL;
  780. }
  781. //
  782. // Initialize the IRP stack location.
  783. //
  784. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  785. pIrpSp->FileObject = pTdiObject->pFileObject;
  786. pIrpSp->DeviceObject = pTdiObject->pDeviceObject;
  787. ASSERT( IrpParametersLength <= sizeof(pIrpSp->Parameters) );
  788. RtlCopyMemory(
  789. &pIrpSp->Parameters,
  790. pIrpParameters,
  791. IrpParametersLength
  792. );
  793. pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  794. pIrpSp->MinorFunction = MinorFunction;
  795. //
  796. // Reference the file object.
  797. //
  798. ObReferenceObject( pTdiObject->pFileObject );
  799. //
  800. // Establish a completion routine to free the MDL and dereference
  801. // the FILE_OBJECT.
  802. //
  803. IoSetCompletionRoutine(
  804. pIrp, // Irp
  805. &UlpRestartDeviceControl, // CompletionRoutine
  806. &ulStatus, // Context
  807. TRUE, // InvokeOnSuccess
  808. TRUE, // InvokeOnError
  809. TRUE // InvokeOnCancel
  810. );
  811. //
  812. // Issue the request.
  813. //
  814. status = UlCallDriver( pTdiObject->pDeviceObject, pIrp );
  815. //
  816. // If necessary, wait for the request to complete and snag the
  817. // final completion status.
  818. //
  819. if (status == STATUS_PENDING)
  820. {
  821. UlWaitForStatusBlockEvent( &ulStatus );
  822. status = ulStatus.IoStatus.Status;
  823. }
  824. return status;
  825. } // UlIssueDeviceControl
  826. /***************************************************************************++
  827. Routine Description:
  828. Allocates the pool necessary for a new UL_RECEIVE_BUFFER structure and
  829. initializes the structure.
  830. Arguments:
  831. PoolType - Supplies the type of pool to allocate. This must always
  832. be NonPagedPool.
  833. ByteLength - Supplies the byte length for the allocation request.
  834. This should be sizeof(UL_RECEIVE_BUFFER), but is basically ignored.
  835. Tag - Supplies the tag to use for the pool. This should be
  836. UL_RCV_BUFFER_POOL_TAG, but is basically ignored.
  837. Note: These parameters are required so that this function has a
  838. signature identical to ExAllocatePoolWithTag.
  839. Return Value:
  840. PVOID - Pointer to the newly allocated block if successful, FALSE
  841. otherwise.
  842. --***************************************************************************/
  843. PVOID
  844. UlAllocateReceiveBufferPool(
  845. IN POOL_TYPE PoolType,
  846. IN SIZE_T ByteLength,
  847. IN ULONG Tag
  848. )
  849. {
  850. PUL_RECEIVE_BUFFER pBuffer;
  851. SIZE_T irpLength;
  852. SIZE_T mdlLength;
  853. SIZE_T ExtraLength;
  854. //
  855. // Sanity check.
  856. //
  857. ASSERT( PoolType == NonPagedPool );
  858. ASSERT( ByteLength == sizeof(UL_RECEIVE_BUFFER) );
  859. ASSERT( Tag == UL_RCV_BUFFER_POOL_TAG );
  860. //
  861. // Calculate the required length of the buffer & allocate it.
  862. //
  863. irpLength = IoSizeOfIrp( g_UlIrpStackSize );
  864. irpLength = ALIGN_UP( irpLength, PVOID );
  865. mdlLength = MmSizeOfMdl( (PVOID)(PAGE_SIZE - 1), g_UlReceiveBufferSize );
  866. mdlLength = ALIGN_UP( mdlLength, PVOID );
  867. ExtraLength = irpLength + (mdlLength*2) + g_UlReceiveBufferSize;
  868. ASSERT( ( ExtraLength & (sizeof(PVOID) - 1) ) == 0 );
  869. pBuffer = UL_ALLOCATE_STRUCT_WITH_SPACE(
  870. NonPagedPool,
  871. UL_RECEIVE_BUFFER,
  872. ExtraLength,
  873. UL_RCV_BUFFER_POOL_TAG
  874. );
  875. if (pBuffer != NULL)
  876. {
  877. PUCHAR pRawBuffer = (PUCHAR)(pBuffer);
  878. //
  879. // Initialize the IRP, MDL, and data pointers within the buffer.
  880. //
  881. // CODEWORK: the signature should be set in invalid here, but
  882. // there's no wrapper around the PplAllocate/Free functions
  883. // for this structure, so set it to the valid sig for now.
  884. //
  885. pBuffer->Signature = UL_RECEIVE_BUFFER_SIGNATURE;
  886. pRawBuffer += ALIGN_UP( sizeof(UL_RECEIVE_BUFFER), PVOID );
  887. pBuffer->pIrp = (PIRP)pRawBuffer;
  888. pRawBuffer += irpLength;
  889. pBuffer->pMdl = (PMDL)pRawBuffer;
  890. pRawBuffer += mdlLength;
  891. pBuffer->pPartialMdl = (PMDL)pRawBuffer;
  892. pRawBuffer += mdlLength;
  893. pBuffer->pDataArea = (PVOID)pRawBuffer;
  894. pBuffer->UnreadDataLength = 0;
  895. //
  896. // Initialize the IRP.
  897. //
  898. IoInitializeIrp(
  899. pBuffer->pIrp, // Irp
  900. (USHORT)irpLength, // PacketSize
  901. g_UlIrpStackSize // StackSize
  902. );
  903. //
  904. // Initialize the primary MDL.
  905. //
  906. MmInitializeMdl(
  907. pBuffer->pMdl, // MemoryDescriptorList
  908. pBuffer->pDataArea, // BaseVa
  909. g_UlReceiveBufferSize // Length
  910. );
  911. MmBuildMdlForNonPagedPool( pBuffer->pMdl );
  912. }
  913. return (PVOID)pBuffer;
  914. } // UlAllocateReceiveBufferPool
  915. /***************************************************************************++
  916. Routine Description:
  917. Frees the pool allocated for a UL_RECEIVE_BUFFER structure.
  918. Arguments:
  919. pBuffer - Supplies the buffer to free.
  920. --***************************************************************************/
  921. VOID
  922. UlFreeReceiveBufferPool(
  923. IN PVOID pBuffer
  924. )
  925. {
  926. PUL_RECEIVE_BUFFER pReceiveBuffer;
  927. //
  928. // Sanity check.
  929. //
  930. pReceiveBuffer = (PUL_RECEIVE_BUFFER)pBuffer;
  931. //
  932. // Kill the signature, then free it.
  933. //
  934. pReceiveBuffer->Signature = UL_RECEIVE_BUFFER_SIGNATURE_X;
  935. UL_FREE_POOL( pReceiveBuffer, UL_RCV_BUFFER_POOL_TAG );
  936. } // UlFreeReceiveBufferPool
  937. /***************************************************************************++
  938. Routine Description:
  939. Allocates the pool necessary for a new UL_IRP_CONTEXT structure and
  940. initializes the structure.
  941. Arguments:
  942. PoolType - Supplies the type of pool to allocate. This must always
  943. be NonPagedPool.
  944. ByteLength - Supplies the byte length for the allocation request.
  945. This should be sizeof(UL_IRP_CONTEXT), but is basically ignored.
  946. Tag - Supplies the tag to use for the pool. This should be
  947. UL_IRP_CONTEXT_POOL_TAG, but is basically ignored.
  948. Note: These parameters are required so that this function has a
  949. signature identical to ExAllocatePoolWithTag.
  950. Return Value:
  951. PVOID - Pointer to the newly allocated block if successful, FALSE
  952. otherwise.
  953. --***************************************************************************/
  954. PVOID
  955. UlAllocateIrpContextPool(
  956. IN POOL_TYPE PoolType,
  957. IN SIZE_T ByteLength,
  958. IN ULONG Tag
  959. )
  960. {
  961. PUL_IRP_CONTEXT pIrpContext;
  962. //
  963. // Sanity check.
  964. //
  965. ASSERT( PoolType == NonPagedPool );
  966. ASSERT( ByteLength == sizeof(UL_IRP_CONTEXT) );
  967. ASSERT( Tag == UL_IRP_CONTEXT_POOL_TAG );
  968. //
  969. // Allocate the IRP context.
  970. //
  971. pIrpContext = UL_ALLOCATE_STRUCT(
  972. NonPagedPool,
  973. UL_IRP_CONTEXT,
  974. UL_IRP_CONTEXT_POOL_TAG
  975. );
  976. if (pIrpContext != NULL)
  977. {
  978. //
  979. // Initialize it.
  980. //
  981. //
  982. // CODEWORK: It's bogus for us to set the valid signature
  983. // here. It should only be valid once the object is really
  984. // in use.
  985. //
  986. pIrpContext->Signature = UL_IRP_CONTEXT_SIGNATURE;
  987. #if DBG
  988. pIrpContext->pCompletionRoutine = &UlDbgInvalidCompletionRoutine;
  989. #endif
  990. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  991. }
  992. return (PVOID)pIrpContext;
  993. } // UlAllocateIrpContextPool
  994. /***************************************************************************++
  995. Routine Description:
  996. Frees the pool allocated for a UL_IRP_CONTEXT structure.
  997. Arguments:
  998. pBuffer - Supplies the buffer to free.
  999. --***************************************************************************/
  1000. VOID
  1001. UlFreeIrpContextPool(
  1002. IN PVOID pBuffer
  1003. )
  1004. {
  1005. PUL_IRP_CONTEXT pIrpContext;
  1006. //
  1007. // Sanity check.
  1008. //
  1009. pIrpContext = (PUL_IRP_CONTEXT)pBuffer;
  1010. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  1011. //
  1012. // Kill the signature, then free it.
  1013. //
  1014. pIrpContext->Signature = UL_IRP_CONTEXT_SIGNATURE_X;
  1015. UL_FREE_POOL( pIrpContext, UL_IRP_CONTEXT_POOL_TAG );
  1016. } // UlFreeIrpContextPool
  1017. /***************************************************************************++
  1018. Routine Description:
  1019. Allocates the pool necessary for a new UL_REQUEST_BUFFER structure and
  1020. initializes the structure.
  1021. Arguments:
  1022. PoolType - Supplies the type of pool to allocate. This must always
  1023. be NonPagedPool.
  1024. ByteLength - Supplies the byte length for the allocation request.
  1025. This should be DEFAULT_MAX_REQUEST_BUFFER_SIZE but is basically
  1026. ignored.
  1027. Tag - Supplies the tag to use for the pool. This should be
  1028. UL_REQUEST_BUFFER_POOL_TAG, but is basically ignored.
  1029. Note: These parameters are required so that this function has a
  1030. signature identical to ExAllocatePoolWithTag.
  1031. Return Value:
  1032. PVOID - Pointer to the newly allocated block if successful, FALSE
  1033. otherwise.
  1034. --***************************************************************************/
  1035. PVOID
  1036. UlAllocateRequestBufferPool(
  1037. IN POOL_TYPE PoolType,
  1038. IN SIZE_T ByteLength,
  1039. IN ULONG Tag
  1040. )
  1041. {
  1042. PUL_REQUEST_BUFFER pRequestBuffer;
  1043. //
  1044. // Sanity check.
  1045. //
  1046. ASSERT( PoolType == NonPagedPool );
  1047. ASSERT( ByteLength == DEFAULT_MAX_REQUEST_BUFFER_SIZE );
  1048. ASSERT( Tag == UL_REQUEST_BUFFER_POOL_TAG );
  1049. //
  1050. // Allocate the request buffer.
  1051. //
  1052. pRequestBuffer = UL_ALLOCATE_STRUCT_WITH_SPACE(
  1053. NonPagedPool,
  1054. UL_REQUEST_BUFFER,
  1055. DEFAULT_MAX_REQUEST_BUFFER_SIZE,
  1056. UL_REQUEST_BUFFER_POOL_TAG
  1057. );
  1058. if (pRequestBuffer != NULL)
  1059. {
  1060. //
  1061. // Initialize it.
  1062. //
  1063. pRequestBuffer->Signature = MAKE_FREE_TAG(UL_REQUEST_BUFFER_POOL_TAG);
  1064. }
  1065. return (PVOID)pRequestBuffer;
  1066. } // UlAllocateRequestBufferPool
  1067. /***************************************************************************++
  1068. Routine Description:
  1069. Frees the pool allocated for a UL_REQUEST_BUFFER structure.
  1070. Arguments:
  1071. pBuffer - Supplies the buffer to free.
  1072. --***************************************************************************/
  1073. VOID
  1074. UlFreeRequestBufferPool(
  1075. IN PVOID pBuffer
  1076. )
  1077. {
  1078. PUL_REQUEST_BUFFER pRequestBuffer;
  1079. //
  1080. // Sanity check.
  1081. //
  1082. pRequestBuffer = (PUL_REQUEST_BUFFER)pBuffer;
  1083. //
  1084. // Kill the signature, then free it.
  1085. //
  1086. UL_FREE_POOL_WITH_SIG(pRequestBuffer, UL_REQUEST_BUFFER_POOL_TAG);
  1087. } // UlFreeRequestBufferPool
  1088. /***************************************************************************++
  1089. Routine Description:
  1090. Allocates the pool necessary for a new UL_INTERNAL_REQUEST structure and
  1091. initializes the structure.
  1092. Arguments:
  1093. PoolType - Supplies the type of pool to allocate. This must always
  1094. be NonPagedPool.
  1095. ByteLength - Supplies the byte length for the allocation request.
  1096. This should be sizeof(UL_INTERNAL_REQUEST) but is basically ignored.
  1097. Tag - Supplies the tag to use for the pool. This should be
  1098. UL_INTERNAL_REQUEST_POOL_TAG, but is basically ignored.
  1099. Note: These parameters are required so that this function has a
  1100. signature identical to ExAllocatePoolWithTag.
  1101. Return Value:
  1102. PVOID - Pointer to the newly allocated block if successful, FALSE
  1103. otherwise.
  1104. --***************************************************************************/
  1105. PVOID
  1106. UlAllocateInternalRequestPool(
  1107. IN POOL_TYPE PoolType,
  1108. IN SIZE_T ByteLength,
  1109. IN ULONG Tag
  1110. )
  1111. {
  1112. PUL_INTERNAL_REQUEST pRequest;
  1113. PUL_FULL_TRACKER pTracker;
  1114. ULONG SpaceLength;
  1115. NTSTATUS Status;
  1116. //
  1117. // Sanity check.
  1118. //
  1119. ASSERT( PoolType == NonPagedPool );
  1120. ASSERT( ByteLength == sizeof(UL_INTERNAL_REQUEST) );
  1121. ASSERT( Tag == UL_INTERNAL_REQUEST_POOL_TAG );
  1122. //
  1123. // Allocate the request buffer plus the default cooked URL buffer and
  1124. // the full tracker plus the auxiliary buffer.
  1125. //
  1126. SpaceLength =
  1127. g_UlFullTrackerSize +
  1128. (g_UlMaxInternalUrlLength/sizeof(WCHAR) + 1) * sizeof(WCHAR);
  1129. pRequest = UL_ALLOCATE_STRUCT_WITH_SPACE(
  1130. NonPagedPool,
  1131. UL_INTERNAL_REQUEST,
  1132. SpaceLength,
  1133. UL_INTERNAL_REQUEST_POOL_TAG
  1134. );
  1135. if (pRequest != NULL)
  1136. {
  1137. //
  1138. // Initialize it.
  1139. //
  1140. pRequest->Signature = MAKE_FREE_TAG(UL_INTERNAL_REQUEST_POOL_TAG);
  1141. pRequest->pTracker =
  1142. (PUL_FULL_TRACKER)((PCHAR)pRequest +
  1143. ALIGN_UP(sizeof(UL_INTERNAL_REQUEST), PVOID));
  1144. pRequest->pUrlBuffer =
  1145. (PWSTR)((PCHAR)pRequest->pTracker + g_UlFullTrackerSize);
  1146. //
  1147. // Initialize the fast/cache tracker.
  1148. //
  1149. pTracker = pRequest->pTracker;
  1150. pTracker->Signature = UL_FULL_TRACKER_POOL_TAG;
  1151. pTracker->IrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE;
  1152. pTracker->IsFromLookaside = FALSE;
  1153. pTracker->IsFromRequest = TRUE;
  1154. pTracker->AuxilaryBufferLength =
  1155. g_UlMaxFixedHeaderSize +
  1156. g_UlMaxVariableHeaderSize +
  1157. g_UlMaxCopyThreshold;
  1158. UlInitializeFullTrackerPool( pTracker, DEFAULT_MAX_IRP_STACK_SIZE );
  1159. }
  1160. return (PVOID)pRequest;
  1161. } // UlAllocateInternalRequestPool
  1162. /***************************************************************************++
  1163. Routine Description:
  1164. Frees the pool allocated for a UL_INTERNAL_REQUEST structure.
  1165. Arguments:
  1166. pBuffer - Supplies the buffer to free.
  1167. --***************************************************************************/
  1168. VOID
  1169. UlFreeInternalRequestPool(
  1170. IN PVOID pBuffer
  1171. )
  1172. {
  1173. PUL_INTERNAL_REQUEST pRequest;
  1174. //
  1175. // Sanity check.
  1176. //
  1177. pRequest = (PUL_INTERNAL_REQUEST)pBuffer;
  1178. //
  1179. // Free the resource.
  1180. //
  1181. ASSERT( pRequest->Signature == MAKE_FREE_TAG(UL_INTERNAL_REQUEST_POOL_TAG));
  1182. //
  1183. // Kill the signature, then free it.
  1184. //
  1185. UL_FREE_POOL_WITH_SIG( pRequest, UL_INTERNAL_REQUEST_POOL_TAG );
  1186. } // UlFreeInternalRequestPool
  1187. /***************************************************************************++
  1188. Routine Description:
  1189. Allocates the pool necessary for a new UL_CHUNK_TRACKER structure and
  1190. initializes the structure.
  1191. Arguments:
  1192. PoolType - Supplies the type of pool to allocate. This must always
  1193. be NonPagedPool.
  1194. ByteLength - Supplies the byte length for the allocation request.
  1195. This should be g_UlChunkTrackerSize but is basically ignored.
  1196. Tag - Supplies the tag to use for the pool. This should be
  1197. UL_CHUNK_TRACKER_POOL_TAG, but is basically ignored.
  1198. Note: These parameters are required so that this function has a
  1199. signature identical to ExAllocatePoolWithTag.
  1200. Return Value:
  1201. PVOID - Pointer to the newly allocated block if successful, FALSE
  1202. otherwise.
  1203. --***************************************************************************/
  1204. PVOID
  1205. UlAllocateChunkTrackerPool(
  1206. IN POOL_TYPE PoolType,
  1207. IN SIZE_T ByteLength,
  1208. IN ULONG Tag
  1209. )
  1210. {
  1211. PUL_CHUNK_TRACKER pTracker;
  1212. //
  1213. // Sanity check.
  1214. //
  1215. ASSERT( PoolType == NonPagedPool );
  1216. ASSERT( ByteLength == g_UlChunkTrackerSize );
  1217. ASSERT( Tag == UL_CHUNK_TRACKER_POOL_TAG );
  1218. //
  1219. // Allocate the tracker buffer.
  1220. //
  1221. pTracker = (PUL_CHUNK_TRACKER)UL_ALLOCATE_POOL(
  1222. NonPagedPool,
  1223. g_UlChunkTrackerSize,
  1224. UL_CHUNK_TRACKER_POOL_TAG
  1225. );
  1226. if (pTracker != NULL)
  1227. {
  1228. pTracker->Signature = MAKE_FREE_TAG(UL_CHUNK_TRACKER_POOL_TAG);
  1229. pTracker->IrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE;
  1230. pTracker->IsFromLookaside = TRUE;
  1231. //
  1232. // Set up the IRP.
  1233. //
  1234. pTracker->pReadIrp =
  1235. (PIRP)((PCHAR)pTracker +
  1236. ALIGN_UP(sizeof(UL_CHUNK_TRACKER), PVOID));
  1237. IoInitializeIrp(
  1238. pTracker->pReadIrp,
  1239. IoSizeOfIrp(DEFAULT_MAX_IRP_STACK_SIZE),
  1240. DEFAULT_MAX_IRP_STACK_SIZE
  1241. );
  1242. pTracker->pSendIrp =
  1243. (PIRP)((PCHAR)pTracker->pReadIrp +
  1244. ALIGN_UP(IoSizeOfIrp(DEFAULT_MAX_IRP_STACK_SIZE), PVOID));
  1245. IoInitializeIrp(
  1246. pTracker->pSendIrp,
  1247. IoSizeOfIrp(DEFAULT_MAX_IRP_STACK_SIZE),
  1248. DEFAULT_MAX_IRP_STACK_SIZE
  1249. );
  1250. //
  1251. // Set up the variable header pointer.
  1252. //
  1253. pTracker->pVariableHeader =
  1254. (PUCHAR)((PCHAR)pTracker->pSendIrp +
  1255. ALIGN_UP(IoSizeOfIrp(DEFAULT_MAX_IRP_STACK_SIZE), PVOID));
  1256. }
  1257. return pTracker;
  1258. } // UlAllocateChunkTrackerPool
  1259. /***************************************************************************++
  1260. Routine Description:
  1261. Frees the pool allocated for a UL_CHUNK_TRACKER structure.
  1262. Arguments:
  1263. pBuffer - Supplies the buffer to free.
  1264. --***************************************************************************/
  1265. VOID
  1266. UlFreeChunkTrackerPool(
  1267. IN PVOID pBuffer
  1268. )
  1269. {
  1270. PUL_CHUNK_TRACKER pTracker = (PUL_CHUNK_TRACKER)pBuffer;
  1271. UL_FREE_POOL_WITH_SIG( pTracker, UL_CHUNK_TRACKER_POOL_TAG );
  1272. } // UlFreeChunkTrackerPool
  1273. /***************************************************************************++
  1274. Routine Description:
  1275. Allocates the pool necessary for a new UL_FULL_TRACKER structure and
  1276. initializes the structure.
  1277. Arguments:
  1278. PoolType - Supplies the type of pool to allocate. This must always
  1279. be NonPagedPool.
  1280. ByteLength - Supplies the byte length for the allocation request.
  1281. This should be g_UlFullTrackerSize but is basically ignored.
  1282. Tag - Supplies the tag to use for the pool. This should be
  1283. UL_FULL_TRACKER_POOL_TAG, but is basically ignored.
  1284. Note: These parameters are required so that this function has a
  1285. signature identical to ExAllocatePoolWithTag.
  1286. Return Value:
  1287. PVOID - Pointer to the newly allocated block if successful, FALSE
  1288. otherwise.
  1289. --***************************************************************************/
  1290. PVOID
  1291. UlAllocateFullTrackerPool(
  1292. IN POOL_TYPE PoolType,
  1293. IN SIZE_T ByteLength,
  1294. IN ULONG Tag
  1295. )
  1296. {
  1297. PUL_FULL_TRACKER pTracker;
  1298. //
  1299. // Sanity check.
  1300. //
  1301. ASSERT( PoolType == NonPagedPool );
  1302. ASSERT( ByteLength == g_UlFullTrackerSize );
  1303. ASSERT( Tag == UL_FULL_TRACKER_POOL_TAG );
  1304. //
  1305. // Allocate the tracker buffer.
  1306. //
  1307. pTracker = (PUL_FULL_TRACKER)UL_ALLOCATE_POOL(
  1308. NonPagedPool,
  1309. g_UlFullTrackerSize,
  1310. UL_FULL_TRACKER_POOL_TAG
  1311. );
  1312. if (pTracker != NULL)
  1313. {
  1314. pTracker->Signature = MAKE_FREE_TAG(UL_FULL_TRACKER_POOL_TAG);
  1315. pTracker->IrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE;
  1316. pTracker->IsFromLookaside = TRUE;
  1317. pTracker->IsFromRequest = FALSE;
  1318. pTracker->AuxilaryBufferLength =
  1319. g_UlMaxFixedHeaderSize +
  1320. g_UlMaxVariableHeaderSize +
  1321. g_UlMaxCopyThreshold;
  1322. UlInitializeFullTrackerPool( pTracker, DEFAULT_MAX_IRP_STACK_SIZE );
  1323. }
  1324. return pTracker;
  1325. } // UlAllocateFullTrackerPool
  1326. /***************************************************************************++
  1327. Routine Description:
  1328. Frees the pool allocated for a UL_FULL_TRACKER structure.
  1329. Arguments:
  1330. pBuffer - Supplies the buffer to free.
  1331. --***************************************************************************/
  1332. VOID
  1333. UlFreeFullTrackerPool(
  1334. IN PVOID pBuffer
  1335. )
  1336. {
  1337. PUL_FULL_TRACKER pTracker = (PUL_FULL_TRACKER)pBuffer;
  1338. UL_FREE_POOL_WITH_SIG( pTracker, UL_FULL_TRACKER_POOL_TAG );
  1339. } // UlFreeFullTrackerPool
  1340. /***************************************************************************++
  1341. Routine Description:
  1342. Allocates the pool necessary for a new UL_INTERNAL_RESPONSE structure and
  1343. initializes the structure.
  1344. Arguments:
  1345. PoolType - Supplies the type of pool to allocate. This must always
  1346. be NonPagedPool.
  1347. ByteLength - Supplies the byte length for the allocation request.
  1348. This should be g_UlResponseBufferSize but is basically ignored.
  1349. Tag - Supplies the tag to use for the pool. This should be
  1350. UL_INTERNAL_RESPONSE_POOL_TAG, but is basically ignored.
  1351. Note: These parameters are required so that this function has a
  1352. signature identical to ExAllocatePoolWithTag.
  1353. Return Value:
  1354. PVOID - Pointer to the newly allocated block if successful, FALSE
  1355. otherwise.
  1356. --***************************************************************************/
  1357. PVOID
  1358. UlAllocateResponseBufferPool(
  1359. IN POOL_TYPE PoolType,
  1360. IN SIZE_T ByteLength,
  1361. IN ULONG Tag
  1362. )
  1363. {
  1364. //
  1365. // Sanity check.
  1366. //
  1367. ASSERT( PoolType == NonPagedPool );
  1368. ASSERT( ByteLength == g_UlResponseBufferSize );
  1369. ASSERT( Tag == UL_INTERNAL_RESPONSE_POOL_TAG );
  1370. //
  1371. // Allocate the default internal response buffer.
  1372. //
  1373. return UL_ALLOCATE_POOL(
  1374. NonPagedPool,
  1375. g_UlResponseBufferSize,
  1376. UL_INTERNAL_RESPONSE_POOL_TAG
  1377. );
  1378. } // UlAllocateResponseBufferPool
  1379. /***************************************************************************++
  1380. Routine Description:
  1381. Frees the pool allocated for a UL_INTERNAL_RESPONSE structure.
  1382. Arguments:
  1383. pBuffer - Supplies the buffer to free.
  1384. --***************************************************************************/
  1385. VOID
  1386. UlFreeResponseBufferPool(
  1387. IN PVOID pBuffer
  1388. )
  1389. {
  1390. PUL_INTERNAL_RESPONSE pResponseBuffer;
  1391. pResponseBuffer = (PUL_INTERNAL_RESPONSE)pBuffer;
  1392. UL_FREE_POOL_WITH_SIG( pResponseBuffer, UL_INTERNAL_RESPONSE_POOL_TAG );
  1393. } // UlFreeResponseBufferPool
  1394. /***************************************************************************++
  1395. Routine Description:
  1396. Allocates the pool necessary for a new UL_FILE_LOG_BUFFER structure and
  1397. initializes the structure.
  1398. Arguments:
  1399. PoolType - Supplies the type of pool to allocate. This must always
  1400. be PagedPool.
  1401. ByteLength - Supplies the byte length for the allocation request.
  1402. This should be sizeof(UL_LOG_FILE_BUFFER) but is basically ignored.
  1403. Tag - Supplies the tag to use for the pool. This should be
  1404. UL_LOG_FILE_BUFFER_POOL_TAG, but is basically ignored.
  1405. Note: These parameters are required so that this function has a
  1406. signature identical to ExAllocatePoolWithTag.
  1407. Return Value:
  1408. PVOID - Pointer to the newly allocated block if successful, FALSE
  1409. otherwise.
  1410. --***************************************************************************/
  1411. PVOID
  1412. UlAllocateLogBufferPool(
  1413. IN POOL_TYPE PoolType,
  1414. IN SIZE_T ByteLength,
  1415. IN ULONG Tag
  1416. )
  1417. {
  1418. PUL_LOG_FILE_BUFFER pLogBuffer;
  1419. //
  1420. // Sanity check.
  1421. //
  1422. ASSERT( PoolType == NonPagedPool );
  1423. ASSERT( ByteLength == sizeof(UL_LOG_FILE_BUFFER) );
  1424. ASSERT( Tag == UL_LOG_FILE_BUFFER_POOL_TAG );
  1425. //
  1426. // Allocate the default log buffer.
  1427. //
  1428. pLogBuffer = UL_ALLOCATE_STRUCT_WITH_SPACE(
  1429. PagedPool,
  1430. UL_LOG_FILE_BUFFER,
  1431. g_UlLogBufferSize,
  1432. UL_LOG_FILE_BUFFER_POOL_TAG
  1433. );
  1434. if ( pLogBuffer != NULL )
  1435. {
  1436. pLogBuffer->Signature = MAKE_FREE_TAG(UL_LOG_FILE_BUFFER_POOL_TAG);
  1437. pLogBuffer->BufferUsed = 0;
  1438. pLogBuffer->Buffer = (PUCHAR) (pLogBuffer + 1);
  1439. }
  1440. return pLogBuffer;
  1441. } // UlAllocateLogBufferPool
  1442. /***************************************************************************++
  1443. Routine Description:
  1444. Frees the pool allocated for a UL_LOG_FILE_BUFFER structure.
  1445. Arguments:
  1446. pBuffer - Supplies the buffer to free.
  1447. --***************************************************************************/
  1448. VOID
  1449. UlFreeLogBufferPool(
  1450. IN PVOID pBuffer
  1451. )
  1452. {
  1453. PUL_LOG_FILE_BUFFER pLogBuffer;
  1454. pLogBuffer = (PUL_LOG_FILE_BUFFER) pBuffer;
  1455. UL_FREE_POOL_WITH_SIG( pLogBuffer, UL_LOG_FILE_BUFFER_POOL_TAG );
  1456. } // UlFreeLogBufferPool
  1457. //
  1458. // Private routines.
  1459. //
  1460. /***************************************************************************++
  1461. Routine Description:
  1462. Completion handler for device control IRPs.
  1463. Arguments:
  1464. pDeviceObject - Supplies the device object for the IRP being
  1465. completed.
  1466. pIrp - Supplies the IRP being completed.
  1467. pContext - Supplies the context associated with this request. In
  1468. this case, it's a pointer to a UL_STATUS_BLOCK structure.
  1469. Return Value:
  1470. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  1471. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  1472. this IRP.
  1473. --***************************************************************************/
  1474. NTSTATUS
  1475. UlpRestartDeviceControl(
  1476. IN PDEVICE_OBJECT pDeviceObject,
  1477. IN PIRP pIrp,
  1478. IN PVOID pContext
  1479. )
  1480. {
  1481. PUL_STATUS_BLOCK pStatus;
  1482. //
  1483. // If we attached an MDL to the IRP, then free it here and reset
  1484. // the MDL pointer to NULL. IO can't handle a nonpaged MDL in an
  1485. // IRP, so we do it here.
  1486. //
  1487. if (pIrp->MdlAddress != NULL)
  1488. {
  1489. UlFreeMdl( pIrp->MdlAddress );
  1490. pIrp->MdlAddress = NULL;
  1491. }
  1492. //
  1493. // Complete the request.
  1494. //
  1495. pStatus = (PUL_STATUS_BLOCK)pContext;
  1496. UlSignalStatusBlock(
  1497. pStatus,
  1498. pIrp->IoStatus.Status,
  1499. pIrp->IoStatus.Information
  1500. );
  1501. //
  1502. // Tell IO to continue processing this IRP.
  1503. //
  1504. return STATUS_SUCCESS;
  1505. } // UlpRestartDeviceControl
  1506. /*++
  1507. Routine Description:
  1508. Routine to initialize the utilitu code.
  1509. Arguments:
  1510. Return Value:
  1511. --*/
  1512. NTSTATUS
  1513. InitializeHttpUtil(
  1514. VOID
  1515. )
  1516. {
  1517. ULONG i;
  1518. UCHAR c;
  1519. // Initialize the HttpChars array appropriately.
  1520. for (i = 0; i < 128; i++)
  1521. {
  1522. HttpChars[i] = HTTP_CHAR;
  1523. }
  1524. for (i = 'A'; i <= 'Z'; i++)
  1525. {
  1526. HttpChars[i] |= HTTP_UPCASE;
  1527. }
  1528. for (i = 'a'; i <= 'z'; i++)
  1529. {
  1530. HttpChars[i] |= HTTP_LOCASE;
  1531. }
  1532. for (i = '0'; i <= '9'; i++)
  1533. {
  1534. HttpChars[i] |= (HTTP_DIGIT | HTTP_HEX);
  1535. }
  1536. for (i = 0; i <= 31; i++)
  1537. {
  1538. HttpChars[i] |= HTTP_CTL;
  1539. }
  1540. HttpChars[127] |= HTTP_CTL;
  1541. HttpChars[SP] |= HTTP_LWS;
  1542. HttpChars[HT] |= HTTP_LWS;
  1543. for (i = 'A'; i <= 'F'; i++)
  1544. {
  1545. HttpChars[i] |= HTTP_HEX;
  1546. }
  1547. for (i = 'a'; i <= 'f'; i++)
  1548. {
  1549. HttpChars[i] |= HTTP_HEX;
  1550. }
  1551. HttpChars['('] |= HTTP_SEPERATOR;
  1552. HttpChars[')'] |= HTTP_SEPERATOR;
  1553. HttpChars['<'] |= HTTP_SEPERATOR;
  1554. HttpChars['>'] |= HTTP_SEPERATOR;
  1555. HttpChars['@'] |= HTTP_SEPERATOR;
  1556. HttpChars[','] |= HTTP_SEPERATOR;
  1557. HttpChars[';'] |= HTTP_SEPERATOR;
  1558. HttpChars[':'] |= HTTP_SEPERATOR;
  1559. HttpChars['\\'] |= HTTP_SEPERATOR;
  1560. HttpChars['"'] |= HTTP_SEPERATOR;
  1561. HttpChars['/'] |= HTTP_SEPERATOR;
  1562. HttpChars['['] |= HTTP_SEPERATOR;
  1563. HttpChars[']'] |= HTTP_SEPERATOR;
  1564. HttpChars['?'] |= HTTP_SEPERATOR;
  1565. HttpChars['='] |= HTTP_SEPERATOR;
  1566. HttpChars['{'] |= HTTP_SEPERATOR;
  1567. HttpChars['}'] |= HTTP_SEPERATOR;
  1568. HttpChars[SP] |= HTTP_SEPERATOR;
  1569. HttpChars[HT] |= HTTP_SEPERATOR;
  1570. //
  1571. // URL "reserved" characters (rfc2396)
  1572. //
  1573. HttpChars[';'] |= URL_LEGAL;
  1574. HttpChars['/'] |= URL_LEGAL;
  1575. HttpChars['\\'] |= URL_LEGAL;
  1576. HttpChars['?'] |= URL_LEGAL;
  1577. HttpChars[':'] |= URL_LEGAL;
  1578. HttpChars['@'] |= URL_LEGAL;
  1579. HttpChars['&'] |= URL_LEGAL;
  1580. HttpChars['='] |= URL_LEGAL;
  1581. HttpChars['+'] |= URL_LEGAL;
  1582. HttpChars['$'] |= URL_LEGAL;
  1583. HttpChars[','] |= URL_LEGAL;
  1584. //
  1585. // URL escape character
  1586. //
  1587. HttpChars['%'] |= URL_LEGAL;
  1588. //
  1589. // URL "mark" characters (rfc2396)
  1590. //
  1591. HttpChars['-'] |= URL_LEGAL;
  1592. HttpChars['_'] |= URL_LEGAL;
  1593. HttpChars['.'] |= URL_LEGAL;
  1594. HttpChars['!'] |= URL_LEGAL;
  1595. HttpChars['~'] |= URL_LEGAL;
  1596. HttpChars['*'] |= URL_LEGAL;
  1597. HttpChars['\''] |= URL_LEGAL;
  1598. HttpChars['('] |= URL_LEGAL;
  1599. HttpChars[')'] |= URL_LEGAL;
  1600. //
  1601. // RFC2396 describes these characters as `unwise' "because gateways and
  1602. // other transport agents are known to sometimes modify such characters,
  1603. // or they are used as delimiters". However, for compatibility with IIS
  1604. // 5.0 and DAV, we must allow these unwise characters in URLs.
  1605. //
  1606. HttpChars['{'] |= URL_LEGAL;
  1607. HttpChars['}'] |= URL_LEGAL;
  1608. HttpChars['|'] |= URL_LEGAL;
  1609. HttpChars['^'] |= URL_LEGAL;
  1610. HttpChars['['] |= URL_LEGAL;
  1611. HttpChars[']'] |= URL_LEGAL;
  1612. HttpChars['`'] |= URL_LEGAL;
  1613. //
  1614. // These US-ASCII characters are "excluded"; i.e. not URL_LEGAL (see RFC):
  1615. // '<' | '>' | '#' | '%' | '"' (0x22) | ' ' (0x20)
  1616. // In addition, control characters (0x00-0x1F and 0x7F) and
  1617. // non US-ASCII characters (0x80-0xFF) are not URL_LEGAL.
  1618. //
  1619. for (i = 0; i < 128; i++)
  1620. {
  1621. if (!IS_HTTP_SEPERATOR(i) && !IS_HTTP_CTL(i))
  1622. {
  1623. HttpChars[i] |= HTTP_TOKEN;
  1624. }
  1625. }
  1626. //
  1627. // Fast path for PopChar
  1628. //
  1629. RtlZeroMemory(FastPopChars, 256 * sizeof(USHORT));
  1630. RtlZeroMemory(DummyPopChars, 256 * sizeof(USHORT));
  1631. for (i = 0; i < 256; i++)
  1632. {
  1633. c = (UCHAR)i;
  1634. if (IS_URL_TOKEN(c) && c != '%' && (c & 0x80) != 0x80)
  1635. {
  1636. FastPopChars[i] = (USHORT)c;
  1637. }
  1638. }
  1639. //
  1640. // Turn backslashes into forward slashes
  1641. //
  1642. FastPopChars['\\'] = L'/';
  1643. return STATUS_SUCCESS;
  1644. }
  1645. /***************************************************************************++
  1646. Routine Description:
  1647. Allocates brand new UL_NONPAGED_RESOURCE structures from the
  1648. lookaside lists
  1649. Arguments:
  1650. Return Value:
  1651. the resource. NULL = out of memory.
  1652. --***************************************************************************/
  1653. PUL_NONPAGED_RESOURCE
  1654. UlResourceNew(
  1655. ULONG OwnerTag
  1656. )
  1657. {
  1658. PUL_NONPAGED_RESOURCE pResource;
  1659. pResource = (PUL_NONPAGED_RESOURCE)(
  1660. PplAllocate(
  1661. g_pUlNonpagedData->ResourceLookaside
  1662. )
  1663. );
  1664. if (pResource != NULL)
  1665. {
  1666. pResource->Signature = UL_NONPAGED_RESOURCE_SIGNATURE;
  1667. #if DBG
  1668. pResource->Resource.OwnerTag = OwnerTag;
  1669. #endif
  1670. pResource->RefCount = 1;
  1671. UlTrace(
  1672. REFCOUNT,
  1673. ("ul!UlResourceNew res=%p tag=0x%08x refcount=%d\n",
  1674. pResource, OwnerTag,
  1675. pResource->RefCount)
  1676. );
  1677. }
  1678. return pResource;
  1679. }
  1680. /***************************************************************************++
  1681. Routine Description:
  1682. Reference a resource.
  1683. Arguments:
  1684. pResource - the resource
  1685. Return Value:
  1686. VOID
  1687. --***************************************************************************/
  1688. VOID
  1689. UlReferenceResource(
  1690. PUL_NONPAGED_RESOURCE pResource
  1691. REFERENCE_DEBUG_FORMAL_PARAMS
  1692. )
  1693. {
  1694. LONG refCount;
  1695. //
  1696. // Sanity check.
  1697. //
  1698. PAGED_CODE();
  1699. ASSERT(IS_VALID_UL_NONPAGED_RESOURCE(pResource));
  1700. refCount = InterlockedIncrement( &pResource->RefCount );
  1701. UlTrace(
  1702. REFCOUNT,
  1703. ("ul!UlReferenceResource res=%p refcount=%d\n",
  1704. pResource,
  1705. refCount)
  1706. );
  1707. } // UlReferenceResource
  1708. /***************************************************************************++
  1709. Routine Description:
  1710. Dereference a resource.
  1711. Arguments:
  1712. pResource - the resource
  1713. Return Value:
  1714. VOID
  1715. --***************************************************************************/
  1716. VOID
  1717. UlDereferenceResource(
  1718. PUL_NONPAGED_RESOURCE pResource
  1719. REFERENCE_DEBUG_FORMAL_PARAMS
  1720. )
  1721. {
  1722. LONG refCount;
  1723. //
  1724. // Sanity check.
  1725. //
  1726. PAGED_CODE();
  1727. ASSERT(IS_VALID_UL_NONPAGED_RESOURCE(pResource));
  1728. refCount = InterlockedDecrement( &pResource->RefCount );
  1729. UlTrace(
  1730. REFCOUNT,
  1731. ("ul!UlDereferenceResource res=%p refcount=%d\n",
  1732. pResource,
  1733. refCount)
  1734. );
  1735. if (refCount == 0)
  1736. {
  1737. //
  1738. // free it
  1739. //
  1740. PplFree(
  1741. g_pUlNonpagedData->ResourceLookaside,
  1742. pResource
  1743. );
  1744. }
  1745. } // UlDereferenceResource
  1746. /***************************************************************************++
  1747. Routine Description:
  1748. support function for lookasides to allocate the memory for
  1749. UL_NONPAGED_RESOURCEs
  1750. Arguments:
  1751. PoolType - the pool type
  1752. ByteLength - how much to alloc
  1753. Tag - the tag to use
  1754. Return Value:
  1755. nt status code
  1756. --***************************************************************************/
  1757. PVOID
  1758. UlResourceAllocatePool(
  1759. IN POOL_TYPE PoolType,
  1760. IN SIZE_T ByteLength,
  1761. IN ULONG Tag
  1762. )
  1763. {
  1764. NTSTATUS Status;
  1765. PUL_NONPAGED_RESOURCE pResource;
  1766. ASSERT( PoolType == NonPagedPool );
  1767. ASSERT( ByteLength == sizeof(UL_NONPAGED_RESOURCE) );
  1768. ASSERT( Tag == UL_NONPAGED_RESOURCE_POOL_TAG );
  1769. pResource = UL_ALLOCATE_STRUCT(
  1770. NonPagedPool,
  1771. UL_NONPAGED_RESOURCE,
  1772. UL_NONPAGED_RESOURCE_POOL_TAG
  1773. );
  1774. if (pResource != NULL)
  1775. {
  1776. pResource->Signature = UL_NONPAGED_RESOURCE_SIGNATURE;
  1777. pResource->RefCount = 1;
  1778. Status = UlInitializeResource(
  1779. &pResource->Resource,
  1780. "UL_NONPAGED_RESOURCE[%p].Resource",
  1781. pResource,
  1782. UL_NONPAGED_RESOURCE_POOL_TAG
  1783. );
  1784. if (NT_SUCCESS(Status) == FALSE)
  1785. {
  1786. UL_FREE_POOL_WITH_SIG(pResource, UL_NONPAGED_RESOURCE_POOL_TAG);
  1787. return NULL;
  1788. }
  1789. }
  1790. return (PVOID)(pResource);
  1791. }
  1792. /***************************************************************************++
  1793. Routine Description:
  1794. support function for lookasides to free the memory for
  1795. UL_NONPAGED_RESOURCE's
  1796. Arguments:
  1797. pBuffer - the UL_NONPAGED_RESOURCE buffer to free
  1798. Return Value:
  1799. VOID
  1800. --***************************************************************************/
  1801. VOID
  1802. UlResourceFreePool(
  1803. IN PVOID pBuffer
  1804. )
  1805. {
  1806. PUL_NONPAGED_RESOURCE pResource;
  1807. NTSTATUS Status;
  1808. pResource = (PUL_NONPAGED_RESOURCE)(pBuffer);
  1809. ASSERT(pResource != NULL);
  1810. ASSERT(pResource->Signature == UL_NONPAGED_RESOURCE_SIGNATURE);
  1811. pResource->Signature = UL_NONPAGED_RESOURCE_SIGNATURE_X;
  1812. Status = UlDeleteResource(&pResource->Resource);
  1813. ASSERT(NT_SUCCESS(Status));
  1814. UL_FREE_POOL_WITH_SIG(
  1815. pResource,
  1816. UL_NONPAGED_RESOURCE_POOL_TAG
  1817. );
  1818. } // UlResourceFreePool
  1819. /***************************************************************************++
  1820. Routine Description:
  1821. Invokes the completion routine (if specified) and determines the
  1822. appropriate return code. This routine ensures that, if the completion
  1823. routine is invoked, the caller always returns STATUS_PENDING.
  1824. Arguments:
  1825. Status - Supplies the completion status.
  1826. Information - Optionally supplies additional information about
  1827. the completed operation, such as the number of bytes
  1828. transferred.
  1829. pCompletionRoutine - Supplies a pointer to a completion routine to
  1830. invoke after the listening endpoint is fully closed.
  1831. pCompletionContext - Supplies an uninterpreted context value for the
  1832. completion routine.
  1833. Return Value:
  1834. NTSTATUS - Completion status. Will always be STATUS_PENDING if the
  1835. completion routine is invoked.
  1836. --***************************************************************************/
  1837. NTSTATUS
  1838. UlInvokeCompletionRoutine(
  1839. IN NTSTATUS Status,
  1840. IN ULONG_PTR Information,
  1841. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  1842. IN PVOID pCompletionContext
  1843. )
  1844. {
  1845. if (pCompletionRoutine != NULL)
  1846. {
  1847. (pCompletionRoutine)(
  1848. pCompletionContext,
  1849. Status,
  1850. Information
  1851. );
  1852. Status = STATUS_PENDING;
  1853. }
  1854. return Status;
  1855. } // UlInvokeCompletionRoutine
  1856. //
  1857. // constants used by the date formatter
  1858. //
  1859. const PWSTR pDays[] =
  1860. {
  1861. L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat"
  1862. };
  1863. const PWSTR pMonths[] =
  1864. {
  1865. L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul",
  1866. L"Aug", L"Sep", L"Oct", L"Nov", L"Dec"
  1867. };
  1868. __inline
  1869. VOID
  1870. TwoDigitsToUnicode(
  1871. PWSTR pBuffer,
  1872. ULONG Number
  1873. )
  1874. {
  1875. pBuffer[0] = L'0' + (WCHAR)(Number / 10);
  1876. pBuffer[1] = L'0' + (WCHAR)(Number % 10);
  1877. }
  1878. /***************************************************************************++
  1879. Routine Description:
  1880. Converts the given system time to string representation containing
  1881. GMT Formatted String.
  1882. Arguments:
  1883. pTime - System time that needs to be converted.
  1884. pBuffer - pointer to string which will contain the GMT time on
  1885. successful return.
  1886. BufferLength - size of pszBuff in bytes
  1887. Return Value:
  1888. NTSTATUS
  1889. History:
  1890. MuraliK 3-Jan-1995
  1891. paulmcd 4-Mar-1999 copied to ul
  1892. --***************************************************************************/
  1893. NTSTATUS
  1894. TimeFieldsToHttpDate(
  1895. IN PTIME_FIELDS pTime,
  1896. OUT PWSTR pBuffer,
  1897. IN ULONG BufferLength
  1898. )
  1899. {
  1900. NTSTATUS Status;
  1901. ASSERT(pBuffer != NULL);
  1902. if (BufferLength < (HTTP_DATE_COUNT + 1)*sizeof(WCHAR))
  1903. {
  1904. return STATUS_BUFFER_TOO_SMALL;
  1905. }
  1906. // 0 1 2
  1907. // 01234567890123456789012345678
  1908. // Formats a string like: "Thu, 14 Jul 1994 15:26:05 GMT"
  1909. //
  1910. //
  1911. // write the constants
  1912. //
  1913. pBuffer[3] = L',';
  1914. pBuffer[4] = pBuffer[7] = pBuffer[11] = L' ';
  1915. pBuffer[19] = pBuffer[22] = L':';
  1916. //
  1917. // now the variants
  1918. //
  1919. //
  1920. // 0-based Weekday
  1921. //
  1922. RtlCopyMemory(&(pBuffer[0]), pDays[pTime->Weekday], 3*sizeof(WCHAR));
  1923. TwoDigitsToUnicode(&(pBuffer[5]), pTime->Day);
  1924. //
  1925. // 1-based Month
  1926. //
  1927. RtlCopyMemory(&(pBuffer[8]), pMonths[pTime->Month - 1], 3*sizeof(WCHAR)); // 1-based
  1928. Status = _RtlIntegerToUnicode(pTime->Year, 10, 5, &(pBuffer[12]));
  1929. ASSERT(NT_SUCCESS(Status));
  1930. pBuffer[16] = L' ';
  1931. TwoDigitsToUnicode(&(pBuffer[17]), pTime->Hour);
  1932. TwoDigitsToUnicode(&(pBuffer[20]), pTime->Minute);
  1933. TwoDigitsToUnicode(&(pBuffer[23]), pTime->Second);
  1934. RtlCopyMemory(&(pBuffer[25]), L" GMT", sizeof(L" GMT"));
  1935. return STATUS_SUCCESS;
  1936. } // TimeFieldsToHttpDate
  1937. __inline
  1938. SHORT
  1939. FASTCALL
  1940. AsciiToShort(
  1941. PCHAR pString
  1942. )
  1943. {
  1944. return (SHORT)atoi(pString);
  1945. }
  1946. __inline
  1947. SHORT
  1948. FASTCALL
  1949. TwoAsciisToShort(
  1950. PCHAR pString
  1951. )
  1952. {
  1953. SHORT Value;
  1954. SHORT Number;
  1955. Number = pString[1] - '0';
  1956. if (Number <= 9)
  1957. {
  1958. Value = Number;
  1959. Number = pString[0] - '0';
  1960. if (Number <= 9)
  1961. {
  1962. Value += Number * 10;
  1963. return Value;
  1964. }
  1965. }
  1966. return 0;
  1967. }
  1968. /***************************************************************************++
  1969. DateTime function ported from user mode W3SVC
  1970. --***************************************************************************/
  1971. /************************************************************
  1972. * Data
  1973. ************************************************************/
  1974. static const PSTR s_rgchMonths[] = {
  1975. "Jan", "Feb", "Mar", "Apr",
  1976. "May", "Jun", "Jul", "Aug",
  1977. "Sep", "Oct", "Nov", "Dec"
  1978. };
  1979. // Custom hash table for NumericToAsciiMonth() for mapping "Apr" to 4
  1980. static const CHAR MonthIndexTable[64] = {
  1981. -1,'A', 2, 12, -1, -1, -1, 8, // A to G
  1982. -1, -1, -1, -1, 7, -1,'N', -1, // F to O
  1983. 9, -1,'R', -1, 10, -1, 11, -1, // P to W
  1984. -1, 5, -1, -1, -1, -1, -1, -1, // X to Z
  1985. -1,'A', 2, 12, -1, -1, -1, 8, // a to g
  1986. -1, -1, -1, -1, 7, -1,'N', -1, // f to o
  1987. 9, -1,'R', -1, 10, -1, 11, -1, // p to w
  1988. -1, 5, -1, -1, -1, -1, -1, -1 // x to z
  1989. };
  1990. /************************************************************
  1991. * Functions
  1992. ************************************************************/
  1993. /***************************************************************************++
  1994. Converts three letters of a month to numeric month
  1995. Arguments:
  1996. s String to convert
  1997. Returns:
  1998. numeric equivalent, 0 on failure.
  1999. --***************************************************************************/
  2000. __inline
  2001. SHORT
  2002. FASTCALL
  2003. NumericToAsciiMonth(
  2004. PCHAR s
  2005. )
  2006. {
  2007. UCHAR monthIndex;
  2008. UCHAR c;
  2009. PSTR monthString;
  2010. //
  2011. // use the third character as the index
  2012. //
  2013. c = (s[2] - 0x40) & 0x3F;
  2014. monthIndex = MonthIndexTable[c];
  2015. if ( monthIndex < 13 ) {
  2016. goto verify;
  2017. }
  2018. //
  2019. // ok, we need to look at the second character
  2020. //
  2021. if ( monthIndex == 'N' ) {
  2022. //
  2023. // we got an N which we need to resolve further
  2024. //
  2025. //
  2026. // if s[1] is 'u' then Jun, if 'a' then Jan
  2027. //
  2028. if ( MonthIndexTable[(s[1]-0x40) & 0x3f] == 'A' ) {
  2029. monthIndex = 1;
  2030. } else {
  2031. monthIndex = 6;
  2032. }
  2033. } else if ( monthIndex == 'R' ) {
  2034. //
  2035. // if s[1] is 'a' then March, if 'p' then April
  2036. //
  2037. if ( MonthIndexTable[(s[1]-0x40) & 0x3f] == 'A' ) {
  2038. monthIndex = 3;
  2039. } else {
  2040. monthIndex = 4;
  2041. }
  2042. } else {
  2043. goto error_exit;
  2044. }
  2045. verify:
  2046. monthString = (PSTR) s_rgchMonths[monthIndex-1];
  2047. if ( (s[0] == monthString[0]) &&
  2048. (s[1] == monthString[1]) &&
  2049. (s[2] == monthString[2]) ) {
  2050. return(monthIndex);
  2051. } else if ( (toupper(s[0]) == monthString[0]) &&
  2052. (tolower(s[1]) == monthString[1]) &&
  2053. (tolower(s[2]) == monthString[2]) ) {
  2054. return monthIndex;
  2055. }
  2056. error_exit:
  2057. return(0);
  2058. } // NumericToAsciiMonth
  2059. /***************************************************************************++
  2060. Converts a string representation of a GMT time (three different
  2061. varieties) to an NT representation of a file time.
  2062. We handle the following variations:
  2063. Sun, 06 Nov 1994 08:49:37 GMT (RFC 822 updated by RFC 1123)
  2064. Sunday, 06-Nov-94 08:49:37 GMT (RFC 850)
  2065. Sun Nov 6 08:49:37 1994 (ANSI C's asctime() format
  2066. Arguments:
  2067. pszTime String representation of time field
  2068. pliTime large integer containing the time in NT format.
  2069. Returns:
  2070. TRUE on success and FALSE on failure.
  2071. History:
  2072. Johnl 24-Jan-1995 Modified from WWW library
  2073. ericsten 30-Nov-2000 Ported from user-mode W3SVC
  2074. --***************************************************************************/
  2075. BOOLEAN
  2076. StringTimeToSystemTime(
  2077. IN const PSTR pszTime,
  2078. OUT LARGE_INTEGER * pliTime
  2079. )
  2080. {
  2081. PCHAR s;
  2082. TIME_FIELDS st;
  2083. if (pszTime == NULL) {
  2084. return FALSE;
  2085. }
  2086. st.Milliseconds = 0;
  2087. if ((s = strchr(pszTime, ','))) {
  2088. ULONG len;
  2089. //
  2090. // Thursday, 10-Jun-93 01:29:59 GMT
  2091. // or: Thu, 10 Jan 1993 01:29:59 GMT */
  2092. //
  2093. s++;
  2094. while (*s && *s==' ') s++;
  2095. len = strlen(s);
  2096. if (len < 18) {
  2097. return FALSE;
  2098. }
  2099. if ( *(s+2) == '-' ) { /* First format */
  2100. st.Day = AsciiToShort(s);
  2101. st.Month = NumericToAsciiMonth(s+3);
  2102. st.Year = AsciiToShort(s+7);
  2103. st.Hour = AsciiToShort(s+10);
  2104. st.Minute = AsciiToShort(s+13);
  2105. st.Second = AsciiToShort(s+16);
  2106. } else { /* Second format */
  2107. if (len < 20) {
  2108. return FALSE;
  2109. }
  2110. st.Day = TwoAsciisToShort(s);
  2111. st.Month = NumericToAsciiMonth(s+3);
  2112. st.Year = TwoAsciisToShort(s+7) * 100 + TwoAsciisToShort(s+9);
  2113. st.Hour = TwoAsciisToShort(s+12);
  2114. st.Minute = TwoAsciisToShort(s+15);
  2115. st.Second = TwoAsciisToShort(s+18);
  2116. }
  2117. } else { /* Try the other format: Wed Jun 9 01:29:59 1993 GMT */
  2118. s = (PCHAR) pszTime;
  2119. while (*s && *s==' ') s++;
  2120. if ((int)strlen(s) < 24) {
  2121. return FALSE;
  2122. }
  2123. if (isdigit(*(s+8))) {
  2124. st.Day = AsciiToShort(s+8);
  2125. } else {
  2126. if ( ' ' != *(s+8) ) {
  2127. return FALSE;
  2128. }
  2129. st.Day = AsciiToShort(s+9);
  2130. }
  2131. st.Month = NumericToAsciiMonth(s+4);
  2132. st.Year = AsciiToShort(s+20);
  2133. st.Hour = AsciiToShort(s+11);
  2134. st.Minute = AsciiToShort(s+14);
  2135. st.Second = AsciiToShort(s+17);
  2136. }
  2137. //
  2138. // Adjust for dates with only two digits
  2139. //
  2140. if ( st.Year < 1000 ) {
  2141. if ( st.Year < 50 ) {
  2142. st.Year += 2000;
  2143. } else {
  2144. st.Year += 1900;
  2145. }
  2146. }
  2147. if ( !RtlTimeFieldsToTime( &st, pliTime )) {
  2148. return FALSE;
  2149. }
  2150. return(TRUE);
  2151. }
  2152. /***************************************************************************++
  2153. End of DateTime function ported from user mode W3SVC
  2154. --***************************************************************************/
  2155. //
  2156. // Some Unicode to Utf8 conversion utilities taken and modified frm
  2157. // base\win32\winnls\utf.c. Use this until they expose the same functionality
  2158. // in kernel.
  2159. //
  2160. /***************************************************************************++
  2161. Routine Description:
  2162. Maps a Unicode character string to its UTF-8 string counterpart
  2163. Conversion continues until the source is finished or an error happens in
  2164. either case it returns the number of UTF-8 characters written.
  2165. If the supllied buffer is not big enough it returns 0.
  2166. --***************************************************************************/
  2167. ULONG
  2168. HttpUnicodeToUTF8(
  2169. IN PCWSTR lpSrcStr,
  2170. IN LONG cchSrc,
  2171. OUT LPSTR lpDestStr,
  2172. IN LONG cchDest
  2173. )
  2174. {
  2175. LPCWSTR lpWC = lpSrcStr;
  2176. LONG cchU8 = 0; // # of UTF8 chars generated
  2177. DWORD dwSurrogateChar;
  2178. WCHAR wchHighSurrogate = 0;
  2179. BOOLEAN bHandled;
  2180. while ((cchSrc--) && ((cchDest == 0) || (cchU8 < cchDest)))
  2181. {
  2182. bHandled = FALSE;
  2183. //
  2184. // Check if high surrogate is available
  2185. //
  2186. if ((*lpWC >= HIGH_SURROGATE_START) && (*lpWC <= HIGH_SURROGATE_END))
  2187. {
  2188. if (cchDest)
  2189. {
  2190. // Another high surrogate, then treat the 1st as normal
  2191. // Unicode character.
  2192. if (wchHighSurrogate)
  2193. {
  2194. if ((cchU8 + 2) < cchDest)
  2195. {
  2196. lpDestStr[cchU8++] = UTF8_1ST_OF_3 | HIGHER_6_BIT(wchHighSurrogate);
  2197. lpDestStr[cchU8++] = UTF8_TRAIL | MIDDLE_6_BIT(wchHighSurrogate);
  2198. lpDestStr[cchU8++] = UTF8_TRAIL | LOWER_6_BIT(wchHighSurrogate);
  2199. }
  2200. else
  2201. {
  2202. // not enough buffer
  2203. cchSrc++;
  2204. break;
  2205. }
  2206. }
  2207. }
  2208. else
  2209. {
  2210. cchU8 += 3;
  2211. }
  2212. wchHighSurrogate = *lpWC;
  2213. bHandled = TRUE;
  2214. }
  2215. if (!bHandled && wchHighSurrogate)
  2216. {
  2217. if ((*lpWC >= LOW_SURROGATE_START) && (*lpWC <= LOW_SURROGATE_END))
  2218. {
  2219. // wheee, valid surrogate pairs
  2220. if (cchDest)
  2221. {
  2222. if ((cchU8 + 3) < cchDest)
  2223. {
  2224. dwSurrogateChar = (((wchHighSurrogate-0xD800) << 10) + (*lpWC - 0xDC00) + 0x10000);
  2225. lpDestStr[cchU8++] = (UTF8_1ST_OF_4 | (unsigned char)(dwSurrogateChar >> 18)); // 3 bits from 1st byte
  2226. lpDestStr[cchU8++] = (UTF8_TRAIL | (unsigned char)((dwSurrogateChar >> 12) & 0x3f)); // 6 bits from 2nd byte
  2227. lpDestStr[cchU8++] = (UTF8_TRAIL | (unsigned char)((dwSurrogateChar >> 6) & 0x3f)); // 6 bits from 3rd byte
  2228. lpDestStr[cchU8++] = (UTF8_TRAIL | (unsigned char)(0x3f &dwSurrogateChar)); // 6 bits from 4th byte
  2229. }
  2230. else
  2231. {
  2232. // not enough buffer
  2233. cchSrc++;
  2234. break;
  2235. }
  2236. }
  2237. else
  2238. {
  2239. // we already counted 3 previously (in high surrogate)
  2240. cchU8 += 1;
  2241. }
  2242. bHandled = TRUE;
  2243. }
  2244. else
  2245. {
  2246. // Bad Surrogate pair : ERROR
  2247. // Just process wchHighSurrogate , and the code below will
  2248. // process the current code point
  2249. if (cchDest)
  2250. {
  2251. if ((cchU8 + 2) < cchDest)
  2252. {
  2253. lpDestStr[cchU8++] = UTF8_1ST_OF_3 | HIGHER_6_BIT(wchHighSurrogate);
  2254. lpDestStr[cchU8++] = UTF8_TRAIL | MIDDLE_6_BIT(wchHighSurrogate);
  2255. lpDestStr[cchU8++] = UTF8_TRAIL | LOWER_6_BIT(wchHighSurrogate);
  2256. }
  2257. else
  2258. {
  2259. // not enough buffer
  2260. cchSrc++;
  2261. break;
  2262. }
  2263. }
  2264. }
  2265. wchHighSurrogate = 0;
  2266. }
  2267. if (!bHandled)
  2268. {
  2269. if (*lpWC <= ASCII)
  2270. {
  2271. //
  2272. // Found ASCII.
  2273. //
  2274. if (cchDest)
  2275. {
  2276. lpDestStr[cchU8] = (char)*lpWC;
  2277. }
  2278. cchU8++;
  2279. }
  2280. else if (*lpWC <= UTF8_2_MAX)
  2281. {
  2282. //
  2283. // Found 2 byte sequence if < 0x07ff (11 bits).
  2284. //
  2285. if (cchDest)
  2286. {
  2287. if ((cchU8 + 1) < cchDest)
  2288. {
  2289. //
  2290. // Use upper 5 bits in first byte.
  2291. // Use lower 6 bits in second byte.
  2292. //
  2293. lpDestStr[cchU8++] = UTF8_1ST_OF_2 | (*lpWC >> 6);
  2294. lpDestStr[cchU8++] = UTF8_TRAIL | LOWER_6_BIT(*lpWC);
  2295. }
  2296. else
  2297. {
  2298. //
  2299. // Error - buffer too small.
  2300. //
  2301. cchSrc++;
  2302. break;
  2303. }
  2304. }
  2305. else
  2306. {
  2307. cchU8 += 2;
  2308. }
  2309. }
  2310. else
  2311. {
  2312. //
  2313. // Found 3 byte sequence.
  2314. //
  2315. if (cchDest)
  2316. {
  2317. if ((cchU8 + 2) < cchDest)
  2318. {
  2319. //
  2320. // Use upper 4 bits in first byte.
  2321. // Use middle 6 bits in second byte.
  2322. // Use lower 6 bits in third byte.
  2323. //
  2324. lpDestStr[cchU8++] = UTF8_1ST_OF_3 | HIGHER_6_BIT(*lpWC);
  2325. lpDestStr[cchU8++] = UTF8_TRAIL | MIDDLE_6_BIT(*lpWC);
  2326. lpDestStr[cchU8++] = UTF8_TRAIL | LOWER_6_BIT(*lpWC);
  2327. }
  2328. else
  2329. {
  2330. //
  2331. // Error - buffer too small.
  2332. //
  2333. cchSrc++;
  2334. break;
  2335. }
  2336. }
  2337. else
  2338. {
  2339. cchU8 += 3;
  2340. }
  2341. }
  2342. }
  2343. lpWC++;
  2344. }
  2345. //
  2346. // If the last character was a high surrogate, then handle it as a normal
  2347. // unicode character.
  2348. //
  2349. if ((cchSrc < 0) && (wchHighSurrogate != 0))
  2350. {
  2351. if (cchDest)
  2352. {
  2353. if ((cchU8 + 2) < cchDest)
  2354. {
  2355. lpDestStr[cchU8++] = UTF8_1ST_OF_3 | HIGHER_6_BIT(wchHighSurrogate);
  2356. lpDestStr[cchU8++] = UTF8_TRAIL | MIDDLE_6_BIT(wchHighSurrogate);
  2357. lpDestStr[cchU8++] = UTF8_TRAIL | LOWER_6_BIT(wchHighSurrogate);
  2358. }
  2359. else
  2360. {
  2361. cchSrc++;
  2362. }
  2363. }
  2364. }
  2365. //
  2366. // Make sure the destination buffer was large enough.
  2367. //
  2368. if (cchDest && (cchSrc >= 0))
  2369. {
  2370. return 0;
  2371. }
  2372. //
  2373. // Return the number of UTF-8 characters written.
  2374. //
  2375. return cchU8;
  2376. }
  2377. /*++
  2378. Routine Description:
  2379. Search input list of ETags for one that matches our local ETag.
  2380. Arguments:
  2381. pLocalETag - The local ETag we're using.
  2382. pETagList - The ETag list we've received from the client.
  2383. bWeakCompare - Whether using Weak Comparison is ok
  2384. Returns:
  2385. TRUE if we found a matching ETag, FALSE otherwise.
  2386. Author:
  2387. Anil Ruia (AnilR) 3-Apr-2000
  2388. History:
  2389. Eric Stenson (EricSten) 6-Dec-2000 ported from user-mode
  2390. --*/
  2391. BOOLEAN FindInETagList(
  2392. IN PUCHAR pLocalETag,
  2393. IN PUCHAR pETagList,
  2394. IN BOOLEAN fWeakCompare
  2395. )
  2396. {
  2397. ULONG QuoteCount;
  2398. PUCHAR pFileETag;
  2399. BOOLEAN Matched;
  2400. // We'll loop through the ETag string, looking for ETag to
  2401. // compare, as long as we have an ETag to look at.
  2402. do
  2403. {
  2404. while (isspace(*pETagList))
  2405. {
  2406. pETagList++;
  2407. }
  2408. if (!*pETagList)
  2409. {
  2410. // Ran out of ETag.
  2411. return FALSE;
  2412. }
  2413. // If this ETag is *, it's a match.
  2414. if (*pETagList == '*')
  2415. {
  2416. return TRUE;
  2417. }
  2418. // See if this ETag is weak.
  2419. if (pETagList[0] == 'W' && pETagList[1] == '/')
  2420. {
  2421. // This is a weak validator. If we're not doing the weak
  2422. // comparison, fail.
  2423. if (!fWeakCompare)
  2424. {
  2425. return FALSE;
  2426. }
  2427. // Skip over the 'W/', and any intervening whitespace.
  2428. pETagList += 2;
  2429. while (isspace(*pETagList))
  2430. {
  2431. pETagList++;
  2432. }
  2433. if (!*pETagList)
  2434. {
  2435. // Ran out of ETag.
  2436. return FALSE;
  2437. }
  2438. }
  2439. if (*pETagList != '"')
  2440. {
  2441. // This isn't a quoted string, so fail.
  2442. return FALSE;
  2443. }
  2444. // OK, right now we should be at the start of a quoted string that
  2445. // we can compare against our current ETag.
  2446. QuoteCount = 0;
  2447. Matched = TRUE;
  2448. pFileETag = pLocalETag;
  2449. // Do the actual compare. We do this by scanning the current ETag,
  2450. // which is a quoted string. We look for two quotation marks, the
  2451. // the delimiters if the quoted string. If after we find two quotes
  2452. // in the ETag everything has matched, then we've matched this ETag.
  2453. // Otherwise we'll try the next one.
  2454. do
  2455. {
  2456. CHAR Temp;
  2457. Temp = *pETagList;
  2458. if (Temp == '"')
  2459. {
  2460. QuoteCount++;
  2461. }
  2462. if (*pFileETag != Temp)
  2463. {
  2464. Matched = FALSE;
  2465. }
  2466. if (!Temp)
  2467. {
  2468. return FALSE;
  2469. }
  2470. pETagList++;
  2471. if (*pFileETag == '\0')
  2472. {
  2473. break;
  2474. }
  2475. pFileETag++;
  2476. }
  2477. while (QuoteCount != 2);
  2478. if (Matched)
  2479. {
  2480. return TRUE;
  2481. }
  2482. // Otherwise, at this point we need to look at the next ETag.
  2483. while (QuoteCount != 2)
  2484. {
  2485. if (*pETagList == '"')
  2486. {
  2487. QuoteCount++;
  2488. }
  2489. else
  2490. {
  2491. if (*pETagList == '\0')
  2492. {
  2493. return FALSE;
  2494. }
  2495. }
  2496. pETagList++;
  2497. }
  2498. while (isspace(*pETagList))
  2499. {
  2500. pETagList++;
  2501. }
  2502. if (*pETagList == ',')
  2503. {
  2504. pETagList++;
  2505. }
  2506. else
  2507. {
  2508. return FALSE;
  2509. }
  2510. }
  2511. while ( *pETagList );
  2512. return FALSE;
  2513. }
  2514. /*++
  2515. Routine Description:
  2516. Build a NULL terminated UNICODE string from the IP and Port address
  2517. Arguments:
  2518. IpAddressStringW - String buffer to place the UNICODE string
  2519. (caller allocated)
  2520. IpAddress - 32-bit version of the IP address
  2521. IpPortNum - 16-bit version of the TCP Port
  2522. Returns:
  2523. Count of bytes written into IpAddressStringW.
  2524. Author:
  2525. Eric Stenson (EricSten) 29-Jan-2001
  2526. --*/
  2527. ULONG
  2528. HostAddressAndPortToStringW(
  2529. IN OUT PWCHAR IpAddressStringW,
  2530. IN ULONG IpAddress,
  2531. IN USHORT IpPortNum
  2532. )
  2533. {
  2534. PWCHAR pszW = IpAddressStringW;
  2535. pszW = UlStrPrintUlongW(pszW, (IpAddress >> 24) & 0xFF, 0, '.');
  2536. pszW = UlStrPrintUlongW(pszW, (IpAddress >> 16) & 0xFF, 0, '.');
  2537. pszW = UlStrPrintUlongW(pszW, (IpAddress >> 8) & 0xFF, 0, '.');
  2538. pszW = UlStrPrintUlongW(pszW, (IpAddress >> 0) & 0xFF, 0, ':');
  2539. pszW = UlStrPrintUlongW(pszW, IpPortNum, 0, '\0');
  2540. return DIFF(pszW - IpAddressStringW) * sizeof(WCHAR);
  2541. }
  2542. /*++
  2543. Routine Description:
  2544. Calculates current bias (daylight time aware) and time zone ID.
  2545. Captured from base\client\datetime.c
  2546. Until this two functions are exposed in the kernel we have to
  2547. keep them here.
  2548. Arguments:
  2549. IN CONST TIME_ZONE_INFORMATION *ptzi - time zone for which to calculate bias
  2550. OUT KSYSTEM_TIME *pBias - current bias
  2551. Return Value:
  2552. TIME_ZONE_ID_UNKNOWN - daylight saving time is not used in the
  2553. current time zone.
  2554. TIME_ZONE_ID_STANDARD - The system is operating in the range covered
  2555. by StandardDate.
  2556. TIME_ZONE_ID_DAYLIGHT - The system is operating in the range covered
  2557. by DaylightDate.
  2558. TIME_ZONE_ID_INVALID - The operation failed.
  2559. --*/
  2560. ULONG
  2561. UlCalcTimeZoneIdAndBias(
  2562. IN RTL_TIME_ZONE_INFORMATION *ptzi,
  2563. OUT PLONG pBias
  2564. )
  2565. {
  2566. LARGE_INTEGER TimeZoneBias;
  2567. LARGE_INTEGER NewTimeZoneBias;
  2568. LARGE_INTEGER LocalCustomBias;
  2569. LARGE_INTEGER UtcStandardTime;
  2570. LARGE_INTEGER UtcDaylightTime;
  2571. LARGE_INTEGER StandardTime;
  2572. LARGE_INTEGER DaylightTime;
  2573. LARGE_INTEGER CurrentUniversalTime;
  2574. ULONG CurrentTimeZoneId = UL_TIME_ZONE_ID_INVALID;
  2575. NewTimeZoneBias.QuadPart = Int32x32To64(ptzi->Bias*60, 10000000);
  2576. //
  2577. // Now see if we have stored cutover times
  2578. //
  2579. if (ptzi->StandardStart.Month && ptzi->DaylightStart.Month)
  2580. {
  2581. KeQuerySystemTime(&CurrentUniversalTime);
  2582. //
  2583. // We have timezone cutover information. Compute the
  2584. // cutover dates and compute what our current bias
  2585. // is
  2586. //
  2587. if((!UlCutoverTimeToSystemTime(
  2588. &ptzi->StandardStart,
  2589. &StandardTime,
  2590. &CurrentUniversalTime)
  2591. ) ||
  2592. (!UlCutoverTimeToSystemTime(
  2593. &ptzi->DaylightStart,
  2594. &DaylightTime,
  2595. &CurrentUniversalTime)
  2596. )
  2597. )
  2598. {
  2599. return UL_TIME_ZONE_ID_INVALID;
  2600. }
  2601. //
  2602. // Convert standard time and daylight time to utc
  2603. //
  2604. LocalCustomBias.QuadPart = Int32x32To64(ptzi->StandardBias*60, 10000000);
  2605. TimeZoneBias.QuadPart = NewTimeZoneBias.QuadPart + LocalCustomBias.QuadPart;
  2606. UtcDaylightTime.QuadPart = DaylightTime.QuadPart + TimeZoneBias.QuadPart;
  2607. LocalCustomBias.QuadPart = Int32x32To64(ptzi->DaylightBias*60, 10000000);
  2608. TimeZoneBias.QuadPart = NewTimeZoneBias.QuadPart + LocalCustomBias.QuadPart;
  2609. UtcStandardTime.QuadPart = StandardTime.QuadPart + TimeZoneBias.QuadPart;
  2610. //
  2611. // If daylight < standard, then time >= daylight and
  2612. // less than standard is daylight
  2613. //
  2614. if (UtcDaylightTime.QuadPart < UtcStandardTime.QuadPart)
  2615. {
  2616. //
  2617. // If today is >= DaylightTime and < StandardTime, then
  2618. // We are in daylight savings time
  2619. //
  2620. if ((CurrentUniversalTime.QuadPart >= UtcDaylightTime.QuadPart) &&
  2621. (CurrentUniversalTime.QuadPart < UtcStandardTime.QuadPart))
  2622. {
  2623. CurrentTimeZoneId = UL_TIME_ZONE_ID_DAYLIGHT;
  2624. }
  2625. else
  2626. {
  2627. CurrentTimeZoneId = UL_TIME_ZONE_ID_STANDARD;
  2628. }
  2629. }
  2630. else
  2631. {
  2632. //
  2633. // If today is >= StandardTime and < DaylightTime, then
  2634. // We are in standard time
  2635. //
  2636. if ((CurrentUniversalTime.QuadPart >= UtcStandardTime.QuadPart) &&
  2637. (CurrentUniversalTime.QuadPart < UtcDaylightTime.QuadPart))
  2638. {
  2639. CurrentTimeZoneId = UL_TIME_ZONE_ID_STANDARD;
  2640. }
  2641. else
  2642. {
  2643. CurrentTimeZoneId = UL_TIME_ZONE_ID_DAYLIGHT;
  2644. }
  2645. }
  2646. // Bias in minutes
  2647. *pBias = ptzi->Bias + (CurrentTimeZoneId == UL_TIME_ZONE_ID_DAYLIGHT ?
  2648. ptzi->DaylightBias : ptzi->StandardBias
  2649. );
  2650. }
  2651. else
  2652. {
  2653. *pBias = ptzi->Bias;
  2654. CurrentTimeZoneId = UL_TIME_ZONE_ID_UNKNOWN;
  2655. }
  2656. return CurrentTimeZoneId;
  2657. }
  2658. BOOLEAN
  2659. UlCutoverTimeToSystemTime(
  2660. PTIME_FIELDS CutoverTime,
  2661. PLARGE_INTEGER SystemTime,
  2662. PLARGE_INTEGER CurrentSystemTime
  2663. )
  2664. {
  2665. TIME_FIELDS CurrentTimeFields;
  2666. //
  2667. // Get the current system time
  2668. //
  2669. RtlTimeToTimeFields(CurrentSystemTime,&CurrentTimeFields);
  2670. //
  2671. // check for absolute time field. If the year is specified,
  2672. // the the time is an abosulte time
  2673. //
  2674. if ( CutoverTime->Year )
  2675. {
  2676. return FALSE;
  2677. }
  2678. else
  2679. {
  2680. TIME_FIELDS WorkingTimeField;
  2681. TIME_FIELDS ScratchTimeField;
  2682. LARGE_INTEGER ScratchTime;
  2683. CSHORT BestWeekdayDate;
  2684. CSHORT WorkingWeekdayNumber;
  2685. CSHORT TargetWeekdayNumber;
  2686. CSHORT TargetYear;
  2687. CSHORT TargetMonth;
  2688. CSHORT TargetWeekday; // range [0..6] == [Sunday..Saturday]
  2689. BOOLEAN MonthMatches;
  2690. //
  2691. // The time is an day in the month style time
  2692. //
  2693. // the convention is the Day is 1-5 specifying 1st, 2nd... Last
  2694. // day within the month. The day is WeekDay.
  2695. //
  2696. //
  2697. // Compute the target month and year
  2698. //
  2699. TargetWeekdayNumber = CutoverTime->Day;
  2700. if ( TargetWeekdayNumber > 5 || TargetWeekdayNumber == 0 ) {
  2701. return FALSE;
  2702. }
  2703. TargetWeekday = CutoverTime->Weekday;
  2704. TargetMonth = CutoverTime->Month;
  2705. MonthMatches = FALSE;
  2706. TargetYear = CurrentTimeFields.Year;
  2707. try_next_year:
  2708. BestWeekdayDate = 0;
  2709. WorkingTimeField.Year = TargetYear;
  2710. WorkingTimeField.Month = TargetMonth;
  2711. WorkingTimeField.Day = 1;
  2712. WorkingTimeField.Hour = CutoverTime->Hour;
  2713. WorkingTimeField.Minute = CutoverTime->Minute;
  2714. WorkingTimeField.Second = CutoverTime->Second;
  2715. WorkingTimeField.Milliseconds = CutoverTime->Milliseconds;
  2716. WorkingTimeField.Weekday = 0;
  2717. //
  2718. // Convert to time and then back to time fields so we can determine
  2719. // the weekday of day 1 on the month
  2720. //
  2721. if ( !RtlTimeFieldsToTime(&WorkingTimeField,&ScratchTime) ) {
  2722. return FALSE;
  2723. }
  2724. RtlTimeToTimeFields(&ScratchTime,&ScratchTimeField);
  2725. //
  2726. // Compute bias to target weekday
  2727. //
  2728. if ( ScratchTimeField.Weekday > TargetWeekday ) {
  2729. WorkingTimeField.Day += (7-(ScratchTimeField.Weekday - TargetWeekday));
  2730. }
  2731. else if ( ScratchTimeField.Weekday < TargetWeekday ) {
  2732. WorkingTimeField.Day += (TargetWeekday - ScratchTimeField.Weekday);
  2733. }
  2734. //
  2735. // We are now at the first weekday that matches our target weekday
  2736. //
  2737. BestWeekdayDate = WorkingTimeField.Day;
  2738. WorkingWeekdayNumber = 1;
  2739. //
  2740. // Keep going one week at a time until we either pass the
  2741. // target weekday, or we match exactly
  2742. //
  2743. while ( WorkingWeekdayNumber < TargetWeekdayNumber ) {
  2744. WorkingTimeField.Day += 7;
  2745. if ( !RtlTimeFieldsToTime(&WorkingTimeField,&ScratchTime) ) {
  2746. break;
  2747. }
  2748. RtlTimeToTimeFields(&ScratchTime,&ScratchTimeField);
  2749. WorkingWeekdayNumber++;
  2750. BestWeekdayDate = ScratchTimeField.Day;
  2751. }
  2752. WorkingTimeField.Day = BestWeekdayDate;
  2753. //
  2754. // If the months match, and the date is less than the current
  2755. // date, then be have to go to next year.
  2756. //
  2757. if ( !RtlTimeFieldsToTime(&WorkingTimeField,&ScratchTime) ) {
  2758. return FALSE;
  2759. }
  2760. if ( MonthMatches ) {
  2761. if ( WorkingTimeField.Day < CurrentTimeFields.Day ) {
  2762. MonthMatches = FALSE;
  2763. TargetYear++;
  2764. goto try_next_year;
  2765. }
  2766. if ( WorkingTimeField.Day == CurrentTimeFields.Day ) {
  2767. if (ScratchTime.QuadPart < CurrentSystemTime->QuadPart) {
  2768. MonthMatches = FALSE;
  2769. TargetYear++;
  2770. goto try_next_year;
  2771. }
  2772. }
  2773. }
  2774. *SystemTime = ScratchTime;
  2775. return TRUE;
  2776. }
  2777. }