Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1882 lines
53 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. rxact.c
  5. Abstract:
  6. This Module implements a simple transaction mechanism for registry
  7. database operations which helps eliminate the possibility of partial
  8. updates being made. The cases covered are specifically partial updates
  9. caused by system crashes or program aborts during multiple-write updates.
  10. WARNING: This package does not yet deal with full-disk problems
  11. automatically. If a full disk is encountered during
  12. transaction commit, then manual interaction may be required
  13. to free enough space to complete the commit. There is
  14. no means provided for backing out the commit.
  15. Author:
  16. Jim Kelly (JimK) 15-May-1991
  17. Robert Reichel (RobertRe) 15-July-1992
  18. Environment:
  19. Pure Runtime Library Routine
  20. Revision History:
  21. --*/
  22. /*
  23. ////////////////////////////////////////////////////////////////////////////
  24. High Level Description:
  25. The simple transaction mechanism expects the following to be true:
  26. (1) A single server is responsible for operations on an entire
  27. sub-tree of the registry database. For example, the security
  28. account manager server (SAM) is responsible for everything
  29. below \REGISTRY\LOCAL_MACHINE\SECURITY\SAM.
  30. (2) Transactions on the sub-tree are serialized by the server
  31. responsible for the sub-tree. That is, the server will not
  32. start a second user request until all previous user requests
  33. have been completed.
  34. The simple transaction mechanism helps eliminate the problem of partial
  35. updates caused by system crash or program abort during multiple-write
  36. updates to the registry database. This is achieved by:
  37. (1) Keeping all actions in-memory until instructed to commit. The
  38. presence of in-memory data structures implicitly indicates
  39. that a transaction is in progress.
  40. The initial state is no transaction in progress.
  41. (2) Providing a service which allows a server to initiate a transaction.
  42. This allocates in-memory data structures, thereby changing the
  43. state to transaction in progress.
  44. (3) Keeping a log of all keys in the sub-tree that are to be
  45. updated in a single transaction. Each record in this log
  46. contains the following information:
  47. (a) The name of the sub-key effected
  48. (b) The operation to be performed on the sub-key
  49. either DELETE or SET_VALUE. Note that these
  50. operations are idempotent and may be applied
  51. again in the event that the server aborts during
  52. an initial commit.
  53. (c) The new value of the sub-key (if applicable)
  54. (d) (optionally) The attribute name of the subkey
  55. to be operated on.
  56. (note that SET_VALUE is used to create new sub-keys
  57. as well as updated existing ones).
  58. The entire list of sub-keys to be modified must be entered
  59. into this log before ANY of the sub-keys is actually modified.
  60. (4) Providing a commit service that applies all changes indicated
  61. in the change log. This is done by first writing the contents
  62. of the in-memory structures to a single key value ("Log") in
  63. the registry and flushing the data to disk. The presence of
  64. the "Log" value and data imply that a commit is in progress.
  65. All necessary changes are applied, the "Log" value and its
  66. data are deleted, and in-memory data structres are freed,
  67. thereby changing the state to no-transaction.
  68. The package also includes a service which must be called upon server
  69. startup. This service checks to make sure the state of the sub-tree
  70. is NO_TRANSACTION. If it is not, then one of the actions below is
  71. performed based upon the current state of the sub-tree:
  72. COMMITTING - This means the server was previously aborted while
  73. a transaction was being committed (applied to the registry).
  74. In this case, the commit is performed again from the beginning
  75. of the change log. After the commit is completed, the state
  76. of the sub-tree is set to NO_TRANSACTION.
  77. ////////////////////////////////////////////////////////////////////////////
  78. */
  79. /*
  80. ////////////////////////////////////////////////////////////////////////////
  81. Detailed Description:
  82. Registry State
  83. --------------
  84. The registry state of a subtree is kept in a sub-key of that tree
  85. named:
  86. "RXACT"
  87. The value field of that registry key includes a revision field.
  88. RXact Context
  89. -------------
  90. A call to RtlInitializeRXact will return a pointer to an
  91. RTL_RXACT_CONTEXT structure. This structure contains:
  92. (1) the passed RootRegistryKey (eg, key to "Sam"),
  93. (2) a handle to the top of the RXact subtree (eg, key to
  94. "Sam\RXACT"),
  95. (3) a flag indicating if handles stored in the log are
  96. valid,
  97. (4) a pointer to the current RXactLog.
  98. The subsystem calling RtlInitializeRXact must keep this returned
  99. pointer and pass it back to RXact in all subsequent calls.
  100. Operation Log
  101. -------------
  102. The operation log of a registry sub-tree transaction is kept as sequence
  103. of "operation log entries".
  104. An in-memory log is a block of heap memory allocted by RtlStartRXact.
  105. It has a header which contains:
  106. (1) The count of operations in the log.
  107. (2) The maximum size of the log.
  108. (3) The amount of the log currently in use.
  109. The log data itself follows the header directly.
  110. Operation Log Entries
  111. ---------------------
  112. An operation log entry is described by the following structure:
  113. typedef struct _RXACT_LOG_ENTRY {
  114. ULONG LogEntrySize;
  115. RTL_RXACT_OPERATION Operation;
  116. UNICODE_STRING SubKeyName; // Self-relativized (Buffer is really offset)
  117. UNICODE_STRING AttributeName; // Self-relativized (Buffer is really offset)
  118. HANDLE KeyHandle; // optional, not valid if read from disk.
  119. ULONG NewKeyValueType;
  120. ULONG NewKeyValueLength;
  121. PVOID NewKeyValue; // Contains offset to data from start of log
  122. } RXACT_LOG_ENTRY, *PRXACT_LOG_ENTRY;
  123. The log entry contains all of the information passed in during a call
  124. to RtlAddActionToRXact or RtlAddAttributeActionToRXact.
  125. The UNICODE_STRING structures contain an offset to the string data
  126. rather than a pointer. These offsets are relative to the start of
  127. the log data, and are adjusted in place as each log entry is commited.
  128. The KeyHandle is valid if it is not equal to INVALID_HANDLE_VALUE and
  129. if the HandlesValid flag in the RXactContext structure is TRUE. This
  130. is so that we do not attempt to use the handles if the log has been
  131. read from disk after a reboot.
  132. ////////////////////////////////////////////////////////////////////////////
  133. */
  134. #include "ntrtlp.h"
  135. //
  136. // Cannot include <windows.h> from kernel code
  137. //
  138. #define INVALID_HANDLE_VALUE (HANDLE)-1
  139. ///////////////////////////////////////////////////////////////////////////////
  140. // //
  141. // Local Macros & Definitions //
  142. // //
  143. ///////////////////////////////////////////////////////////////////////////////
  144. //
  145. // Revision level of a registry transaction .
  146. //
  147. #define RTLP_RXACT_REVISION1 (1l)
  148. #define RTLP_RXACT_CURRENT_REVISION RTLP_RXACT_REVISION1
  149. #define RTLP_RXACT_KEY_NAME L"RXACT"
  150. #define RTLP_RXACT_LOG_NAME L"Log"
  151. #define RTLP_INITIAL_LOG_SIZE 0x4000
  152. //
  153. // Given a value return its longword aligned equivalent value
  154. //
  155. #define DwordAlign(Value) ( \
  156. (ULONG)((((ULONG)(Value)) + 3) & 0xfffffffc) \
  157. )
  158. //
  159. // The value field of the RXACT registry key is one of the following data
  160. // structures.
  161. //
  162. //
  163. // The state of a registry sub-tree is one of the following:
  164. //
  165. // RtlpRXactStateNoTransaction - There is not a transaction in progress.
  166. //
  167. // RtlpRXactStateCommitting - The actions of a transaction are being
  168. // applied to the registry database.
  169. //
  170. typedef enum _RTLP_RXACT_STATE {
  171. RtlpRXactStateNoTransaction = 2,
  172. RtlpRXactStateCommitting
  173. } RTLP_RXACT_STATE, *PRTLP_RXACT_STATE;
  174. typedef struct _RTLP_RXACT {
  175. ULONG Revision;
  176. RTLP_RXACT_STATE State; // no longer used
  177. ULONG OperationCount; // no longer used
  178. } RTLP_RXACT, *PRTLP_RXACT;
  179. typedef struct _RXACT_LOG_ENTRY {
  180. ULONG LogEntrySize;
  181. RTL_RXACT_OPERATION Operation;
  182. UNICODE_STRING SubKeyName; // Self-relativized (Buffer is really offset)
  183. UNICODE_STRING AttributeName; // Self-relativized (Buffer is really offset)
  184. HANDLE KeyHandle; // optional, not valid if read from disk.
  185. ULONG NewKeyValueType;
  186. ULONG NewKeyValueLength;
  187. PVOID NewKeyValue; // Contains offset to data from start of log
  188. } RXACT_LOG_ENTRY, *PRXACT_LOG_ENTRY;
  189. ////////////////////////////////////////////////////////////////////////////////
  190. // //
  191. // Prototypes for local procedures //
  192. // //
  193. ////////////////////////////////////////////////////////////////////////////////
  194. NTSTATUS
  195. RXactpCommit(
  196. IN PRTL_RXACT_CONTEXT RXactContext
  197. );
  198. NTSTATUS
  199. RXactpOpenTargetKey(
  200. IN HANDLE RootRegistryKey,
  201. IN RTL_RXACT_OPERATION Operation,
  202. IN PUNICODE_STRING SubKeyName,
  203. OUT PHANDLE TargetKey
  204. );
  205. VOID
  206. RXactInitializeContext(
  207. IN PRTL_RXACT_CONTEXT RXactContext,
  208. IN HANDLE RootRegistryKey,
  209. IN HANDLE RXactKey
  210. );
  211. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  212. #pragma alloc_text(PAGE,RXactpCommit)
  213. #pragma alloc_text(PAGE,RXactpOpenTargetKey)
  214. #pragma alloc_text(PAGE,RXactInitializeContext)
  215. #pragma alloc_text(PAGE,RtlInitializeRXact)
  216. #pragma alloc_text(PAGE,RtlStartRXact)
  217. #pragma alloc_text(PAGE,RtlAbortRXact)
  218. #pragma alloc_text(PAGE,RtlAddAttributeActionToRXact)
  219. #pragma alloc_text(PAGE,RtlAddActionToRXact)
  220. #pragma alloc_text(PAGE,RtlApplyRXact)
  221. #pragma alloc_text(PAGE,RtlApplyRXactNoFlush)
  222. #endif
  223. ///////////////////////////////////////////////////////////////////////////////
  224. // //
  225. // Exported Procedures (defined in ntrtl.h) //
  226. // //
  227. ///////////////////////////////////////////////////////////////////////////////
  228. NTSTATUS
  229. RtlInitializeRXact(
  230. IN HANDLE RootRegistryKey,
  231. IN BOOLEAN CommitIfNecessary,
  232. OUT PRTL_RXACT_CONTEXT *RXactContext
  233. )
  234. /*++
  235. Routine Description:
  236. This routine should be called by a server exactly once when it starts.
  237. This routine will check to see that the registry transaction information
  238. exists for the specified registry sub-tree, and will create it if it
  239. doesn't exist.
  240. Arguments:
  241. RootRegistryKey - A handle to the registry key within whose sub-tree
  242. a transaction is to be initialized.
  243. CommitIfNecessary - A BOOLEAN value indicating whether or not any
  244. previously aborted commit discovered should be commited at this
  245. time. A value of TRUE indicates the commit should be applied
  246. if encountered. A value of FALSE indicates a previously
  247. aborted COMMIT should not be committed at this time.
  248. RXactContext - Returns a pointer to an RTL_RXACT_CONTEXT structure
  249. allocated out of the local heap. The caller must keep this
  250. pointer and pass it back in for all future RXact transactions
  251. for the passed RootRegistryKey.
  252. Return Value:
  253. STATUS_SUCCESS - Indicates the transaction state already exists for the
  254. registry sub-tree and is already in the NO_TRANSACTION state.
  255. STATUS_UNKNOWN_REVISION - Indicates that a transaction state already
  256. exists for the specified sub-tree, but is a revision level that is
  257. unknown by this service.
  258. STATUS_RXACT_STATE_CREATED - This informational level status indicates
  259. that a specified registry sub-tree transaction state did not yet
  260. exist and had to be created.
  261. STATUS_RXACT_COMMIT_NECESSARY - This warning level status indicates that the
  262. transaction state already exists for the registry sub-tree, but that
  263. a transaction commit was previously aborted. The commit has NOT been
  264. completed. Another call to this service with a CommitIfNecessary value
  265. of TRUE may be used to commit the transaction.
  266. STATUS_RXACT_INVALID_STATE - Indicates that the transaction state
  267. of the registry sub-tree is incompatible with the requested operation.
  268. For example, a request to start a new transaction while one is already
  269. in progress, or a request to apply a transaction when one is not
  270. currently in progress.
  271. --*/
  272. {
  273. HANDLE RXactKey;
  274. LARGE_INTEGER LastWriteTime;
  275. NTSTATUS Status, TmpStatus;
  276. OBJECT_ATTRIBUTES RXactAttributes;
  277. PKEY_VALUE_FULL_INFORMATION FullInformation;
  278. RTLP_RXACT RXactKeyValue;
  279. UCHAR BasicInformation[128]; // Should be more than long enough
  280. ULONG Disposition;
  281. ULONG KeyValueLength;
  282. ULONG KeyValueType;
  283. ULONG ResultLength;
  284. UNICODE_STRING RXactKeyName;
  285. UNICODE_STRING ValueName;
  286. UNICODE_STRING NullName;
  287. RTL_PAGED_CODE();
  288. //
  289. // Initialize some stuff
  290. //
  291. KeyValueLength = (ULONG)sizeof( RTLP_RXACT );
  292. KeyValueType = 0; // Not used by RXact
  293. RtlInitUnicodeString( &NullName, NULL );
  294. //
  295. // Create or open the RXACT key.
  296. //
  297. RtlInitUnicodeString( &RXactKeyName, RTLP_RXACT_KEY_NAME);
  298. InitializeObjectAttributes(
  299. &RXactAttributes,
  300. &RXactKeyName,
  301. OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
  302. RootRegistryKey,
  303. NULL);
  304. // Status = RtlpNtCreateKey(
  305. // &RXactKey,
  306. // (KEY_READ | KEY_WRITE | DELETE),
  307. // &RXactAttributes,
  308. // 0,
  309. // NULL,
  310. // &Disposition
  311. // );
  312. Status = NtCreateKey( &RXactKey,
  313. (KEY_READ | KEY_WRITE | DELETE),
  314. &RXactAttributes,
  315. 0, //TitleIndex
  316. NULL, //Class OPTIONAL,
  317. REG_OPTION_NON_VOLATILE, //CreateOptions,
  318. &Disposition
  319. );
  320. if ( !NT_SUCCESS(Status) ) {
  321. return(Status);
  322. }
  323. //
  324. // Allocate the RXactContext block
  325. //
  326. *RXactContext = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( RTL_RXACT_CONTEXT ));
  327. if ( *RXactContext == NULL ) {
  328. //
  329. // Something prevented value assignment...
  330. // Get rid of the RXact key and return the error
  331. //
  332. TmpStatus = NtDeleteKey( RXactKey );
  333. ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group
  334. TmpStatus = NtClose( RXactKey );
  335. ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group
  336. return( STATUS_NO_MEMORY );
  337. }
  338. //
  339. // Initialize the newly created RXactContext structure.
  340. //
  341. RXactInitializeContext( *RXactContext, RootRegistryKey, RXactKey );
  342. //
  343. // If we created (as opposed to opened an existing) rxact key,
  344. // then we need to initialize it.
  345. //
  346. if ( Disposition == REG_CREATED_NEW_KEY ) {
  347. RXactKeyValue.Revision = RTLP_RXACT_REVISION1;
  348. Status = NtSetValueKey( RXactKey,
  349. &NullName, // ValueName
  350. 0, // TitleIndex
  351. KeyValueType,
  352. &RXactKeyValue,
  353. KeyValueLength
  354. );
  355. if ( !NT_SUCCESS(Status) ) {
  356. //
  357. // Something prevented value assignment...
  358. // Get rid of the RXact key and return the error
  359. //
  360. TmpStatus = NtDeleteKey( RXactKey );
  361. ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group
  362. TmpStatus = NtClose( RXactKey );
  363. ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group
  364. RtlFreeHeap( RtlProcessHeap(), 0, *RXactContext );
  365. return( Status );
  366. }
  367. return( STATUS_RXACT_STATE_CREATED );
  368. }
  369. //
  370. // We have opened an existing RXACT key.
  371. // See if it is a revision level we know about.
  372. //
  373. Status = RtlpNtQueryValueKey(
  374. RXactKey, // KeyHandle
  375. &KeyValueType, // KeyValueType
  376. &RXactKeyValue, // KeyValue
  377. &KeyValueLength, // KeyValueLength
  378. &LastWriteTime // LastWriteTime
  379. );
  380. if ( !NT_SUCCESS(Status) ) {
  381. //
  382. // Something prevented value query...
  383. //
  384. TmpStatus = NtClose( RXactKey );
  385. ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group
  386. RtlFreeHeap( RtlProcessHeap(), 0, *RXactContext );
  387. return( Status );
  388. }
  389. if ( KeyValueLength != (ULONG)sizeof(RTLP_RXACT) ) {
  390. TmpStatus = NtClose( RXactKey );
  391. ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group
  392. RtlFreeHeap( RtlProcessHeap(), 0, *RXactContext );
  393. return( STATUS_UNKNOWN_REVISION );
  394. }
  395. if (RXactKeyValue.Revision != RTLP_RXACT_REVISION1) {
  396. TmpStatus = NtClose( RXactKey );
  397. ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group
  398. RtlFreeHeap( RtlProcessHeap(), 0, *RXactContext );
  399. return( STATUS_UNKNOWN_REVISION );
  400. }
  401. //
  402. // Right revision...
  403. // See if there is a transaction or commit in progress. If not,
  404. // return success
  405. //
  406. //
  407. // If a log file exists, then we are committing.
  408. //
  409. RtlInitUnicodeString( &ValueName, RTLP_RXACT_LOG_NAME );
  410. Status = NtQueryValueKey(
  411. RXactKey,
  412. &ValueName,
  413. KeyValueBasicInformation,
  414. &BasicInformation[0],
  415. 128,
  416. &ResultLength
  417. );
  418. if ( NT_SUCCESS( Status )) {
  419. //
  420. // We found a value called 'Log'. This means that a commit
  421. // was in progress.
  422. //
  423. if ( CommitIfNecessary ) {
  424. //
  425. // Query the full value of the log, then call a low level routine
  426. // to actually perform the commit.
  427. //
  428. Status = NtQueryValueKey(
  429. RXactKey,
  430. &ValueName,
  431. KeyValueFullInformation,
  432. NULL,
  433. 0,
  434. &ResultLength
  435. );
  436. if ( Status != STATUS_BUFFER_TOO_SMALL ) {
  437. return( Status );
  438. }
  439. FullInformation = RtlAllocateHeap( RtlProcessHeap(), 0, ResultLength );
  440. if ( FullInformation == NULL ) {
  441. return( STATUS_NO_MEMORY );
  442. }
  443. Status = NtQueryValueKey(
  444. RXactKey,
  445. &ValueName,
  446. KeyValueFullInformation,
  447. FullInformation,
  448. ResultLength,
  449. &ResultLength
  450. );
  451. if ( !NT_SUCCESS( Status )) {
  452. RtlFreeHeap( RtlProcessHeap(), 0, FullInformation );
  453. RtlFreeHeap( RtlProcessHeap(), 0, *RXactContext );
  454. return( Status );
  455. }
  456. //
  457. // The log information is buried in the returned FullInformation
  458. // buffer. Dig it out and make the RXactLog in the RXactContext
  459. // structure point to it. Then commit.
  460. //
  461. (*RXactContext)->RXactLog = (PRTL_RXACT_LOG)((PCHAR)FullInformation + FullInformation->DataOffset);
  462. //
  463. // Don't use any handles we may find in the log file
  464. //
  465. (*RXactContext)->HandlesValid = FALSE;
  466. Status = RXactpCommit( *RXactContext );
  467. if ( !NT_SUCCESS( Status )) {
  468. RtlFreeHeap( RtlProcessHeap(), 0, FullInformation );
  469. RtlFreeHeap( RtlProcessHeap(), 0, *RXactContext );
  470. return( Status );
  471. }
  472. //
  473. // The commit was successful. Clean up.
  474. // Delete the log file value and data
  475. //
  476. Status = NtDeleteValueKey( RXactKey, &ValueName );
  477. //
  478. // This should never fail
  479. //
  480. ASSERT( NT_SUCCESS( Status ));
  481. //
  482. // Get rid of the in memory data structures. Abort
  483. // will free the RXactLog, so put what we want
  484. // freed in there and it will go away.
  485. //
  486. (*RXactContext)->RXactLog = (PRTL_RXACT_LOG)FullInformation;
  487. Status = RtlAbortRXact( *RXactContext );
  488. //
  489. // This should never fail
  490. //
  491. ASSERT( NT_SUCCESS( Status ));
  492. return( Status );
  493. } else {
  494. return( STATUS_RXACT_COMMIT_NECESSARY );
  495. }
  496. } else {
  497. //
  498. // No log, so nothing to do here.
  499. //
  500. return( STATUS_SUCCESS );
  501. }
  502. }
  503. VOID
  504. RXactInitializeContext(
  505. IN PRTL_RXACT_CONTEXT RXactContext,
  506. IN HANDLE RootRegistryKey,
  507. IN HANDLE RXactKey
  508. )
  509. /*++
  510. Routine Description:
  511. Initializes an in-memory RXactContext structure.
  512. Arguments:
  513. RXactContext - Supplies a pointer to an RXact Context created
  514. by RtlInitializeRXact.
  515. RootRegistryKey - Supplies the RootRegistryKey for this component.
  516. RXactKey - Supplies the {RootRegistryKey}\RXactKey for this component
  517. Return Value:
  518. None.
  519. --*/
  520. {
  521. //
  522. // Initialize the RXactContext for this client
  523. //
  524. RXactContext->RootRegistryKey = RootRegistryKey;
  525. RXactContext->HandlesValid = TRUE;
  526. RXactContext->RXactLog = NULL;
  527. RXactContext->RXactKey = RXactKey;
  528. return;
  529. }
  530. NTSTATUS
  531. RtlStartRXact(
  532. IN PRTL_RXACT_CONTEXT RXactContext
  533. )
  534. /*++
  535. Routine Description:
  536. This routine is used to start a new transaction in a registry sub-tree.
  537. Transactions must be serialized by the server so that only one transaction
  538. is in progress at a time.
  539. Arguments:
  540. RXactContext - Supplies a pointer to an RTL_RXACT_CONTEXT structure
  541. that is not currently in use.
  542. Return Value:
  543. STATUS_SUCCESS - Indicates the transaction was started.
  544. STATUS_RXACT_INVALID_STATE - Indicates that the transaction state
  545. of the registry sub-tree is incompatible with the requested operation.
  546. For example, a request to start a new transaction while one is already
  547. in progress, or a request to apply a transaction when one is not
  548. currently in progress. This may also indicate that there is no
  549. transaction state at all for the specified registry sub-tree.
  550. --*/
  551. {
  552. PRTL_RXACT_LOG RXactLogHeader;
  553. RTL_PAGED_CODE();
  554. //
  555. // Allocate in-memory log file and initialize. This implicitly
  556. // sets the state to 'transaction in progress'.
  557. //
  558. if ( RXactContext->RXactLog != NULL ) {
  559. //
  560. // There is already a transaction in progress for this
  561. // context. Return an error.
  562. //
  563. return( STATUS_RXACT_INVALID_STATE );
  564. }
  565. RXactLogHeader = RtlAllocateHeap( RtlProcessHeap(), 0, RTLP_INITIAL_LOG_SIZE );
  566. if ( RXactLogHeader == NULL ) {
  567. return( STATUS_NO_MEMORY );
  568. }
  569. //
  570. // Fill in the log header information at the top of the
  571. // newly allocated buffer.
  572. //
  573. RXactLogHeader->OperationCount = 0;
  574. RXactLogHeader->LogSize = RTLP_INITIAL_LOG_SIZE;
  575. RXactLogHeader->LogSizeInUse = sizeof( RTL_RXACT_LOG );
  576. RXactContext->RXactLog = RXactLogHeader;
  577. return( STATUS_SUCCESS );
  578. }
  579. NTSTATUS
  580. RtlAbortRXact(
  581. IN PRTL_RXACT_CONTEXT RXactContext
  582. )
  583. /*++
  584. Routine Description:
  585. This routine is used to abort a transaction in a registry sub-tree.
  586. Arguments:
  587. RootRegistryKey - A handle to the registry key within whose sub-tree
  588. the transaction is to be aborted.
  589. Return Value:
  590. STATUS_SUCCESS - Indicates the transaction was aborted.
  591. STATUS_UNKNOWN_REVISION - Indicates that a transaction state
  592. exists for the specified sub-tree, but has a revision level that is
  593. unknown by this service.
  594. STATUS_RXACT_INVALID_STATE - Indicates that the transaction state
  595. of the registry sub-tree is incompatible with the requested operation.
  596. For example, a request to start a new transaction while one is already
  597. in progress, or a request to apply a transaction when one is not
  598. currently in progress. This may also indicate that there is no
  599. transaction state at all for the specified registry sub-tree.
  600. --*/
  601. {
  602. RTL_PAGED_CODE();
  603. if ( RXactContext->RXactLog == NULL ) {
  604. //
  605. // There is no transaction in progress for this
  606. // context. Return an error.
  607. //
  608. return( STATUS_RXACT_INVALID_STATE );
  609. }
  610. (VOID) RtlFreeHeap( RtlProcessHeap(), 0, RXactContext->RXactLog );
  611. //
  612. // Reinitialize the RXactContext structure with the same initial data.
  613. //
  614. RXactInitializeContext(
  615. RXactContext,
  616. RXactContext->RootRegistryKey,
  617. RXactContext->RXactKey
  618. );
  619. return( STATUS_SUCCESS );
  620. }
  621. NTSTATUS
  622. RtlAddAttributeActionToRXact(
  623. IN PRTL_RXACT_CONTEXT RXactContext,
  624. IN RTL_RXACT_OPERATION Operation,
  625. IN PUNICODE_STRING SubKeyName,
  626. IN HANDLE KeyHandle OPTIONAL,
  627. IN PUNICODE_STRING AttributeName,
  628. IN ULONG NewValueType,
  629. IN PVOID NewValue,
  630. IN ULONG NewValueLength
  631. )
  632. /*++
  633. Routine Description:
  634. This routine is used to add a new action to the transaction operation log.
  635. Upon commit, these operations are applied in the order they are added
  636. to the log.
  637. This routine differs from RtlAddActionToRXact in that it takes an Attribute
  638. Name parameter, rather than using the default ("NULL") Attribute of the
  639. specified key.
  640. Arguments:
  641. RXactContext - Supplies a pointer to the RXactContext structure for this
  642. subsystem's root registry key.
  643. Operation - Indicates the type of operation to perform (e.g., delete
  644. a sub-key or set the value of a sub-key). Sub-keys may be created
  645. by setting a value of a previously non-existent sub-key. This will
  646. cause all sub-keys between the root and the specified sub-key to
  647. be created.
  648. SubKeyName - Specifies the name of the target registry key. This name
  649. is relative to the Root of the Registry transaction sub-tree
  650. and must NOT start with a delimiter character ("\").
  651. KeyHandle - Optionally supplies a handle to the target key. If
  652. not specified, the name passed for SubKeyName will determine
  653. the target key.
  654. AttributeName - Supplies the name of the key attribute to be
  655. modified.
  656. NewKeyValueType - (Optional) Contains the KeyValueType to assign
  657. to the target registry key. This parameter is ignored if the
  658. Operation is not RtlRXactOperationSetValue.
  659. NewKeyValue - (Optional) Points to a buffer containing the value
  660. to assign to the specified target registry key. This parameter
  661. is ignored if the Operation is not RtlRXactOperationSetValue.
  662. NewKeyValueLength - Indicates the length (number of bytes) of the
  663. NewKeyValue buffer. This parameter is ignored if the Operation
  664. is not RtlRXactOperationSetValue.
  665. Return Value:
  666. STATUS_SUCCESS - Indicates the request completed successfully..
  667. STATUS_INVALID_PARAMETER - Indicates that an unknown Operation
  668. was requested.
  669. STATUS_NO_MEMORY - Insufficient memeory was available to complete
  670. this operation.
  671. STATUS_UNKNOWN_REVISION - Indicates that a transaction state
  672. exists for the specified sub-tree, but has a revision level that is
  673. unknown by this service.
  674. --*/
  675. {
  676. PRTL_RXACT_LOG NewLog;
  677. PRXACT_LOG_ENTRY Base;
  678. ULONG End;
  679. ULONG LogEntrySize;
  680. ULONG NewLogSize;
  681. RTL_PAGED_CODE();
  682. //
  683. // Make sure we were passed a legitimate operation.
  684. //
  685. if ( (Operation != RtlRXactOperationDelete) &&
  686. (Operation != RtlRXactOperationSetValue) ) {
  687. return STATUS_INVALID_PARAMETER;
  688. }
  689. //
  690. // Compute the total size of the new data
  691. //
  692. LogEntrySize = sizeof( RXACT_LOG_ENTRY ) +
  693. DwordAlign( SubKeyName->Length ) +
  694. DwordAlign( AttributeName->Length ) +
  695. DwordAlign( NewValueLength );
  696. LogEntrySize = ALIGN_UP( LogEntrySize, PVOID );
  697. //
  698. // Make sure there is enough space in the current
  699. // log file for this data. If not, we must create
  700. // a larger log, copy all the old data, and then
  701. // append this to the end.
  702. //
  703. if ( RXactContext->RXactLog->LogSizeInUse + LogEntrySize >
  704. RXactContext->RXactLog->LogSize ) {
  705. //
  706. // We must allocate a bigger log file.
  707. //
  708. NewLogSize = RXactContext->RXactLog->LogSize;
  709. do {
  710. NewLogSize = NewLogSize * 2;
  711. } while ( NewLogSize <
  712. ( RXactContext->RXactLog->LogSizeInUse + LogEntrySize ) );
  713. NewLog = RtlAllocateHeap( RtlProcessHeap(), 0, NewLogSize );
  714. if ( NewLog == NULL ) {
  715. return( STATUS_NO_MEMORY );
  716. }
  717. //
  718. // Copy over previous information
  719. //
  720. RtlCopyMemory( NewLog, RXactContext->RXactLog, RXactContext->RXactLog->LogSizeInUse );
  721. //
  722. // Free the old log file
  723. //
  724. RtlFreeHeap( RtlProcessHeap(), 0, RXactContext->RXactLog );
  725. //
  726. // Install the new log file and adjust its size in its header
  727. //
  728. RXactContext->RXactLog = NewLog;
  729. RXactContext->RXactLog->LogSize = NewLogSize;
  730. }
  731. //
  732. // The log file is big enough, append data to
  733. // the end.
  734. //
  735. Base = (PRXACT_LOG_ENTRY)((PCHAR)(RXactContext->RXactLog) +
  736. (RXactContext->RXactLog->LogSizeInUse));
  737. //
  738. // Append each parameter to the end of the log. Unicode string data
  739. // will be appended to the end of the entry. The Buffer field in the
  740. // Unicode string structure will contain the offset to the Buffer,
  741. // relative to the beginning of the log file.
  742. //
  743. Base->LogEntrySize = LogEntrySize;
  744. Base->Operation = Operation;
  745. Base->SubKeyName = *SubKeyName;
  746. Base->AttributeName = *AttributeName;
  747. Base->NewKeyValueType = NewValueType;
  748. Base->NewKeyValueLength = NewValueLength;
  749. Base->KeyHandle = KeyHandle;
  750. //
  751. // Fill in the variable length data: SubKeyName, AttributeName,
  752. // and NewKeyValue
  753. //
  754. //
  755. // End is an offset relative to the beginning of the entire log
  756. // structure. It is initialized to 'point' to the offset immediately
  757. // following the structure we just filled in above.
  758. //
  759. End = (ULONG)((RXactContext->RXactLog->LogSizeInUse) +
  760. sizeof( *Base ));
  761. //
  762. // Append SubKeyName information to the log file
  763. //
  764. RtlMoveMemory (
  765. (PCHAR)(RXactContext->RXactLog) + End,
  766. SubKeyName->Buffer,
  767. SubKeyName->Length
  768. );
  769. Base->SubKeyName.Buffer = (PWSTR)ULongToPtr(End);
  770. End += DwordAlign( SubKeyName->Length );
  771. //
  772. // Append AttributeName information to the log file
  773. //
  774. RtlMoveMemory(
  775. (PCHAR)(RXactContext->RXactLog) + End,
  776. AttributeName->Buffer,
  777. AttributeName->Length
  778. );
  779. Base->AttributeName.Buffer = (PWSTR)ULongToPtr(End);
  780. End += DwordAlign( AttributeName->Length );
  781. //
  782. // Append NewKeyValue information (if present) to the log file
  783. //
  784. if ( Operation == RtlRXactOperationSetValue ) {
  785. RtlMoveMemory(
  786. (PCHAR)(RXactContext->RXactLog) + End,
  787. NewValue,
  788. NewValueLength
  789. );
  790. Base->NewKeyValue = (PVOID)ULongToPtr(End);
  791. End += DwordAlign( NewValueLength );
  792. }
  793. End = ALIGN_UP( End, PVOID );
  794. RXactContext->RXactLog->LogSizeInUse = End;
  795. RXactContext->RXactLog->OperationCount++;
  796. //
  797. // We're done
  798. //
  799. return(STATUS_SUCCESS);
  800. }
  801. NTSTATUS
  802. RtlAddActionToRXact(
  803. IN PRTL_RXACT_CONTEXT RXactContext,
  804. IN RTL_RXACT_OPERATION Operation,
  805. IN PUNICODE_STRING SubKeyName,
  806. IN ULONG NewKeyValueType,
  807. IN PVOID NewKeyValue OPTIONAL,
  808. IN ULONG NewKeyValueLength
  809. )
  810. /*++
  811. Routine Description:
  812. This routine is used to add a new action to the transaction operation log.
  813. Upon commit, these operations are applied in the order they are added
  814. to the log.
  815. Arguments:
  816. RXactContext - Supplies a pointer to the RXactContext structure for this
  817. subsystem's root registry key.
  818. Operation - Indicates the type of operation to perform (e.g., delete
  819. a sub-key or set the value of a sub-key). Sub-keys may be created
  820. by setting a value of a previously non-existent sub-key. This will
  821. cause all sub-keys between the root and the specified sub-key to
  822. be created.
  823. SubKeyName - Specifies the name of the target registry key. This name
  824. is relative to the Root of the Registry transaction sub-tree
  825. and must NOT start with a delimiter character ("\").
  826. NewKeyValueType - (Optional) Contains the KeyValueType to assign
  827. to the target registry key. This parameter is ignored if the
  828. Operation is not RtlRXactOperationSetValue.
  829. NewKeyValue - (Optional) Points to a buffer containing the value
  830. to assign to the specified target registry key. This parameter
  831. is ignored if the Operation is not RtlRXactOperationSetValue.
  832. NewKeyValueLength - Indicates the length (number of bytes) of the
  833. NewKeyValue buffer. This parameter is ignored if the Operation
  834. is not RtlRXactOperationSetValue.
  835. Return Value:
  836. STATUS_SUCCESS - Indicates the request completed successfully..
  837. STATUS_UNKNOWN_REVISION - Indicates that a transaction state
  838. exists for the specified sub-tree, but has a revision level that is
  839. unknown by this service.
  840. Others - Other status values that may be returned from registry key
  841. services (such as STATUS_ACCESS_DENIED).
  842. --*/
  843. {
  844. UNICODE_STRING AttributeName;
  845. NTSTATUS Status;
  846. RTL_PAGED_CODE();
  847. RtlInitUnicodeString( &AttributeName, NULL );
  848. Status = RtlAddAttributeActionToRXact(
  849. RXactContext,
  850. Operation,
  851. SubKeyName,
  852. INVALID_HANDLE_VALUE,
  853. &AttributeName,
  854. NewKeyValueType,
  855. NewKeyValue,
  856. NewKeyValueLength
  857. );
  858. return( Status );
  859. }
  860. NTSTATUS
  861. RtlApplyRXact(
  862. IN PRTL_RXACT_CONTEXT RXactContext
  863. )
  864. /*++
  865. Routine Description:
  866. This routine is used to apply the changes of a registry sub-tree
  867. Transaction to that registry sub-tree. This routine is meant to be
  868. called for the common case, where the hive is automatically
  869. lazy-flushed. That means that this routine must write the change log
  870. to disk, then flush the hive (to ensure that pieces of changes aren't
  871. lazy-written to disk before this routine finishes an atomic operation),
  872. the apply the changes, then delete the change log.
  873. The actual changes will be lazy-written to disk, but the registry
  874. guarantees that none or all will make it. If the machine goes down
  875. while this routine is executing, the flushed change log guarantees
  876. that the hive can be put into a consistent state.
  877. Arguments:
  878. RXactContext - Supplies a pointer to the RXactContext structure for this
  879. subsystem's root registry key.
  880. Return Value:
  881. STATUS_SUCCESS - Indicates the transaction was completed.
  882. STATUS_UNKNOWN_REVISION - Indicates that a transaction state
  883. exists for the specified sub-tree, but has a revision level that is
  884. unknown by this service.
  885. STATUS_RXACT_INVALID_STATE - Indicates that the transaction state
  886. of the registry sub-tree is incompatible with the requested operation.
  887. For example, a request to start a new transaction while one is already
  888. in progress, or a request to apply a transaction when one is not
  889. currently in progress. This may also indicate that there is no
  890. transaction state at all for the specified registry sub-tree.
  891. --*/
  892. {
  893. NTSTATUS Status;
  894. UNICODE_STRING LogName;
  895. HANDLE RXactKey;
  896. RTL_PAGED_CODE();
  897. //
  898. // Commit the contents of the current log to disk
  899. //
  900. RXactKey = RXactContext->RXactKey;
  901. RtlInitUnicodeString( &LogName, RTLP_RXACT_LOG_NAME );
  902. Status = NtSetValueKey( RXactKey,
  903. &LogName, // ValueName
  904. 0, // TitleIndex
  905. REG_BINARY,
  906. RXactContext->RXactLog,
  907. RXactContext->RXactLog->LogSizeInUse
  908. );
  909. if ( !NT_SUCCESS( Status )) {
  910. return( Status );
  911. }
  912. Status = NtFlushKey( RXactKey );
  913. if ( !NT_SUCCESS( Status )) {
  914. //
  915. // If this fails, maintain the in-memory data,
  916. // but get rid of what we just tried to write
  917. // to disk.
  918. //
  919. // Ignore the error, since we're in a funky
  920. // state right now.
  921. //
  922. (VOID) NtDeleteValueKey( RXactKey, &LogName );
  923. return( Status );
  924. }
  925. //
  926. // The log is safe, now execute what is in it
  927. //
  928. Status = RXactpCommit( RXactContext );
  929. if ( !NT_SUCCESS( Status )) {
  930. //
  931. // As above, try to get rid of what's on
  932. // disk, leave the in-memory stuff alone,
  933. // so that the caller may try again.
  934. //
  935. (VOID) NtDeleteValueKey( RXactKey, &LogName );
  936. return( Status );
  937. }
  938. //
  939. // Delete the log file value and data
  940. //
  941. Status = NtDeleteValueKey( RXactKey, &LogName );
  942. //
  943. // This should never fail
  944. //
  945. ASSERT( NT_SUCCESS( Status ));
  946. //
  947. // Get rid of the in memory data structures. Abort
  948. // does exactly what we want to do.
  949. //
  950. Status = RtlAbortRXact( RXactContext );
  951. //
  952. // This should never fail
  953. //
  954. ASSERT( NT_SUCCESS( Status ));
  955. return( STATUS_SUCCESS );
  956. }
  957. NTSTATUS
  958. RtlApplyRXactNoFlush(
  959. IN PRTL_RXACT_CONTEXT RXactContext
  960. )
  961. /*++
  962. Routine Description:
  963. This routine is used to apply the changes of a registry sub-tree
  964. Transaction to that registry sub-tree. This routine should only be
  965. called for special hives that do not have automatic lazy-flushing.
  966. The caller must decide when to flush the hive in order to guarantee
  967. a consistent hive.
  968. Arguments:
  969. RXactContext - Supplies a pointer to the RXactContext structure for this
  970. subsystem's root registry key.
  971. Return Value:
  972. STATUS_SUCCESS - Indicates the transaction was completed.
  973. STATUS_UNKNOWN_REVISION - Indicates that a transaction state
  974. exists for the specified sub-tree, but has a revision level that is
  975. unknown by this service.
  976. STATUS_RXACT_INVALID_STATE - Indicates that the transaction state
  977. of the registry sub-tree is incompatible with the requested operation.
  978. For example, a request to start a new transaction while one is already
  979. in progress, or a request to apply a transaction when one is not
  980. currently in progress. This may also indicate that there is no
  981. transaction state at all for the specified registry sub-tree.
  982. --*/
  983. {
  984. NTSTATUS Status;
  985. RTL_PAGED_CODE();
  986. //
  987. // Execute the contents of the RXACT log.
  988. //
  989. Status = RXactpCommit( RXactContext );
  990. if ( NT_SUCCESS( Status ) ) {
  991. //
  992. // Get rid of the in memory data structures. Abort
  993. // does exactly what we want to do.
  994. //
  995. Status = RtlAbortRXact( RXactContext );
  996. //
  997. // This should never fail
  998. //
  999. ASSERT( NT_SUCCESS( Status ));
  1000. }
  1001. return( Status );
  1002. }
  1003. ///////////////////////////////////////////////////////////////////////////////
  1004. // //
  1005. // Internal Procedures (defined in within this file) //
  1006. // //
  1007. ///////////////////////////////////////////////////////////////////////////////
  1008. NTSTATUS
  1009. RXactpCommit(
  1010. IN PRTL_RXACT_CONTEXT RXactContext
  1011. )
  1012. /*++
  1013. Routine Description:
  1014. This routine commits the operations in the operation log.
  1015. When all changes have been applied, the transaction state
  1016. is changed to NO_TRANSACTION.
  1017. Arguments:
  1018. RXactContext - Supplies a pointer to the RXactContext structure for this
  1019. subsystem's root registry key.
  1020. Return Value:
  1021. STATUS_SUCCESS - Indicates the transaction was completed.
  1022. --*/
  1023. {
  1024. BOOLEAN HandlesValid;
  1025. HANDLE TargetKey;
  1026. HANDLE RXactKey;
  1027. HANDLE RootRegistryKey;
  1028. PRTL_RXACT_LOG RXactLog;
  1029. PRXACT_LOG_ENTRY RXactLogEntry;
  1030. RTL_RXACT_OPERATION Operation;
  1031. ULONG OperationCount;
  1032. ULONG i;
  1033. NTSTATUS Status = STATUS_SUCCESS;
  1034. NTSTATUS TmpStatus = STATUS_SUCCESS;
  1035. BOOLEAN CloseTargetKey;
  1036. //
  1037. // Extract information from the RXactContext to simplify
  1038. // the code that follows
  1039. //
  1040. RootRegistryKey = RXactContext->RootRegistryKey;
  1041. RXactKey = RXactContext->RXactKey;
  1042. RXactLog = RXactContext->RXactLog;
  1043. OperationCount = RXactLog->OperationCount;
  1044. HandlesValid = RXactContext->HandlesValid;
  1045. //
  1046. // Keep a pointer to the beginning of the current log entry.
  1047. //
  1048. RXactLogEntry = (PRXACT_LOG_ENTRY)((PCHAR)RXactLog + sizeof( RTL_RXACT_LOG ));
  1049. //
  1050. // Go through and perform each operation log. Notice that some operation
  1051. // logs may already have been deleted by a previous commit attempt.
  1052. // So, don't get alarmed if we don't successfully open some operation
  1053. // log entry keys.
  1054. //
  1055. for ( i=0 ; i<OperationCount ; i++ ) {
  1056. //
  1057. // Turn the self-relative offsets in the structure
  1058. // back into real pointers.
  1059. //
  1060. RXactLogEntry->SubKeyName.Buffer = (PWSTR) ((PCHAR)RXactLogEntry->SubKeyName.Buffer +
  1061. (ULONG_PTR)RXactLog);
  1062. RXactLogEntry->AttributeName.Buffer = (PWSTR) ((PCHAR)RXactLogEntry->AttributeName.Buffer +
  1063. (ULONG_PTR)RXactLog);
  1064. RXactLogEntry->NewKeyValue = (PVOID)((PCHAR)RXactLogEntry->NewKeyValue + (ULONG_PTR)RXactLog);
  1065. Operation = RXactLogEntry->Operation;
  1066. //
  1067. // Perform this operation
  1068. //
  1069. switch (Operation) {
  1070. case RtlRXactOperationDelete:
  1071. //
  1072. // Open the target key and delete it.
  1073. // The name is relative to the RootRegistryKey.
  1074. //
  1075. if ( ((RXactLogEntry->KeyHandle == INVALID_HANDLE_VALUE) || !HandlesValid) ) {
  1076. Status = RXactpOpenTargetKey(
  1077. RootRegistryKey,
  1078. RtlRXactOperationDelete,
  1079. &RXactLogEntry->SubKeyName,
  1080. &TargetKey
  1081. );
  1082. if ( !NT_SUCCESS(Status)) {
  1083. //
  1084. // We must allow the object not to be found,
  1085. // because we may be replaying this log after
  1086. // it had been partially executed.
  1087. //
  1088. if ( Status != STATUS_OBJECT_NAME_NOT_FOUND ) {
  1089. return( Status );
  1090. } else {
  1091. break;
  1092. }
  1093. }
  1094. CloseTargetKey = TRUE;
  1095. } else {
  1096. TargetKey = RXactLogEntry->KeyHandle;
  1097. CloseTargetKey = FALSE;
  1098. }
  1099. //
  1100. // If this fails, then it is an error
  1101. // because the key should exist at
  1102. // this point.
  1103. //
  1104. Status = NtDeleteKey( TargetKey );
  1105. //
  1106. // Only close the target key if we opened it
  1107. //
  1108. if ( CloseTargetKey ) {
  1109. TmpStatus = NtClose( TargetKey );
  1110. //
  1111. // If we opened this handle, then we should
  1112. // be able to close it, whether it has been
  1113. // deleted or not.
  1114. //
  1115. ASSERT(NT_SUCCESS(TmpStatus)); // safe to ignore, but curious...
  1116. }
  1117. if (!NT_SUCCESS(Status)) {
  1118. return(Status);
  1119. }
  1120. break;
  1121. case RtlRXactOperationSetValue:
  1122. //
  1123. // Open the target key.
  1124. // The name is relative to the RootRegistryKey.
  1125. //
  1126. if ( ((RXactLogEntry->KeyHandle == INVALID_HANDLE_VALUE) || !HandlesValid) ) {
  1127. Status = RXactpOpenTargetKey(
  1128. RootRegistryKey,
  1129. RtlRXactOperationSetValue,
  1130. &RXactLogEntry->SubKeyName,
  1131. &TargetKey
  1132. );
  1133. if ( !NT_SUCCESS(Status) ) {
  1134. return(Status);
  1135. }
  1136. CloseTargetKey = TRUE;
  1137. } else {
  1138. TargetKey = RXactLogEntry->KeyHandle;
  1139. CloseTargetKey = FALSE;
  1140. }
  1141. //
  1142. // Assign to the target key's new value
  1143. //
  1144. Status = NtSetValueKey( TargetKey,
  1145. &RXactLogEntry->AttributeName,
  1146. 0, // TitleIndex
  1147. RXactLogEntry->NewKeyValueType,
  1148. RXactLogEntry->NewKeyValue,
  1149. RXactLogEntry->NewKeyValueLength
  1150. );
  1151. //
  1152. // Only close the target key if we opened it
  1153. //
  1154. if ( CloseTargetKey ) {
  1155. TmpStatus = NtClose( TargetKey );
  1156. ASSERT(NT_SUCCESS(TmpStatus)); // safe to ignore, but curious...
  1157. }
  1158. if ( !NT_SUCCESS(Status) ) {
  1159. return(Status);
  1160. }
  1161. break;
  1162. default:
  1163. //
  1164. // Unknown operation type. This should never happen.
  1165. //
  1166. ASSERT( FALSE );
  1167. return(STATUS_INVALID_PARAMETER);
  1168. }
  1169. RXactLogEntry = (PRXACT_LOG_ENTRY)((PCHAR)RXactLogEntry + RXactLogEntry->LogEntrySize);
  1170. }
  1171. //
  1172. // Commit complete
  1173. //
  1174. return( STATUS_SUCCESS );
  1175. }
  1176. NTSTATUS
  1177. RXactpOpenTargetKey(
  1178. IN HANDLE RootRegistryKey,
  1179. IN RTL_RXACT_OPERATION Operation,
  1180. IN PUNICODE_STRING SubKeyName,
  1181. OUT PHANDLE TargetKey
  1182. )
  1183. /*++
  1184. Routine Description:
  1185. This routine opens the target registry key of an operation.
  1186. Arguments:
  1187. RootRegistryKey - A handle to the registry key within whose sub-tree
  1188. a transaction is to be initialized.
  1189. Operation - Indicates what operation is to be performed on the target.
  1190. This will effect how the target is opened.
  1191. OperationNameKey - A handle to the operation log sub-key
  1192. containing the name of the target registry key.
  1193. TargetKey - Receives a handle to the target registry key.
  1194. Return Value:
  1195. STATUS_SUCCESS - Indicates the operation log entry was opened.
  1196. STATUS_NO_MEMORY - Ran out of heap.
  1197. --*/
  1198. {
  1199. NTSTATUS Status;
  1200. OBJECT_ATTRIBUTES TargetKeyAttributes;
  1201. ACCESS_MASK DesiredAccess;
  1202. ULONG Disposition;
  1203. if (Operation == RtlRXactOperationDelete) {
  1204. DesiredAccess = DELETE;
  1205. InitializeObjectAttributes(
  1206. &TargetKeyAttributes,
  1207. SubKeyName,
  1208. OBJ_CASE_INSENSITIVE,
  1209. RootRegistryKey,
  1210. NULL);
  1211. // Status = RtlpNtOpenKey(
  1212. // TargetKey,
  1213. // DesiredAccess,
  1214. // &TargetKeyAttributes,
  1215. // 0);
  1216. Status = NtOpenKey( TargetKey,
  1217. DesiredAccess,
  1218. &TargetKeyAttributes
  1219. );
  1220. } else if (Operation == RtlRXactOperationSetValue) {
  1221. DesiredAccess = KEY_WRITE;
  1222. InitializeObjectAttributes(
  1223. &TargetKeyAttributes,
  1224. SubKeyName,
  1225. OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
  1226. RootRegistryKey,
  1227. NULL);
  1228. Status = NtCreateKey(
  1229. TargetKey,
  1230. DesiredAccess,
  1231. &TargetKeyAttributes,
  1232. 0,
  1233. NULL,
  1234. REG_OPTION_NON_VOLATILE,
  1235. &Disposition
  1236. );
  1237. } else {
  1238. return STATUS_INVALID_PARAMETER;
  1239. }
  1240. return( Status );
  1241. }
  1242. //NTSTATUS
  1243. //RXactpAssignTargetValue(
  1244. // IN PVOID NewKeyValue,
  1245. // IN ULONG NewKeyValueLength,
  1246. // IN ULONG NewKeyValueType,
  1247. // IN HANDLE TargetKey,
  1248. // IN PUNICODE_STRING AttributeName
  1249. // );
  1250. //NTSTATUS
  1251. //RXactpAssignTargetValue(
  1252. // IN PVOID NewKeyValue,
  1253. // IN ULONG NewKeyValueLength,
  1254. // IN ULONG NewKeyValueType,
  1255. // IN HANDLE TargetKey,
  1256. // IN PUNICODE_STRING AttributeName
  1257. // )
  1258. //
  1259. ///*++
  1260. //
  1261. //Routine Description:
  1262. //
  1263. // This routine copies the value of an operation log entry to its
  1264. // corresponding target key. The target key must already be open.
  1265. //
  1266. //Arguments:
  1267. //
  1268. // NewKeyValue - The new value for the key being modified.
  1269. //
  1270. // NewKeyValueLength - The size in bytes of the new value information.
  1271. //
  1272. // NewKeyValueType - The type of the data for the new key.
  1273. //
  1274. // TargetKey - A handle to the target registry key.
  1275. //
  1276. // AttributeName - Supplies the name of the key attribute being edited.
  1277. //
  1278. //Return Value:
  1279. //
  1280. // STATUS_SUCCESS - Indicates the value was successfully applied to
  1281. // the target registry key.
  1282. //
  1283. // STATUS_NO_MEMORY - ran out of heap.
  1284. //
  1285. //
  1286. //--*/
  1287. //{
  1288. // NTSTATUS Status;
  1289. //
  1290. // //
  1291. // // Now apply the value to the target key
  1292. // //
  1293. // // Even if there is no key value, we need to do the assign so that
  1294. // // the key value type is assigned.
  1295. // //
  1296. //
  1297. // Status = NtSetValueKey( TargetKey,
  1298. // AttributeName,
  1299. // 0, // TitleIndex
  1300. // NewKeyValueType,
  1301. // NewKeyValue,
  1302. // NewKeyValueLength
  1303. // );
  1304. //
  1305. //
  1306. // return( Status );
  1307. //}