test: rxact.c Source File

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 //}