Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

rxact.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 rxact.c 00008 00009 Abstract: 00010 00011 This Module implements a simple transaction mechanism for registry 00012 database operations which helps eliminate the possibility of partial 00013 updates being made. The cases covered are specifically partial updates 00014 caused by system crashes or program aborts during multiple-write updates. 00015 00016 00017 WARNING: This package does not yet deal with full-disk problems 00018 automatically. If a full disk is encountered during 00019 transaction commit, then manual interaction may be required 00020 to free enough space to complete the commit. There is 00021 no means provided for backing out the commit. 00022 00023 Author: 00024 00025 Jim Kelly (JimK) 15-May-1991 00026 Robert Reichel (RobertRe) 15-July-1992 00027 00028 Environment: 00029 00030 Pure Runtime Library Routine 00031 00032 Revision History: 00033 00034 00035 00036 --*/ 00037 00038 00039 /* 00041 00042 High Level Description: 00043 00044 The simple transaction mechanism expects the following to be true: 00045 00046 (1) A single server is responsible for operations on an entire 00047 sub-tree of the registry database. For example, the security 00048 account manager server (SAM) is responsible for everything 00049 below \REGISTRY\LOCAL_MACHINE\SECURITY\SAM. 00050 00051 (2) Transactions on the sub-tree are serialized by the server 00052 responsible for the sub-tree. That is, the server will not 00053 start a second user request until all previous user requests 00054 have been completed. 00055 00056 The simple transaction mechanism helps eliminate the problem of partial 00057 updates caused by system crash or program abort during multiple-write 00058 updates to the registry database. This is achieved by: 00059 00060 (1) Keeping all actions in-memory until instructed to commit. The 00061 presence of in-memory data structures implicitly indicates 00062 that a transaction is in progress. 00063 00064 The initial state is no transaction in progress. 00065 00066 (2) Providing a service which allows a server to initiate a transaction. 00067 This allocates in-memory data structures, thereby changing the 00068 state to transaction in progress. 00069 00070 (3) Keeping a log of all keys in the sub-tree that are to be 00071 updated in a single transaction. Each record in this log 00072 contains the following information: 00073 00074 (a) The name of the sub-key effected 00075 00076 (b) The operation to be performed on the sub-key 00077 either DELETE or SET_VALUE. Note that these 00078 operations are idempotent and may be applied 00079 again in the event that the server aborts during 00080 an initial commit. 00081 00082 (c) The new value of the sub-key (if applicable) 00083 00084 (d) (optionally) The attribute name of the subkey 00085 to be operated on. 00086 00087 (note that SET_VALUE is used to create new sub-keys 00088 as well as updated existing ones). 00089 00090 The entire list of sub-keys to be modified must be entered 00091 into this log before ANY of the sub-keys is actually modified. 00092 00093 (4) Providing a commit service that applies all changes indicated 00094 in the change log. This is done by first writing the contents 00095 of the in-memory structures to a single key value ("Log") in 00096 the registry and flushing the data to disk. The presence of 00097 the "Log" value and data imply that a commit is in progress. 00098 00099 All necessary changes are applied, the "Log" value and its 00100 data are deleted, and in-memory data structres are freed, 00101 thereby changing the state to no-transaction. 00102 00103 00104 The package also includes a service which must be called upon server 00105 startup. This service checks to make sure the state of the sub-tree 00106 is NO_TRANSACTION. If it is not, then one of the actions below is 00107 performed based upon the current state of the sub-tree: 00108 00109 COMMITTING - This means the server was previously aborted while 00110 a transaction was being committed (applied to the registry). 00111 In this case, the commit is performed again from the beginning 00112 of the change log. After the commit is completed, the state 00113 of the sub-tree is set to NO_TRANSACTION. 00114 00116 */ 00117 00118 00119 00120 /* 00122 00123 Detailed Description: 00124 00125 Registry State 00126 -------------- 00127 00128 The registry state of a subtree is kept in a sub-key of that tree 00129 named: 00130 00131 "RXACT" 00132 00133 The value field of that registry key includes a revision field. 00134 00135 00136 RXact Context 00137 ------------- 00138 00139 A call to RtlInitializeRXact will return a pointer to an 00140 RTL_RXACT_CONTEXT structure. This structure contains: 00141 00142 (1) the passed RootRegistryKey (eg, key to "Sam"), 00143 00144 (2) a handle to the top of the RXact subtree (eg, key to 00145 "Sam\RXACT"), 00146 00147 (3) a flag indicating if handles stored in the log are 00148 valid, 00149 00150 (4) a pointer to the current RXactLog. 00151 00152 The subsystem calling RtlInitializeRXact must keep this returned 00153 pointer and pass it back to RXact in all subsequent calls. 00154 00155 00156 Operation Log 00157 ------------- 00158 00159 The operation log of a registry sub-tree transaction is kept as sequence 00160 of "operation log entries". 00161 00162 An in-memory log is a block of heap memory allocted by RtlStartRXact. 00163 It has a header which contains: 00164 00165 (1) The count of operations in the log. 00166 00167 (2) The maximum size of the log. 00168 00169 (3) The amount of the log currently in use. 00170 00171 The log data itself follows the header directly. 00172 00173 00174 Operation Log Entries 00175 --------------------- 00176 00177 An operation log entry is described by the following structure: 00178 00179 typedef struct _RXACT_LOG_ENTRY { 00180 ULONG LogEntrySize; 00181 RTL_RXACT_OPERATION Operation; 00182 UNICODE_STRING SubKeyName; // Self-relativized (Buffer is really offset) 00183 UNICODE_STRING AttributeName; // Self-relativized (Buffer is really offset) 00184 HANDLE KeyHandle; // optional, not valid if read from disk. 00185 ULONG NewKeyValueType; 00186 ULONG NewKeyValueLength; 00187 PVOID NewKeyValue; // Contains offset to data from start of log 00188 } RXACT_LOG_ENTRY, *PRXACT_LOG_ENTRY; 00189 00190 The log entry contains all of the information passed in during a call 00191 to RtlAddActionToRXact or RtlAddAttributeActionToRXact. 00192 00193 The UNICODE_STRING structures contain an offset to the string data 00194 rather than a pointer. These offsets are relative to the start of 00195 the log data, and are adjusted in place as each log entry is commited. 00196 00197 The KeyHandle is valid if it is not equal to INVALID_HANDLE_VALUE and 00198 if the HandlesValid flag in the RXactContext structure is TRUE. This 00199 is so that we do not attempt to use the handles if the log has been 00200 read from disk after a reboot. 00201 00202 00204 */ 00205 00206 00207 #include "ntrtlp.h" 00208 00209 // 00210 // Cannot include <windows.h> from kernel code 00211 // 00212 #define INVALID_HANDLE_VALUE (HANDLE)-1 00213 00214 00215 00216 00217 00219 // // 00220 // Local Macros & Definitions // 00221 // // 00223 00224 // 00225 // Revision level of a registry transaction . 00226 // 00227 00228 #define RTLP_RXACT_REVISION1 (1l) 00229 #define RTLP_RXACT_CURRENT_REVISION RTLP_RXACT_REVISION1 00230 00231 00232 #define RTLP_RXACT_KEY_NAME L"RXACT" 00233 00234 #define RTLP_RXACT_LOG_NAME L"Log" 00235 00236 #define RTLP_INITIAL_LOG_SIZE 0x4000 00237 00238 // 00239 // Given a value return its longword aligned equivalent value 00240 // 00241 00242 #define DwordAlign(Value) ( \ 00243 (ULONG)((((ULONG)(Value)) + 3) & 0xfffffffc) \ 00244 ) 00245 00246 // 00247 // The value field of the RXACT registry key is one of the following data 00248 // structures. 00249 // 00250 00251 // 00252 // The state of a registry sub-tree is one of the following: 00253 // 00254 // RtlpRXactStateNoTransaction - There is not a transaction in progress. 00255 // 00256 // RtlpRXactStateCommitting - The actions of a transaction are being 00257 // applied to the registry database. 00258 // 00259 00260 typedef enum _RTLP_RXACT_STATE { 00261 RtlpRXactStateNoTransaction = 2, 00262 RtlpRXactStateCommitting 00263 } RTLP_RXACT_STATE, *PRTLP_RXACT_STATE; 00264 00265 00266 typedef struct _RTLP_RXACT { 00267 ULONG Revision; 00268 RTLP_RXACT_STATE State; // no longer used 00269 ULONG OperationCount; // no longer used 00270 } RTLP_RXACT, *PRTLP_RXACT; 00271 00272 00273 typedef struct _RXACT_LOG_ENTRY { 00274 ULONG LogEntrySize; 00275 RTL_RXACT_OPERATION Operation; 00276 UNICODE_STRING SubKeyName; // Self-relativized (Buffer is really offset) 00277 UNICODE_STRING AttributeName; // Self-relativized (Buffer is really offset) 00278 HANDLE KeyHandle; // optional, not valid if read from disk. 00279 ULONG NewKeyValueType; 00280 ULONG NewKeyValueLength; 00281 PVOID NewKeyValue; // Contains offset to data from start of log 00282 } RXACT_LOG_ENTRY, *PRXACT_LOG_ENTRY; 00283 00284 00285 00286 00288 // // 00289 // Prototypes for local procedures // 00290 // // 00292 00293 00294 00295 00296 NTSTATUS 00297 RXactpCommit( 00298 IN PRTL_RXACT_CONTEXT RXactContext 00299 ); 00300 00301 NTSTATUS 00302 RXactpOpenTargetKey( 00303 IN HANDLE RootRegistryKey, 00304 IN RTL_RXACT_OPERATION Operation, 00305 IN PUNICODE_STRING SubKeyName, 00306 OUT PHANDLE TargetKey 00307 ); 00308 00309 00310 00311 VOID 00312 RXactInitializeContext( 00313 IN PRTL_RXACT_CONTEXT RXactContext, 00314 IN HANDLE RootRegistryKey, 00315 IN HANDLE RXactKey 00316 ); 00317 00318 00319 #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME) 00320 #pragma alloc_text(PAGE,RXactpCommit) 00321 #pragma alloc_text(PAGE,RXactpOpenTargetKey) 00322 #pragma alloc_text(PAGE,RXactInitializeContext) 00323 #pragma alloc_text(PAGE,RtlInitializeRXact) 00324 #pragma alloc_text(PAGE,RtlStartRXact) 00325 #pragma alloc_text(PAGE,RtlAbortRXact) 00326 #pragma alloc_text(PAGE,RtlAddAttributeActionToRXact) 00327 #pragma alloc_text(PAGE,RtlAddActionToRXact) 00328 #pragma alloc_text(PAGE,RtlApplyRXact) 00329 #pragma alloc_text(PAGE,RtlApplyRXactNoFlush) 00330 #endif 00331 00332 00334 // // 00335 // Exported Procedures (defined in ntrtl.h) // 00336 // // 00338 00339 00340 NTSTATUS 00341 RtlInitializeRXact( 00342 IN HANDLE RootRegistryKey, 00343 IN BOOLEAN CommitIfNecessary, 00344 OUT PRTL_RXACT_CONTEXT *RXactContext 00345 ) 00346 00347 /*++ 00348 00349 Routine Description: 00350 00351 This routine should be called by a server exactly once when it starts. 00352 This routine will check to see that the registry transaction information 00353 exists for the specified registry sub-tree, and will create it if it 00354 doesn't exist. 00355 00356 Arguments: 00357 00358 RootRegistryKey - A handle to the registry key within whose sub-tree 00359 a transaction is to be initialized. 00360 00361 CommitIfNecessary - A BOOLEAN value indicating whether or not any 00362 previously aborted commit discovered should be commited at this 00363 time. A value of TRUE indicates the commit should be applied 00364 if encountered. A value of FALSE indicates a previously 00365 aborted COMMIT should not be committed at this time. 00366 00367 RXactContext - Returns a pointer to an RTL_RXACT_CONTEXT structure 00368 allocated out of the local heap. The caller must keep this 00369 pointer and pass it back in for all future RXact transactions 00370 for the passed RootRegistryKey. 00371 00372 00373 Return Value: 00374 00375 STATUS_SUCCESS - Indicates the transaction state already exists for the 00376 registry sub-tree and is already in the NO_TRANSACTION state. 00377 00378 STATUS_UNKNOWN_REVISION - Indicates that a transaction state already 00379 exists for the specified sub-tree, but is a revision level that is 00380 unknown by this service. 00381 00382 STATUS_RXACT_STATE_CREATED - This informational level status indicates 00383 that a specified registry sub-tree transaction state did not yet 00384 exist and had to be created. 00385 00386 STATUS_RXACT_COMMIT_NECESSARY - This warning level status indicates that the 00387 transaction state already exists for the registry sub-tree, but that 00388 a transaction commit was previously aborted. The commit has NOT been 00389 completed. Another call to this service with a CommitIfNecessary value 00390 of TRUE may be used to commit the transaction. 00391 00392 00393 STATUS_RXACT_INVALID_STATE - Indicates that the transaction state 00394 of the registry sub-tree is incompatible with the requested operation. 00395 For example, a request to start a new transaction while one is already 00396 in progress, or a request to apply a transaction when one is not 00397 currently in progress. 00398 00399 --*/ 00400 00401 { 00402 00403 HANDLE RXactKey; 00404 LARGE_INTEGER LastWriteTime; 00405 NTSTATUS Status, TmpStatus; 00406 OBJECT_ATTRIBUTES RXactAttributes; 00407 PKEY_VALUE_FULL_INFORMATION FullInformation; 00408 RTLP_RXACT RXactKeyValue; 00409 UCHAR BasicInformation[128]; // Should be more than long enough 00410 ULONG Disposition; 00411 ULONG KeyValueLength; 00412 ULONG KeyValueType; 00413 ULONG ResultLength; 00414 UNICODE_STRING RXactKeyName; 00415 UNICODE_STRING ValueName; 00416 UNICODE_STRING NullName; 00417 00418 RTL_PAGED_CODE(); 00419 00420 // 00421 // Initialize some stuff 00422 // 00423 00424 KeyValueLength = (ULONG)sizeof( RTLP_RXACT ); 00425 KeyValueType = 0; // Not used by RXact 00426 00427 RtlInitUnicodeString( &NullName, NULL ); 00428 00429 // 00430 // Create or open the RXACT key. 00431 // 00432 00433 RtlInitUnicodeString( &RXactKeyName, RTLP_RXACT_KEY_NAME); 00434 00435 InitializeObjectAttributes( 00436 &RXactAttributes, 00437 &RXactKeyName, 00438 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 00439 RootRegistryKey, 00440 NULL); 00441 00442 // Status = RtlpNtCreateKey( 00443 // &RXactKey, 00444 // (KEY_READ | KEY_WRITE | DELETE), 00445 // &RXactAttributes, 00446 // 0, 00447 // NULL, 00448 // &Disposition 00449 // ); 00450 00451 Status = NtCreateKey( &RXactKey, 00452 (KEY_READ | KEY_WRITE | DELETE), 00453 &RXactAttributes, 00454 0, //TitleIndex 00455 NULL, //Class OPTIONAL, 00456 REG_OPTION_NON_VOLATILE, //CreateOptions, 00457 &Disposition 00458 ); 00459 00460 if ( !NT_SUCCESS(Status) ) { 00461 return(Status); 00462 } 00463 00464 // 00465 // Allocate the RXactContext block 00466 // 00467 00468 *RXactContext = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( RTL_RXACT_CONTEXT )); 00469 00470 if ( *RXactContext == NULL ) { 00471 00472 // 00473 // Something prevented value assignment... 00474 // Get rid of the RXact key and return the error 00475 // 00476 00477 TmpStatus = NtDeleteKey( RXactKey ); 00478 ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group 00479 TmpStatus = NtClose( RXactKey ); 00480 ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group 00481 00482 return( STATUS_NO_MEMORY ); 00483 } 00484 00485 // 00486 // Initialize the newly created RXactContext structure. 00487 // 00488 00489 RXactInitializeContext( *RXactContext, RootRegistryKey, RXactKey ); 00490 00491 // 00492 // If we created (as opposed to opened an existing) rxact key, 00493 // then we need to initialize it. 00494 // 00495 00496 if ( Disposition == REG_CREATED_NEW_KEY ) { 00497 00498 RXactKeyValue.Revision = RTLP_RXACT_REVISION1; 00499 00500 Status = NtSetValueKey( RXactKey, 00501 &NullName, // ValueName 00502 0, // TitleIndex 00503 KeyValueType, 00504 &RXactKeyValue, 00505 KeyValueLength 00506 ); 00507 00508 if ( !NT_SUCCESS(Status) ) { 00509 00510 // 00511 // Something prevented value assignment... 00512 // Get rid of the RXact key and return the error 00513 // 00514 00515 TmpStatus = NtDeleteKey( RXactKey ); 00516 ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group 00517 TmpStatus = NtClose( RXactKey ); 00518 ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group 00519 00520 RtlFreeHeap( RtlProcessHeap(), 0, *RXactContext ); 00521 00522 return( Status ); 00523 } 00524 00525 return( STATUS_RXACT_STATE_CREATED ); 00526 } 00527 00528 00529 00530 // 00531 // We have opened an existing RXACT key. 00532 // See if it is a revision level we know about. 00533 // 00534 00535 Status = RtlpNtQueryValueKey( 00536 RXactKey, // KeyHandle 00537 &KeyValueType, // KeyValueType 00538 &RXactKeyValue, // KeyValue 00539 &KeyValueLength, // KeyValueLength 00540 &LastWriteTime // LastWriteTime 00541 ); 00542 00543 00544 if ( !NT_SUCCESS(Status) ) { 00545 00546 // 00547 // Something prevented value query... 00548 // 00549 00550 TmpStatus = NtClose( RXactKey ); 00551 ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group 00552 RtlFreeHeap( RtlProcessHeap(), 0, *RXactContext ); 00553 return( Status ); 00554 } 00555 00556 00557 if ( KeyValueLength != (ULONG)sizeof(RTLP_RXACT) ) { 00558 TmpStatus = NtClose( RXactKey ); 00559 ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group 00560 RtlFreeHeap( RtlProcessHeap(), 0, *RXactContext ); 00561 return( STATUS_UNKNOWN_REVISION ); 00562 } 00563 00564 if (RXactKeyValue.Revision != RTLP_RXACT_REVISION1) { 00565 TmpStatus = NtClose( RXactKey ); 00566 ASSERT(NT_SUCCESS(TmpStatus)); //Safe to ignore, notify security group 00567 RtlFreeHeap( RtlProcessHeap(), 0, *RXactContext ); 00568 return( STATUS_UNKNOWN_REVISION ); 00569 } 00570 00571 00572 00573 // 00574 // Right revision... 00575 // See if there is a transaction or commit in progress. If not, 00576 // return success 00577 // 00578 00579 // 00580 // If a log file exists, then we are committing. 00581 // 00582 00583 RtlInitUnicodeString( &ValueName, RTLP_RXACT_LOG_NAME ); 00584 00585 Status = NtQueryValueKey( 00586 RXactKey, 00587 &ValueName, 00588 KeyValueBasicInformation, 00589 &BasicInformation, 00590 128, 00591 &ResultLength 00592 ); 00593 00594 if ( NT_SUCCESS( Status )) { 00595 00596 // 00597 // We found a value called 'Log'. This means that a commit 00598 // was in progress. 00599 // 00600 00601 if ( CommitIfNecessary ) { 00602 00603 // 00604 // Query the full value of the log, then call a low level routine 00605 // to actually perform the commit. 00606 // 00607 00608 Status = NtQueryValueKey( 00609 RXactKey, 00610 &ValueName, 00611 KeyValueFullInformation, 00612 NULL, 00613 0, 00614 &ResultLength 00615 ); 00616 00617 if ( Status != STATUS_BUFFER_TOO_SMALL ) { 00618 return( Status ); 00619 } 00620 00621 FullInformation = RtlAllocateHeap( RtlProcessHeap(), 0, ResultLength ); 00622 00623 if ( FullInformation == NULL ) { 00624 return( STATUS_NO_MEMORY ); 00625 } 00626 00627 00628 Status = NtQueryValueKey( 00629 RXactKey, 00630 &ValueName, 00631 KeyValueFullInformation, 00632 FullInformation, 00633 ResultLength, 00634 &ResultLength 00635 ); 00636 00637 if ( !NT_SUCCESS( Status )) { 00638 00639 RtlFreeHeap( RtlProcessHeap(), 0, FullInformation ); 00640 RtlFreeHeap( RtlProcessHeap(), 0, *RXactContext ); 00641 return( Status ); 00642 } 00643 00644 // 00645 // The log information is buried in the returned FullInformation 00646 // buffer. Dig it out and make the RXactLog in the RXactContext 00647 // structure point to it. Then commit. 00648 // 00649 00650 (*RXactContext)->RXactLog = (PRTL_RXACT_LOG)((PCHAR)FullInformation + FullInformation->DataOffset); 00651 00652 // 00653 // Don't use any handles we may find in the log file 00654 // 00655 00656 (*RXactContext)->HandlesValid = FALSE; 00657 00658 Status = RXactpCommit( *RXactContext ); 00659 00660 if ( !NT_SUCCESS( Status )) { 00661 00662 RtlFreeHeap( RtlProcessHeap(), 0, FullInformation ); 00663 RtlFreeHeap( RtlProcessHeap(), 0, *RXactContext ); 00664 return( Status ); 00665 } 00666 00667 00668 // 00669 // The commit was successful. Clean up. 00670 // Delete the log file value and data 00671 // 00672 00673 Status = NtDeleteValueKey( RXactKey, &ValueName ); 00674 00675 // 00676 // This should never fail 00677 // 00678 00679 ASSERT( NT_SUCCESS( Status )); 00680 00681 // 00682 // Get rid of the in memory data structures. Abort 00683 // will free the RXactLog, so put what we want 00684 // freed in there and it will go away. 00685 // 00686 00687 (*RXactContext)->RXactLog = (PRTL_RXACT_LOG)FullInformation; 00688 00689 Status = RtlAbortRXact( *RXactContext ); 00690 00691 // 00692 // This should never fail 00693 // 00694 00695 ASSERT( NT_SUCCESS( Status )); 00696 return( Status ); 00697 } else { 00698 00699 return( STATUS_RXACT_COMMIT_NECESSARY ); 00700 } 00701 00702 } else { 00703 00704 // 00705 // No log, so nothing to do here. 00706 // 00707 00708 return( STATUS_SUCCESS ); 00709 } 00710 00711 } 00712 00713 00714 00715 VOID 00716 RXactInitializeContext( 00717 IN PRTL_RXACT_CONTEXT RXactContext, 00718 IN HANDLE RootRegistryKey, 00719 IN HANDLE RXactKey 00720 ) 00721 00722 /*++ 00723 00724 Routine Description: 00725 00726 Initializes an in-memory RXactContext structure. 00727 00728 Arguments: 00729 00730 RXactContext - Supplies a pointer to an RXact Context created 00731 by RtlInitializeRXact. 00732 00733 RootRegistryKey - Supplies the RootRegistryKey for this component. 00734 00735 RXactKey - Supplies the {RootRegistryKey}\RXactKey for this component 00736 00737 00738 Return Value: 00739 00740 None. 00741 00742 --*/ 00743 00744 { 00745 // 00746 // Initialize the RXactContext for this client 00747 // 00748 00749 RXactContext->RootRegistryKey = RootRegistryKey; 00750 RXactContext->HandlesValid = TRUE; 00751 RXactContext->RXactLog = NULL; 00752 RXactContext->RXactKey = RXactKey; 00753 00754 return; 00755 } 00756 00757 00758 00759 NTSTATUS 00760 RtlStartRXact( 00761 IN PRTL_RXACT_CONTEXT RXactContext 00762 ) 00763 00764 /*++ 00765 00766 Routine Description: 00767 00768 This routine is used to start a new transaction in a registry sub-tree. 00769 Transactions must be serialized by the server so that only one transaction 00770 is in progress at a time. 00771 00772 Arguments: 00773 00774 RXactContext - Supplies a pointer to an RTL_RXACT_CONTEXT structure 00775 that is not currently in use. 00776 00777 Return Value: 00778 00779 STATUS_SUCCESS - Indicates the transaction was started. 00780 00781 STATUS_RXACT_INVALID_STATE - Indicates that the transaction state 00782 of the registry sub-tree is incompatible with the requested operation. 00783 For example, a request to start a new transaction while one is already 00784 in progress, or a request to apply a transaction when one is not 00785 currently in progress. This may also indicate that there is no 00786 transaction state at all for the specified registry sub-tree. 00787 00788 --*/ 00789 { 00790 PRTL_RXACT_LOG RXactLogHeader; 00791 00792 RTL_PAGED_CODE(); 00793 00794 // 00795 // Allocate in-memory log file and initialize. This implicitly 00796 // sets the state to 'transaction in progress'. 00797 // 00798 00799 if ( RXactContext->RXactLog != NULL ) { 00800 00801 // 00802 // There is already a transaction in progress for this 00803 // context. Return an error. 00804 // 00805 00806 return( STATUS_RXACT_INVALID_STATE ); 00807 } 00808 00809 RXactLogHeader = RtlAllocateHeap( RtlProcessHeap(), 0, RTLP_INITIAL_LOG_SIZE ); 00810 00811 if ( RXactLogHeader == NULL ) { 00812 return( STATUS_NO_MEMORY ); 00813 } 00814 00815 // 00816 // Fill in the log header information at the top of the 00817 // newly allocated buffer. 00818 // 00819 00820 00821 RXactLogHeader->OperationCount = 0; 00822 RXactLogHeader->LogSize = RTLP_INITIAL_LOG_SIZE; 00823 RXactLogHeader->LogSizeInUse = sizeof( RTL_RXACT_LOG ); 00824 00825 RXactContext->RXactLog = RXactLogHeader; 00826 00827 return( STATUS_SUCCESS ); 00828 00829 } 00830 00831 00832 NTSTATUS 00833 RtlAbortRXact( 00834 IN PRTL_RXACT_CONTEXT RXactContext 00835 ) 00836 00837 /*++ 00838 00839 Routine Description: 00840 00841 This routine is used to abort a transaction in a registry sub-tree. 00842 00843 Arguments: 00844 00845 RootRegistryKey - A handle to the registry key within whose sub-tree 00846 the transaction is to be aborted. 00847 00848 Return Value: 00849 00850 STATUS_SUCCESS - Indicates the transaction was aborted. 00851 00852 00853 STATUS_UNKNOWN_REVISION - Indicates that a transaction state 00854 exists for the specified sub-tree, but has a revision level that is 00855 unknown by this service. 00856 00857 00858 STATUS_RXACT_INVALID_STATE - Indicates that the transaction state 00859 of the registry sub-tree is incompatible with the requested operation. 00860 For example, a request to start a new transaction while one is already 00861 in progress, or a request to apply a transaction when one is not 00862 currently in progress. This may also indicate that there is no 00863 transaction state at all for the specified registry sub-tree. 00864 00865 --*/ 00866 00867 { 00868 RTL_PAGED_CODE(); 00869 00870 if ( RXactContext->RXactLog == NULL ) { 00871 00872 // 00873 // There is no transaction in progress for this 00874 // context. Return an error. 00875 // 00876 00877 return( STATUS_RXACT_INVALID_STATE ); 00878 } 00879 00880 (VOID) RtlFreeHeap( RtlProcessHeap(), 0, RXactContext->RXactLog ); 00881 00882 // 00883 // Reinitialize the RXactContext structure with the same initial data. 00884 // 00885 00886 RXactInitializeContext( 00887 RXactContext, 00888 RXactContext->RootRegistryKey, 00889 RXactContext->RXactKey 00890 ); 00891 00892 00893 return( STATUS_SUCCESS ); 00894 00895 } 00896 00897 00898 00899 NTSTATUS 00900 RtlAddAttributeActionToRXact( 00901 IN PRTL_RXACT_CONTEXT RXactContext, 00902 IN RTL_RXACT_OPERATION Operation, 00903 IN PUNICODE_STRING SubKeyName, 00904 IN HANDLE KeyHandle OPTIONAL, 00905 IN PUNICODE_STRING AttributeName, 00906 IN ULONG NewValueType, 00907 IN PVOID NewValue, 00908 IN ULONG NewValueLength 00909 ) 00910 00911 /*++ 00912 00913 Routine Description: 00914 00915 This routine is used to add a new action to the transaction operation log. 00916 Upon commit, these operations are applied in the order they are added 00917 to the log. 00918 00919 This routine differs from RtlAddActionToRXact in that it takes an Attribute 00920 Name parameter, rather than using the default ("NULL") Attribute of the 00921 specified key. 00922 00923 00924 Arguments: 00925 00926 RXactContext - Supplies a pointer to the RXactContext structure for this 00927 subsystem's root registry key. 00928 00929 Operation - Indicates the type of operation to perform (e.g., delete 00930 a sub-key or set the value of a sub-key). Sub-keys may be created 00931 by setting a value of a previously non-existent sub-key. This will 00932 cause all sub-keys between the root and the specified sub-key to 00933 be created. 00934 00935 SubKeyName - Specifies the name of the target registry key. This name 00936 is relative to the Root of the Registry transaction sub-tree 00937 and must NOT start with a delimiter character ("\"). 00938 00939 KeyHandle - Optionally supplies a handle to the target key. If 00940 not specified, the name passed for SubKeyName will determine 00941 the target key. 00942 00943 AttributeName - Supplies the name of the key attribute to be 00944 modified. 00945 00946 NewKeyValueType - (Optional) Contains the KeyValueType to assign 00947 to the target registry key. This parameter is ignored if the 00948 Operation is not RtlRXactOperationSetValue. 00949 00950 NewKeyValue - (Optional) Points to a buffer containing the value 00951 to assign to the specified target registry key. This parameter 00952 is ignored if the Operation is not RtlRXactOperationSetValue. 00953 00954 NewKeyValueLength - Indicates the length (number of bytes) of the 00955 NewKeyValue buffer. This parameter is ignored if the Operation 00956 is not RtlRXactOperationSetValue. 00957 00958 00959 Return Value: 00960 00961 STATUS_SUCCESS - Indicates the request completed successfully.. 00962 00963 STATUS_INVALID_PARAMETER - Indicates that an unknown Operation 00964 was requested. 00965 00966 STATUS_NO_MEMORY - Insufficient memeory was available to complete 00967 this operation. 00968 00969 STATUS_UNKNOWN_REVISION - Indicates that a transaction state 00970 exists for the specified sub-tree, but has a revision level that is 00971 unknown by this service. 00972 00973 00974 --*/ 00975 00976 { 00977 00978 PRTL_RXACT_LOG NewLog; 00979 PRXACT_LOG_ENTRY Base; 00980 00981 ULONG End; 00982 ULONG LogEntrySize; 00983 ULONG NewLogSize; 00984 00985 RTL_PAGED_CODE(); 00986 00987 // 00988 // Make sure we were passed a legitimate operation. 00989 // 00990 00991 if ( (Operation != RtlRXactOperationDelete) && 00992 (Operation != RtlRXactOperationSetValue) ) { 00993 return STATUS_INVALID_PARAMETER; 00994 } 00995 00996 // 00997 // Compute the total size of the new data 00998 // 00999 01000 LogEntrySize = sizeof( RXACT_LOG_ENTRY ) + 01001 DwordAlign( SubKeyName->Length ) + 01002 DwordAlign( AttributeName->Length ) + 01003 DwordAlign( NewValueLength ); 01004 01005 LogEntrySize = ALIGN_UP( LogEntrySize, PVOID ); 01006 01007 // 01008 // Make sure there is enough space in the current 01009 // log file for this data. If not, we must create 01010 // a larger log, copy all the old data, and then 01011 // append this to the end. 01012 // 01013 01014 if ( RXactContext->RXactLog->LogSizeInUse + LogEntrySize > 01015 RXactContext->RXactLog->LogSize ) { 01016 01017 // 01018 // We must allocate a bigger log file. 01019 // 01020 01021 NewLogSize = RXactContext->RXactLog->LogSize; 01022 01023 do { 01024 01025 NewLogSize = NewLogSize * 2; 01026 01027 } while ( NewLogSize < 01028 ( RXactContext->RXactLog->LogSizeInUse + LogEntrySize ) ); 01029 01030 NewLog = RtlAllocateHeap( RtlProcessHeap(), 0, NewLogSize ); 01031 01032 if ( NewLog == NULL ) { 01033 return( STATUS_NO_MEMORY ); 01034 } 01035 01036 // 01037 // Copy over previous information 01038 // 01039 01040 RtlMoveMemory( NewLog, RXactContext->RXactLog, RXactContext->RXactLog->LogSizeInUse ); 01041 01042 // 01043 // Free the old log file 01044 // 01045 01046 RtlFreeHeap( RtlProcessHeap(), 0, RXactContext->RXactLog ); 01047 01048 // 01049 // Install the new log file and adjust its size in its header 01050 // 01051 01052 RXactContext->RXactLog = NewLog; 01053 RXactContext->RXactLog->LogSize = NewLogSize; 01054 } 01055 01056 // 01057 // The log file is big enough, append data to 01058 // the end. 01059 // 01060 01061 Base = (PRXACT_LOG_ENTRY)((PCHAR)(RXactContext->RXactLog) + 01062 (RXactContext->RXactLog->LogSizeInUse)); 01063 01064 01065 // 01066 // Append each parameter to the end of the log. Unicode string data 01067 // will be appended to the end of the entry. The Buffer field in the 01068 // Unicode string structure will contain the offset to the Buffer, 01069 // relative to the beginning of the log file. 01070 // 01071 01072 Base->LogEntrySize = LogEntrySize; 01073 Base->Operation = Operation; 01074 Base->SubKeyName = *SubKeyName; 01075 Base->AttributeName = *AttributeName; 01076 Base->NewKeyValueType = NewValueType; 01077 Base->NewKeyValueLength = NewValueLength; 01078 Base->KeyHandle = KeyHandle; 01079 01080 // 01081 // Fill in the variable length data: SubKeyName, AttributeName, 01082 // and NewKeyValue 01083 // 01084 01085 // 01086 // End is an offset relative to the beginning of the entire log 01087 // structure. It is initialized to 'point' to the offset immediately 01088 // following the structure we just filled in above. 01089 // 01090 01091 End = (ULONG)((RXactContext->RXactLog->LogSizeInUse) + 01092 sizeof( *Base )); 01093 01094 01095 // 01096 // Append SubKeyName information to the log file 01097 // 01098 01099 RtlMoveMemory ( 01100 (PCHAR)(RXactContext->RXactLog) + End, 01101 SubKeyName->Buffer, 01102 SubKeyName->Length 01103 ); 01104 01105 Base->SubKeyName.Buffer = (PWSTR)ULongToPtr(End); 01106 End += DwordAlign( SubKeyName->Length ); 01107 01108 01109 01110 // 01111 // Append AttributeName information to the log file 01112 // 01113 01114 01115 RtlMoveMemory( 01116 (PCHAR)(RXactContext->RXactLog) + End, 01117 AttributeName->Buffer, 01118 AttributeName->Length 01119 ); 01120 01121 Base->AttributeName.Buffer = (PWSTR)ULongToPtr(End); 01122 End += DwordAlign( AttributeName->Length ); 01123 01124 01125 01126 // 01127 // Append NewKeyValue information (if present) to the log file 01128 // 01129 01130 if ( Operation == RtlRXactOperationSetValue ) { 01131 01132 RtlMoveMemory( 01133 (PCHAR)(RXactContext->RXactLog) + End, 01134 NewValue, 01135 NewValueLength 01136 ); 01137 01138 Base->NewKeyValue = (PVOID)ULongToPtr(End); 01139 End += DwordAlign( NewValueLength ); 01140 } 01141 01142 End = ALIGN_UP( End, PVOID ); 01143 01144 RXactContext->RXactLog->LogSizeInUse = End; 01145 RXactContext->RXactLog->OperationCount++; 01146 01147 // 01148 // We're done 01149 // 01150 01151 return(STATUS_SUCCESS); 01152 } 01153 01154 01155 NTSTATUS 01156 RtlAddActionToRXact( 01157 IN PRTL_RXACT_CONTEXT RXactContext, 01158 IN RTL_RXACT_OPERATION Operation, 01159 IN PUNICODE_STRING SubKeyName, 01160 IN ULONG NewKeyValueType, 01161 IN PVOID NewKeyValue OPTIONAL, 01162 IN ULONG NewKeyValueLength 01163 ) 01164 01165 /*++ 01166 01167 Routine Description: 01168 01169 This routine is used to add a new action to the transaction operation log. 01170 Upon commit, these operations are applied in the order they are added 01171 to the log. 01172 01173 Arguments: 01174 01175 RXactContext - Supplies a pointer to the RXactContext structure for this 01176 subsystem's root registry key. 01177 01178 Operation - Indicates the type of operation to perform (e.g., delete 01179 a sub-key or set the value of a sub-key). Sub-keys may be created 01180 by setting a value of a previously non-existent sub-key. This will 01181 cause all sub-keys between the root and the specified sub-key to 01182 be created. 01183 01184 SubKeyName - Specifies the name of the target registry key. This name 01185 is relative to the Root of the Registry transaction sub-tree 01186 and must NOT start with a delimiter character ("\"). 01187 01188 NewKeyValueType - (Optional) Contains the KeyValueType to assign 01189 to the target registry key. This parameter is ignored if the 01190 Operation is not RtlRXactOperationSetValue. 01191 01192 NewKeyValue - (Optional) Points to a buffer containing the value 01193 to assign to the specified target registry key. This parameter 01194 is ignored if the Operation is not RtlRXactOperationSetValue. 01195 01196 NewKeyValueLength - Indicates the length (number of bytes) of the 01197 NewKeyValue buffer. This parameter is ignored if the Operation 01198 is not RtlRXactOperationSetValue. 01199 01200 Return Value: 01201 01202 STATUS_SUCCESS - Indicates the request completed successfully.. 01203 01204 01205 STATUS_UNKNOWN_REVISION - Indicates that a transaction state 01206 exists for the specified sub-tree, but has a revision level that is 01207 unknown by this service. 01208 01209 Others - Other status values that may be returned from registry key 01210 services (such as STATUS_ACCESS_DENIED). 01211 01212 --*/ 01213 { 01214 UNICODE_STRING AttributeName; 01215 NTSTATUS Status; 01216 01217 RTL_PAGED_CODE(); 01218 01219 RtlInitUnicodeString( &AttributeName, NULL ); 01220 01221 Status = RtlAddAttributeActionToRXact( 01222 RXactContext, 01223 Operation, 01224 SubKeyName, 01225 INVALID_HANDLE_VALUE, 01226 &AttributeName, 01227 NewKeyValueType, 01228 NewKeyValue, 01229 NewKeyValueLength 01230 ); 01231 01232 return( Status ); 01233 01234 01235 } 01236 01237 01238 01239 NTSTATUS 01240 RtlApplyRXact( 01241 IN PRTL_RXACT_CONTEXT RXactContext 01242 ) 01243 01244 /*++ 01245 01246 Routine Description: 01247 01248 This routine is used to apply the changes of a registry sub-tree 01249 Transaction to that registry sub-tree. This routine is meant to be 01250 called for the common case, where the hive is automatically 01251 lazy-flushed. That means that this routine must write the change log 01252 to disk, then flush the hive (to ensure that pieces of changes aren't 01253 lazy-written to disk before this routine finishes an atomic operation), 01254 the apply the changes, then delete the change log. 01255 01256 The actual changes will be lazy-written to disk, but the registry 01257 guarantees that none or all will make it. If the machine goes down 01258 while this routine is executing, the flushed change log guarantees 01259 that the hive can be put into a consistent state. 01260 01261 Arguments: 01262 01263 RXactContext - Supplies a pointer to the RXactContext structure for this 01264 subsystem's root registry key. 01265 01266 Return Value: 01267 01268 STATUS_SUCCESS - Indicates the transaction was completed. 01269 01270 STATUS_UNKNOWN_REVISION - Indicates that a transaction state 01271 exists for the specified sub-tree, but has a revision level that is 01272 unknown by this service. 01273 01274 01275 STATUS_RXACT_INVALID_STATE - Indicates that the transaction state 01276 of the registry sub-tree is incompatible with the requested operation. 01277 For example, a request to start a new transaction while one is already 01278 in progress, or a request to apply a transaction when one is not 01279 currently in progress. This may also indicate that there is no 01280 transaction state at all for the specified registry sub-tree. 01281 01282 01283 --*/ 01284 { 01285 NTSTATUS Status; 01286 UNICODE_STRING LogName; 01287 HANDLE RXactKey; 01288 01289 RTL_PAGED_CODE(); 01290 01291 // 01292 // Commit the contents of the current log to disk 01293 // 01294 01295 RXactKey = RXactContext->RXactKey; 01296 01297 RtlInitUnicodeString( &LogName, RTLP_RXACT_LOG_NAME ); 01298 01299 Status = NtSetValueKey( RXactKey, 01300 &LogName, // ValueName 01301 0, // TitleIndex 01302 REG_BINARY, 01303 RXactContext->RXactLog, 01304 RXactContext->RXactLog->LogSizeInUse 01305 ); 01306 01307 if ( !NT_SUCCESS( Status )) { 01308 return( Status ); 01309 } 01310 01311 Status = NtFlushKey( RXactKey ); 01312 01313 if ( !NT_SUCCESS( Status )) { 01314 01315 // 01316 // If this fails, maintain the in-memory data, 01317 // but get rid of what we just tried to write 01318 // to disk. 01319 // 01320 // Ignore the error, since we're in a funky 01321 // state right now. 01322 // 01323 01324 (VOID) NtDeleteValueKey( RXactKey, &LogName ); 01325 01326 return( Status ); 01327 } 01328 01329 // 01330 // The log is safe, now execute what is in it 01331 // 01332 01333 Status = RXactpCommit( RXactContext ); 01334 01335 if ( !NT_SUCCESS( Status )) { 01336 01337 // 01338 // As above, try to get rid of what's on 01339 // disk, leave the in-memory stuff alone, 01340 // so that the caller may try again. 01341 // 01342 01343 (VOID) NtDeleteValueKey( RXactKey, &LogName ); 01344 01345 return( Status ); 01346 } 01347 01348 // 01349 // Delete the log file value and data 01350 // 01351 01352 Status = NtDeleteValueKey( RXactKey, &LogName ); 01353 01354 // 01355 // This should never fail 01356 // 01357 01358 ASSERT( NT_SUCCESS( Status )); 01359 01360 // 01361 // Get rid of the in memory data structures. Abort 01362 // does exactly what we want to do. 01363 // 01364 01365 Status = RtlAbortRXact( RXactContext ); 01366 01367 // 01368 // This should never fail 01369 // 01370 01371 ASSERT( NT_SUCCESS( Status )); 01372 01373 return( STATUS_SUCCESS ); 01374 01375 } 01376 01377 01378 01379 NTSTATUS 01380 RtlApplyRXactNoFlush( 01381 IN PRTL_RXACT_CONTEXT RXactContext 01382 ) 01383 01384 /*++ 01385 01386 Routine Description: 01387 01388 This routine is used to apply the changes of a registry sub-tree 01389 Transaction to that registry sub-tree. This routine should only be 01390 called for special hives that do not have automatic lazy-flushing. 01391 The caller must decide when to flush the hive in order to guarantee 01392 a consistent hive. 01393 01394 Arguments: 01395 01396 RXactContext - Supplies a pointer to the RXactContext structure for this 01397 subsystem's root registry key. 01398 01399 Return Value: 01400 01401 STATUS_SUCCESS - Indicates the transaction was completed. 01402 01403 STATUS_UNKNOWN_REVISION - Indicates that a transaction state 01404 exists for the specified sub-tree, but has a revision level that is 01405 unknown by this service. 01406 01407 01408 STATUS_RXACT_INVALID_STATE - Indicates that the transaction state 01409 of the registry sub-tree is incompatible with the requested operation. 01410 For example, a request to start a new transaction while one is already 01411 in progress, or a request to apply a transaction when one is not 01412 currently in progress. This may also indicate that there is no 01413 transaction state at all for the specified registry sub-tree. 01414 01415 01416 --*/ 01417 { 01418 NTSTATUS Status; 01419 01420 RTL_PAGED_CODE(); 01421 01422 // 01423 // Execute the contents of the RXACT log. 01424 // 01425 01426 Status = RXactpCommit( RXactContext ); 01427 01428 if ( NT_SUCCESS( Status ) ) { 01429 01430 // 01431 // Get rid of the in memory data structures. Abort 01432 // does exactly what we want to do. 01433 // 01434 01435 Status = RtlAbortRXact( RXactContext ); 01436 01437 // 01438 // This should never fail 01439 // 01440 01441 ASSERT( NT_SUCCESS( Status )); 01442 } 01443 01444 return( Status ); 01445 01446 } 01447 01448 01449 01451 // // 01452 // Internal Procedures (defined in within this file) // 01453 // // 01455 01456 01457 01458 01459 01460 NTSTATUS 01461 RXactpCommit( 01462 IN PRTL_RXACT_CONTEXT RXactContext 01463 ) 01464 01465 /*++ 01466 01467 Routine Description: 01468 01469 This routine commits the operations in the operation log. 01470 01471 When all changes have been applied, the transaction state 01472 is changed to NO_TRANSACTION. 01473 01474 Arguments: 01475 01476 RXactContext - Supplies a pointer to the RXactContext structure for this 01477 subsystem's root registry key. 01478 01479 Return Value: 01480 01481 STATUS_SUCCESS - Indicates the transaction was completed. 01482 01483 01484 01485 --*/ 01486 { 01487 BOOLEAN HandlesValid; 01488 01489 HANDLE TargetKey; 01490 HANDLE RXactKey; 01491 HANDLE RootRegistryKey; 01492 01493 PRTL_RXACT_LOG RXactLog; 01494 PRXACT_LOG_ENTRY RXactLogEntry; 01495 RTL_RXACT_OPERATION Operation; 01496 01497 ULONG OperationCount; 01498 ULONG i; 01499 01500 NTSTATUS Status = STATUS_SUCCESS; 01501 NTSTATUS TmpStatus = STATUS_SUCCESS; 01502 BOOLEAN CloseTargetKey; 01503 01504 // 01505 // Extract information from the RXactContext to simplify 01506 // the code that follows 01507 // 01508 01509 RootRegistryKey = RXactContext->RootRegistryKey; 01510 RXactKey = RXactContext->RXactKey; 01511 RXactLog = RXactContext->RXactLog; 01512 01513 OperationCount = RXactLog->OperationCount; 01514 01515 HandlesValid = RXactContext->HandlesValid; 01516 01517 01518 // 01519 // Keep a pointer to the beginning of the current log entry. 01520 // 01521 01522 RXactLogEntry = (PRXACT_LOG_ENTRY)((PCHAR)RXactLog + sizeof( RTL_RXACT_LOG )); 01523 01524 01525 // 01526 // Go through and perform each operation log. Notice that some operation 01527 // logs may already have been deleted by a previous commit attempt. 01528 // So, don't get alarmed if we don't successfully open some operation 01529 // log entry keys. 01530 // 01531 01532 for ( i=0 ; i<OperationCount ; i++ ) { 01533 01534 // 01535 // Turn the self-relative offsets in the structure 01536 // back into real pointers. 01537 // 01538 01539 RXactLogEntry->SubKeyName.Buffer = (PWSTR) ((PCHAR)RXactLogEntry->SubKeyName.Buffer + 01540 (ULONG_PTR)RXactLog); 01541 01542 RXactLogEntry->AttributeName.Buffer = (PWSTR) ((PCHAR)RXactLogEntry->AttributeName.Buffer + 01543 (ULONG_PTR)RXactLog); 01544 01545 RXactLogEntry->NewKeyValue = (PVOID)((PCHAR)RXactLogEntry->NewKeyValue + (ULONG_PTR)RXactLog); 01546 01547 Operation = RXactLogEntry->Operation; 01548 01549 // 01550 // Perform this operation 01551 // 01552 01553 switch (Operation) { 01554 case RtlRXactOperationDelete: 01555 01556 // 01557 // Open the target key and delete it. 01558 // The name is relative to the RootRegistryKey. 01559 // 01560 01561 if ( ((RXactLogEntry->KeyHandle == INVALID_HANDLE_VALUE) || !HandlesValid) ) { 01562 01563 Status = RXactpOpenTargetKey( 01564 RootRegistryKey, 01565 RtlRXactOperationDelete, 01566 &RXactLogEntry->SubKeyName, 01567 &TargetKey 01568 ); 01569 01570 if ( !NT_SUCCESS(Status)) { 01571 01572 // 01573 // We must allow the object not to be found, 01574 // because we may be replaying this log after 01575 // it had been partially executed. 01576 // 01577 01578 if ( Status != STATUS_OBJECT_NAME_NOT_FOUND ) { 01579 01580 return( Status ); 01581 01582 } else { 01583 01584 break; 01585 } 01586 } 01587 01588 CloseTargetKey = TRUE; 01589 01590 } else { 01591 01592 TargetKey = RXactLogEntry->KeyHandle; 01593 CloseTargetKey = FALSE; 01594 } 01595 01596 01597 // 01598 // If this fails, then it is an error 01599 // because the key should exist at 01600 // this point. 01601 // 01602 01603 Status = NtDeleteKey( TargetKey ); 01604 01605 01606 // 01607 // Only close the target key if we opened it 01608 // 01609 01610 if ( CloseTargetKey ) { 01611 01612 TmpStatus = NtClose( TargetKey ); 01613 01614 // 01615 // If we opened this handle, then we should 01616 // be able to close it, whether it has been 01617 // deleted or not. 01618 // 01619 01620 ASSERT(NT_SUCCESS(TmpStatus)); // safe to ignore, but curious... 01621 } 01622 01623 01624 if (!NT_SUCCESS(Status)) { 01625 return(Status); 01626 } 01627 01628 break; 01629 01630 case RtlRXactOperationSetValue: 01631 01632 // 01633 // Open the target key. 01634 // The name is relative to the RootRegistryKey. 01635 // 01636 01637 if ( ((RXactLogEntry->KeyHandle == INVALID_HANDLE_VALUE) || !HandlesValid) ) { 01638 01639 Status = RXactpOpenTargetKey( 01640 RootRegistryKey, 01641 RtlRXactOperationSetValue, 01642 &RXactLogEntry->SubKeyName, 01643 &TargetKey 01644 ); 01645 01646 if ( !NT_SUCCESS(Status) ) { 01647 return(Status); 01648 } 01649 01650 CloseTargetKey = TRUE; 01651 01652 } else { 01653 01654 TargetKey = RXactLogEntry->KeyHandle; 01655 CloseTargetKey = FALSE; 01656 } 01657 01658 // 01659 // Assign to the target key's new value 01660 // 01661 01662 Status = NtSetValueKey( TargetKey, 01663 &RXactLogEntry->AttributeName, 01664 0, // TitleIndex 01665 RXactLogEntry->NewKeyValueType, 01666 RXactLogEntry->NewKeyValue, 01667 RXactLogEntry->NewKeyValueLength 01668 ); 01669 01670 // 01671 // Only close the target key if we opened it 01672 // 01673 01674 if ( CloseTargetKey ) { 01675 01676 TmpStatus = NtClose( TargetKey ); 01677 ASSERT(NT_SUCCESS(TmpStatus)); // safe to ignore, but curious... 01678 01679 } 01680 01681 if ( !NT_SUCCESS(Status) ) { 01682 return(Status); 01683 } 01684 01685 break; 01686 01687 01688 01689 default: 01690 01691 // 01692 // Unknown operation type. This should never happen. 01693 // 01694 01695 ASSERT( FALSE ); 01696 01697 return(STATUS_INVALID_PARAMETER); 01698 01699 } 01700 01701 RXactLogEntry = (PRXACT_LOG_ENTRY)((PCHAR)RXactLogEntry + RXactLogEntry->LogEntrySize); 01702 01703 } 01704 01705 // 01706 // Commit complete 01707 // 01708 01709 return( STATUS_SUCCESS ); 01710 01711 } 01712 01713 01714 01715 01716 NTSTATUS 01717 RXactpOpenTargetKey( 01718 IN HANDLE RootRegistryKey, 01719 IN RTL_RXACT_OPERATION Operation, 01720 IN PUNICODE_STRING SubKeyName, 01721 OUT PHANDLE TargetKey 01722 ) 01723 01724 /*++ 01725 01726 Routine Description: 01727 01728 This routine opens the target registry key of an operation. 01729 01730 Arguments: 01731 01732 RootRegistryKey - A handle to the registry key within whose sub-tree 01733 a transaction is to be initialized. 01734 01735 Operation - Indicates what operation is to be performed on the target. 01736 This will effect how the target is opened. 01737 01738 OperationNameKey - A handle to the operation log sub-key 01739 containing the name of the target registry key. 01740 01741 TargetKey - Receives a handle to the target registry key. 01742 01743 Return Value: 01744 01745 STATUS_SUCCESS - Indicates the operation log entry was opened. 01746 01747 STATUS_NO_MEMORY - Ran out of heap. 01748 01749 01750 --*/ 01751 { 01752 01753 NTSTATUS Status; 01754 OBJECT_ATTRIBUTES TargetKeyAttributes; 01755 ACCESS_MASK DesiredAccess; 01756 ULONG Disposition; 01757 01758 01759 if (Operation == RtlRXactOperationDelete) { 01760 01761 DesiredAccess = DELETE; 01762 01763 InitializeObjectAttributes( 01764 &TargetKeyAttributes, 01765 SubKeyName, 01766 OBJ_CASE_INSENSITIVE, 01767 RootRegistryKey, 01768 NULL); 01769 01770 // Status = RtlpNtOpenKey( 01771 // TargetKey, 01772 // DesiredAccess, 01773 // &TargetKeyAttributes, 01774 // 0); 01775 01776 Status = NtOpenKey( TargetKey, 01777 DesiredAccess, 01778 &TargetKeyAttributes 01779 ); 01780 01781 01782 } else if (Operation == RtlRXactOperationSetValue) { 01783 01784 DesiredAccess = KEY_WRITE; 01785 01786 InitializeObjectAttributes( 01787 &TargetKeyAttributes, 01788 SubKeyName, 01789 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 01790 RootRegistryKey, 01791 NULL); 01792 01793 Status = NtCreateKey( 01794 TargetKey, 01795 DesiredAccess, 01796 &TargetKeyAttributes, 01797 0, 01798 NULL, 01799 REG_OPTION_NON_VOLATILE, 01800 &Disposition 01801 ); 01802 01803 } else { 01804 return STATUS_INVALID_PARAMETER; 01805 } 01806 01807 01808 01809 return( Status ); 01810 01811 } 01812 01813 01814 01815 //NTSTATUS 01816 //RXactpAssignTargetValue( 01817 // IN PVOID NewKeyValue, 01818 // IN ULONG NewKeyValueLength, 01819 // IN ULONG NewKeyValueType, 01820 // IN HANDLE TargetKey, 01821 // IN PUNICODE_STRING AttributeName 01822 // ); 01823 01824 01825 //NTSTATUS 01826 //RXactpAssignTargetValue( 01827 // IN PVOID NewKeyValue, 01828 // IN ULONG NewKeyValueLength, 01829 // IN ULONG NewKeyValueType, 01830 // IN HANDLE TargetKey, 01831 // IN PUNICODE_STRING AttributeName 01832 // ) 01833 // 01835 // 01836 //Routine Description: 01837 // 01838 // This routine copies the value of an operation log entry to its 01839 // corresponding target key. The target key must already be open. 01840 // 01841 //Arguments: 01842 // 01843 // NewKeyValue - The new value for the key being modified. 01844 // 01845 // NewKeyValueLength - The size in bytes of the new value information. 01846 // 01847 // NewKeyValueType - The type of the data for the new key. 01848 // 01849 // TargetKey - A handle to the target registry key. 01850 // 01851 // AttributeName - Supplies the name of the key attribute being edited. 01852 // 01853 //Return Value: 01854 // 01855 // STATUS_SUCCESS - Indicates the value was successfully applied to 01856 // the target registry key. 01857 // 01858 // STATUS_NO_MEMORY - ran out of heap. 01859 // 01860 // 01861 //--*/ 01862 //{ 01863 // NTSTATUS Status; 01864 // 01865 // // 01866 // // Now apply the value to the target key 01867 // // 01868 // // Even if there is no key value, we need to do the assign so that 01869 // // the key value type is assigned. 01870 // // 01871 // 01872 // Status = NtSetValueKey( TargetKey, 01873 // AttributeName, 01874 // 0, // TitleIndex 01875 // NewKeyValueType, 01876 // NewKeyValue, 01877 // NewKeyValueLength 01878 // ); 01879 // 01880 // 01881 // return( Status ); 01882 //}

Generated on Sat May 15 19:41:43 2004 for test by doxygen 1.3.7