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

962 lines
32 KiB

  1. /*
  2. coguid.cpp - self contained GUID allocator module
  3. Bob Atkinson (BobAtk@microsoft.com) June 1993
  4. Modified for temporary use by billm April 1994
  5. This file contains all that is necessary to generate GUIDs with high
  6. frequency and robustness without a network card on WIN32.
  7. We allocate a pseudo-random node id based
  8. on machine state.
  9. There is only one public API in this file: HrCreateGuidNoNet().
  10. The following are relevant reference documents:
  11. Project 802: Local and Metropolitan Area Network Standard
  12. Draft Standard P802.1A/D10 1 April 1990
  13. Prepared by the IEEE 802.1
  14. (Describes IEEE address allocation)
  15. DEC / HP
  16. Network Computing Architecture
  17. Remote Procedure Call RunTime Extensions Specification
  18. Version OSF TX1.0.11 Steven Miller July 23, 1992
  19. (Chapter 10 describes UUID allocation)
  20. A word about "GUID" vs "UUID" vs ... In fact, they're all the SAME THING.
  21. Meaning that, once allocated, they're all interoperable / comparable / etc.
  22. The standard describes a memory layout for a 16-byte structure (long, word,
  23. word, array of bytes) which gets around byte order issues. It then goes on
  24. to describe three different "variants" of allocation algorithm for these 16
  25. byte structures; each variant is encoded by certain high order bits in the
  26. "clockSeqHiAndReserved" byte.
  27. Variant 0 is (I believe) the historical Apollo allocation algorithm.
  28. Variant 1 is what is implemented here.
  29. Variant 2 is created according to the "Microsoft GUID specification."
  30. Careful: Despite the name here being HrCreateGuidNoNet() we are NOT allocating
  31. according to Variant 2; we are using Variant 1. Variant 2 works by having
  32. a range of the bits be a (MS allocated, for now) authority identifier, and
  33. the remaining bits be whatever that authority wants. Variant 1, by
  34. contrast, has a precise standard for how all the bits are allocated. But
  35. as the resulting 16 bytes are in fact all mutually compatible, this
  36. confusion in terminology is of no actual consequence.
  37. Variant 1 is allocated as follows. First, Variant 1 allocates four bits
  38. as a "version" field. Here we implement according to version 1; version 2
  39. is defined for "UUIDs genereated for OSF DCE Security purposes, conformant
  40. to this specification, but substuting a Unix id value for the timeLow
  41. value." I know of no other legal versions that have been allocated.
  42. The other fields of Variant 1 are as follows. The high 6 bytes are the
  43. IEEE allocated node id on which the allocator is running. The low eight
  44. bytes are the current "time": we are to take the current time as
  45. avialable to the precision of milliseconds and multiply by 10,000, thus
  46. giving a logical precision of 100 ns. Within these lower bits, we are to
  47. sequentially increment a count as we allocate guids. Thus, the maximum rate
  48. at which we can allocate is indeed 1 GUID / 100 ns. The remaining two bytes
  49. are used for a "clock sequence". The intent of the clock sequence is to
  50. provide some protection against the real clock going backwards in time.
  51. We initially randomly allocate the clock sequence, and then increment it
  52. each time we detect the clock going backwards (the last time used and the
  53. current clock sequence are stored in the registry).
  54. Presently (93.06.11) this implementation contains byte-order sensitivities,
  55. particularly in the 64-bit arithmetic helper routines below. This
  56. implementation is also not suitable for use on a premptive system.
  57. This function is only called when UuidCreate() fails.
  58. */
  59. #include "_apipch.h"
  60. #ifndef STATIC
  61. #ifdef DEBUG
  62. #define STATIC
  63. #else
  64. #define STATIC static
  65. #endif
  66. #endif
  67. #ifdef WIN32
  68. #define INTERNAL STATIC HRESULT __stdcall
  69. #define INTERNAL_(type) STATIC type __stdcall
  70. //==============================================================
  71. // Start of 64 bit arithmetic utility class
  72. //==============================================================
  73. INTERNAL_(BOOL)
  74. FLessThanOrEqualFTs(FILETIME ft1, FILETIME ft2)
  75. {
  76. if (ft1.dwHighDateTime < ft2.dwHighDateTime)
  77. return TRUE;
  78. else if (ft1.dwHighDateTime == ft2.dwHighDateTime)
  79. return ft1.dwLowDateTime <= ft2.dwLowDateTime;
  80. else
  81. return FALSE;
  82. }
  83. INTERNAL_(FILETIME)
  84. FtAddUShort(FILETIME ft1, USHORT ush)
  85. {
  86. FILETIME ft;
  87. ft.dwLowDateTime = ft1.dwLowDateTime + ush;
  88. ft.dwHighDateTime = ft1.dwHighDateTime +
  89. ((ft.dwLowDateTime < ft1.dwLowDateTime ||
  90. ft.dwLowDateTime < ush) ?
  91. 1L : 0L);
  92. return ft;
  93. }
  94. //==============================================================
  95. // End of 64 bit arithmetic utility
  96. //==============================================================
  97. #pragma pack(1)
  98. struct _NODEID // machine identifier
  99. {
  100. union {
  101. BYTE rgb[6];
  102. WORD rgw[3];
  103. };
  104. };
  105. #pragma pack()
  106. typedef struct _NODEID NODEID;
  107. typedef USHORT CLKSEQ;
  108. typedef CLKSEQ FAR * PCLKSEQ;
  109. #define clkseqNil ((CLKSEQ)-1)
  110. struct _UDBK // data from which a block of UUIDs can be generated
  111. {
  112. DWORD timeLowNext; // lower bound of block of time values
  113. DWORD timeLowLast; // upper bound of block of time values
  114. DWORD timeHigh; // high dword of timeLowXXXX
  115. CLKSEQ clkseq; // the clock sequence
  116. NODEID nodeid;
  117. };
  118. typedef struct _UDBK UDBK;
  119. INTERNAL_(BOOL) FLessThanOrEqualFTs(FILETIME ft1, FILETIME ft2);
  120. INTERNAL_(FILETIME) FtAddUShort(FILETIME ft1, USHORT ush);
  121. INTERNAL GetPseudoRandomNodeId(NODEID*);
  122. INTERNAL_(void) GetCurrentTimeULong64(FILETIME *);
  123. INTERNAL GetNextBlockOTime(PCLKSEQ pClockSeq, FILETIME *pftCur);
  124. INTERNAL ReadRegistry (PCLKSEQ pClockSeqPrev, FILETIME *pftPrev);
  125. INTERNAL InitRegistry (PCLKSEQ pClockSeqPrev, FILETIME *pftPrev);
  126. INTERNAL WriteRegistry(CLKSEQ, CLKSEQ, const FILETIME);
  127. INTERNAL_(LONG) CountFilesInDirectory(LPCSTR szDirPath);
  128. INTERNAL_(void) FromHexString(LPCSTR sz, LPVOID rgb, USHORT cb);
  129. INTERNAL_(void) ToHexString(LPVOID rgb, USHORT cb, LPSTR sz);
  130. INTERNAL_(WORD) Cyc(WORD w);
  131. INTERNAL_(void) ShiftNodeid(NODEID FAR* pnodeid);
  132. #ifdef MAC
  133. OSErr __pascal GetDirName(short vRefNum, long ulDirID, StringPtr name);
  134. int MacCountFiles(StringPtr pathName, short vRefNum, long parID);
  135. #endif
  136. // We amortize the overhead cost of allocating UUIDs by returning them in
  137. // time-grouped blocks to the actual CoCreateGUID routine. This two-level
  138. // grouping is largely historical, having been derived from the original
  139. // NT UuidCreate() routine, but has been retained here with the thought that
  140. // the efficiencies gained will be needed in future premptive system (Windows 95).
  141. static const ULONG cuuidBuffer = 1000; // how many uuids to get per registry hit.
  142. static const ULONG cuuidReturnMax = 100; // how many max to return on each GetUDBK.
  143. static const DWORD dwMax = 0xFFFFFFFF; // largest legal DWORD
  144. //================================================================================
  145. // Start of meat of implementation
  146. //================================================================================
  147. INTERNAL GetUDBK(UDBK *pudbk)
  148. // Init the given UDBK so that a bunch of UUIDs can be generated therefrom. This
  149. // routine hits the system registry and the disk, and so is somewhat slow. But we
  150. // amortize the cost over the block of UUIDs that are returned.
  151. {
  152. HRESULT hr;
  153. ULONG cuuidReturn;
  154. ULONG cuuidLeftInBuffer;
  155. FILETIME ftCur;
  156. // These next block of variables in effect comprise the internal state of
  157. // the UUID generator. Notice that this works only in a shared-data space
  158. // DLL world, such as Win3.1. In non-shared environments, this will
  159. // need to be done differently, perhaps by putting this all in a server process.
  160. // In a premptively scheduled system, this function is all a critical section.
  161. static DWORD timeLowFirst = 0;
  162. static DWORD timeLowLast = 0;
  163. static CLKSEQ clkseq;
  164. static DWORD timeHigh;
  165. static NODEID nodeid = { 0, 0, 0, 0, 0, 0 };
  166. cuuidLeftInBuffer = timeLowLast - timeLowFirst;
  167. if (cuuidLeftInBuffer == 0) {
  168. // Our buffer of uuid space is empty, or this is the first time in to this routine.
  169. // Get another block of time from which we can generate UUIDs.
  170. hr = GetNextBlockOTime(&clkseq, &ftCur);
  171. if (hr != NOERROR) return hr;
  172. if (nodeid.rgw[0] == 0 && nodeid.rgw[1] == 0 && nodeid.rgw[2] == 0) {
  173. hr = GetPseudoRandomNodeId(&nodeid);
  174. if (hr != NOERROR) return hr;
  175. }
  176. timeHigh = ftCur.dwHighDateTime;
  177. // Set the buffer bottom. Return few enough so that we don't wrap the low dw.
  178. timeLowFirst = ftCur.dwLowDateTime;
  179. timeLowLast = (timeLowFirst > (dwMax - cuuidBuffer)) ? dwMax : timeLowFirst + cuuidBuffer;
  180. cuuidLeftInBuffer = timeLowLast - timeLowFirst;
  181. }
  182. cuuidReturn = (cuuidLeftInBuffer < cuuidReturnMax) ? cuuidLeftInBuffer : cuuidReturnMax;
  183. // Set the output values and bump the usage count
  184. pudbk->timeLowNext = timeLowFirst;
  185. timeLowFirst += cuuidReturn;
  186. pudbk->timeLowLast = timeLowFirst;
  187. pudbk->timeHigh = timeHigh;
  188. pudbk->clkseq = clkseq;
  189. pudbk->nodeid = nodeid;
  190. return NOERROR;
  191. }
  192. INTERNAL_(void) GetCurrentTimeUlong64(FILETIME *pft)
  193. // Return the current time (# of 100 nanoseconds intervals since 1/1/1601).
  194. // Make sure that we never return the same time twice by high-frequency calls
  195. // to this function.
  196. //
  197. {
  198. static FILETIME ftPrev = {0};
  199. SYSTEMTIME syst;
  200. GetSystemTime(&syst);
  201. if (!SystemTimeToFileTime(&syst, pft))
  202. {
  203. TrapSz1("Error %08lX calling SystemTimeToFileTime", GetLastError());
  204. pft->dwLowDateTime = 0;
  205. pft->dwHighDateTime =0;
  206. }
  207. if (memcmp(pft, &ftPrev, sizeof(FILETIME)) == 0)
  208. *pft = FtAddUShort(*pft, 1);
  209. memcpy(&ftPrev, pft, sizeof(FILETIME));
  210. }
  211. INTERNAL GetNextBlockOTime(PCLKSEQ pclkseq, FILETIME *pft)
  212. // Updates, and potentially create, the registry entries that maintain
  213. // the block of time values for UUIDs that we've created. The algorithm
  214. // is basically:
  215. // If the registry entries don't exist, then create them. Use
  216. // a random number for the clock sequence.
  217. // If the entries do exist, the dig out of them the previous
  218. // clock sequence and previous time allocated. If the previous time
  219. // is greater than the current time then bump (and store) the
  220. // clock sequence.
  221. {
  222. FILETIME ftRegistry;
  223. HRESULT hr;
  224. CLKSEQ clkseqPrev;
  225. GetCurrentTimeUlong64(pft);
  226. hr = ReadRegistry(pclkseq, &ftRegistry);
  227. if (hr != NOERROR)
  228. return InitRegistry(pclkseq, pft);
  229. // If the clock's gone backwards, bump the clock seq. The clock
  230. // seq is only 14 bits significant; don't use more.
  231. clkseqPrev = *pclkseq;
  232. if (FLessThanOrEqualFTs(*pft, ftRegistry)) {
  233. clkseqPrev = clkseqNil;
  234. *pclkseq += 1;
  235. if (*pclkseq == 16384) // 2^14
  236. *pclkseq = 0;
  237. }
  238. return WriteRegistry(*pclkseq, clkseqPrev, *pft);
  239. }
  240. // Use a private ini file for now. This will go away when CoCreateGuid
  241. // is available on NT and Windows 95.
  242. static const char szDataKey[] = "CoCreateGuid";
  243. static const char szClkSeq[] = "PreviousClockSequence"; // same as UUIDGEN.EXE
  244. static const char szTime[] = "PreviousTimeAllocated"; // same as UUIDGEN.EXE
  245. static const char szNodeId[] = "NodeId";
  246. static const char szBlank[] = ""; // used for default GetPrivateProfileString values
  247. static const char szProfileFile[] = "mapiuid.ini";
  248. #define CCHHEXBUFFERMAX 32
  249. INTERNAL ReadRegistry(PCLKSEQ pclkseq, FILETIME *pft)
  250. // Read the previous values of the clock sequence and the time from
  251. // the registry, if they are there. If they are not, then return
  252. // an error.
  253. {
  254. SCODE sc = S_OK;
  255. LONG cch = 0;
  256. char szHexBuffer[CCHHEXBUFFERMAX];
  257. // use our private ini file
  258. cch = CCHHEXBUFFERMAX;
  259. cch = GetPrivateProfileString(szDataKey, szClkSeq, szBlank,
  260. szHexBuffer, (int)cch, szProfileFile);
  261. if (cch == 0 || cch >= CCHHEXBUFFERMAX) {
  262. sc = MAPI_E_DISK_ERROR;
  263. goto ErrRet;
  264. }
  265. FromHexString(szHexBuffer, pclkseq, sizeof(CLKSEQ));
  266. cch = CCHHEXBUFFERMAX;
  267. cch = GetPrivateProfileString(szDataKey, szTime, szBlank,
  268. szHexBuffer, (int)cch, szProfileFile);
  269. if (cch == 0 || cch >= CCHHEXBUFFERMAX) {
  270. sc = MAPI_E_DISK_ERROR;
  271. goto ErrRet;
  272. }
  273. FromHexString(szHexBuffer, pft, sizeof(FILETIME));
  274. // Fall through to ErrRet
  275. ErrRet:
  276. return ResultFromScode(sc);
  277. }
  278. INTERNAL InitRegistry(PCLKSEQ pclkseq, FILETIME *pft)
  279. // Invent a new clock sequence using a pseudo random number. Then
  280. // write the clock sequence and the current time to the registry.
  281. {
  282. LONG cfile;
  283. #ifdef MAC
  284. short vRefNum;
  285. long ulDirID;
  286. Str32 stDirName;
  287. FindFolder((short)kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
  288. &vRefNum, &ulDirID);
  289. GetDirName(vRefNum, ulDirID, stDirName);
  290. cfile = MacCountFiles(stDirName, vRefNum, ulDirID);
  291. #else
  292. const int cchWindowsDir = 145; // 144 is recommended size according to SDK
  293. LPSTR szWindowsDir = NULL;
  294. if ( FAILED(MAPIAllocateBuffer(cchWindowsDir, (LPVOID *) &szWindowsDir))
  295. || GetWindowsDirectory(szWindowsDir, cchWindowsDir) == 0)
  296. goto ErrRet;
  297. // For the clock sequence, we use the number of files in the current
  298. // windows directory, on the theory that that this is highly sensitive
  299. // to the exact set of applications that have been installed on this
  300. // particular machine.
  301. cfile = CountFilesInDirectory(szWindowsDir);
  302. if (cfile == -1)
  303. goto ErrRet;
  304. MAPIFreeBuffer(szWindowsDir);
  305. szWindowsDir = NULL;
  306. goto NormRet;
  307. ErrRet:
  308. MAPIFreeBuffer(szWindowsDir);
  309. return ResultFromScode(MAPI_E_CALL_FAILED);
  310. NormRet:
  311. #endif // MAC
  312. *pclkseq = (CLKSEQ)Cyc((WORD)cfile);
  313. // Also use ms since boot so as to get a more time-varying value
  314. *pclkseq ^= (CLKSEQ)Cyc((WORD)GetTickCount());
  315. *pclkseq &= 16384-1; // only allow 14 bits of significance in clock seq
  316. GetCurrentTimeUlong64(pft);
  317. return WriteRegistry(*pclkseq, clkseqNil, *pft);
  318. }
  319. INTERNAL WriteRegistry(CLKSEQ clkseq, CLKSEQ clkseqPrev, const FILETIME ft)
  320. // Write the clock sequence and time into the registry so that we can
  321. // retrieve it later on a subsequent reboot. clkseqPrev is passed so that
  322. // we can avoid writing the clock sequence if in fact we know it to be
  323. // currently valid. This was measured as important for performance.
  324. {
  325. SCODE sc = S_OK;
  326. char szHexBuffer[CCHHEXBUFFERMAX];
  327. if (clkseq != clkseqPrev) { // don't write if clock sequence same (often is)
  328. ToHexString((LPVOID)&clkseq, sizeof(CLKSEQ), szHexBuffer);
  329. if (!WritePrivateProfileString(szDataKey, szClkSeq, szHexBuffer, szProfileFile)) {
  330. sc = MAPI_E_DISK_ERROR;
  331. goto ErrRet;
  332. }
  333. }
  334. ToHexString((LPVOID)&ft, sizeof(FILETIME), szHexBuffer);
  335. if (!WritePrivateProfileString(szDataKey, szTime, szHexBuffer, szProfileFile)) {
  336. sc = MAPI_E_DISK_ERROR;
  337. goto ErrRet;
  338. }
  339. ErrRet:
  340. WritePrivateProfileString(NULL,NULL,NULL,szProfileFile); // flush the ini cache
  341. return ResultFromScode(sc);
  342. }
  343. #ifdef MAC
  344. #define GET_DIR_INFO -1
  345. int MacCountFiles(StringPtr pathName, short vRefNum, long parID)
  346. // Return the number of files in the specified Mac directory.
  347. {
  348. CInfoPBRec paramBlk;
  349. paramBlk.hFileInfo.ioNamePtr = pathName; // Pascal string
  350. paramBlk.hFileInfo.ioVRefNum = vRefNum;
  351. // not necessary for full pathname
  352. paramBlk.hFileInfo.ioDirID = paramBlk.dirInfo.ioDrParID = parID;
  353. paramBlk.hFileInfo.ioFDirIndex = GET_DIR_INFO;
  354. PBGetCatInfoSync(&paramBlk);
  355. return(((DirInfo *) &paramBlk)->ioDrNmFls);
  356. }
  357. #endif
  358. INTERNAL_(LONG) CountFilesInDirectory(LPCSTR szDirPath)
  359. // Return the number of files in this directory. The path may or may not
  360. // currently end with a slash.
  361. {
  362. int cfile = 0;
  363. #ifndef MAC
  364. LPCSTR szStar = "*.*";
  365. char chLast = szDirPath[lstrlen(szDirPath)-1];
  366. LPSTR szPath;
  367. WIN32_FIND_DATA ffd;
  368. HANDLE hFile;
  369. if (FAILED(MAPIAllocateBuffer(lstrlen(szDirPath) +1 +lstrlen(szStar) +1,
  370. (LPVOID *) &szPath)))
  371. return -1;
  372. lstrcpy(szPath, szDirPath);
  373. /***
  374. #ifdef DBCS
  375. chLast = *(SzGPrev(szDirPath, szDirPath+lstrlen(szDirPath)));
  376. #endif
  377. ***/
  378. // Get the last character in above szDirPath
  379. {
  380. LPCSTR lp = szDirPath;
  381. while(*lp)
  382. {
  383. chLast = *lp;
  384. lp = CharNext(lp);
  385. }
  386. }
  387. if (!(chLast == '\\' || chLast == '/'))
  388. lstrcat(szPath, "\\");
  389. lstrcat(szPath, szStar);
  390. ffd.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
  391. hFile = FindFirstFile(szPath, &ffd);
  392. if (hFile != INVALID_HANDLE_VALUE)
  393. {
  394. cfile++;
  395. while (FindNextFile(hFile, &ffd))
  396. cfile++;
  397. FindClose(hFile);
  398. }
  399. MAPIFreeBuffer(szPath);
  400. #else
  401. FSSpec pfss;
  402. if (UnwrapFile(szDirPath, &pfss))
  403. cfile = MacCountFiles(pfss.name, pfss.vRefNum, pfss.parID);
  404. else
  405. cfile = Random();
  406. #endif
  407. return cfile;
  408. }
  409. #pragma warning (disable:4616) // warning number out of range
  410. #pragma warning (disable:4704) // in-line assembler precludes global optimizations
  411. INTERNAL_(void) ShiftNodeid(NODEID FAR* pnodeid)
  412. // Shift the nodeid so as to get a randomizing effect
  413. {
  414. // Rotate the whole NODEID left one bit. NODEIDs are 6 bytes long.
  415. #if !defined(M_I8086) && !defined(M_I286) && !defined(M_I386) && !defined(_M_IX86)
  416. BYTE bTmp;
  417. BYTE bOld=0;
  418. /* Compilers complain about conversions here. Pragma the warning off. */
  419. #pragma warning(disable:4244) // possible data loss in conversion
  420. bTmp = pnodeid->rgb[5];
  421. pnodeid->rgb[5] = (pnodeid->rgb[5] << 1) + bOld;
  422. bOld = (bTmp & 0x80);
  423. bTmp = pnodeid->rgb[4];
  424. pnodeid->rgb[4] = (pnodeid->rgb[4] << 1) + bOld;
  425. bOld = (bTmp & 0x80);
  426. bTmp = pnodeid->rgb[3];
  427. pnodeid->rgb[3] = (pnodeid->rgb[3] << 1) + bOld;
  428. bOld = (bTmp & 0x80);
  429. bTmp = pnodeid->rgb[2];
  430. pnodeid->rgb[2] = (pnodeid->rgb[2] << 1) + bOld;
  431. bOld = (bTmp & 0x80);
  432. bTmp = pnodeid->rgb[1];
  433. pnodeid->rgb[1] = (pnodeid->rgb[1] << 1) + bOld;
  434. bOld = (bTmp & 0x80);
  435. bTmp = pnodeid->rgb[0];
  436. pnodeid->rgb[0] = (pnodeid->rgb[0] << 1) + bOld;
  437. bOld = (bTmp & 0x80);
  438. pnodeid->rgb[5] = pnodeid->rgb[5] + bOld;
  439. #pragma warning(default:4244)
  440. #else
  441. _asm {
  442. mov ebx, pnodeid
  443. sal WORD PTR [ebx], 1 // low order bit now zero
  444. rcl WORD PTR [ebx+2], 1
  445. rcl WORD PTR [ebx+4], 1
  446. // Now put bit that fell off end into low order bit
  447. adc WORD PTR [ebx],0 // add carry bit back in
  448. }
  449. #endif
  450. }
  451. INTERNAL_(WORD) Cyc(WORD w)
  452. // Randomizing function used to distribute random state values uniformly
  453. // in 0..65535 before use.
  454. {
  455. // // // Use one iteration of the library random number generator.
  456. // // srand(w);
  457. // // return rand();
  458. //
  459. // The following is what this would actually do, taken from the library
  460. // source. It really isn't very good.
  461. // return (WORD)( ((((long)w) * 214013L + 2531011L) >> 16) & 0x7fff );
  462. // Really what we do: use the random number generator presented in
  463. // CACM Oct 1988 Vol 31 Number 10 p 1195, slightly optimized since
  464. // we are only interested in 16bit input/seed values.
  465. const LONG a = 16807L;
  466. const LONG m = 2147483647L; // 2^31 -1. Is prime.
  467. const LONG q = 127773L; // m div a
  468. const LONG r = 2386L; // m mod a
  469. LONG seed = (LONG)w + 1L; // +1 so as to avoid problems with zero
  470. // LONG hi = seed / q; // seed div q. Here always zero, since seed < q.
  471. // LONG lo = seed % q; // seed mod q. Here always seed.
  472. LONG test = a*seed; // a * lo - r * hi
  473. if (test > 0)
  474. seed = test;
  475. else
  476. seed = test + m;
  477. // In a true random number generator, what we do now is scale the bits
  478. // to return a floating point number in the range 0..1. However, we have
  479. // no need here for that degree of quality of number sequence, and we
  480. // wish to avoid the floating point calculations. Therefore we simply xor
  481. // the words together.
  482. // // p1193, top right column: seed is in the range 1..m-1, inclusive
  483. // return (double)seed / m; // what the text recommends
  484. // return (double)(seed-1) / (m-1); // variation: allows zero as legal value
  485. return (WORD) (LOWORD(seed) ^ HIWORD(seed)); // use all the bits
  486. }
  487. INTERNAL GenerateNewNodeId(NODEID* pnodeid)
  488. // Can't get from net. Generate one. We do this by using
  489. // various statistics files in certain key directories on
  490. // the machine.
  491. {
  492. // REVIEW: Consider not bothering to init the NODEID, thus getting
  493. // random state from RAM?
  494. #ifndef MAC
  495. // Not including this should help make up for some of the (here)
  496. // randomizing funcitons the MAC doesn't support.
  497. memset(pnodeid, 0, sizeof(*pnodeid));
  498. { // BLOCK
  499. // First, merge in random state generated from the file system
  500. DWORD dwSectPerClust;
  501. DWORD dwBytesPerSect;
  502. DWORD dwFreeClust;
  503. DWORD dwClusters;
  504. (void) GetDiskFreeSpace(NULL, &dwSectPerClust, &dwBytesPerSect,
  505. &dwFreeClust, &dwClusters);
  506. pnodeid->rgw[0] ^= Cyc(LOWORD(dwBytesPerSect));
  507. pnodeid->rgw[1] ^= Cyc(HIWORD(dwBytesPerSect));
  508. pnodeid->rgw[2] ^= Cyc(HIWORD(dwClusters));
  509. ShiftNodeid(pnodeid);
  510. pnodeid->rgw[0] ^= Cyc(LOWORD(dwFreeClust));
  511. pnodeid->rgw[1] ^= Cyc(HIWORD(dwFreeClust));
  512. pnodeid->rgw[2] ^= Cyc(LOWORD(dwClusters));
  513. } // BLOCK
  514. #else
  515. { // BLOCK
  516. ParamBlockRec paramBlk = {0};
  517. paramBlk.volumeParam.ioVolIndex = 1;
  518. PBGetVInfoSync(&paramBlk);
  519. pnodeid->rgw[0] ^= Cyc(LOWORD(paramBlk.volumeParam.ioVAlBlkSiz));
  520. pnodeid->rgw[1] ^= Cyc(HIWORD(paramBlk.volumeParam.ioVAlBlkSiz));
  521. pnodeid->rgw[2] ^= Cyc(HIWORD(paramBlk.volumeParam.ioVNmAlBlks));
  522. ShiftNodeid(pnodeid);
  523. pnodeid->rgw[0] ^= Cyc(LOWORD(paramBlk.volumeParam.ioVFrBlk));
  524. pnodeid->rgw[1] ^= Cyc(HIWORD(paramBlk.volumeParam.ioVFrBlk));
  525. pnodeid->rgw[2] ^= Cyc(LOWORD(paramBlk.volumeParam.ioVNmAlBlks));
  526. } // BLOCK
  527. #endif
  528. { // BLOCK
  529. // Next, mix in other stuff.
  530. // As we generate and *store* the nodeid, using the time should not
  531. // cause corellation problems with the fact that the time is also
  532. // used as part of the fundamental uuid generation algorithm.
  533. MEMORYSTATUS ms;
  534. FILETIME ft;
  535. DWORD dw;
  536. POINT pt;
  537. #ifndef MAC
  538. LPVOID lpv;
  539. #else
  540. PSN psn;
  541. DWORD dwFeature;
  542. Gestalt(gestaltOSAttr, &dwFeature);
  543. if (BitTst(&dwFeature, 31 - gestaltTempMemSupport))
  544. {
  545. // If temporary memory is available.
  546. ms.dwAvailPhys = (DWORD) TempFreeMem();
  547. ms.dwAvailVirtual = (DWORD) TempMaxMem(&ms.dwAvailVirtual);
  548. ms.dwAvailPageFile = (DWORD) TempTopMem();
  549. }
  550. else
  551. {
  552. // If temporary memory is not available.
  553. ms.dwAvailPhys = (DWORD) TickCount();
  554. GetDateTime(&ms.dwAvailVirtual);
  555. }
  556. #endif
  557. #ifndef MAC
  558. ms.dwLength = sizeof(MEMORYSTATUS);
  559. GlobalMemoryStatus(&ms);
  560. #endif
  561. ShiftNodeid(pnodeid);
  562. GetCurrentTimeUlong64(&ft);
  563. pnodeid->rgw[0] ^= Cyc(HIWORD(ft.dwHighDateTime)); // Use hi-order six bytes as time is *10000
  564. pnodeid->rgw[1] ^= Cyc(LOWORD(ft.dwHighDateTime));
  565. pnodeid->rgw[2] ^= Cyc(HIWORD(ft.dwLowDateTime));
  566. ShiftNodeid(pnodeid);
  567. pnodeid->rgw[0] ^= Cyc(LOWORD(ms.dwAvailPhys));
  568. pnodeid->rgw[1] ^= Cyc(LOWORD(ms.dwAvailVirtual));
  569. pnodeid->rgw[2] ^= Cyc(LOWORD(ms.dwAvailPageFile));
  570. ShiftNodeid(pnodeid);
  571. pnodeid->rgw[0] ^= Cyc(HIWORD(ms.dwAvailPhys));
  572. pnodeid->rgw[1] ^= Cyc(HIWORD(ms.dwAvailVirtual));
  573. pnodeid->rgw[2] ^= Cyc(HIWORD(ms.dwAvailPageFile));
  574. ShiftNodeid(pnodeid);
  575. dw = GetTickCount();
  576. pnodeid->rgw[0] ^= Cyc(HIWORD(dw)); // Time (ms) since boot
  577. pnodeid->rgw[1] ^= Cyc(LOWORD(dw));
  578. #ifndef MAC
  579. pnodeid->rgw[2] ^= Cyc(LOWORD(CountClipboardFormats()));// Number of items on the clipboard
  580. #endif
  581. GetCursorPos(&pt); // Cursor Position
  582. ShiftNodeid(pnodeid);
  583. pnodeid->rgw[0] ^= Cyc((WORD)(pt.x));
  584. pnodeid->rgw[1] ^= Cyc((WORD)(pt.y));
  585. #ifdef MAC
  586. MacGetCurrentProcess(&psn);
  587. pnodeid->rgw[2] ^= Cyc(LOWORD(psn.lowLongOfPSN));
  588. #else
  589. pnodeid->rgw[2] ^= Cyc(LOWORD((DWORD)GetCurrentThread())); // Current thread we're running in
  590. #endif
  591. ShiftNodeid(pnodeid);
  592. #ifdef MAC
  593. pnodeid->rgw[0] ^= Cyc(HIWORD(psn.lowLongOfPSN));
  594. pnodeid->rgw[1] ^= Cyc(LOWORD(psn.highLongOfPSN));
  595. #else
  596. pnodeid->rgw[0] ^= Cyc(HIWORD(GetCurrentThread()));
  597. pnodeid->rgw[1] ^= Cyc((WORD)GetOEMCP()); // sensitive to different countries
  598. #endif
  599. pnodeid->rgw[2] ^= Cyc((WORD)GetSystemMetrics(SM_SWAPBUTTON)); // different for lefties vs righties
  600. ShiftNodeid(pnodeid);
  601. #ifndef MAC
  602. lpv = GetEnvironmentStrings();
  603. pnodeid->rgw[0] ^= Cyc(HIWORD((DWORD)lpv));
  604. pnodeid->rgw[1] ^= Cyc(LOWORD((DWORD)lpv));
  605. #endif
  606. pnodeid->rgw[2] ^= Cyc(HIWORD(GetCursor()));
  607. ShiftNodeid(pnodeid);
  608. #ifdef MAC
  609. GetCursorPos(&pt);
  610. #else
  611. GetCaretPos(&pt);
  612. #endif
  613. pnodeid->rgw[0] ^= Cyc((WORD)(pt.x));
  614. pnodeid->rgw[1] ^= Cyc((WORD)(pt.y));
  615. pnodeid->rgw[2] ^= Cyc(LOWORD((DWORD)GetCursor()));
  616. ShiftNodeid(pnodeid);
  617. pnodeid->rgw[0] ^= Cyc((WORD)(DWORD)GetDesktopWindow());
  618. pnodeid->rgw[1] ^= Cyc((WORD)(DWORD)GetActiveWindow());
  619. #ifndef MAC
  620. pnodeid->rgw[2] ^= Cyc((WORD)(DWORD)GetModuleHandle("OLE32"));
  621. #endif
  622. } // BLOCK
  623. /* The following exerpts are taken from
  624. Project 802: Local and Metropolitan Area Network Standard
  625. Draft Standard P802.1A/D10 1 April 1990
  626. Prepared by the IEEE 802.1
  627. and is available in MS technical library. The key point about this is the
  628. second LSB in the first byte of a real IEEE address is always zero.
  629. Page 18:
  630. "5. Universal Addresses and Protocol Identifiers
  631. The IEEE makes it possible for organizations to employ unique individual
  632. LAN MAC addresses, group addresses, and protocol identifiers. It does so by
  633. assigning organizationally unique identifiers, which are 24 bits in length.
  634. [...] Though the organizationally unique identifiers are 24 bits in length,
  635. their true address space is 22 bits. The first bit can be set to 1 or 0
  636. depending on the application. The second bit for all assignments is zero.
  637. The remaining 22 bits [...] result in 2**22 (approximately
  638. 4 million identifiers.
  639. [...] The multicast bit is the least significant bit of the first octet, A.
  640. [...] 5.1 Organizationally Unique Identifier
  641. [...] The organizationally unique identifier is 24 bits in length and its
  642. bit pattern is shown below. Organizationally unique identifiers are
  643. assigned as 24 bit values with both values (0,1) being assigned to the
  644. first bit and the second bit being set to 0 indicates that the assignment
  645. is universal. Organizationally unique identifiers with the second bit set
  646. to 1 are locally assigned and have no relationship to the IEEE-assigned
  647. values (as described herein).
  648. The organizationally unique identifier is defined to be:
  649. 1st bit 24th bit
  650. | |
  651. a b c d e ....... x y
  652. | |
  653. | Always set to zero
  654. Bit can be set to 0 or 1 depending on application [application here is
  655. noting at all to do with what we, MS, call an application]
  656. [...] 5.2 48-Bit Universal LAN Mac Addresses
  657. [...] A 48 bit universal address consists of two parts. The first 24 bits
  658. correspond to the organizationally unique identifier as assigned by the
  659. IEEE except that the assignee may set the first bit to 1 for group
  660. addresses or set it to 0 for individual addresses. The second part,
  661. comprising the remaining 24 bits, is administered locally by the assignee.
  662. [...]
  663. octet:
  664. 0 1 2 3 4 5
  665. 0011 0101 0111 1011 0001 0010 0000 0000 0000 0000 0000 0001
  666. |
  667. First bit transmitted on the LAN medium. (Also the Individual/Group
  668. Address Bit.) The hexadecimal representation is: AC-DE-48-00-00-80
  669. The Individual/Group (I/G) Address Bit (1st bit of octet 0) is used to
  670. identify the destination address either as an individual or as a group
  671. address. If the Individual/Group Address Bit is 0, it indicates that
  672. the address field contains an individual address. If this bit is 1, the
  673. address field contains a group address that identifies one or more (or
  674. all) stations connected to the LAN. The all-stations broadcast address
  675. is a special, pre-defined group address of all 1's.
  676. The Universally or Locally Administered Address Bit (2nd bit of octet 0)
  677. is the bit directly following the I/G bit. This bit indicates whether
  678. the address has been assigned by a local or universal administrator.
  679. Universally administered addresses have this bit set to 0. If this bit
  680. is set to 1, the entire address (i.e.: 48 bits) has been locally administered."
  681. */
  682. pnodeid->rgb[0] |= 2; // Ensure that this is a locally administered address
  683. pnodeid->rgb[0] &= ~1; // For future expandability: ensure one bit is
  684. // always zero.
  685. return NOERROR;
  686. }
  687. INTERNAL GetPseudoRandomNodeId(NODEID* pnodeid)
  688. // Use the same nodeid we did last time if it's there; otherwise,
  689. // make a new one.
  690. {
  691. HRESULT hr = NOERROR;
  692. char szHexBuffer[CCHHEXBUFFERMAX];
  693. LONG cch = CCHHEXBUFFERMAX;
  694. // See if we already have a nodeid registered
  695. cch = GetPrivateProfileString(szDataKey, szNodeId, szBlank,
  696. szHexBuffer, (int)cch, szProfileFile);
  697. if (cch != 0 && cch < CCHHEXBUFFERMAX) {
  698. FromHexString(szHexBuffer, pnodeid, sizeof(*pnodeid));
  699. } else {
  700. // If we don't presently have a nodeid registered, make one, then register it
  701. hr = GenerateNewNodeId(pnodeid);
  702. if (hr != NOERROR) goto Exit;
  703. ToHexString(pnodeid, sizeof(*pnodeid), szHexBuffer);
  704. if (WritePrivateProfileString(szDataKey, szNodeId, szHexBuffer,szProfileFile)) {
  705. WritePrivateProfileString(NULL,NULL,NULL,szProfileFile); // flush ini cache
  706. } else {
  707. hr = ResultFromScode(REGDB_E_WRITEREGDB);
  708. goto Exit;
  709. }
  710. }
  711. Exit:
  712. return hr;
  713. }
  714. //========================================================================
  715. INTERNAL_(unsigned char) ToUpper(unsigned char ch)
  716. {
  717. if (ch >= 'a' && ch <= 'z')
  718. return (unsigned char)(ch - 'a' + 'A');
  719. else
  720. return ch;
  721. }
  722. INTERNAL_(BYTE) FromHex(unsigned char ch)
  723. {
  724. BYTE b = (BYTE) (ToUpper(ch) - '0');
  725. if (b > 9)
  726. b -= 'A' -'9' -1;
  727. return b;
  728. }
  729. INTERNAL_(void) FromHexString(LPCSTR sz, LPVOID pv, USHORT cb)
  730. // Set the value of this array of bytes from the given hex string
  731. {
  732. BYTE FAR *rgb = (BYTE FAR*)pv;
  733. const char FAR *pch = sz;
  734. memset(rgb, 0, cb);
  735. if ((lstrlen(pch) & 1) != 0)
  736. rgb[0] = FromHex(*pch++); // Odd length; do the leading nibble separately
  737. while (*pch != '\0') {
  738. BYTE b = FromHex(*pch++); // get next nibble
  739. b = (BYTE)((b<<4) | FromHex(*pch++)); // and the next
  740. MoveMemory(&rgb[1], &rgb[0], cb-1); // shift us over one byte
  741. rgb[0] = b;
  742. }
  743. }
  744. INTERNAL_(unsigned char) ToHex(BYTE b)
  745. {
  746. b &= 0x0f;
  747. if (b > 9)
  748. return (BYTE)(b -10 + 'A');
  749. else
  750. return (BYTE)(b -0 + '0');
  751. }
  752. INTERNAL_(void) ToHexString(LPVOID pv, USHORT cb, LPSTR sz)
  753. // sz must be at least 2*cb +1 characters long
  754. {
  755. const BYTE FAR *rgb = (const BYTE FAR *)pv;
  756. const int ibLast = cb-1;
  757. int ib;
  758. for (ib = ibLast; ib >= 0; ib--) {
  759. sz[(ibLast-ib)*2] = ToHex((BYTE)(rgb[ib]>>4));
  760. sz[(ibLast-ib)*2+1] = ToHex(rgb[ib]);
  761. }
  762. sz[(ibLast+1)*2] = '\0';
  763. }
  764. //========================================================================
  765. // NOTE: As much as it might appear, this structure definition is NOT byte
  766. // order sensitive. That is, the structure definition and the field
  767. // manipulations that we use are in fact correct on both little and big
  768. // endian machines.
  769. #pragma pack(1)
  770. struct _INTERNALUUID
  771. {
  772. ULONG timeLow;
  773. USHORT timeMid;
  774. USHORT timeHighAndVersion;
  775. BYTE clkseqHighAndReserved;
  776. BYTE clkseqLow;
  777. BYTE nodeid[6];
  778. };
  779. #pragma pack()
  780. typedef struct _INTERNALUUID INTERNALUUID;
  781. enum {
  782. // Constants used below for manipulating fields in the UUID
  783. uuidReserved = 0x80, // we are a variant 1 UUID
  784. uuidVersion = 0x1000, // version 1 (high nibble significant)
  785. };
  786. //=================================================================
  787. STDAPI HrCreateGuidNoNet(GUID FAR *pguid)
  788. // This is the only public function in this file.
  789. // Return a newly allocated GUID.
  790. {
  791. static UDBK udbk; // We rely on static initialization to zero
  792. HRESULT hr;
  793. INTERNALUUID FAR* puuid = (INTERNALUUID FAR *)pguid;
  794. if (udbk.timeLowNext == udbk.timeLowLast)
  795. {
  796. if ((hr = GetUDBK(&udbk)) != NOERROR)
  797. return hr;
  798. }
  799. puuid->timeLow = udbk.timeLowNext++;
  800. puuid->timeMid = (USHORT)(udbk.timeHigh & 0xffff);
  801. puuid->timeHighAndVersion =
  802. (USHORT) (((USHORT)((udbk.timeHigh >> 16) & 0x0fff))
  803. | ((USHORT) uuidVersion));
  804. puuid->clkseqHighAndReserved =
  805. (BYTE)((BYTE) ((udbk.clkseq >> 8) & 0x3f)
  806. | (BYTE) uuidReserved);
  807. puuid->clkseqLow = (BYTE)(udbk.clkseq & 0xff);
  808. memcpy(&puuid->nodeid[0], &udbk.nodeid.rgb[0], sizeof(NODEID));
  809. return hrSuccess;
  810. }
  811. #endif /* WIN32 only */
  812.