Source code of Windows XP (NT5)
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.

825 lines
19 KiB

  1. /*++
  2. Author:
  3. Doron J. Holan (doronh), 1-22-1998
  4. --*/
  5. #ifndef WIN32_LEAN_AND_MEAN
  6. #define WIN32_LEAN_AND_MEAN
  7. #endif
  8. #include <windows.h>
  9. #include <msports.h>
  10. #include <tchar.h>
  11. #define GROWTH_VALUE 1024
  12. #define BITS_INA_BYTE 8
  13. typedef struct _DB_INFO {
  14. HANDLE RegChangedEvent;
  15. HANDLE AccessMutex;
  16. HKEY DBKey;
  17. PBYTE Ports;
  18. ULONG PortsLength;
  19. } DB_INFO, * PDB_INFO;
  20. #define HandleToDBInfo(h) ((PDB_INFO) (h))
  21. #define IsEventSignalled(hevent) (WaitForSingleObject(hevent, 0) == WAIT_OBJECT_0)
  22. #define SanityCheckComNumber(num) { if (num > COMDB_MAX_PORTS_ARBITRATED) return ERROR_INVALID_PARAMETER; }
  23. #define SanityCheckDBInfo(dbi) { if ((HANDLE) dbi == INVALID_HANDLE_VALUE) return ERROR_INVALID_PARAMETER; }
  24. const TCHAR szMutexName[] = _T("ComPortNumberDatabaseMutexObject");
  25. const TCHAR szComDBName[] = _T("ComDB");
  26. const TCHAR szComDBMerge[] = _T("ComDB Merge");
  27. const TCHAR szComDBPath[] = _T("System\\CurrentControlSet\\Control\\COM Name Arbiter");
  28. const TCHAR szComDBPathOld[] = _T("System\\CurrentControlSet\\Services\\Serial");
  29. #ifdef malloc
  30. #undef malloc
  31. #endif
  32. #define malloc(size) LocalAlloc(LPTR, (size))
  33. #ifdef free
  34. #undef free
  35. #endif
  36. #define free LocalFree
  37. VOID
  38. DestroyDBInfo(
  39. PDB_INFO DBInfo
  40. )
  41. {
  42. if (DBInfo->AccessMutex &&
  43. DBInfo->AccessMutex != INVALID_HANDLE_VALUE) {
  44. CloseHandle(DBInfo->AccessMutex);
  45. }
  46. if (DBInfo->RegChangedEvent &&
  47. DBInfo->RegChangedEvent != INVALID_HANDLE_VALUE) {
  48. CloseHandle(DBInfo->RegChangedEvent);
  49. }
  50. if (DBInfo->DBKey &&
  51. DBInfo->DBKey != (HKEY) INVALID_HANDLE_VALUE) {
  52. RegCloseKey(DBInfo->DBKey);
  53. }
  54. if (DBInfo->Ports) {
  55. free(DBInfo->Ports);
  56. }
  57. free(DBInfo);
  58. }
  59. LONG
  60. CreationFailure (
  61. PHCOMDB PHComDB,
  62. PDB_INFO DBInfo
  63. )
  64. {
  65. if (DBInfo->AccessMutex != 0)
  66. ReleaseMutex(DBInfo->AccessMutex);
  67. DestroyDBInfo(DBInfo);
  68. *PHComDB = (HCOMDB) INVALID_HANDLE_VALUE;
  69. return ERROR_ACCESS_DENIED;
  70. }
  71. VOID
  72. RegisterForNotification(
  73. PDB_INFO DBInfo
  74. )
  75. {
  76. ResetEvent(DBInfo->RegChangedEvent);
  77. if (RegNotifyChangeKeyValue(DBInfo->DBKey,
  78. FALSE,
  79. REG_NOTIFY_CHANGE_LAST_SET,
  80. DBInfo->RegChangedEvent,
  81. TRUE) != ERROR_SUCCESS) {
  82. //
  83. // Can't get a notification of when the DB is changed so close the handle
  84. // and we must update the DB at every access no matter what
  85. //
  86. CloseHandle(DBInfo->RegChangedEvent);
  87. DBInfo->RegChangedEvent = INVALID_HANDLE_VALUE;
  88. }
  89. }
  90. BOOL
  91. ResizeDatabase(
  92. PDB_INFO DBInfo,
  93. ULONG NumberPorts
  94. )
  95. {
  96. PBYTE newPorts = NULL;
  97. ULONG newPortsLength;
  98. if (DBInfo->Ports) {
  99. newPortsLength = NumberPorts / BITS_INA_BYTE;
  100. newPorts = (PBYTE) malloc(newPortsLength * sizeof(BYTE));
  101. if (newPorts) {
  102. memcpy(newPorts, DBInfo->Ports, DBInfo->PortsLength);
  103. free(DBInfo->Ports);
  104. DBInfo->Ports = newPorts;
  105. DBInfo->PortsLength = newPortsLength;
  106. return TRUE;
  107. }
  108. else {
  109. return FALSE;
  110. }
  111. }
  112. else {
  113. //
  114. // Just alloc and be done with it
  115. //
  116. DBInfo->PortsLength = NumberPorts / BITS_INA_BYTE;
  117. DBInfo->Ports = (PBYTE) malloc(DBInfo->PortsLength * sizeof(BYTE));
  118. return DBInfo->Ports ? TRUE : FALSE;
  119. }
  120. }
  121. LONG
  122. WINAPI
  123. ComDBOpen (
  124. PHCOMDB PHComDB
  125. )
  126. /*++
  127. Routine Description:
  128. Opens name data base, and returns a handle to be used in future calls.
  129. Arguments:
  130. None.
  131. Return Value:
  132. INVALID_HANDLE_VALUE if the call fails, otherwise a valid handle
  133. If INVALID_HANDLE_VALUE, call GetLastError() to get details (??)
  134. --*/
  135. {
  136. PDB_INFO dbInfo = malloc(sizeof(DB_INFO));
  137. DWORD type, size, disposition = 0x0;
  138. BOOLEAN migrated = FALSE;
  139. LONG res;
  140. BYTE merge[COMDB_MIN_PORTS_ARBITRATED / BITS_INA_BYTE /* 32 */];
  141. if (dbInfo == 0) {
  142. *PHComDB = (HCOMDB) INVALID_HANDLE_VALUE;
  143. return ERROR_ACCESS_DENIED;
  144. }
  145. dbInfo->AccessMutex = CreateMutex(NULL, FALSE, szMutexName);
  146. if (dbInfo->AccessMutex == 0) {
  147. return CreationFailure(PHComDB, dbInfo);
  148. }
  149. //
  150. // Enter the mutex so we can guarantee only one thread pounding on the reg
  151. // key at once
  152. //
  153. WaitForSingleObject(dbInfo->AccessMutex, INFINITE);
  154. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  155. szComDBPath,
  156. 0,
  157. (TCHAR *) NULL,
  158. REG_OPTION_NON_VOLATILE,
  159. KEY_ALL_ACCESS | KEY_NOTIFY,
  160. (LPSECURITY_ATTRIBUTES) NULL,
  161. &dbInfo->DBKey,
  162. &disposition) != ERROR_SUCCESS) {
  163. //
  164. // Try again w/out notification caps
  165. //
  166. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  167. szComDBPath,
  168. 0,
  169. (TCHAR *) NULL,
  170. REG_OPTION_NON_VOLATILE,
  171. KEY_ALL_ACCESS,
  172. (LPSECURITY_ATTRIBUTES) NULL,
  173. &dbInfo->DBKey,
  174. &disposition) != ERROR_SUCCESS) {
  175. return CreationFailure(PHComDB, dbInfo);
  176. }
  177. dbInfo->RegChangedEvent = INVALID_HANDLE_VALUE;
  178. }
  179. else {
  180. dbInfo->RegChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  181. if (dbInfo->RegChangedEvent == 0) {
  182. dbInfo->RegChangedEvent = INVALID_HANDLE_VALUE;
  183. }
  184. }
  185. if (disposition == REG_CREATED_NEW_KEY) {
  186. //
  187. // Must migrate the previous values from the old com db path
  188. //
  189. HKEY hOldDB;
  190. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  191. szComDBPathOld,
  192. 0,
  193. KEY_ALL_ACCESS,
  194. &hOldDB) == ERROR_SUCCESS &&
  195. RegQueryValueEx(hOldDB,
  196. szComDBName,
  197. 0,
  198. &type,
  199. NULL,
  200. &dbInfo->PortsLength) == ERROR_SUCCESS) {
  201. //
  202. // The old value is still there, get its contents, copy it to the
  203. // new location and delete the old value
  204. //
  205. migrated = TRUE;
  206. ResizeDatabase(dbInfo, dbInfo->PortsLength * BITS_INA_BYTE);
  207. size = dbInfo->PortsLength;
  208. res = RegQueryValueEx(hOldDB,
  209. szComDBName,
  210. 0,
  211. &type,
  212. (PBYTE) dbInfo->Ports,
  213. &size);
  214. RegDeleteValue(hOldDB, szComDBName);
  215. //
  216. // The value does not exist, write it out
  217. //
  218. if (RegSetValueEx(dbInfo->DBKey,
  219. szComDBName,
  220. 0,
  221. REG_BINARY,
  222. dbInfo->Ports,
  223. dbInfo->PortsLength) != ERROR_SUCCESS) {
  224. RegCloseKey(hOldDB);
  225. return CreationFailure(PHComDB, dbInfo);
  226. }
  227. RegCloseKey(hOldDB);
  228. }
  229. }
  230. //
  231. // If we haven't migrated values from the old path, then either create a
  232. // new chunk or read in values previously written
  233. //
  234. if (!migrated) {
  235. res = RegQueryValueEx(dbInfo->DBKey,
  236. szComDBName,
  237. 0,
  238. &type,
  239. NULL,
  240. &dbInfo->PortsLength);
  241. if (res == ERROR_FILE_NOT_FOUND) {
  242. ResizeDatabase(dbInfo, COMDB_MIN_PORTS_ARBITRATED);
  243. //
  244. // The value does not exist, write it out
  245. //
  246. res = RegSetValueEx(dbInfo->DBKey,
  247. szComDBName,
  248. 0,
  249. REG_BINARY,
  250. dbInfo->Ports,
  251. dbInfo->PortsLength);
  252. if (res != ERROR_SUCCESS) {
  253. return CreationFailure(PHComDB, dbInfo);
  254. }
  255. }
  256. else if (res == ERROR_MORE_DATA || res != ERROR_SUCCESS || type != REG_BINARY) {
  257. return CreationFailure(PHComDB, dbInfo);
  258. }
  259. else if (res == ERROR_SUCCESS) {
  260. ResizeDatabase(dbInfo, dbInfo->PortsLength * BITS_INA_BYTE);
  261. size = dbInfo->PortsLength;
  262. res = RegQueryValueEx(dbInfo->DBKey,
  263. szComDBName,
  264. 0,
  265. &type,
  266. (PBYTE) dbInfo->Ports,
  267. &size);
  268. }
  269. }
  270. size = sizeof(merge);
  271. if (RegQueryValueEx(dbInfo->DBKey,
  272. szComDBMerge,
  273. 0,
  274. &type,
  275. (PBYTE) merge,
  276. &size) == ERROR_SUCCESS &&
  277. size <= dbInfo->PortsLength) {
  278. int i;
  279. for (i = 0 ; i < COMDB_MIN_PORTS_ARBITRATED / BITS_INA_BYTE; i++) {
  280. dbInfo->Ports[i] |= merge[i];
  281. }
  282. RegDeleteValue(dbInfo->DBKey, szComDBMerge);
  283. RegSetValueEx(dbInfo->DBKey,
  284. szComDBName,
  285. 0,
  286. REG_BINARY,
  287. dbInfo->Ports,
  288. dbInfo->PortsLength);
  289. }
  290. if (dbInfo->RegChangedEvent != INVALID_HANDLE_VALUE) {
  291. RegisterForNotification(dbInfo);
  292. }
  293. ReleaseMutex(dbInfo->AccessMutex);
  294. //
  295. // All done! phew...
  296. //
  297. *PHComDB = (HCOMDB) dbInfo;
  298. return ERROR_SUCCESS;
  299. }
  300. LONG
  301. WINAPI
  302. ComDBClose (
  303. HCOMDB HComDB
  304. )
  305. /*++
  306. Routine Description:
  307. frees a handle to the database returned from OpenComPortDataBase
  308. Arguments:
  309. Handle returned from OpenComPortDataBase.
  310. Return Value:
  311. None
  312. --*/
  313. {
  314. PDB_INFO dbInfo = HandleToDBInfo(HComDB);
  315. SanityCheckDBInfo(dbInfo);
  316. DestroyDBInfo(dbInfo);
  317. return ERROR_SUCCESS;
  318. }
  319. BOOL
  320. EnterDB(
  321. PDB_INFO DBInfo
  322. )
  323. {
  324. BOOL eventSignalled = FALSE;
  325. LONG res;
  326. DWORD type, size;
  327. WaitForSingleObject(DBInfo->AccessMutex, INFINITE);
  328. if (DBInfo->RegChangedEvent == INVALID_HANDLE_VALUE ||
  329. (eventSignalled = IsEventSignalled(DBInfo->RegChangedEvent))) {
  330. size = 0;
  331. res = RegQueryValueEx(DBInfo->DBKey,
  332. szComDBName,
  333. 0,
  334. &type,
  335. 0,
  336. &size);
  337. //
  338. // Couldn't update the DB ... fail
  339. //
  340. if (res != ERROR_SUCCESS || type != REG_BINARY) {
  341. ReleaseMutex(DBInfo->AccessMutex);
  342. return FALSE;
  343. }
  344. if (size != DBInfo->PortsLength) {
  345. ResizeDatabase(DBInfo, size * BITS_INA_BYTE);
  346. }
  347. RegQueryValueEx(DBInfo->DBKey,
  348. szComDBName,
  349. 0,
  350. &type,
  351. DBInfo->Ports,
  352. &size);
  353. //
  354. // Reregister the notification with the registry
  355. //
  356. if (eventSignalled) {
  357. RegisterForNotification(DBInfo);
  358. }
  359. }
  360. return TRUE;
  361. }
  362. LONG
  363. LeaveDB(
  364. PDB_INFO DBInfo,
  365. BOOL CommitChanges
  366. )
  367. {
  368. LONG retVal = ERROR_SUCCESS;
  369. if (CommitChanges) {
  370. if (RegSetValueEx(DBInfo->DBKey,
  371. szComDBName,
  372. 0,
  373. REG_BINARY,
  374. DBInfo->Ports,
  375. DBInfo->PortsLength) != ERROR_SUCCESS) {
  376. retVal = ERROR_CANTWRITE;
  377. }
  378. //
  379. // The setting of the value in the reg signals the event...but we don't
  380. // need to resync w/the reg off of this change b/c it is our own! Instead
  381. // reset the event and rereg for the event
  382. //
  383. if (DBInfo->RegChangedEvent != INVALID_HANDLE_VALUE) {
  384. RegisterForNotification(DBInfo);
  385. }
  386. }
  387. ReleaseMutex(DBInfo->AccessMutex);
  388. return retVal;
  389. }
  390. VOID
  391. GetByteAndMask(
  392. PDB_INFO DBInfo,
  393. DWORD ComNumber,
  394. PBYTE *Byte,
  395. PBYTE Mask
  396. )
  397. {
  398. ComNumber--;
  399. *Byte = DBInfo->Ports + (ComNumber / BITS_INA_BYTE);
  400. *Mask = 1 << (ComNumber % BITS_INA_BYTE);
  401. }
  402. LONG
  403. WINAPI
  404. ComDBGetCurrentPortUsage (
  405. HCOMDB HComDB,
  406. PBYTE Buffer,
  407. DWORD BufferSize,
  408. ULONG ReportType,
  409. LPDWORD MaxPortsReported
  410. )
  411. /*++
  412. Handle requests that require no synch w/DB first.
  413. --*/
  414. {
  415. PDB_INFO dbInfo = HandleToDBInfo(HComDB);
  416. PBYTE curSrc, curDest, endDest;
  417. BYTE mask;
  418. SanityCheckDBInfo(dbInfo);
  419. if (!EnterDB(dbInfo)) {
  420. return ERROR_NOT_CONNECTED;
  421. }
  422. if (Buffer == 0) {
  423. if (!MaxPortsReported) {
  424. LeaveDB(dbInfo, FALSE);
  425. return ERROR_INVALID_PARAMETER;
  426. }
  427. else {
  428. *MaxPortsReported = dbInfo->PortsLength * BITS_INA_BYTE;
  429. return LeaveDB(dbInfo, FALSE);
  430. }
  431. }
  432. if (ReportType == CDB_REPORT_BITS) {
  433. if (BufferSize > dbInfo->PortsLength) {
  434. BufferSize = dbInfo->PortsLength;
  435. }
  436. memcpy(Buffer, dbInfo->Ports, BufferSize);
  437. if (MaxPortsReported) {
  438. *MaxPortsReported = BufferSize * BITS_INA_BYTE;
  439. }
  440. }
  441. else if (ReportType == CDB_REPORT_BYTES) {
  442. if (BufferSize > dbInfo->PortsLength * BITS_INA_BYTE) {
  443. BufferSize = dbInfo->PortsLength * BITS_INA_BYTE;
  444. }
  445. curSrc = dbInfo->Ports;
  446. endDest = Buffer + BufferSize;
  447. curDest = Buffer;
  448. for (mask = 1; curDest != endDest; curDest++) {
  449. *curDest = (*curSrc & mask) ? 1 : 0;
  450. if (mask & 0x80) {
  451. mask = 0x1;
  452. curSrc++;
  453. }
  454. else
  455. mask <<= 1;
  456. }
  457. }
  458. else {
  459. LeaveDB(dbInfo, FALSE);
  460. return ERROR_INVALID_PARAMETER;
  461. }
  462. return LeaveDB(dbInfo, FALSE);
  463. }
  464. LONG
  465. WINAPI
  466. ComDBClaimNextFreePort (
  467. HCOMDB HComDB,
  468. LPDWORD ComNumber
  469. )
  470. /*++
  471. Routine Description:
  472. returns the first free COMx value
  473. Arguments:
  474. Handle returned from OpenComPortDataBase.
  475. Return Value:
  476. returns ERROR_SUCCESS if successful. or other ERROR_ if not
  477. if successful, then ComNumber will be that next free com value and claims it in the database
  478. --*/
  479. {
  480. PDB_INFO dbInfo = HandleToDBInfo(HComDB);
  481. DWORD num;
  482. BOOL commit = FALSE;
  483. PBYTE curSrc, srcEnd;
  484. BYTE mask;
  485. LONG ret;
  486. SanityCheckDBInfo(dbInfo);
  487. if (!EnterDB(dbInfo)) {
  488. return ERROR_NOT_CONNECTED;
  489. }
  490. curSrc = dbInfo->Ports;
  491. srcEnd = curSrc + dbInfo->PortsLength;
  492. for (num = 3, mask = 0x4; curSrc != srcEnd; num++) {
  493. if (!(*curSrc & mask)) {
  494. *ComNumber = num;
  495. *curSrc |= mask;
  496. commit = TRUE;
  497. break;
  498. }
  499. else if (mask & 0x80) {
  500. mask = 0x1;
  501. curSrc++;
  502. }
  503. else {
  504. mask <<= 1;
  505. }
  506. }
  507. if (curSrc == srcEnd && !commit && num < COMDB_MAX_PORTS_ARBITRATED) {
  508. // DB entirely full
  509. ResizeDatabase(dbInfo, ((num / GROWTH_VALUE) + 1) * GROWTH_VALUE);
  510. *ComNumber = num;
  511. GetByteAndMask(dbInfo, num, &curSrc, &mask);
  512. *curSrc |= mask;
  513. commit = TRUE;
  514. }
  515. ret = LeaveDB(dbInfo, commit);
  516. if (!commit) {
  517. ret = ERROR_NO_LOG_SPACE;
  518. }
  519. return ret;
  520. }
  521. LONG
  522. WINAPI
  523. ComDBClaimPort (
  524. HCOMDB HComDB,
  525. DWORD ComNumber,
  526. BOOL ForceClaim,
  527. PBOOL Forced
  528. )
  529. /*++
  530. Routine Description:
  531. Attempts to claim a com name in the database
  532. Arguments:
  533. DataBaseHandle - returned from OpenComPortDataBase.
  534. ComNumber - The port value to be claimed
  535. Force - If TRUE, will force the port to be claimed even if in use already
  536. Return Value:
  537. returns ERROR_SUCCESS if port name was not already claimed, or if it was claimed
  538. and Force was TRUE.
  539. ERROR_SHARING_VIOLATION if port name is use and Force is false
  540. --*/
  541. {
  542. PDB_INFO dbInfo = HandleToDBInfo(HComDB);
  543. PBYTE curByte;
  544. BYTE mask;
  545. BOOL commit = TRUE;
  546. LONG res;
  547. ULONG newSize;
  548. BOOL f;
  549. if (!(Forced)) {
  550. Forced = &f;
  551. }
  552. SanityCheckComNumber(ComNumber);
  553. SanityCheckDBInfo(dbInfo);
  554. if (!EnterDB(dbInfo)) {
  555. return ERROR_NOT_CONNECTED;
  556. }
  557. if (ComNumber > dbInfo->PortsLength * BITS_INA_BYTE) {
  558. ResizeDatabase(dbInfo, ((ComNumber / GROWTH_VALUE) + 1) * GROWTH_VALUE);
  559. }
  560. GetByteAndMask(dbInfo, ComNumber, &curByte, &mask);
  561. if (*curByte & mask) {
  562. commit = FALSE;
  563. if (ForceClaim) {
  564. if (Forced)
  565. *Forced = TRUE;
  566. }
  567. else {
  568. res = LeaveDB(dbInfo, commit);
  569. if (res == ERROR_SUCCESS) {
  570. return ERROR_SHARING_VIOLATION;
  571. }
  572. else {
  573. return res;
  574. }
  575. }
  576. }
  577. else {
  578. if (Forced)
  579. *Forced = FALSE;
  580. *curByte |= mask;
  581. }
  582. return LeaveDB(dbInfo, commit);
  583. }
  584. LONG
  585. WINAPI
  586. ComDBReleasePort (
  587. HCOMDB HComDB,
  588. DWORD ComNumber
  589. )
  590. /*++
  591. Routine Description:
  592. un-claims the port in the database
  593. Arguments:
  594. DatabaseHandle - returned from OpenComPortDataBase.
  595. ComNumber - port to be unclaimed in database
  596. Return Value:
  597. returns ERROR_SUCCESS if successful. or other ERROR_ if not
  598. --*/
  599. {
  600. PDB_INFO dbInfo = HandleToDBInfo(HComDB);
  601. PBYTE byte;
  602. BYTE mask;
  603. SanityCheckDBInfo(dbInfo);
  604. if (!EnterDB(dbInfo)) {
  605. return ERROR_NOT_CONNECTED;
  606. }
  607. if (ComNumber > dbInfo->PortsLength * BITS_INA_BYTE) {
  608. LeaveDB(dbInfo, FALSE);
  609. return ERROR_INVALID_PARAMETER;
  610. }
  611. GetByteAndMask(dbInfo, ComNumber, &byte, &mask);
  612. *byte &= ~mask;
  613. return LeaveDB(dbInfo, TRUE);
  614. }
  615. LONG
  616. WINAPI
  617. ComDBResizeDatabase (
  618. HCOMDB HComDB,
  619. DWORD NewSize
  620. )
  621. /*++
  622. Routine Description:
  623. Resizes the database to the new size. To get the current size, call
  624. ComDBGetCurrentPortUsage with a Buffer == NULL.
  625. Arguments:
  626. DatabaseHandle - returned from OpenComPortDataBase.
  627. NewSize - must be a multiple of 1024, with a max of 4096
  628. Return Value:
  629. returns ERROR_SUCCESS if successful
  630. ERROR_BAD_LENGTH if NewSize is not greater than the current size or
  631. NewSize is greater than COMDB_MAX_PORTS_ARBITRATED
  632. --*/
  633. {
  634. PDB_INFO dbInfo = HandleToDBInfo(HComDB);
  635. BOOL commit = FALSE;
  636. SanityCheckDBInfo(dbInfo);
  637. if (NewSize % GROWTH_VALUE) {
  638. return ERROR_INVALID_PARAMETER;
  639. }
  640. if (!EnterDB(dbInfo)) {
  641. return ERROR_NOT_CONNECTED;
  642. }
  643. if (NewSize > COMDB_MAX_PORTS_ARBITRATED ||
  644. dbInfo->PortsLength * BITS_INA_BYTE >= NewSize) {
  645. LeaveDB(dbInfo, FALSE);
  646. return ERROR_BAD_LENGTH;
  647. }
  648. ResizeDatabase(dbInfo, NewSize);
  649. return LeaveDB(dbInfo, TRUE);
  650. }