+ NTSTATUS Status;
+ LONG AllocatedCount;
+ LARGE_INTEGER Time;
+ BOOLEAN Valid;
+
+ PAGED_CODE();
+
+ Status = STATUS_SUCCESS;
+ /* Loop until we have an UUID to return */
+ while (TRUE)
+ {
+ /* Try to gather node values */
+ do
+ {
+ Time.QuadPart = ExpUuidCachedValues.Time;
+
+ RtlCopyMemory(&Uuid->Data4[0],
+ &ExpUuidCachedValues.NodeId[0],
+ SEED_BUFFER_SIZE);
+ Valid = ExpUuidCacheValid;
+ AllocatedCount = InterlockedDecrement(&ExpUuidCachedValues.AllocatedCount);
+ }
+ /* Loop till we can do it without being disturbed */
+ while (Time.QuadPart != ExpUuidCachedValues.Time);
+
+ /* We have more than an allocated UUID left, that's OK to return! */
+ if (AllocatedCount >= 0)
+ {
+ break;
+ }
+
+ /*
+ * Here, we're out of UUIDs, we need to allocate more
+ * We need to be alone to do it, so lock the mutex
+ */
+ ExAcquireFastMutex(&ExpUuidLock);
+ if (Time.QuadPart == ExpUuidCachedValues.Time)
+ {
+ /* If allocation fails, bail out! */
+ Status = ExpUuidGetValues(&ExpUuidCachedValues);
+ if (Status != STATUS_SUCCESS)
+ {
+ ExReleaseFastMutex(&ExpUuidLock);
+ return Status;
+ }
+
+ /* Save our current sequence if changed */
+ ExpUuidSaveSequenceNumberIf();
+ }
+ ExReleaseFastMutex(&ExpUuidLock);
+ }
+
+ /*
+ * Once here, we've got an UUID to return
+ * But, if our init wasn't sane, then, make
+ * sure it's only used locally
+ */
+ if (!Valid)
+ {
+ Status = RPC_NT_UUID_LOCAL_ONLY;
+ }
+
+ /* Set our timestamp - see RFC4211 */
+ Time.QuadPart -= AllocatedCount;
+ Uuid->Data1 = Time.LowPart;
+ Uuid->Data2 = Time.HighPart;
+ /* We also set the bit for GUIDv1 */
+ Uuid->Data3 = ((Time.HighPart >> 16) & 0x0FFF) | 0x1000;
+
+ return Status;