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

uuid.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1994-1997 Microsoft Corporation 00004 00005 Module Name: 00006 00007 uuid.c 00008 00009 Abstract: 00010 00011 This module implements the core time and sequence number allocation 00012 for UUIDs (exposed to user mode), as well as complete UUID 00013 creation (exposed to kernel mode only). 00014 00015 (e.g. RPC Runtime) (e.g. NTFS) 00016 | | 00017 V V 00018 NtAllocateUuids ExUuidCreate 00019 | | 00020 V V 00021 | ExpUuidGetValues 00022 | | 00023 | | 00024 +------> ExpAllocateUuids <----+ 00025 00026 00027 00028 Author: 00029 00030 Mario Goertzel (MarioGo) 22-Nov-1994 00031 00032 Revision History: 00033 00034 MikeHill 17-Jan-96 Ported ExUuidCreate & ExpUuidGetValues from RPCRT4. 00035 MazharM 17-Feb-98 Add PNP support 00036 00037 --*/ 00038 00039 #include "exp.h" 00040 00041 00042 00043 // 00044 // Well known values 00045 // 00046 00047 // Registry info for the sequen number 00048 #define RPC_SEQUENCE_NUMBER_PATH L"\\Registry\\Machine\\Software\\Microsoft\\Rpc" 00049 #define RPC_SEQUENCE_NUMBER_NAME L"UuidSequenceNumber" 00050 00051 // Masks and constants to interpret the UUID 00052 #define UUID_TIME_HIGH_MASK 0x0FFF 00053 #define UUID_VERSION 0x1000 00054 #define UUID_RESERVED 0x80 00055 #define UUID_CLOCK_SEQ_HI_MASK 0x3F 00056 00057 // Values for ExpUuidCacheValid 00058 #define CACHE_LOCAL_ONLY 0 00059 #define CACHE_VALID 1 00060 00061 // 00062 // Custom types 00063 // 00064 00065 // An alternative data-template for a UUID, useful during generation. 00066 typedef struct _UUID_GENERATE { 00067 ULONG TimeLow; 00068 USHORT TimeMid; 00069 USHORT TimeHiAndVersion; 00070 UCHAR ClockSeqHiAndReserved; 00071 UCHAR ClockSeqLow; 00072 UCHAR NodeId[6]; 00073 } UUID_GENERATE; 00074 00075 // A cache of allocated UUIDs 00076 typedef struct _UUID_CACHED_VALUES_STRUCT { 00077 ULONGLONG Time; // End time of allocation 00078 LONG AllocatedCount; // Number of UUIDs allocated 00079 UCHAR ClockSeqHiAndReserved; 00080 UCHAR ClockSeqLow; 00081 UCHAR NodeId[6]; 00082 } UUID_CACHED_VALUES_STRUCT; 00083 00084 00085 // 00086 // Global variables 00087 // 00088 00089 // UUID cache information 00090 LARGE_INTEGER ExpUuidLastTimeAllocated; 00091 BOOLEAN ExpUuidCacheValid = CACHE_LOCAL_ONLY; 00092 00093 // Make cache allocate UUIDs on first call. 00094 // Time = 0. Allocated = -1, ..., multicast bit in node id 00095 UUID_CACHED_VALUES_STRUCT ExpUuidCachedValues = { 0, -1, 0, 0, { 0x80, 'm', 'a', 'r', 'i', 'o' }}; 00096 00097 // UUID Sequence number information 00098 ULONG ExpUuidSequenceNumber; 00099 BOOLEAN ExpUuidSequenceNumberValid; 00100 BOOLEAN ExpUuidSequenceNumberNotSaved; 00101 00102 // A lock to protect all of the above global data. 00103 FAST_MUTEX ExpUuidLock; 00104 00105 // 00106 // Code section allocations 00107 // 00108 00109 extern NTSTATUS ExpUuidLoadSequenceNumber( 00110 OUT PULONG 00111 ); 00112 00113 extern NTSTATUS ExpUuidSaveSequenceNumber( 00114 IN ULONG 00115 ); 00116 00117 extern NTSTATUS ExpUuidSaveSequenceNumberIf (); 00118 00119 extern NTSTATUS ExpUuidGetValues( 00120 OUT UUID_CACHED_VALUES_STRUCT *Values 00121 ); 00122 00123 00124 #ifdef ALLOC_PRAGMA 00125 #pragma alloc_text(PAGE, ExpUuidLoadSequenceNumber) 00126 #pragma alloc_text(PAGE, ExpUuidSaveSequenceNumber) 00127 #pragma alloc_text(PAGE, ExpUuidSaveSequenceNumberIf) 00128 #pragma alloc_text(INIT, ExpUuidInitialization) 00129 #pragma alloc_text(PAGE, NtAllocateUuids) 00130 #pragma alloc_text(PAGE, NtSetUuidSeed) 00131 #pragma alloc_text(PAGE, ExpUuidGetValues) 00132 #pragma alloc_text(PAGE, ExUuidCreate) 00133 #endif 00134 00135 00136 NTSTATUS 00137 ExpUuidLoadSequenceNumber( 00138 OUT PULONG Sequence 00139 ) 00140 /*++ 00141 00142 Routine Description: 00143 00144 This function loads the saved sequence number from the registry. 00145 This function is called only during system startup. 00146 00147 Arguments: 00148 00149 Sequence - Pointer to storage for the sequence number. 00150 00151 Return Value: 00152 00153 STATUS_SUCCESS when the sequence number is successfully read from the 00154 registry. 00155 00156 STATUS_UNSUCCESSFUL when the sequence number is not correctly stored 00157 in the registry. 00158 00159 Failure codes from ZwOpenKey() and ZwQueryValueKey() maybe returned. 00160 00161 --*/ 00162 { 00163 NTSTATUS Status; 00164 OBJECT_ATTRIBUTES ObjectAttributes; 00165 UNICODE_STRING KeyPath, KeyName; 00166 HANDLE Key; 00167 CHAR KeyValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; 00168 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation; 00169 ULONG ResultLength; 00170 00171 PAGED_CODE(); 00172 00173 KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer; 00174 00175 RtlInitUnicodeString(&KeyPath, RPC_SEQUENCE_NUMBER_PATH); 00176 RtlInitUnicodeString(&KeyName, RPC_SEQUENCE_NUMBER_NAME); 00177 00178 InitializeObjectAttributes( &ObjectAttributes, 00179 &KeyPath, 00180 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00181 NULL, 00182 NULL 00183 ); 00184 00185 Status = 00186 ZwOpenKey( &Key, 00187 GENERIC_READ, 00188 &ObjectAttributes 00189 ); 00190 00191 if (NT_SUCCESS(Status)) { 00192 Status = 00193 ZwQueryValueKey( Key, 00194 &KeyName, 00195 KeyValuePartialInformation, 00196 KeyValueInformation, 00197 sizeof(KeyValueBuffer), 00198 &ResultLength 00199 ); 00200 00201 ZwClose( Key ); 00202 } 00203 00204 if (NT_SUCCESS(Status)) { 00205 if ( KeyValueInformation->Type == REG_DWORD && 00206 KeyValueInformation->DataLength == sizeof(ULONG) 00207 ) { 00208 *Sequence = *(PULONG)KeyValueInformation->Data; 00209 } 00210 else { 00211 Status = STATUS_UNSUCCESSFUL; 00212 } 00213 } 00214 00215 return(Status); 00216 } 00217 00218 00219 NTSTATUS 00220 ExpUuidSaveSequenceNumber( 00221 IN ULONG Sequence 00222 ) 00223 /*++ 00224 00225 Routine Description: 00226 00227 This function saves the uuid sequence number in the registry. This 00228 value will be read by ExpUuidLoadSequenceNumber during the next boot. 00229 00230 This routine assumes that the current thread has exclusive access 00231 to the the ExpUuid* values. 00232 00233 Arguments: 00234 00235 Sequence - The sequence number to save. 00236 00237 Return Value: 00238 00239 STATUS_SUCCESS 00240 00241 Failure codes from ZwOpenKey() and ZwSetValueKey() maybe returned. 00242 00243 --*/ 00244 { 00245 NTSTATUS Status; 00246 OBJECT_ATTRIBUTES ObjectAttributes; 00247 UNICODE_STRING KeyPath, KeyName; 00248 HANDLE Key; 00249 00250 PAGED_CODE(); 00251 00252 RtlInitUnicodeString(&KeyPath, RPC_SEQUENCE_NUMBER_PATH); 00253 RtlInitUnicodeString(&KeyName, RPC_SEQUENCE_NUMBER_NAME); 00254 00255 InitializeObjectAttributes( &ObjectAttributes, 00256 &KeyPath, 00257 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00258 NULL, 00259 NULL 00260 ); 00261 00262 Status = 00263 ZwOpenKey( &Key, 00264 GENERIC_READ | GENERIC_WRITE, 00265 &ObjectAttributes 00266 ); 00267 00268 if (NT_SUCCESS(Status)) { 00269 Status = 00270 ZwSetValueKey( Key, 00271 &KeyName, 00272 0, 00273 REG_DWORD, 00274 &Sequence, 00275 sizeof(ULONG) 00276 ); 00277 00278 ZwClose( Key ); 00279 } 00280 00281 return(Status); 00282 } 00283 00284 00285 00286 NTSTATUS 00287 ExpUuidSaveSequenceNumberIf () 00288 00289 /*++ 00290 00291 Routine Description: 00292 00293 This function saves the ExpUuidSequenceNumber, but only 00294 if necessary (as determined by the ExpUuidSequenceNumberNotSaved 00295 flag). 00296 00297 This routine assumes that the current thread has exclusive access 00298 to the ExpUuid* values. 00299 00300 Arguments: 00301 00302 None. 00303 00304 Return Value: 00305 00306 STATUS_SUCCESS if the operation was successful. 00307 00308 --*/ 00309 00310 { 00311 NTSTATUS Status = STATUS_SUCCESS; 00312 00313 PAGED_CODE(); 00314 00315 // Does the sequence number need to be saved? 00316 if (ExpUuidSequenceNumberNotSaved == TRUE) { 00317 00318 // Print this message just to make sure we aren't hitting the 00319 // registry too much under normal usage. 00320 00321 KdPrint(("Uuid: Saving new sequence number.\n")); 00322 00323 // Save the sequence number 00324 00325 Status = ExpUuidSaveSequenceNumber(ExpUuidSequenceNumber); 00326 00327 // Indicate that it's now been saved. 00328 if (NT_SUCCESS(Status)) { 00329 ExpUuidSequenceNumberNotSaved = FALSE; 00330 } 00331 } 00332 00333 return( Status ); 00334 } 00335 00336 00337 00338 00339 BOOLEAN 00340 ExpUuidInitialization ( 00341 VOID 00342 ) 00343 /*++ 00344 00345 Routine Description: 00346 00347 This function initializes the UUID allocation. 00348 00349 Arguments: 00350 00351 None. 00352 00353 Return Value: 00354 00355 A value of TRUE is returned if the initialization is successfully 00356 completed. Otherwise, a value of FALSE is returned. 00357 00358 --*/ 00359 00360 { 00361 NTSTATUS Status; 00362 00363 PAGED_CODE(); 00364 00365 ExInitializeFastMutex(&ExpUuidLock); 00366 00367 ExpUuidSequenceNumberValid = FALSE; 00368 00369 // We can use the current time since we'll be changing the sequence number. 00370 00371 KeQuerySystemTime(&ExpUuidLastTimeAllocated); 00372 00373 return TRUE; 00374 } 00375 00376 00377 NTSTATUS 00378 ExpAllocateUuids ( 00379 OUT PLARGE_INTEGER Time, 00380 OUT PULONG Range, 00381 OUT PULONG Sequence 00382 ) 00383 00384 /*++ 00385 00386 Routine Description: 00387 00388 Allocates a sequence number and a range of times for a set of UUIDs. 00389 The caller can use this together with the network address to 00390 generate complete UUIDs. 00391 00392 This routine assumes that the current thread has exclusive access 00393 to the ExpUuid* values. 00394 00395 Arguments: 00396 00397 Time - Supplies the address of a variable that will receive the 00398 start time (SYSTEMTIME format) of the range of time reserved. 00399 00400 Range - Supplies the address of a variable that will receive the 00401 number of ticks (100ns) reserved after the value in Time. 00402 The range reserved is *Time to (*Time+*Range-1). 00403 00404 Sequence - Supplies the address of a variable that will receive 00405 the time sequence number. This value is used with the associated 00406 range of time to prevent problems with clocks going backwards. 00407 00408 Return Value: 00409 00410 STATUS_SUCCESS is returned if the service is successfully executed. 00411 00412 STATUS_RETRY is returned if we're unable to reserve a range of 00413 UUIDs. This will occur if system clock hasn't advanced 00414 and the allocator is out of cached values. 00415 00416 STATUS_UNSUCCESSFUL is returned if some other service reports 00417 an error, most likly the registery. 00418 00419 --*/ 00420 00421 { 00422 NTSTATUS Status; 00423 LARGE_INTEGER CurrentTime; 00424 LARGE_INTEGER AvailableTime; 00425 00426 PAGED_CODE(); 00427 00428 // 00429 // Make sure we have a valid sequence number. If not, make one up. 00430 // 00431 00432 if (ExpUuidSequenceNumberValid == FALSE) { 00433 00434 Status = ExpUuidLoadSequenceNumber(&ExpUuidSequenceNumber); 00435 00436 if (!NT_SUCCESS(Status)) { 00437 // Unable read the sequence number, this means we should make one up. 00438 00439 LARGE_INTEGER PerfCounter; 00440 LARGE_INTEGER PerfFrequency; 00441 00442 // This should only happen when we're called 00443 // for the first time on a given machine. (machine, not boot) 00444 00445 KdPrint(("Uuid: Generating first sequence number.\n")); 00446 00447 PerfCounter = KeQueryPerformanceCounter(&PerfFrequency); 00448 00449 ExpUuidSequenceNumber ^= (ULONG)((ULONG_PTR)&Status) ^ PerfCounter.LowPart ^ 00450 PerfCounter.HighPart ^ (ULONG)((ULONG_PTR)Sequence); 00451 } 00452 else { 00453 // We increment the sequence number on every boot. 00454 ExpUuidSequenceNumber++; 00455 } 00456 00457 ExpUuidSequenceNumberValid = TRUE; 00458 ExpUuidSequenceNumberNotSaved = TRUE; 00459 00460 } 00461 00462 // 00463 // Get the current time, usually we will have plenty of avaliable 00464 // to give the caller. But we may need to deal with time going 00465 // backwards and really fast machines. 00466 // 00467 00468 KeQuerySystemTime(&CurrentTime); 00469 00470 AvailableTime.QuadPart = CurrentTime.QuadPart - ExpUuidLastTimeAllocated.QuadPart; 00471 00472 if (AvailableTime.QuadPart < 0) { 00473 00474 // Time has been set time backwards. This means that we must make sure 00475 // that somebody increments the sequence number and saves the new 00476 // sequence number in the registry. 00477 00478 ExpUuidSequenceNumberNotSaved = TRUE; 00479 ExpUuidSequenceNumber++; 00480 00481 // The sequence number has been changed, so it's now okay to set time 00482 // backwards. Since time is going backwards anyway, it's okay to set 00483 // it back an extra millisecond or two. 00484 00485 ExpUuidLastTimeAllocated.QuadPart = CurrentTime.QuadPart - 20000; 00486 AvailableTime.QuadPart = 20000; 00487 } 00488 00489 if (AvailableTime.QuadPart == 0) { 00490 // System time hasn't moved. The caller should yield the CPU and retry. 00491 return(STATUS_RETRY); 00492 } 00493 00494 // 00495 // Common case, time has moved forward. 00496 // 00497 00498 if (AvailableTime.QuadPart > 10*1000*1000) { 00499 // We never want to give out really old (> 1 second) Uuids. 00500 AvailableTime.QuadPart = 10*1000*1000; 00501 } 00502 00503 if (AvailableTime.QuadPart > 10*1000) { 00504 // We've got over a millisecond to give out. We'll save some time for 00505 // another caller so that we can avoid returning STATUS_RETRY very often. 00506 *Range = 10*1000; 00507 AvailableTime.QuadPart -= 10*1000; 00508 } 00509 else { 00510 // Not much time avaiable, give it all away. 00511 *Range = (ULONG)AvailableTime.QuadPart; 00512 AvailableTime.QuadPart = 0; 00513 } 00514 00515 Time->QuadPart = CurrentTime.QuadPart - (*Range + AvailableTime.QuadPart); 00516 00517 ExpUuidLastTimeAllocated.QuadPart = Time->QuadPart + *Range; 00518 00519 // Last time allocated is just after the range we hand back to the caller 00520 // this may be almost a second behind the true system time. 00521 00522 *Sequence = ExpUuidSequenceNumber; 00523 00524 00525 return(STATUS_SUCCESS); 00526 } 00527 00528 #define SEED_SIZE 6 * sizeof(CHAR) 00529 00530 00531 NTSTATUS 00532 NtSetUuidSeed ( 00533 IN PCHAR Seed 00534 ) 00535 /*++ 00536 00537 Routine Description: 00538 00539 This routine is used to set the seed used for UUID generation. The seed 00540 will be set by RPCSS at startup and each time a card is replaced. 00541 00542 Arguments: 00543 00544 Seed - Pointer to a six byte buffer 00545 00546 Return Value: 00547 00548 STATUS_SUCCESS is returned if the service is successfully executed. 00549 00550 STATUS_ACCESS_DENIED If caller doesn't have the permissions to make this call. 00551 You need to be logged on as Local System in order to call this API. 00552 00553 STATUS_ACCESS_VIOLATION is returned if the Seed could not be read. 00554 00555 --*/ 00556 { 00557 NTSTATUS Status; 00558 LUID AuthenticationId; 00559 SECURITY_SUBJECT_CONTEXT SubjectContext; 00560 LUID SystemLuid = SYSTEM_LUID; 00561 BOOLEAN CapturedSubjectContext = FALSE; 00562 00563 PAGED_CODE(); 00564 00565 ASSERT(KeGetPreviousMode() != KernelMode); 00566 00567 try { 00568 // 00569 // Check if the caller has the appropriate permission 00570 // 00571 SeCaptureSubjectContext(&SubjectContext); 00572 CapturedSubjectContext = TRUE; 00573 00574 Status = SeQueryAuthenticationIdToken( 00575 SeQuerySubjectContextToken(&SubjectContext), 00576 &AuthenticationId); 00577 if (!NT_SUCCESS(Status)) { 00578 ExRaiseStatus(Status); 00579 } 00580 00581 if (RtlCompareMemory(&AuthenticationId, &SystemLuid, sizeof(LUID)) != sizeof(LUID)) { 00582 ExRaiseStatus(STATUS_ACCESS_DENIED); 00583 } 00584 00585 // 00586 // Store the UUID seed 00587 // 00588 ProbeForRead(Seed, SEED_SIZE, sizeof(CHAR)); 00589 RtlCopyMemory(&ExpUuidCachedValues.NodeId[0], Seed, SEED_SIZE); 00590 00591 if ((Seed[0] & 0x80) == 0) 00592 { 00593 // If the high bit is not set the NodeId is a valid IEEE 802 00594 // address and should be globally unique. 00595 ExpUuidCacheValid = CACHE_VALID; 00596 } 00597 else 00598 { 00599 ExpUuidCacheValid = CACHE_LOCAL_ONLY; 00600 } 00601 00602 Status = STATUS_SUCCESS; 00603 } 00604 except (EXCEPTION_EXECUTE_HANDLER) { 00605 Status = GetExceptionCode(); 00606 } 00607 00608 if (CapturedSubjectContext) { 00609 SeReleaseSubjectContext( &SubjectContext ); 00610 } 00611 00612 return Status; 00613 } 00614 00615 00616 NTSTATUS 00617 NtAllocateUuids ( 00618 OUT PULARGE_INTEGER Time, 00619 OUT PULONG Range, 00620 OUT PULONG Sequence, 00621 OUT PCHAR Seed 00622 ) 00623 00624 /*++ 00625 00626 Routine Description: 00627 00628 This function reserves a range of time for the caller(s) to use for 00629 handing out Uuids. As far a possible the same range of time and 00630 sequence number will never be given out. 00631 00632 (It's possible to reboot 2^14-1 times and set the clock backwards and then 00633 call this allocator and get a duplicate. Since only the low 14bits of the 00634 sequence number are used in a real uuid.) 00635 00636 Arguments: 00637 00638 Time - Supplies the address of a variable that will receive the 00639 start time (SYSTEMTIME format) of the range of time reserved. 00640 00641 Range - Supplies the address of a variable that will receive the 00642 number of ticks (100ns) reserved after the value in Time. 00643 The range reserved is *Time to (*Time + *Range - 1). 00644 00645 Sequence - Supplies the address of a variable that will receive 00646 the time sequence number. This value is used with the associated 00647 range of time to prevent problems with clocks going backwards. 00648 00649 Seed - Pointer to a 6 byte buffer. The current seed is written into this buffer. 00650 00651 Return Value: 00652 00653 STATUS_SUCCESS is returned if the service is successfully executed. 00654 00655 STATUS_RETRY is returned if we're unable to reserve a range of 00656 UUIDs. This may (?) occur if system clock hasn't advanced 00657 and the allocator is out of cached values. 00658 00659 STATUS_ACCESS_VIOLATION is returned if the output parameter for the 00660 UUID cannot be written. 00661 00662 STATUS_UNSUCCESSFUL is returned if some other service reports 00663 an error, most likly the registery. 00664 00665 --*/ 00666 00667 { 00668 00669 KPROCESSOR_MODE PreviousMode; 00670 NTSTATUS Status; 00671 00672 LARGE_INTEGER OutputTime; 00673 ULONG OutputRange; 00674 ULONG OutputSequence; 00675 00676 PAGED_CODE(); 00677 00678 // 00679 // Establish an exception handler and attempt to write the output 00680 // arguments. If the write attempt fails, then return 00681 // the exception code as the service status. Otherwise return success 00682 // as the service status. 00683 // 00684 00685 try { 00686 00687 // 00688 // Get previous processor mode and probe arguments if necessary. 00689 // 00690 00691 PreviousMode = KeGetPreviousMode(); 00692 if (PreviousMode != KernelMode) { 00693 ProbeForWrite((PVOID)Time, sizeof(LARGE_INTEGER), sizeof(ULONG)); 00694 ProbeForWrite((PVOID)Range, sizeof(ULONG), sizeof(ULONG)); 00695 ProbeForWrite((PVOID)Sequence, sizeof(ULONG), sizeof(ULONG)); 00696 ProbeForWrite((PVOID)Seed, SEED_SIZE, sizeof(CHAR)); 00697 } 00698 } 00699 except (ExSystemExceptionFilter()) { 00700 return GetExceptionCode(); 00701 } 00702 00703 // Take the lock, because we're about to update the UUID cache. 00704 00705 KeEnterCriticalRegion(); 00706 ExAcquireFastMutexUnsafe(&ExpUuidLock); 00707 00708 // Get the sequence number and a range of times that can 00709 // be used in UUID-generation. 00710 00711 Status = ExpAllocateUuids( &OutputTime, &OutputRange, &OutputSequence ); 00712 00713 if( !NT_SUCCESS(Status) ) { 00714 ExReleaseFastMutexUnsafe(&ExpUuidLock); 00715 KeLeaveCriticalRegion(); 00716 return( Status ); 00717 } 00718 00719 // If necessary, save the sequence number. If there's an error, 00720 // we'll just leave it marked as dirty, and retry on some future call. 00721 00722 ExpUuidSaveSequenceNumberIf(); 00723 00724 // Release the lock 00725 ExReleaseFastMutexUnsafe(&ExpUuidLock); 00726 KeLeaveCriticalRegion(); 00727 00728 // 00729 // Attempt to store the result of this call into the output parameters. 00730 // This is done within an exception handler in case output parameters 00731 // are now invalid. 00732 // 00733 00734 try { 00735 Time->QuadPart = OutputTime.QuadPart; 00736 *Range = OutputRange; 00737 *Sequence = OutputSequence; 00738 RtlCopyMemory((PVOID) Seed, &ExpUuidCachedValues.NodeId[0], SEED_SIZE); 00739 } 00740 except (ExSystemExceptionFilter()) { 00741 return GetExceptionCode(); 00742 } 00743 00744 return(STATUS_SUCCESS); 00745 } 00746 00747 00748 00749 00750 NTSTATUS 00751 ExpUuidGetValues( 00752 OUT UUID_CACHED_VALUES_STRUCT *Values 00753 ) 00754 /*++ 00755 00756 Routine Description: 00757 00758 This routine allocates a block of UUIDs and stores them in 00759 the caller-provided cached-values structure. 00760 00761 This routine assumes that the current thread has exclusive 00762 access to the ExpUuid* values. 00763 00764 Note that the Time value in this cache is different than the 00765 Time value returned by NtAllocateUuids (and ExpAllocateUuids). 00766 As a result, the cache must be interpreted differently in 00767 order to determine the valid range. The valid range from 00768 these two routines is: 00769 00770 NtAllocateUuids: [ Time, Time+Range ) 00771 ExpUuidGetValues: ( Values.Time-Values.Range, Values.Time ] 00772 00773 Arguments: 00774 00775 Values - Set to contain everything needed to allocate a block of uuids. 00776 00777 Return Value: 00778 00779 STATUS_SUCCESS is returned if the service is successfully executed. 00780 00781 STATUS_RETRY is returned if we're unable to reserve a range of 00782 UUIDs. This will occur if system clock hasn't advanced 00783 and the allocator is out of cached values. 00784 00785 STATUS_NO_MEMORY is returned if we're unable to reserve a range 00786 of UUIDs, for some reason other than the clock not advancing. 00787 00788 --*/ 00789 { 00790 NTSTATUS Status; 00791 LARGE_INTEGER Time; 00792 ULONG Range; 00793 ULONG Sequence; 00794 00795 PAGED_CODE(); 00796 00797 // Allocate a range of times for use in UUIDs. 00798 00799 Status = ExpAllocateUuids(&Time, &Range, &Sequence); 00800 00801 if (STATUS_RETRY == Status) { 00802 return(Status); 00803 } 00804 00805 else if (!NT_SUCCESS(Status)) { 00806 return(STATUS_NO_MEMORY); 00807 } 00808 00809 // ExpAllocateUuids keeps time in SYSTEM_TIME format which is 100ns ticks since 00810 // Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582. 00811 00812 // 17 Days in Oct + 30 (Nov) + 31 (Dec) + 18 years and 5 leap days. 00813 00814 Time.QuadPart += (ULONGLONG) (1000*1000*10) // seconds 00815 * (ULONGLONG) (60 * 60 * 24) // days 00816 * (ULONGLONG) (17+30+31+365*18+5); // # of days 00817 00818 ASSERT(Range); 00819 00820 Values->ClockSeqHiAndReserved = 00821 UUID_RESERVED | (((UCHAR) (Sequence >> 8)) 00822 & (UCHAR) UUID_CLOCK_SEQ_HI_MASK); 00823 00824 Values->ClockSeqLow = (UCHAR) (Sequence & 0x00FF); 00825 00826 00827 // We'll modify the Time value so that it indicates the 00828 // end of the range rather than the beginning of it. 00829 00830 // The order of these assignments is important 00831 00832 Values->Time = Time.QuadPart + (Range - 1); 00833 Values->AllocatedCount = Range; 00834 00835 return(STATUS_SUCCESS); 00836 } 00837 00838 00839 00840 NTSTATUS 00841 ExUuidCreate( 00842 OUT UUID *Uuid 00843 ) 00844 00845 /*++ 00846 00847 Routine Description: 00848 00849 This routine creates a DCE UUID and returns it in the caller's 00850 buffer. 00851 00852 Arguments: 00853 00854 Uuid - will receive the UUID. 00855 00856 Return Value: 00857 00858 STATUS_SUCCESS is returned if the service is successfully executed. 00859 00860 STATUS_RETRY is returned if we're unable to reserve a range of 00861 UUIDs. This will occur if system clock hasn't advanced 00862 and the allocator is out of cached values. 00863 00864 --*/ 00865 00866 { 00867 NTSTATUS Status = STATUS_SUCCESS; 00868 00869 UUID_GENERATE *UuidGen = (UUID_GENERATE *) Uuid; 00870 ULONGLONG Time; 00871 LONG Delta; 00872 00873 PAGED_CODE(); 00874 00875 // 00876 // Get a value from the cache. If the cache is empty, we'll fill 00877 // it and retry. The first time cache will be empty. 00878 // 00879 00880 for(;;) { 00881 00882 // Get the highest value in the cache (though it may not 00883 // be available). 00884 Time = ExpUuidCachedValues.Time; 00885 00886 // Copy the static info into the UUID. We can't do this later 00887 // because the clock sequence could be updated by another thread. 00888 00889 *(PULONG)&UuidGen->ClockSeqHiAndReserved = 00890 *(PULONG)&ExpUuidCachedValues.ClockSeqHiAndReserved; 00891 *(PULONG)&UuidGen->NodeId[2] = 00892 *(PULONG)&ExpUuidCachedValues.NodeId[2]; 00893 00894 // See what we need to subtract from Time to get a valid GUID. 00895 Delta = InterlockedDecrement(&ExpUuidCachedValues.AllocatedCount); 00896 00897 if (Time != ExpUuidCachedValues.Time) { 00898 00899 // If our captured time doesn't match the cache then another 00900 // thread already took the lock and updated the cache. We'll 00901 // just loop and try again. 00902 continue; 00903 } 00904 00905 // If the cache hadn't already run dry, we can break out of this retry 00906 // loop. 00907 if (Delta >= 0) { 00908 break; 00909 } 00910 00911 // 00912 // Allocate a new block of Uuids. 00913 // 00914 00915 // Take the cache lock 00916 KeEnterCriticalRegion(); 00917 ExAcquireFastMutexUnsafe(&ExpUuidLock); 00918 00919 // If the cache has already been updated, try again. 00920 if (Time != ExpUuidCachedValues.Time) { 00921 // Release the lock 00922 ExReleaseFastMutexUnsafe(&ExpUuidLock); 00923 KeLeaveCriticalRegion(); 00924 continue; 00925 } 00926 00927 // Update the cache. 00928 Status = ExpUuidGetValues( &ExpUuidCachedValues ); 00929 00930 if (Status != STATUS_SUCCESS) { 00931 // Release the lock 00932 ExReleaseFastMutexUnsafe(&ExpUuidLock); 00933 KeLeaveCriticalRegion(); 00934 return(Status); 00935 } 00936 00937 // The sequence number may have been dirtied, see if it needs 00938 // to be saved. If there's an error, we'll ignore it and 00939 // retry on a future call. 00940 00941 ExpUuidSaveSequenceNumberIf(); 00942 00943 // Release the lock 00944 ExReleaseFastMutexUnsafe(&ExpUuidLock); 00945 KeLeaveCriticalRegion(); 00946 00947 // Loop 00948 } 00949 00950 // Adjust the time to that of the next available UUID. 00951 Time -= Delta; 00952 00953 // Finish filling in the UUID. 00954 00955 UuidGen->TimeLow = (ULONG) Time; 00956 UuidGen->TimeMid = (USHORT) (Time >> 32); 00957 UuidGen->TimeHiAndVersion = (USHORT) 00958 (( (USHORT)(Time >> (32+16)) 00959 & UUID_TIME_HIGH_MASK) | UUID_VERSION); 00960 00961 ASSERT(Status == STATUS_SUCCESS); 00962 00963 if (ExpUuidCacheValid == CACHE_LOCAL_ONLY) { 00964 Status = RPC_NT_UUID_LOCAL_ONLY; 00965 } 00966 00967 return(Status); 00968 }

Generated on Sat May 15 19:42:17 2004 for test by doxygen 1.3.7