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.

2980 lines
67 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Regnckey.c
  5. Abstract:
  6. This module contains the Win32 Registry APIs to notify a caller about
  7. a changed Key value. That is:
  8. - RegNotifyChangeKey
  9. Author:
  10. David J. Gilman (davegi) 10-Feb-1992
  11. Notes:
  12. The RegNotifyChangeKey server creates an event and calls
  13. NtNotifyChangeKey asynchronously with that event. It then
  14. places the event (plus some other client information, such
  15. as a named pipe and a client event) in a "Notification List"
  16. and returns to the client.
  17. A Notification List is a list of events controled by a
  18. handler thread. The handler thread waits on the events in
  19. the list. When an event is signaled the handler thread
  20. identifies the client to which the event belongs, and
  21. gives the client (via named pipe) the corresponding client
  22. event.
  23. Since there is a limit on the number of events on which a
  24. thread can wait, there may be several Notification Lists.
  25. Since all the calls to RegNotifyChangeKey in a client
  26. process use the same named pipe, we maintain only one copy
  27. of each pipe. Pipe information is maintained in a symbol table
  28. for fast lookup.
  29. Revision History:
  30. 02-Apr-1992 Ramon J. San Andres (ramonsa)
  31. Changed to use RPC.
  32. --*/
  33. #include <rpc.h>
  34. #include "regrpc.h"
  35. #include "localreg.h"
  36. #include <string.h>
  37. #ifndef REMOTE_NOTIFICATION_DISABLED
  38. //
  39. // Strings used for generating named pipe names
  40. //
  41. #define NAMED_PIPE_HERE L"\\Device\\NamedPipe\\"
  42. #define NAMED_PIPE_THERE L"\\DosDevices\\UNC\\"
  43. //
  44. // Pipe names are maintained in a symbol table. The symbol table has
  45. // one entry for each different pipe given by a client. The entry
  46. // is maintained for as long as there is at least one entry in a
  47. // Notification List referencing it.
  48. //
  49. typedef struct _PIPE_ENTRY *PPIPE_ENTRY;
  50. typedef struct _PIPE_ENTRY {
  51. PPIPE_ENTRY Previous;
  52. PPIPE_ENTRY Next;
  53. UNICODE_STRING PipeName;
  54. DWORD ReferenceCount;
  55. PSECURITY_DESCRIPTOR SecurityDescriptor;
  56. } PIPE_ENTRY;
  57. //
  58. // The PIPE_SYMBOL_TABLE structure contains the symbol table for
  59. // all the pipes being used by the clients of
  60. // RegNotifyChangeKey
  61. //
  62. #define BUCKETS_IN_SYMBOL_TABLE 211
  63. typedef struct _PIPE_SYMBOL_TABLE *PPIPE_SYMBOL_TABLE;
  64. typedef struct _PIPE_SYMBOL_TABLE {
  65. PPIPE_ENTRY Bucket[ BUCKETS_IN_SYMBOL_TABLE ];
  66. } PIPE_SYMBOL_TABLE;
  67. //
  68. // Information about a pending event is maintained in a
  69. // NOTIFICATION_ENTRY structure.
  70. //
  71. typedef struct _NOTIFICATION_ENTRY *PNOTIFICATION_ENTRY;
  72. typedef struct _NOTIFICATION_ENTRY {
  73. DWORD ClientEvent; // Event in client side
  74. HANDLE hKey; // Key handle
  75. DWORD Flags; // Misc. flags
  76. PPIPE_ENTRY PipeEntry; // Pipe Entry
  77. } NOTIFICATION_ENTRY;
  78. //
  79. // Flag values
  80. //
  81. #define CLIENT_IS_DEAD 0x00000001
  82. #define MUST_NOTIFY 0x00000002
  83. #define NOTIFICATION_FAILED 0x00000004
  84. //
  85. // The pending events are maintained in notification lists. Each
  86. // notification list contains:
  87. //
  88. // Previous - Previous in chain
  89. // Next - Next in chain
  90. // EventsInUse - Number of entries being used in this list
  91. // EventHandle - Array of event handles
  92. // ClientEvent - Array of events in client
  93. // PipeEntry - Array of pointers to pipe entries in symbol table
  94. //
  95. //
  96. // The first event in the EventHandle list is the event used to wake
  97. // up the thread whenever we add new entries to the list.
  98. //
  99. // The array entries 0..EventsInUse-1 contain the pending events.
  100. // New events are always added at position EventsInUse. When removing
  101. // an event, all the arrays are shifted.
  102. //
  103. // Whenever EventsInUse == 1, the list is empty of client events and
  104. // it can be removed (together with its thread).
  105. //
  106. //
  107. // Notification Lists are kept in a doubly-linked list. A new
  108. // Notification List is created and added to the chain whenever an
  109. // event is added and all the existing lists are full. Notification
  110. // lists are deleted when the last event in the list is signaled.
  111. //
  112. //
  113. typedef struct _NOTIFICATION_LIST *PNOTIFICATION_LIST;
  114. typedef struct _NOTIFICATION_LIST {
  115. PNOTIFICATION_LIST Previous;
  116. PNOTIFICATION_LIST Next;
  117. DWORD EventsInUse;
  118. HANDLE HandlerThread;
  119. CLIENT_ID HandlerClientId;
  120. DWORD PendingNotifications;
  121. HANDLE EventHandle[ MAXIMUM_WAIT_OBJECTS ];
  122. NOTIFICATION_ENTRY Event[ MAXIMUM_WAIT_OBJECTS ];
  123. DWORD TimeOutCount;
  124. BOOLEAN ResetCount;
  125. } NOTIFICATION_LIST;
  126. #define MAX_TIMEOUT_COUNT 128
  127. #if DBG
  128. #define BIGDBG 0
  129. #else
  130. #define BIGDBG 0
  131. #endif
  132. #define HASH(a,b) Hash(a,b)
  133. // *****************************************************************
  134. //
  135. // Static Variables
  136. //
  137. // *****************************************************************
  138. //
  139. // Head of chain of Notification lists
  140. //
  141. PNOTIFICATION_LIST NotificationListChainHead;
  142. //
  143. // The critical sesction protects all the global structures.
  144. //
  145. RTL_CRITICAL_SECTION NotificationCriticalSection;
  146. //
  147. // Symbol table for named pipes in use.
  148. //
  149. PIPE_SYMBOL_TABLE PipeSymbolTable;
  150. //
  151. // Our machine name is used for determining if requests are local
  152. // or remote.
  153. //
  154. WCHAR OurMachineNameBuffer[ MAX_PATH ];
  155. UNICODE_STRING OurMachineName;
  156. //
  157. // The I/O Status Block is updated by the NtNotifyChangeKey API
  158. // upon notification. We cannot put this structure on the stack
  159. // because at notification time this stack might belong to someone
  160. // else. We can use a single variable because we don't care about
  161. // its contents so it's ok if several people mess with it at the
  162. // same time.
  163. //
  164. IO_STATUS_BLOCK IoStatusBlock;
  165. // *****************************************************************
  166. //
  167. // Local Prototypes
  168. //
  169. // *****************************************************************
  170. LONG
  171. CreateNotificationList (
  172. OUT PNOTIFICATION_LIST *NotificationListUsed
  173. );
  174. LONG
  175. DeleteNotificationList (
  176. IN OUT PNOTIFICATION_LIST NotificationList
  177. );
  178. LONG
  179. AddEvent (
  180. IN HKEY hKey,
  181. IN HANDLE EventHandle,
  182. IN DWORD ClientEvent,
  183. IN PUNICODE_STRING PipeName,
  184. IN PRPC_SECURITY_ATTRIBUTES pRpcSa OPTIONAL,
  185. OUT PNOTIFICATION_LIST *NotificationListUsed
  186. );
  187. LONG
  188. RemoveEvent (
  189. IN HANDLE EventHandle,
  190. IN OUT PNOTIFICATION_LIST NotificationList
  191. );
  192. LONG
  193. GetAvailableNotificationList (
  194. OUT PNOTIFICATION_LIST *NotificationListUsed
  195. );
  196. LONG
  197. AddEntryToNotificationList(
  198. IN OUT PNOTIFICATION_LIST NotificationList,
  199. IN HKEY hKey,
  200. IN HANDLE EventHandle,
  201. IN DWORD ClientEvent,
  202. IN PUNICODE_STRING PipeName,
  203. IN PRPC_SECURITY_ATTRIBUTES pRpcSa OPTIONAL
  204. );
  205. LONG
  206. RemoveEntryFromNotificationList (
  207. IN OUT PNOTIFICATION_LIST NotificationList,
  208. IN DWORD EntryIndex
  209. );
  210. LONG
  211. CompactNotificationList (
  212. IN OUT PNOTIFICATION_LIST NotificationList
  213. );
  214. VOID
  215. AddNotificationListToChain(
  216. IN OUT PNOTIFICATION_LIST NotificationList
  217. );
  218. VOID
  219. RemoveNotificationListFromChain(
  220. IN OUT PNOTIFICATION_LIST NotificationList
  221. );
  222. LONG
  223. GetFullPipeName(
  224. IN PUNICODE_STRING MachineName,
  225. IN PUNICODE_STRING PipeName,
  226. IN OUT PUNICODE_STRING FullPipeName
  227. );
  228. LONG
  229. CreatePipeEntry (
  230. IN PUNICODE_STRING PipeName,
  231. IN PRPC_SECURITY_ATTRIBUTES pRpcSa OPTIONAL,
  232. OUT PPIPE_ENTRY *PipeEntryUsed
  233. );
  234. LONG
  235. DeletePipeEntry(
  236. IN OUT PPIPE_ENTRY PipeEntry
  237. );
  238. LONG
  239. AddPipe(
  240. IN PUNICODE_STRING PipeName,
  241. IN PRPC_SECURITY_ATTRIBUTES pRpcSa OPTIONAL,
  242. OUT PPIPE_ENTRY *PipeEntryUsed
  243. );
  244. LONG
  245. RemovePipe(
  246. IN OUT PPIPE_ENTRY PipeEntry
  247. );
  248. LONG
  249. AddPipeEntryToSymbolTable(
  250. IN OUT PPIPE_ENTRY PipeEntry
  251. );
  252. LONG
  253. RemovePipeEntryFromSymbolTable(
  254. IN OUT PPIPE_ENTRY PipeEntry
  255. );
  256. LONG
  257. LookForPipeEntryInSymbolTable(
  258. IN PUNICODE_STRING PipeName,
  259. OUT PPIPE_ENTRY *PipeEntryUsed
  260. );
  261. DWORD
  262. Hash(
  263. IN PUNICODE_STRING Symbol,
  264. IN DWORD Buckets
  265. );
  266. VOID
  267. NotificationHandler(
  268. IN PNOTIFICATION_LIST NotificationList
  269. );
  270. DWORD
  271. NotificationListMaintenance(
  272. IN OUT PNOTIFICATION_LIST NotificationList
  273. );
  274. LONG
  275. SendEventToClient(
  276. IN DWORD ClientEvent,
  277. IN PPIPE_ENTRY PipeEntry
  278. );
  279. #if BIGDBG
  280. VOID
  281. DumpNotificationLists(
  282. );
  283. VOID
  284. DumpPipeTable(
  285. );
  286. #endif
  287. #endif // REMOTE_NOTIFICATION_DISABLED
  288. // *****************************************************************
  289. //
  290. // BaseRegNotifyChangeKeyValue
  291. //
  292. // *****************************************************************
  293. BOOL
  294. InitializeRegNotifyChangeKeyValue(
  295. )
  296. /*++
  297. Routine Description:
  298. Initializes the static data structures used by the
  299. RegNotifyChangeKeyValue server. Called once at program
  300. initialization.
  301. Arguments:
  302. None
  303. Return Value:
  304. BOOLEAN - TRUE if successful.
  305. --*/
  306. {
  307. #ifdef REMOTE_NOTIFICATION_DISABLED
  308. return( TRUE );
  309. #else // REMOTE_NOTIFICATION_DISABLED
  310. NTSTATUS NtStatus;
  311. DWORD Bucket;
  312. DWORD MachineNameLength;
  313. NotificationListChainHead = NULL;
  314. //
  315. // Determine our machine name
  316. //
  317. MachineNameLength = MAX_PATH;
  318. if ( !GetComputerNameW( OurMachineNameBuffer, &MachineNameLength ) ) {
  319. return FALSE;
  320. }
  321. OurMachineName.Buffer = OurMachineNameBuffer;
  322. OurMachineName.Length = (USHORT)(MachineNameLength * sizeof(WCHAR));
  323. OurMachineName.MaximumLength = (USHORT)(MAX_PATH * sizeof(WCHAR));
  324. //
  325. // Initialize Notification critical section
  326. //
  327. NtStatus = RtlInitializeCriticalSection(
  328. &NotificationCriticalSection
  329. );
  330. if ( !NT_SUCCESS( NtStatus ) ) {
  331. return FALSE;
  332. }
  333. //
  334. // Initialize the pipe symbol table
  335. //
  336. for ( Bucket = 0; Bucket < BUCKETS_IN_SYMBOL_TABLE; Bucket++ ) {
  337. PipeSymbolTable.Bucket[Bucket] = NULL;
  338. }
  339. return TRUE;
  340. #endif // REMOTE_NOTIFICATION_DISABLED
  341. }
  342. error_status_t
  343. BaseRegNotifyChangeKeyValue(
  344. IN HKEY hKey,
  345. IN BOOLEAN fWatchSubtree,
  346. IN DWORD dwNotifyFilter,
  347. IN DWORD hEvent,
  348. IN PUNICODE_STRING MachineName,
  349. IN PUNICODE_STRING PipeName,
  350. IN PRPC_SECURITY_ATTRIBUTES pRpcSa OPTIONAL
  351. )
  352. /*++
  353. Routine Description:
  354. This API is used to watch a key or sub-tree for changes. It is
  355. asynchronous. It is possible to filter the criteria by which the
  356. notification occurs.
  357. Arguments:
  358. hKey - Supplies a handle to a key that has been previously opened with
  359. KEY_NOTIFY access.
  360. fWatchSubtree - Supplies a boolean value that if TRUE causes the
  361. system to monitor the key and all of its decsendants. A value of
  362. FALSE causes the system to monitor only the specified key.
  363. dwNotifyFilter - Supplies a set of flags that specify the filter
  364. conditions the system uses to satisfy a change notification.
  365. REG_NOTIFY_CHANGE_KEYNAME - Any key name changes that occur
  366. in a key or subtree being watched will satisfy a
  367. change notification wait. This includes creations
  368. and deletions.
  369. REG_NOTIFY_CHANGE_ATTRIBUTES - Any attribute changes that occur
  370. in a key or subtree being watched will satisfy a
  371. change notification.
  372. REG_NOTIFY_CHANGE_LAST_WRITE - Any last write time changes that
  373. occur in a key or subtree being watched will satisfy a
  374. change notification.
  375. REG_NOTIFY_CHANGE_SECURITY - Any security descriptor changes
  376. that occur in a key or subtree being watched will
  377. satisfy a change notification.
  378. hEvent - Supplies a DWORD which represents an event that will have to
  379. be communicated to the client (via named pipe) when a key
  380. has to be notified.
  381. PipeName - Supplies the name of the pipe used for communicating
  382. the notification to the client.
  383. pRpcSa - Supplies the optional security attributes of the named
  384. pipe.
  385. Return Value:
  386. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  387. --*/
  388. {
  389. #ifdef REMOTE_NOTIFICATION_DISABLED
  390. return ERROR_INVALID_PARAMETER;
  391. #else // REMOTE_NOTIFICATION_DISABLED
  392. NTSTATUS NtStatus;
  393. HANDLE EventHandle;
  394. PNOTIFICATION_LIST NotificationList;
  395. LONG Error;
  396. UNICODE_STRING FullPipeName;
  397. RPC_IMPERSONATE_CLIENT( NULL );
  398. //
  399. // Enter the critical section
  400. //
  401. NtStatus = RtlEnterCriticalSection( &NotificationCriticalSection );
  402. if ( !NT_SUCCESS( NtStatus ) ) {
  403. return (error_status_t)RtlNtStatusToDosError( NtStatus );
  404. }
  405. try {
  406. #if BIGDBG
  407. DbgPrint( "WINREG: RegNotify entered\n" );
  408. //DbgPrint( "WINREG: Notification requested. HKEY 0x%x, Client 0x%x, pipe %wZ\n",
  409. // hKey, hEvent, PipeName );
  410. //DbgPrint( " Watch subtree: 0x%x, filter 0x%x\n", fWatchSubtree, dwNotifyFilter );
  411. #endif
  412. //
  413. // Subtract the NULL from the Length of all the strings.
  414. // This was added by the client so that RPC would transmit
  415. // the whole thing.
  416. //
  417. if ( MachineName->Length > 0 ) {
  418. MachineName->Length -= sizeof(UNICODE_NULL );
  419. }
  420. if ( PipeName->Length > 0 ) {
  421. PipeName->Length -= sizeof(UNICODE_NULL );
  422. }
  423. //
  424. // Construct the full pipe name based on the machine name
  425. // and the pipe name given.
  426. //
  427. FullPipeName.Buffer = RtlAllocateHeap(
  428. RtlProcessHeap( ), 0,
  429. MAX_PATH * sizeof(WCHAR)
  430. );
  431. if ( !FullPipeName.Buffer ) {
  432. Error = ERROR_OUTOFMEMORY;
  433. } else {
  434. FullPipeName.Length = 0;
  435. FullPipeName.MaximumLength = MAX_PATH * sizeof(WCHAR);
  436. Error = GetFullPipeName(
  437. MachineName,
  438. PipeName,
  439. &FullPipeName
  440. );
  441. if ( Error == ERROR_SUCCESS ) {
  442. //
  443. // Create an event on which we will wait for completion of
  444. // the API.
  445. //
  446. NtStatus = NtCreateEvent(
  447. &EventHandle,
  448. (ACCESS_MASK)EVENT_ALL_ACCESS,
  449. NULL,
  450. SynchronizationEvent,
  451. FALSE
  452. );
  453. if ( NT_SUCCESS( NtStatus ) ) {
  454. //
  455. // Add the event to a Notification List
  456. //
  457. Error = AddEvent(
  458. hKey,
  459. EventHandle,
  460. hEvent,
  461. &FullPipeName,
  462. pRpcSa,
  463. &NotificationList
  464. );
  465. if ( Error == ERROR_SUCCESS ) {
  466. //
  467. // Call the NT API
  468. //
  469. NtStatus = NtNotifyChangeKey(
  470. hKey,
  471. EventHandle,
  472. NULL,
  473. NULL,
  474. &IoStatusBlock,
  475. dwNotifyFilter,
  476. ( BOOLEAN ) fWatchSubtree,
  477. NULL,
  478. 0,
  479. TRUE
  480. );
  481. if ( NT_SUCCESS( NtStatus ) ||
  482. (NtStatus == STATUS_PENDING) ) {
  483. Error = ERROR_SUCCESS;
  484. } else {
  485. //
  486. // Could not request notification, remove the
  487. // event from the notification list.
  488. //
  489. Error = RemoveEvent(
  490. EventHandle,
  491. NotificationList
  492. );
  493. ASSERT( Error == ERROR_SUCCESS );
  494. Error = RtlNtStatusToDosError( NtStatus );
  495. }
  496. } else {
  497. //
  498. // Could not add the event to any notification
  499. // list.
  500. //
  501. NtStatus = NtClose( EventHandle );
  502. ASSERT( NT_SUCCESS( NtStatus ) );
  503. }
  504. } else {
  505. Error = RtlNtStatusToDosError( NtStatus );
  506. }
  507. }
  508. RtlFreeHeap(
  509. RtlProcessHeap( ), 0,
  510. FullPipeName.Buffer
  511. );
  512. }
  513. } except ( NtStatus = GetExceptionCode() ) {
  514. #if DBG
  515. DbgPrint( "WINREG Error: Exception %x in BaseRegNotifyChangeKeyValue\n",
  516. NtStatus );
  517. DbgBreakPoint();
  518. #endif
  519. Error = RtlNtStatusToDosError( NtStatus );
  520. }
  521. #if BIGDBG
  522. DbgPrint( "WINREG: RegNotify left\n" );
  523. #endif
  524. NtStatus = RtlLeaveCriticalSection( &NotificationCriticalSection );
  525. ASSERT( NT_SUCCESS( NtStatus ) );
  526. RPC_REVERT_TO_SELF();
  527. return (error_status_t)Error;
  528. #endif // REMOTE_NOTIFICATION_DISABLED
  529. }
  530. BOOL
  531. CleanDeadClientInfo(
  532. HKEY hKey
  533. )
  534. /*++
  535. Routine Description:
  536. When a client dies, this function searches the notification lists to
  537. see if we the client has some pending notifications. We flag the
  538. entries in the notification lists and signal the events so that
  539. the notification handler can get rid of these orphans.
  540. Arguments:
  541. hKey - Client's hKey
  542. Return Value:
  543. BOOL - Returns TRUE unless something REALLY weird happened.
  544. --*/
  545. {
  546. #ifdef REMOTE_NOTIFICATION_DISABLED
  547. return( TRUE );
  548. #else // REMOTE_NOTIFICATION_DISABLED
  549. NTSTATUS NtStatus;
  550. PNOTIFICATION_LIST NotificationList;
  551. PNOTIFICATION_ENTRY Event;
  552. DWORD Index;
  553. BOOL Ok = TRUE;
  554. BOOL FoundDeadClients;
  555. //
  556. // Enter the critical section
  557. //
  558. NtStatus = RtlEnterCriticalSection( &NotificationCriticalSection );
  559. if ( !NT_SUCCESS( NtStatus ) ) {
  560. return FALSE;
  561. }
  562. #if BIGDBG
  563. DbgPrint( "WINREG: Dead client, hKey 0x%x\n", hKey );
  564. #endif
  565. try {
  566. //
  567. // Traverse all the lists looking for orphans.
  568. //
  569. for ( NotificationList = NotificationListChainHead;
  570. NotificationList;
  571. NotificationList = NotificationList->Next ) {
  572. FoundDeadClients = FALSE;
  573. Event = NotificationList->Event;
  574. //
  575. // Examine all the entries of the list to see if any
  576. // entry is an orphan.
  577. //
  578. for ( Index = 1;
  579. Index < NotificationList->EventsInUse;
  580. Index++ ) {
  581. //
  582. // If this entry is an orphan, flag it as such and
  583. // signal the event so that the notification handler
  584. // can clean it up.
  585. //
  586. if ( Event->hKey == hKey ) {
  587. #if BIGDBG
  588. DbgPrint( "WINREG: Found notification orphan, hKey 0x%x Client 0x%x\n",
  589. hKey, Event->ClientEvent );
  590. #endif
  591. Event->Flags |= CLIENT_IS_DEAD;
  592. FoundDeadClients = TRUE;
  593. }
  594. Event++;
  595. }
  596. if ( FoundDeadClients ) {
  597. NtStatus = NtSetEvent( NotificationList->EventHandle[0], NULL );
  598. ASSERT( NT_SUCCESS( NtStatus ) );
  599. }
  600. }
  601. } except ( NtStatus = GetExceptionCode() ) {
  602. #if DBG
  603. DbgPrint( "WINREG Error: Exception %x in CleanDeadClientInfo\n",
  604. NtStatus );
  605. DbgBreakPoint();
  606. #endif
  607. Ok = FALSE;
  608. }
  609. #if BIGDBG
  610. DbgPrint( "WINREG: Dead client left\n" );
  611. #endif
  612. NtStatus = RtlLeaveCriticalSection( &NotificationCriticalSection );
  613. ASSERT( NT_SUCCESS( NtStatus ) );
  614. return Ok;
  615. #endif // REMOTE_NOTIFICATION_DISABLED
  616. }
  617. // *****************************************************************
  618. //
  619. // Notification List funcions
  620. //
  621. // *****************************************************************
  622. #ifndef REMOTE_NOTIFICATION_DISABLED
  623. LONG
  624. CreateNotificationList (
  625. OUT PNOTIFICATION_LIST *NotificationListUsed
  626. )
  627. /*++
  628. Routine Description:
  629. Creates a new Notification List and its handler thread.
  630. Arguments:
  631. NotificationListUsed - Supplies pointer to pointer to Notification List
  632. Return Value:
  633. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  634. --*/
  635. {
  636. PNOTIFICATION_LIST NotificationList;
  637. DWORD Index;
  638. NTSTATUS NtStatus;
  639. LONG Error;
  640. #if BIGDBG
  641. DbgPrint( "WINREG: Creating new notification list\n" );
  642. #endif
  643. //
  644. // Allocate memory for the new Notification List
  645. //
  646. NotificationList = RtlAllocateHeap(
  647. RtlProcessHeap( ), 0,
  648. sizeof( NOTIFICATION_LIST )
  649. );
  650. if ( !NotificationList ) {
  651. return ERROR_OUTOFMEMORY;
  652. }
  653. //
  654. // Create the "Wake up" event handle, which is used to wake
  655. // up the handler thread whenever new events are added to
  656. // the notification list.
  657. //
  658. NtStatus = NtCreateEvent(
  659. &(NotificationList->EventHandle[0] ),
  660. (ACCESS_MASK)EVENT_ALL_ACCESS,
  661. NULL,
  662. SynchronizationEvent,
  663. FALSE
  664. );
  665. if ( NT_SUCCESS( NtStatus ) ) {
  666. //
  667. // Mark rest of entries as "available"
  668. //
  669. for ( Index = 1; Index < MAXIMUM_WAIT_OBJECTS; Index++ ) {
  670. NotificationList->EventHandle[Index] = NULL;
  671. }
  672. //
  673. // Set initial number of EventInUse to 1 (which is the
  674. // index to the next available spot in the list).
  675. //
  676. NotificationList->EventsInUse = 1;
  677. //
  678. // Set chain links
  679. //
  680. NotificationList->Previous = NULL;
  681. NotificationList->Next = NULL;
  682. NotificationList->PendingNotifications = 0;
  683. //
  684. // Now that everything has been initialized, create the
  685. // handler thread for the list.
  686. //
  687. NotificationList->HandlerThread =
  688. CreateThread(
  689. NULL,
  690. (32 * 1024),
  691. (LPTHREAD_START_ROUTINE)NotificationHandler,
  692. NotificationList,
  693. 0,
  694. (LPDWORD)&(NotificationList->HandlerClientId)
  695. );
  696. if ( NotificationList->HandlerThread != NULL ) {
  697. *NotificationListUsed = NotificationList;
  698. Error = ERROR_SUCCESS;
  699. } else {
  700. //
  701. // Could not create thread, close the event that we just
  702. // created.
  703. //
  704. Error = GetLastError();
  705. #if DBG
  706. DbgPrint( "WINREG Error: Cannot create notification thread, error %d\n",
  707. Error );
  708. DbgBreakPoint();
  709. #endif
  710. NtStatus = NtClose( NotificationList->EventHandle[0] );
  711. ASSERT( NT_SUCCESS( NtStatus ) );
  712. }
  713. } else {
  714. #if DBG
  715. DbgPrint( "WINREG Error: Cannot create notification event, status 0x%x\n",
  716. NtStatus );
  717. DbgBreakPoint();
  718. #endif
  719. Error = RtlNtStatusToDosError( NtStatus );
  720. }
  721. //
  722. // If something went wrong, free up the notification list
  723. //
  724. if ( Error != ERROR_SUCCESS ) {
  725. RtlFreeHeap(
  726. RtlProcessHeap( ), 0,
  727. NotificationList
  728. );
  729. *NotificationListUsed = NULL;
  730. }
  731. return Error;
  732. }
  733. LONG
  734. DeleteNotificationList (
  735. IN OUT PNOTIFICATION_LIST NotificationList
  736. )
  737. /*++
  738. Routine Description:
  739. Deletes a Notification List. The handler thread is not terminated
  740. because it is the handler thread who deletes notification lists,
  741. commiting suicide afterwards.
  742. Arguments:
  743. NotificationList - Supplies pointer to Notification List
  744. Return Value:
  745. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  746. --*/
  747. {
  748. NTSTATUS NtStatus;
  749. #if BIGDBG
  750. DbgPrint( "WINREG: Removing empty notification list\n" );
  751. #endif
  752. //
  753. // The only event in the list must be the "wakeup" event
  754. //
  755. ASSERT( NotificationList->EventsInUse == 1 );
  756. //
  757. // Delete the "wake up" event
  758. //
  759. NtStatus = NtClose( NotificationList->EventHandle[0] );
  760. ASSERT( NT_SUCCESS( NtStatus ) );
  761. //
  762. // Free up the heap used by the Notification List
  763. //
  764. RtlFreeHeap(
  765. RtlProcessHeap( ), 0,
  766. NotificationList
  767. );
  768. return ERROR_SUCCESS;
  769. }
  770. LONG
  771. AddEvent (
  772. IN HKEY hKey,
  773. IN HANDLE EventHandle,
  774. IN DWORD ClientEvent,
  775. IN PUNICODE_STRING PipeName,
  776. IN PRPC_SECURITY_ATTRIBUTES pRpcSa OPTIONAL,
  777. OUT PNOTIFICATION_LIST *NotificationListUsed
  778. )
  779. /*++
  780. Routine Description:
  781. Adds an event to the first notification list with an available slot.
  782. If no notification list has an available slot, a new notification list
  783. (an its handler thread) is created.
  784. Arguments:
  785. hKey - Supplies registry key handle
  786. EventHandle - Supplies an event on which the handler thread of the
  787. Notification List has to wait.
  788. ClientEvent - Supplies the event which has to be communicated to the
  789. client when out EventHandle is signaled. This event is
  790. communicated to the client via named pipe.
  791. PipeNameU - Supplies the name of the pipe for communicating with the
  792. client.
  793. pRpcSa - Supplies the optional security attributes of the named
  794. pipe.
  795. NotificationListused - Supplies a pointer where the address of the
  796. Notification List in which the event is put
  797. is placed.
  798. Return Value:
  799. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  800. --*/
  801. {
  802. PNOTIFICATION_LIST NotificationList;
  803. LONG Error;
  804. NTSTATUS NtStatus;
  805. ASSERT( EventHandle != NULL );
  806. ASSERT( PipeName && PipeName->Buffer );
  807. ASSERT( NotificationListUsed );
  808. //
  809. // Get a Notification List with an available entry.
  810. //
  811. Error = GetAvailableNotificationList(
  812. &NotificationList
  813. );
  814. if ( Error == ERROR_SUCCESS ) {
  815. //
  816. // Add the entry
  817. //
  818. Error = AddEntryToNotificationList(
  819. NotificationList,
  820. hKey,
  821. EventHandle,
  822. ClientEvent,
  823. PipeName,
  824. pRpcSa
  825. );
  826. if ( Error == ERROR_SUCCESS ) {
  827. //
  828. // A new entry has been added, we have to wake up the
  829. // handler thread so that it will wait on the newly added
  830. // event.
  831. //
  832. NtStatus = NtSetEvent( NotificationList->EventHandle[0], NULL );
  833. ASSERT( NT_SUCCESS( NtStatus ) );
  834. *NotificationListUsed = NotificationList;
  835. } else {
  836. #if DBG
  837. DbgPrint( "WINREG: Could not add notification entry! Error %d\n ", Error);
  838. #endif
  839. }
  840. } else {
  841. #if DBG
  842. DbgPrint( "WINREG: Could not get a notification list! Error %d\n ", Error);
  843. #endif
  844. }
  845. return Error;
  846. }
  847. LONG
  848. RemoveEvent (
  849. IN HANDLE EventHandle,
  850. IN OUT PNOTIFICATION_LIST NotificationList
  851. )
  852. /*++
  853. Routine Description:
  854. Removes an event from the notification list. The caller must
  855. make sure that the event handle given does live in the
  856. Notification List specified.
  857. This function is called if the notification is aborted for some
  858. reason (e.g. the NT notification API fails).
  859. Arguments:
  860. EventHandle - Supplies the event to remove.
  861. NotificationList - Supplies the Notification List in which
  862. the event lives.
  863. Return Value:
  864. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  865. --*/
  866. {
  867. LONG Error;
  868. DWORD EntryIndex;
  869. //
  870. // Search for the entry that we have to remove.
  871. //
  872. for ( EntryIndex = 1;
  873. EntryIndex < NotificationList->EventsInUse;
  874. EntryIndex++ ) {
  875. if ( EventHandle == NotificationList->EventHandle[ EntryIndex ] ) {
  876. break;
  877. }
  878. }
  879. ASSERT( EntryIndex < NotificationList->EventsInUse );
  880. if ( EntryIndex < NotificationList->EventsInUse ) {
  881. //
  882. // Found entry, remove it
  883. //
  884. Error = RemoveEntryFromNotificationList(
  885. NotificationList,
  886. EntryIndex
  887. );
  888. //
  889. // Note that we are leaving a hole in the Notification list,
  890. // the handler will eventually compact it.
  891. //
  892. } else {
  893. Error = ERROR_ARENA_TRASHED;
  894. }
  895. return Error;
  896. }
  897. LONG
  898. GetAvailableNotificationList (
  899. OUT PNOTIFICATION_LIST *NotificationListUsed
  900. )
  901. /*++
  902. Routine Description:
  903. Gets a Notification List with an available entry.
  904. Arguments:
  905. NotificationList - Supplies pointer to where the Notification
  906. List pointer will be placed.
  907. Return Value:
  908. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  909. --*/
  910. {
  911. LONG Error = ERROR_SUCCESS;
  912. PNOTIFICATION_LIST NotificationList;
  913. //
  914. // Traverse the chain of Notification lists until we find a Notification
  915. // list with an available entry.
  916. //
  917. for ( NotificationList = NotificationListChainHead;
  918. NotificationList && NotificationList->EventsInUse >= MAXIMUM_WAIT_OBJECTS;
  919. NotificationList = NotificationList->Next );
  920. //
  921. // If we did not find a Notification List with an available spot,
  922. // create a new Notification List and add it to the chain.
  923. //
  924. if ( !NotificationList ) {
  925. Error = CreateNotificationList( &NotificationList );
  926. if ( Error == ERROR_SUCCESS ) {
  927. ASSERT( NotificationList );
  928. AddNotificationListToChain( NotificationList );
  929. }
  930. }
  931. *NotificationListUsed = NotificationList;
  932. return Error;
  933. }
  934. LONG
  935. AddEntryToNotificationList(
  936. IN OUT PNOTIFICATION_LIST NotificationList,
  937. IN HKEY hKey,
  938. IN HANDLE EventHandle,
  939. IN DWORD ClientEvent,
  940. IN PUNICODE_STRING PipeName,
  941. IN PRPC_SECURITY_ATTRIBUTES pRpcSa OPTIONAL
  942. )
  943. /*++
  944. Routine Description:
  945. Adds an entry to a notification list.
  946. Calls to this function must be protected by the critical
  947. section of the Notification List.
  948. Arguments:
  949. NotificationList - Supplies pointer to Notification List
  950. hKey - Supplies registry key handle
  951. EventHandle - Supplies the event handle
  952. ClientEvent - Supplies the client's event
  953. PipeName - Supplies name of pipe.
  954. pRpcSa - Supplies security attributes for the pipe
  955. Return Value:
  956. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  957. --*/
  958. {
  959. LONG Error;
  960. PPIPE_ENTRY PipeEntry;
  961. DWORD Index;
  962. PNOTIFICATION_ENTRY Event;
  963. //
  964. // Add the pipe information to the pipe symbol table
  965. //
  966. Error = AddPipe( PipeName, pRpcSa, &PipeEntry );
  967. if ( Error == ERROR_SUCCESS ) {
  968. //
  969. // Add the event in the next available spot in the list,
  970. // and increment the number of events in use by the
  971. // list.
  972. //
  973. Index = NotificationList->EventsInUse++;
  974. Event = &(NotificationList->Event[ Index ]);
  975. NotificationList->EventHandle[ Index ] = EventHandle;
  976. Event->ClientEvent = ClientEvent;
  977. Event->hKey = hKey;
  978. Event->Flags = 0;
  979. Event->PipeEntry = PipeEntry;
  980. } else {
  981. #if BIGDBG
  982. DbgPrint( "WINREG: Could not create pipe entry for %wZ\n",
  983. PipeName );
  984. #endif
  985. }
  986. return Error;
  987. }
  988. LONG
  989. RemoveEntryFromNotificationList (
  990. IN OUT PNOTIFICATION_LIST NotificationList,
  991. IN DWORD EntryIndex
  992. )
  993. /*++
  994. Routine Description:
  995. Removes an entry from a Notification List. It leaves a hole
  996. in the list, i.e. the list is not compacted.
  997. Arguments:
  998. NotificationList - Supplies pointer to Notification List.
  999. EntryIndex - Supplies index of entry to remove.
  1000. Return Value:
  1001. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1002. --*/
  1003. {
  1004. LONG Error;
  1005. ASSERT( EntryIndex < NotificationList->EventsInUse );
  1006. ASSERT( NotificationList->EventHandle[ EntryIndex ] != NULL );
  1007. //
  1008. // Remove the entry from the pipe symbol table.
  1009. //
  1010. Error = RemovePipe( NotificationList->Event[ EntryIndex ].PipeEntry );
  1011. if ( Error == ERROR_SUCCESS ) {
  1012. //
  1013. // We "remove" the entry from the notification list by
  1014. // invalidating its handle. Note that we don't decrement
  1015. // the counter of entries in the notification list because
  1016. // that is used for indexing the next available entry.
  1017. // The counter will be fixed by the compaction function.
  1018. //
  1019. NotificationList->EventHandle[ EntryIndex ] = NULL;
  1020. NotificationList->Event[ EntryIndex ].PipeEntry = NULL;
  1021. }
  1022. return Error;
  1023. }
  1024. LONG
  1025. CompactNotificationList (
  1026. IN OUT PNOTIFICATION_LIST NotificationList
  1027. )
  1028. /*++
  1029. Routine Description:
  1030. Compacts (i.e. removes holes from) a Notification List.
  1031. Arguments:
  1032. NotificationList - Supplies pointer to Notification List.
  1033. Return Value:
  1034. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1035. --*/
  1036. {
  1037. DWORD ToIndex;
  1038. DWORD FromIndex;
  1039. DWORD Index;
  1040. DWORD EntriesToMove;
  1041. PVOID Src;
  1042. PVOID Dst;
  1043. #if BIGDBG
  1044. DbgPrint( " * Compacting notification list\n" );
  1045. #endif
  1046. for ( ToIndex = 1; ToIndex < NotificationList->EventsInUse; ToIndex++ ) {
  1047. #if BIGDBG
  1048. DbgPrint( " - %d\n", ToIndex );
  1049. #endif
  1050. //
  1051. // If we find a hole, we compact the arrays i.e. shift them to
  1052. // remove the hole.
  1053. //
  1054. if ( NotificationList->EventHandle[ ToIndex ] == NULL ) {
  1055. //
  1056. // Found the beginning of a hole, search for the next
  1057. // entry in use.
  1058. //
  1059. for ( FromIndex = ToIndex+1;
  1060. (FromIndex < NotificationList->EventsInUse) &&
  1061. (NotificationList->EventHandle[ FromIndex ] == NULL );
  1062. FromIndex++ ) {
  1063. }
  1064. //
  1065. // If there is something to shift, shift it
  1066. //
  1067. if ( FromIndex < NotificationList->EventsInUse ) {
  1068. EntriesToMove = NotificationList->EventsInUse - FromIndex;
  1069. Src = (PVOID)&(NotificationList->EventHandle[ FromIndex ] );
  1070. Dst = (PVOID)&(NotificationList->EventHandle[ ToIndex ] );
  1071. RtlMoveMemory(
  1072. Dst,
  1073. Src,
  1074. EntriesToMove * sizeof( HANDLE )
  1075. );
  1076. Src = &(NotificationList->Event[ FromIndex ] );
  1077. Dst = &(NotificationList->Event[ ToIndex ] );
  1078. RtlMoveMemory(
  1079. Dst,
  1080. Src,
  1081. EntriesToMove * sizeof( NOTIFICATION_ENTRY )
  1082. );
  1083. //
  1084. // Clear the rest of the entries, just to keep things
  1085. // clean.
  1086. //
  1087. for ( Index = ToIndex + EntriesToMove;
  1088. Index < NotificationList->EventsInUse;
  1089. Index++ ) {
  1090. NotificationList->EventHandle[ Index ] = NULL;
  1091. }
  1092. NotificationList->EventsInUse -= (FromIndex - ToIndex);
  1093. } else {
  1094. //
  1095. // Nothing to shift, this will become the
  1096. // first available entry of the list.
  1097. //
  1098. NotificationList->EventsInUse = ToIndex;
  1099. }
  1100. }
  1101. }
  1102. #if BIGDBG
  1103. DbgPrint( " * Compacted.\n" );
  1104. #endif
  1105. return ERROR_SUCCESS;
  1106. }
  1107. VOID
  1108. AddNotificationListToChain(
  1109. IN OUT PNOTIFICATION_LIST NotificationList
  1110. )
  1111. /*++
  1112. Routine Description:
  1113. Adds a Notification list to the chain of Notification Lists.
  1114. The new list is put at the head of the chain.
  1115. Arguments:
  1116. NotificationList - Supplies the Notification list to add
  1117. Return Value:
  1118. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1119. --*/
  1120. {
  1121. NotificationList->Previous = NULL;
  1122. NotificationList->Next = NotificationListChainHead;
  1123. if ( NotificationListChainHead ) {
  1124. NotificationListChainHead->Previous = NotificationList;
  1125. }
  1126. NotificationListChainHead = NotificationList;
  1127. }
  1128. VOID
  1129. RemoveNotificationListFromChain(
  1130. IN OUT PNOTIFICATION_LIST NotificationList
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. Removes a Notification list from the chain
  1135. Arguments:
  1136. NotificationList - Supplies the Notification list to remove
  1137. Return Value:
  1138. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1139. --*/
  1140. {
  1141. if ( NotificationList->Previous ) {
  1142. (NotificationList->Previous)->Next = NotificationList->Next;
  1143. }
  1144. if ( NotificationList->Next ) {
  1145. (NotificationList->Next)->Previous = NotificationList->Previous;
  1146. }
  1147. //
  1148. // If this is at the head of the chain, Let the next
  1149. // list be the new head.
  1150. //
  1151. if ( NotificationListChainHead == NotificationList ) {
  1152. NotificationListChainHead = NotificationList->Next;
  1153. }
  1154. }
  1155. // *****************************************************************
  1156. //
  1157. // Pipe Symbol Table functions
  1158. //
  1159. // *****************************************************************
  1160. LONG
  1161. GetFullPipeName (
  1162. IN PUNICODE_STRING MachineName,
  1163. IN PUNICODE_STRING PipeName,
  1164. OUT PUNICODE_STRING FullPipeName
  1165. )
  1166. /*++
  1167. Routine Description:
  1168. Makes a fully qualified pipe name from the supplied machine
  1169. name and pipe name.
  1170. Arguments:
  1171. PipeName - Supplies the pipe name
  1172. MachineName - Supplies the client's machine name
  1173. FullPipeName - Supplies the full pipe name
  1174. Return Value:
  1175. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1176. --*/
  1177. {
  1178. LONG Error = ERROR_SUCCESS;
  1179. NTSTATUS NtStatus;
  1180. ASSERT( PipeName->Buffer && MachineName->Buffer &&
  1181. PipeName->Length > 0 && MachineName->Length > 0 );
  1182. if( !PipeName->Buffer || !MachineName->Buffer ||
  1183. PipeName->Length == 0 || MachineName->Length == 0 ) {
  1184. Error = ERROR_INVALID_PARAMETER;
  1185. }
  1186. if ( Error == ERROR_SUCCESS ) {
  1187. //
  1188. // If the client's machine name and our machine name match,
  1189. // then we form a local named pipe path, otherwise we
  1190. // form a remote named pipe path.
  1191. //
  1192. if ( RtlEqualUnicodeString(
  1193. MachineName,
  1194. &OurMachineName,
  1195. TRUE
  1196. ) ) {
  1197. //
  1198. // Pipe is local
  1199. //
  1200. RtlMoveMemory(
  1201. FullPipeName->Buffer,
  1202. NAMED_PIPE_HERE,
  1203. sizeof( NAMED_PIPE_HERE )
  1204. );
  1205. FullPipeName->Length = sizeof( NAMED_PIPE_HERE ) - sizeof(UNICODE_NULL);
  1206. } else {
  1207. //
  1208. // Pipe is remote
  1209. //
  1210. RtlMoveMemory(
  1211. FullPipeName->Buffer,
  1212. NAMED_PIPE_THERE,
  1213. sizeof( NAMED_PIPE_THERE )
  1214. );
  1215. FullPipeName->Length = sizeof( NAMED_PIPE_THERE ) - sizeof(UNICODE_NULL);
  1216. NtStatus = RtlAppendUnicodeStringToString(
  1217. FullPipeName,
  1218. MachineName
  1219. );
  1220. ASSERT( NT_SUCCESS( NtStatus ) );
  1221. if ( NT_SUCCESS( NtStatus ) ) {
  1222. NtStatus = RtlAppendUnicodeToString(
  1223. FullPipeName,
  1224. L"\\Pipe\\"
  1225. );
  1226. ASSERT( NT_SUCCESS( NtStatus ) );
  1227. if ( !NT_SUCCESS( NtStatus ) ) {
  1228. Error = RtlNtStatusToDosError( NtStatus );
  1229. }
  1230. } else {
  1231. Error = RtlNtStatusToDosError( NtStatus );
  1232. }
  1233. }
  1234. if ( Error == ERROR_SUCCESS ) {
  1235. NtStatus = RtlAppendUnicodeStringToString(
  1236. FullPipeName,
  1237. PipeName
  1238. );
  1239. ASSERT( NT_SUCCESS( NtStatus ) );
  1240. if ( !NT_SUCCESS( NtStatus ) ) {
  1241. Error = RtlNtStatusToDosError( NtStatus );
  1242. }
  1243. }
  1244. }
  1245. return Error;
  1246. }
  1247. LONG
  1248. CreatePipeEntry (
  1249. IN PUNICODE_STRING PipeName,
  1250. IN PRPC_SECURITY_ATTRIBUTES pRpcSa OPTIONAL,
  1251. OUT PPIPE_ENTRY *PipeEntryUsed
  1252. )
  1253. /*++
  1254. Routine Description:
  1255. Creates a pipe entry
  1256. Arguments:
  1257. PipeName - Supplies the pipe name
  1258. pRpcSa - Supplies the optional security attributes for the pipe
  1259. PipeEntry - Supplies pointer to pointer to pipe entry.
  1260. Return Value:
  1261. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1262. --*/
  1263. {
  1264. PPIPE_ENTRY PipeEntry;
  1265. LONG Error;
  1266. ULONG LengthSd;
  1267. ASSERT( PipeName && PipeName->Buffer );
  1268. //
  1269. // Validate the security descriptor if one was provided
  1270. //
  1271. if ( pRpcSa ) {
  1272. if ( !RtlValidSecurityDescriptor(
  1273. pRpcSa->RpcSecurityDescriptor.lpSecurityDescriptor
  1274. ) ) {
  1275. return ERROR_INVALID_PARAMETER;
  1276. }
  1277. }
  1278. //
  1279. // Allocate space for the Pipe Entry
  1280. //
  1281. PipeEntry = RtlAllocateHeap(
  1282. RtlProcessHeap( ), 0,
  1283. sizeof( PIPE_ENTRY )
  1284. );
  1285. if ( !PipeEntry ) {
  1286. return ERROR_OUTOFMEMORY;
  1287. }
  1288. //
  1289. // Allocate space for the pipe's name
  1290. //
  1291. PipeEntry->PipeName.Buffer = RtlAllocateHeap(
  1292. RtlProcessHeap( ), 0,
  1293. PipeName->Length + sizeof( UNICODE_NULL )
  1294. );
  1295. PipeEntry->PipeName.MaximumLength = PipeName->Length + (USHORT)sizeof( UNICODE_NULL );
  1296. if ( PipeEntry->PipeName.Buffer ) {
  1297. //
  1298. // Copy the pipe name
  1299. //
  1300. RtlCopyUnicodeString(
  1301. &(PipeEntry->PipeName),
  1302. PipeName
  1303. );
  1304. PipeEntry->Previous = NULL;
  1305. PipeEntry->Next = NULL;
  1306. PipeEntry->ReferenceCount = 0;
  1307. //
  1308. // Allocate space for the security descriptor if one
  1309. // is provided.
  1310. //
  1311. if ( pRpcSa ) {
  1312. LengthSd = RtlLengthSecurityDescriptor(
  1313. pRpcSa->RpcSecurityDescriptor.lpSecurityDescriptor
  1314. );
  1315. PipeEntry->SecurityDescriptor = RtlAllocateHeap(
  1316. RtlProcessHeap( ), 0,
  1317. LengthSd
  1318. );
  1319. if ( PipeEntry->SecurityDescriptor ) {
  1320. //
  1321. // Copy the security descriptor
  1322. //
  1323. RtlMoveMemory (
  1324. PipeEntry->SecurityDescriptor,
  1325. pRpcSa->RpcSecurityDescriptor.lpSecurityDescriptor,
  1326. LengthSd
  1327. );
  1328. *PipeEntryUsed = PipeEntry;
  1329. return ERROR_SUCCESS;
  1330. } else {
  1331. Error = ERROR_OUTOFMEMORY;
  1332. }
  1333. RtlFreeHeap(
  1334. RtlProcessHeap( ), 0,
  1335. PipeEntry->PipeName.Buffer
  1336. );
  1337. } else {
  1338. PipeEntry->SecurityDescriptor = NULL;
  1339. *PipeEntryUsed = PipeEntry;
  1340. return ERROR_SUCCESS;
  1341. }
  1342. } else {
  1343. Error = ERROR_OUTOFMEMORY;
  1344. }
  1345. RtlFreeHeap(
  1346. RtlProcessHeap( ), 0,
  1347. PipeEntry
  1348. );
  1349. return Error;
  1350. }
  1351. LONG
  1352. DeletePipeEntry(
  1353. IN OUT PPIPE_ENTRY PipeEntry
  1354. )
  1355. /*++
  1356. Routine Description:
  1357. Deletes a pipe entry
  1358. Arguments:
  1359. PipeEntry - Supplies pointer to pipe entry
  1360. Return Value:
  1361. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1362. --*/
  1363. {
  1364. #if BIGDBG
  1365. DbgPrint( " * In DeletePipeEntry\n" );
  1366. #endif
  1367. ASSERT( PipeEntry );
  1368. ASSERT( PipeEntry->PipeName.Buffer );
  1369. if ( PipeEntry->PipeName.Buffer ) {
  1370. RtlFreeHeap(
  1371. RtlProcessHeap( ), 0,
  1372. PipeEntry->PipeName.Buffer
  1373. );
  1374. }
  1375. if ( PipeEntry->SecurityDescriptor != NULL ) {
  1376. RtlFreeHeap(
  1377. RtlProcessHeap( ), 0,
  1378. PipeEntry->SecurityDescriptor
  1379. );
  1380. }
  1381. RtlFreeHeap(
  1382. RtlProcessHeap( ), 0,
  1383. PipeEntry
  1384. );
  1385. #if BIGDBG
  1386. DbgPrint( " * Deleted PipeEntry.\n" );
  1387. #endif
  1388. return ERROR_SUCCESS;
  1389. }
  1390. LONG
  1391. AddPipe(
  1392. IN PUNICODE_STRING PipeName,
  1393. IN PRPC_SECURITY_ATTRIBUTES pRpcSa OPTIONAL,
  1394. OUT PPIPE_ENTRY *PipeEntryUsed
  1395. )
  1396. /*++
  1397. Routine Description:
  1398. Adds a new entry to the pipe symbol table
  1399. Arguments:
  1400. PipeName - Supplies the pipe name
  1401. pRpcSa - Supplies the optional security attributes for the pipe
  1402. PipeEntry - Supplies pointer to pointer to pipe entry in the
  1403. symbol table.
  1404. Return Value:
  1405. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1406. --*/
  1407. {
  1408. PPIPE_ENTRY PipeEntry;
  1409. LONG Error;
  1410. //
  1411. // Look for the pipe name in the symbol table
  1412. //
  1413. Error = LookForPipeEntryInSymbolTable( PipeName, &PipeEntry );
  1414. if ( Error == ERROR_SUCCESS ) {
  1415. //
  1416. // If the pipe is not in the symbol table, add it
  1417. //
  1418. if ( !PipeEntry ) {
  1419. //
  1420. // Create a new pipe entry
  1421. //
  1422. Error = CreatePipeEntry(
  1423. PipeName,
  1424. pRpcSa,
  1425. &PipeEntry
  1426. );
  1427. if ( Error == ERROR_SUCCESS ) {
  1428. //
  1429. // Add the entry to the symbol table
  1430. //
  1431. Error = AddPipeEntryToSymbolTable(
  1432. PipeEntry
  1433. );
  1434. if ( Error != ERROR_SUCCESS ) {
  1435. //
  1436. // Could not add pipe entry, delete it.
  1437. //
  1438. DeletePipeEntry( PipeEntry );
  1439. PipeEntry = NULL;
  1440. }
  1441. }
  1442. }
  1443. //
  1444. // If got a pipe entry, increment its reference count
  1445. //
  1446. if ( PipeEntry ) {
  1447. PipeEntry->ReferenceCount++;
  1448. *PipeEntryUsed = PipeEntry;
  1449. }
  1450. }
  1451. #if BIGDBG
  1452. DbgPrint( "Added Pipe %Z:\n", PipeName );
  1453. DumpPipeTable();
  1454. #endif
  1455. return Error;
  1456. }
  1457. LONG
  1458. RemovePipe(
  1459. IN OUT PPIPE_ENTRY PipeEntry
  1460. )
  1461. /*++
  1462. Routine Description:
  1463. Decrements the reference count of a pipe entry and removes the
  1464. entry if the reference count reaches zero.
  1465. Arguments:
  1466. PipeEntry - Supplies pointer to pipe entry in the symbol table
  1467. Return Value:
  1468. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1469. --*/
  1470. {
  1471. LONG Error = ERROR_SUCCESS;
  1472. PPIPE_ENTRY Entry = PipeEntry;
  1473. ASSERT( Entry );
  1474. ASSERT( Entry->ReferenceCount > 0 );
  1475. #if BIGDBG
  1476. DbgPrint( " * In RemovePipe - Ref. count %d\n", Entry->ReferenceCount );
  1477. #endif
  1478. //
  1479. // Decrement the reference count
  1480. //
  1481. Entry->ReferenceCount--;
  1482. //
  1483. // If the reference count is zero, we can delete the
  1484. // entry
  1485. //
  1486. if ( Entry->ReferenceCount == 0 ) {
  1487. //
  1488. // Remove the pipe entry from the symbol table
  1489. //
  1490. Error = RemovePipeEntryFromSymbolTable(
  1491. Entry
  1492. );
  1493. if ( Error == ERROR_SUCCESS ) {
  1494. //
  1495. // Delete the pipe entry
  1496. //
  1497. ASSERT( PipeEntry > (PPIPE_ENTRY)0x100 );
  1498. Error = DeletePipeEntry( Entry );
  1499. }
  1500. }
  1501. #if BIGDBG
  1502. DbgPrint( " * Pipe Removed.\n" );
  1503. #endif
  1504. return Error;
  1505. }
  1506. LONG
  1507. AddPipeEntryToSymbolTable(
  1508. IN OUT PPIPE_ENTRY PipeEntry
  1509. )
  1510. /*++
  1511. Routine Description:
  1512. Adds a pipe entry to the symbol table at the specified bucket.
  1513. Entries are always added at the head of the chain.
  1514. Calls to this function must be protected by the critical section
  1515. of the pipe symbol table.
  1516. Arguments:
  1517. PipeEntry - Supplies pointer to pipe entry
  1518. Return Value:
  1519. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1520. --*/
  1521. {
  1522. DWORD Bucket;
  1523. Bucket = HASH( &(PipeEntry->PipeName), BUCKETS_IN_SYMBOL_TABLE );
  1524. PipeEntry->Previous = NULL;
  1525. PipeEntry->Next = PipeSymbolTable.Bucket[ Bucket ];
  1526. if ( PipeSymbolTable.Bucket[ Bucket ] ) {
  1527. (PipeSymbolTable.Bucket[ Bucket ])->Previous = PipeEntry;
  1528. }
  1529. PipeSymbolTable.Bucket[ Bucket ] = PipeEntry;
  1530. return ERROR_SUCCESS;
  1531. }
  1532. LONG
  1533. RemovePipeEntryFromSymbolTable(
  1534. IN OUT PPIPE_ENTRY PipeEntry
  1535. )
  1536. /*++
  1537. Routine Description:
  1538. Removes a pipe entry from the symbol table at the specified bucket
  1539. Calls to this function must be protected by the critical section
  1540. of the pipe symbol table.
  1541. Arguments:
  1542. PipeEntry - Supplies pointer to pipe entry
  1543. Return Value:
  1544. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1545. --*/
  1546. {
  1547. DWORD Bucket;
  1548. #if BIGDBG
  1549. DbgPrint( " * In RemovePipeEntryFromSymbolTable\n" );
  1550. #endif
  1551. ASSERT( PipeEntry > (PPIPE_ENTRY)0x100 );
  1552. Bucket = HASH( &(PipeEntry->PipeName), BUCKETS_IN_SYMBOL_TABLE );
  1553. ASSERT( PipeEntry > (PPIPE_ENTRY)0x100 );
  1554. ASSERT( Bucket < BUCKETS_IN_SYMBOL_TABLE );
  1555. //
  1556. // Remove the entry from the chain
  1557. //
  1558. if ( PipeEntry->Previous ) {
  1559. (PipeEntry->Previous)->Next = PipeEntry->Next;
  1560. }
  1561. if ( PipeEntry->Next ) {
  1562. (PipeEntry->Next)->Previous = PipeEntry->Previous;
  1563. }
  1564. //
  1565. // If this entry is at the head of the chain, Let the next
  1566. // entry be the new head.
  1567. //
  1568. ASSERT( PipeSymbolTable.Bucket[ Bucket ] != NULL );
  1569. if ( PipeSymbolTable.Bucket[ Bucket ] == PipeEntry ) {
  1570. PipeSymbolTable.Bucket[ Bucket ] = PipeEntry->Next;
  1571. }
  1572. PipeEntry->Next = NULL;
  1573. PipeEntry->Previous = NULL;
  1574. ASSERT( PipeEntry > (PPIPE_ENTRY)0x100 );
  1575. #if BIGDBG
  1576. DbgPrint( " * Piped entry removed from symbol table.\n" );
  1577. #endif
  1578. return ERROR_SUCCESS;
  1579. }
  1580. LONG
  1581. LookForPipeEntryInSymbolTable(
  1582. IN PUNICODE_STRING PipeName,
  1583. OUT PPIPE_ENTRY *PipeEntryUsed
  1584. )
  1585. /*++
  1586. Routine Description:
  1587. Looks for an entry corresponding to the given name in a particular
  1588. bucket of the pipe symbol table.
  1589. Note that this function always returns ERROR_SUCCESS. To find out
  1590. if the pipe is in the chain or not the returned parameter has to
  1591. be checked.
  1592. Calls to this function must be protected by the critical section
  1593. of the pipe symbol table.
  1594. Arguments:
  1595. PipeName - Supplies the pipe name
  1596. Bucket - Supplies the bucket
  1597. PipeEntry - Supplies pointer to pointer to pipe entry.
  1598. Return Value:
  1599. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1600. --*/
  1601. {
  1602. PPIPE_ENTRY PipeEntry;
  1603. DWORD Bucket;
  1604. Bucket = HASH( PipeName, BUCKETS_IN_SYMBOL_TABLE );
  1605. //
  1606. // Look for the entry
  1607. //
  1608. for ( PipeEntry = PipeSymbolTable.Bucket[ Bucket ];
  1609. PipeEntry && !RtlEqualUnicodeString( PipeName, &(PipeEntry->PipeName), TRUE);
  1610. PipeEntry = PipeEntry->Next );
  1611. *PipeEntryUsed = PipeEntry;
  1612. return ERROR_SUCCESS;
  1613. }
  1614. DWORD
  1615. Hash(
  1616. IN PUNICODE_STRING Symbol,
  1617. IN DWORD Buckets
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. Obtains a hash value for a given symbol
  1622. Arguments:
  1623. Symbol - Supplies the symbol to hash
  1624. Buckets - Supplies the number of buckets in the sybol table.
  1625. Return Value:
  1626. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1627. --*/
  1628. {
  1629. DWORD n;
  1630. DWORD HashValue;
  1631. WCHAR c;
  1632. LPWSTR s;
  1633. #if BIGDBG
  1634. DbgPrint( " * Hashing\n" );
  1635. #endif
  1636. n = Symbol->Length/sizeof(WCHAR);
  1637. s = Symbol->Buffer;
  1638. HashValue = 0;
  1639. while (n--) {
  1640. c = *s++;
  1641. HashValue = HashValue + (c << 1) + (c >> 1) + c;
  1642. }
  1643. return HashValue % Buckets;
  1644. }
  1645. // *****************************************************************
  1646. //
  1647. // Notification List Handler
  1648. //
  1649. // *****************************************************************
  1650. VOID
  1651. NotificationHandler(
  1652. IN PNOTIFICATION_LIST NotificationList
  1653. )
  1654. /*++
  1655. Routine Description:
  1656. Handler of a Notification List.
  1657. Arguments:
  1658. NotificationList - Supplies pointer to the Notification List
  1659. to handle.
  1660. Return Value:
  1661. None
  1662. --*/
  1663. {
  1664. NTSTATUS NtStatus;
  1665. DWORD NumberOfEvents;
  1666. HANDLE Thread;
  1667. BOOLEAN KeepOnGoing = TRUE;
  1668. DWORD Index;
  1669. LARGE_INTEGER TimeOut;
  1670. ASSERT( NotificationList );
  1671. //
  1672. // Initially we'll wait on only one event, i.e. the
  1673. // "wake up" event
  1674. //
  1675. NumberOfEvents = 1;
  1676. NotificationList->TimeOutCount = 0;
  1677. NotificationList->ResetCount = FALSE;
  1678. while ( KeepOnGoing ) {
  1679. TimeOut.QuadPart = Int32x32To64( -10000,
  1680. 5000*NotificationList->TimeOutCount );
  1681. //
  1682. // Wait for some event
  1683. //
  1684. NtStatus = NtWaitForMultipleObjects(
  1685. (CHAR)NumberOfEvents,
  1686. NotificationList->EventHandle,
  1687. WaitAny,
  1688. FALSE,
  1689. (NotificationList->PendingNotifications > 0) ?
  1690. &TimeOut : NULL
  1691. );
  1692. Index = (DWORD)NtStatus;
  1693. if ( (Index < 0) || (Index >= NumberOfEvents) ) {
  1694. Index = 0;
  1695. }
  1696. ASSERT( Index < NumberOfEvents );
  1697. NtStatus = RtlEnterCriticalSection( &NotificationCriticalSection );
  1698. ASSERT( NT_SUCCESS( NtStatus ) );
  1699. #if BIGDBG
  1700. DbgPrint( "WINREG: Notification handler signaled, Index %d\n", Index );
  1701. #endif
  1702. try {
  1703. //
  1704. // If an event was triggered, mark it as a pending notification so
  1705. // that the NotificationListMaintenance function will notify
  1706. // the client.
  1707. //
  1708. if ( Index > 0 ) {
  1709. NotificationList->PendingNotifications++;
  1710. NotificationList->Event[Index].Flags |= MUST_NOTIFY;
  1711. }
  1712. //
  1713. // Notify all the clients with pending notifications and
  1714. // remove entries for dead clients.
  1715. //
  1716. NumberOfEvents = NotificationListMaintenance( NotificationList );
  1717. if( NotificationList->PendingNotifications != 0 ) {
  1718. if( NotificationList->ResetCount ) {
  1719. NotificationList->TimeOutCount = 1;
  1720. NotificationList->ResetCount = FALSE;
  1721. } else {
  1722. if( NotificationList->TimeOutCount == 0 ) {
  1723. NotificationList->TimeOutCount = 1;
  1724. } else {
  1725. if( NotificationList->TimeOutCount != MAX_TIMEOUT_COUNT ) {
  1726. NotificationList->TimeOutCount =
  1727. NotificationList->TimeOutCount << 1;
  1728. }
  1729. }
  1730. }
  1731. } else {
  1732. NotificationList->TimeOutCount = 0;
  1733. }
  1734. //
  1735. // If the list is empty, then try to take it out of the chain, and
  1736. // if successful, our job is done.
  1737. //
  1738. if ( NumberOfEvents == 1 ) {
  1739. #if BIGDBG
  1740. DbgPrint( " * Removing the notification list!\n" );
  1741. #endif
  1742. //
  1743. // Make sure that the list is empty.
  1744. //
  1745. ASSERT( NotificationList->EventsInUse == 1 );
  1746. if (NotificationList->EventsInUse == 1) {
  1747. //
  1748. // The list is empty, remove the list from the chain
  1749. // and delete it.
  1750. //
  1751. RemoveNotificationListFromChain( NotificationList );
  1752. Thread = NotificationList->HandlerThread;
  1753. DeleteNotificationList( NotificationList );
  1754. //
  1755. // The list is gone, we can die.
  1756. //
  1757. KeepOnGoing = FALSE;
  1758. }
  1759. }
  1760. } except ( NtStatus = GetExceptionCode() ) {
  1761. #if DBG
  1762. DbgPrint( "WINREG Error: Exception %x in NotificationHandler\n",
  1763. NtStatus );
  1764. DbgBreakPoint();
  1765. #endif
  1766. }
  1767. #if BIGDBG
  1768. if ( KeepOnGoing ) {
  1769. DbgPrint( "WINREG: Notification handler waiting...\n" );
  1770. } else {
  1771. DbgPrint( "WINREG: Notification handler dying...\n" );
  1772. }
  1773. #endif
  1774. NtStatus = RtlLeaveCriticalSection( &NotificationCriticalSection );
  1775. ASSERT( NT_SUCCESS( NtStatus ) );
  1776. }
  1777. //
  1778. // The list is gone, and so must we.
  1779. //
  1780. ExitThread( 0 );
  1781. ASSERT( FALSE );
  1782. }
  1783. DWORD
  1784. NotificationListMaintenance(
  1785. IN OUT PNOTIFICATION_LIST NotificationList
  1786. )
  1787. /*++
  1788. Routine Description:
  1789. Performs all the maintenance necessary in the notification list.
  1790. The maintenance consists of:
  1791. - Notifying all clients with pending notifications.
  1792. - Removing entries in the list for dead clients.
  1793. - Compacting the notification list.
  1794. Arguments:
  1795. NotificationList - Supplies pointer to the Notification List
  1796. Return Value:
  1797. DWORD - The new number of events in the list
  1798. --*/
  1799. {
  1800. LONG Error;
  1801. DWORD NumberOfEvents;
  1802. DWORD Index;
  1803. BOOLEAN Remove;
  1804. PNOTIFICATION_ENTRY Event;
  1805. NTSTATUS NtStatus;
  1806. PPIPE_ENTRY PipeEntry;
  1807. #if BIGDBG
  1808. DbgPrint( " * In NotificationListMaintenance\n" );
  1809. DumpNotificationLists();
  1810. #endif
  1811. //
  1812. // Traverse the list notifying clients if necessary and removing
  1813. // events that are no longer needed, either because they have
  1814. // already been notified or because the client is dead.
  1815. //
  1816. for (Index = 1; Index < NotificationList->EventsInUse; Index++ ) {
  1817. #if BIGDBG
  1818. DbgPrint( " - %d\n", Index );
  1819. #endif
  1820. Remove = FALSE;
  1821. Event = &(NotificationList->Event[ Index ]);
  1822. if ( Event->Flags & CLIENT_IS_DEAD ) {
  1823. //
  1824. // No client, must remove the entry.
  1825. //
  1826. Remove = TRUE;
  1827. } else if ( Event->Flags & MUST_NOTIFY ) {
  1828. //
  1829. // Must notify this client
  1830. //
  1831. Error = SendEventToClient(
  1832. Event->ClientEvent,
  1833. Event->PipeEntry
  1834. );
  1835. if (Error == ERROR_SUCCESS) {
  1836. //
  1837. // If successfully notified, remove the entry.
  1838. //
  1839. Remove = TRUE;
  1840. Event->Flags &= ~NOTIFICATION_FAILED;
  1841. } else {
  1842. //
  1843. // If couldn't notify, set ResetCount if the notification
  1844. // failed for the first time
  1845. //
  1846. if( ( Event->Flags & NOTIFICATION_FAILED ) == 0 ) {
  1847. NotificationList->ResetCount = TRUE;
  1848. Event->Flags |= NOTIFICATION_FAILED;
  1849. }
  1850. }
  1851. }
  1852. //
  1853. // Remove the entry if no longer needed.
  1854. //
  1855. if ( Remove ) {
  1856. //
  1857. // Remove the pipe entry
  1858. //
  1859. PipeEntry = Event->PipeEntry;
  1860. RemovePipe( PipeEntry );
  1861. Event->PipeEntry = NULL;
  1862. //
  1863. // Remove the event
  1864. //
  1865. #if BIGDBG
  1866. DbgPrint( " Cleanup\n" );
  1867. #endif
  1868. NtStatus = NtClose( NotificationList->EventHandle[ Index ] );
  1869. ASSERT( NT_SUCCESS( NtStatus ) );
  1870. NotificationList->EventHandle[ Index ] = NULL;
  1871. //
  1872. // If this was a pending notification, decrement the
  1873. // counter.
  1874. //
  1875. if ( Event->Flags & MUST_NOTIFY ) {
  1876. NotificationList->PendingNotifications--;
  1877. }
  1878. }
  1879. }
  1880. //
  1881. // Compact the list.
  1882. //
  1883. Error = CompactNotificationList( NotificationList );
  1884. ASSERT( Error == ERROR_SUCCESS );
  1885. //
  1886. // Get the new number of entries in the list
  1887. //
  1888. NumberOfEvents = NotificationList->EventsInUse;
  1889. #if BIGDBG
  1890. DbgPrint( " * Maintenance Done (%d)\n", NumberOfEvents );
  1891. #endif
  1892. return NumberOfEvents;
  1893. }
  1894. LONG
  1895. SendEventToClient(
  1896. IN DWORD ClientEvent,
  1897. IN PPIPE_ENTRY PipeEntry
  1898. )
  1899. /*++
  1900. Routine Description:
  1901. Sends an event to the client via the client's named pipe
  1902. Arguments:
  1903. PipeEntry - Supplies the pipe entry for the client's named
  1904. pipe.
  1905. ClientEvent - Supplies the event that has to be sent to the
  1906. client.
  1907. Return Value:
  1908. LONG - Returns ERROR_SUCCESS (0); error-code for failure.
  1909. --*/
  1910. {
  1911. HANDLE Handle;
  1912. LONG Error = ERROR_SUCCESS;
  1913. OBJECT_ATTRIBUTES Obja;
  1914. NTSTATUS NtStatus;
  1915. ASSERT( PipeEntry != NULL );
  1916. ASSERT( PipeEntry->PipeName.Buffer != NULL );
  1917. //
  1918. // Initialize the Obja structure for the named pipe
  1919. //
  1920. InitializeObjectAttributes(
  1921. &Obja,
  1922. &(PipeEntry->PipeName),
  1923. OBJ_CASE_INSENSITIVE,
  1924. NULL,
  1925. PipeEntry->SecurityDescriptor
  1926. );
  1927. //
  1928. // Open our side of the pipe
  1929. //
  1930. NtStatus = NtOpenFile(
  1931. &Handle,
  1932. GENERIC_WRITE | SYNCHRONIZE,
  1933. &Obja,
  1934. &IoStatusBlock,
  1935. FILE_SHARE_WRITE,
  1936. FILE_NON_DIRECTORY_FILE
  1937. );
  1938. if ( NT_SUCCESS( NtStatus ) ) {
  1939. //
  1940. // Write the event
  1941. //
  1942. NtStatus = NtWriteFile(
  1943. Handle,
  1944. NULL,
  1945. NULL,
  1946. NULL,
  1947. &IoStatusBlock,
  1948. &ClientEvent,
  1949. sizeof(ClientEvent),
  1950. NULL,
  1951. NULL
  1952. );
  1953. if ( NtStatus == STATUS_PENDING ) {
  1954. NtStatus = NtWaitForSingleObject(
  1955. Handle,
  1956. FALSE,
  1957. NULL );
  1958. }
  1959. if ( NT_SUCCESS( NtStatus ) ) {
  1960. #if BIGDBG
  1961. DbgPrint( " --> Client Notified, Event 0x%x\n", ClientEvent );
  1962. #endif
  1963. Error = ERROR_SUCCESS;
  1964. } else {
  1965. Error = RtlNtStatusToDosError( NtStatus );
  1966. }
  1967. //
  1968. // Close our side of the pipe
  1969. //
  1970. NtStatus = NtClose( Handle );
  1971. ASSERT( NT_SUCCESS( NtStatus ) );
  1972. } else {
  1973. //
  1974. // If we couldn't open the pipe because the pipe does
  1975. // not exist, there's no point in keep trying.
  1976. //
  1977. if ( NtStatus == STATUS_OBJECT_NAME_NOT_FOUND ) {
  1978. Error = ERROR_SUCCESS;
  1979. } else {
  1980. Error = RtlNtStatusToDosError( NtStatus );
  1981. #if DBG
  1982. DbgPrint( "WINREG: Cannot Open pipe %Z, event %x, status %x\n",
  1983. &(PipeEntry->PipeName), ClientEvent, NtStatus );
  1984. #endif
  1985. }
  1986. }
  1987. #if DBG
  1988. if (Error != ERROR_SUCCESS ) {
  1989. DbgPrint( "WINREG: Could not notify client, Error %d\n", Error );
  1990. }
  1991. #endif
  1992. return Error;
  1993. }
  1994. #if BIGDBG
  1995. // *****************************************************************
  1996. //
  1997. // Debug Stuff
  1998. //
  1999. // *****************************************************************
  2000. VOID
  2001. DumpNotificationLists(
  2002. )
  2003. /*++
  2004. Routine Description:
  2005. Dumps the notification lists
  2006. Arguments:
  2007. None
  2008. Return Value:
  2009. None
  2010. --*/
  2011. {
  2012. PNOTIFICATION_LIST NotificationList;
  2013. PNOTIFICATION_ENTRY Event;
  2014. DWORD Index;
  2015. DbgPrint( " Notification list dump: \n\n" );
  2016. for ( NotificationList = NotificationListChainHead;
  2017. NotificationList;
  2018. NotificationList = NotificationList->Next ) {
  2019. DbgPrint( " Notification List at 0x%x\n", NotificationList );
  2020. DbgPrint( " Pending notifications: %d\n", NotificationList->PendingNotifications );
  2021. Event = &(NotificationList->Event[1]);
  2022. for ( Index = 1; Index < NotificationList->EventsInUse; Index++ ) {
  2023. DbgPrint( " Event %d EventHandle 0x%x Client 0x%x",
  2024. Index,
  2025. NotificationList->EventHandle[ Index ],
  2026. Event->ClientEvent );
  2027. if ( Event->Flags & CLIENT_IS_DEAD ) {
  2028. DbgPrint( " (Dead)\n" );
  2029. } else if ( Event->Flags & MUST_NOTIFY ) {
  2030. DbgPrint( " (Notify)\n" );
  2031. } else {
  2032. DbgPrint( "\n" );
  2033. }
  2034. Event++;
  2035. }
  2036. DbgPrint( "\n");
  2037. }
  2038. DbgPrint( "\n");
  2039. }
  2040. VOID
  2041. DumpPipeTable(
  2042. )
  2043. /*++
  2044. Routine Description:
  2045. Dumps the pipe table
  2046. Arguments:
  2047. None
  2048. Return Value:
  2049. None
  2050. --*/
  2051. {
  2052. DWORD i;
  2053. PPIPE_ENTRY Entry;
  2054. DbgPrint( "\n\n Pipes:\n\n" );
  2055. for ( i=0; i < BUCKETS_IN_SYMBOL_TABLE; i++ ) {
  2056. Entry = PipeSymbolTable.Bucket[i];
  2057. if ( Entry ) {
  2058. DbgPrint( " Bucket %d:\n",i );
  2059. while ( Entry ) {
  2060. DbgPrint( " %Z (%d)\n", &(Entry->PipeName), Entry->ReferenceCount );
  2061. Entry = Entry->Next;
  2062. }
  2063. }
  2064. }
  2065. DbgPrint( "\n" );
  2066. }
  2067. #endif // BIGDBG
  2068. #endif // REMOTE_NOTIFICATION_DISABLED