1 /* 2 * PROJECT: Ports installer library 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll\win32\msports\comdb.c 5 * PURPOSE: COM port database 6 * COPYRIGHT: Copyright 2011 Eric Kohl 7 */ 8 9 #include "precomp.h" 10 11 #define BITS_PER_BYTE 8 12 #define BITMAP_SIZE_INCREMENT 0x400 13 #define BITMAP_SIZE_INVALID_BITS 0x3FF 14 15 typedef struct _COMDB 16 { 17 HANDLE hMutex; 18 HKEY hKey; 19 } COMDB, *PCOMDB; 20 21 22 LONG 23 WINAPI 24 ComDBClaimNextFreePort(IN HCOMDB hComDB, 25 OUT LPDWORD ComNumber) 26 { 27 PCOMDB pComDB; 28 DWORD dwBitIndex; 29 DWORD dwByteIndex; 30 DWORD dwSize; 31 DWORD dwType; 32 PBYTE pBitmap = NULL; 33 BYTE cMask; 34 LONG lError; 35 36 TRACE("ComDBClaimNextFreePort(%p %p)\n", hComDB, ComNumber); 37 38 if (hComDB == INVALID_HANDLE_VALUE || 39 hComDB == NULL || 40 ComNumber == NULL) 41 return ERROR_INVALID_PARAMETER; 42 43 pComDB = (PCOMDB)hComDB; 44 45 /* Wait for the mutex */ 46 WaitForSingleObject(pComDB->hMutex, INFINITE); 47 48 /* Get the required bitmap size */ 49 lError = RegQueryValueExW(pComDB->hKey, 50 L"ComDB", 51 NULL, 52 &dwType, 53 NULL, 54 &dwSize); 55 if (lError != ERROR_SUCCESS) 56 { 57 ERR("Failed to query the bitmap size!\n"); 58 goto done; 59 } 60 61 /* Allocate the bitmap */ 62 pBitmap = HeapAlloc(GetProcessHeap(), 63 HEAP_ZERO_MEMORY, 64 dwSize); 65 if (pBitmap == NULL) 66 { 67 ERR("Failed to allocate the bitmap!\n"); 68 lError = ERROR_NOT_ENOUGH_MEMORY; 69 goto done; 70 } 71 72 /* Read the bitmap */ 73 lError = RegQueryValueExW(pComDB->hKey, 74 L"ComDB", 75 NULL, 76 &dwType, 77 pBitmap, 78 &dwSize); 79 if (lError != ERROR_SUCCESS) 80 goto done; 81 82 lError = ERROR_INVALID_PARAMETER; 83 for (dwBitIndex = 0; dwBitIndex < (dwSize * BITS_PER_BYTE); dwBitIndex++) 84 { 85 /* Calculate the byte index and a mask for the affected bit */ 86 dwByteIndex = dwBitIndex / BITS_PER_BYTE; 87 cMask = 1 << (dwBitIndex % BITS_PER_BYTE); 88 89 if ((pBitmap[dwByteIndex] & cMask) == 0) 90 { 91 pBitmap[dwByteIndex] |= cMask; 92 *ComNumber = dwBitIndex + 1; 93 lError = ERROR_SUCCESS; 94 break; 95 } 96 } 97 98 /* Save the bitmap if it was modified */ 99 if (lError == ERROR_SUCCESS) 100 { 101 lError = RegSetValueExW(pComDB->hKey, 102 L"ComDB", 103 0, 104 REG_BINARY, 105 pBitmap, 106 dwSize); 107 } 108 109 done:; 110 /* Release the mutex */ 111 ReleaseMutex(pComDB->hMutex); 112 113 /* Release the bitmap */ 114 if (pBitmap != NULL) 115 HeapFree(GetProcessHeap(), 0, pBitmap); 116 117 return lError; 118 } 119 120 121 LONG 122 WINAPI 123 ComDBClaimPort(IN HCOMDB hComDB, 124 IN DWORD ComNumber, 125 IN BOOL ForceClaim, 126 OUT PBOOL Forced) 127 { 128 PCOMDB pComDB; 129 DWORD dwBitIndex; 130 DWORD dwByteIndex; 131 DWORD dwType; 132 DWORD dwSize; 133 PBYTE pBitmap = NULL; 134 BYTE cMask; 135 LONG lError; 136 137 TRACE("ComDBClaimPort(%p %lu)\n", hComDB, ComNumber); 138 139 if (hComDB == INVALID_HANDLE_VALUE || 140 hComDB == NULL || 141 ComNumber == 0 || 142 ComNumber > COMDB_MAX_PORTS_ARBITRATED) 143 return ERROR_INVALID_PARAMETER; 144 145 pComDB = (PCOMDB)hComDB; 146 147 /* Wait for the mutex */ 148 WaitForSingleObject(pComDB->hMutex, INFINITE); 149 150 /* Get the required bitmap size */ 151 lError = RegQueryValueExW(pComDB->hKey, 152 L"ComDB", 153 NULL, 154 &dwType, 155 NULL, 156 &dwSize); 157 if (lError != ERROR_SUCCESS) 158 { 159 ERR("Failed to query the bitmap size!\n"); 160 goto done; 161 } 162 163 /* Allocate the bitmap */ 164 pBitmap = HeapAlloc(GetProcessHeap(), 165 HEAP_ZERO_MEMORY, 166 dwSize); 167 if (pBitmap == NULL) 168 { 169 ERR("Failed to allocate the bitmap!\n"); 170 lError = ERROR_NOT_ENOUGH_MEMORY; 171 goto done; 172 } 173 174 /* Read the bitmap */ 175 lError = RegQueryValueExW(pComDB->hKey, 176 L"ComDB", 177 NULL, 178 &dwType, 179 pBitmap, 180 &dwSize); 181 if (lError != ERROR_SUCCESS) 182 goto done; 183 184 /* Get the bit index */ 185 dwBitIndex = ComNumber - 1; 186 187 /* Check if the bit to set fits into the bitmap */ 188 if (dwBitIndex >= (dwSize * BITS_PER_BYTE)) 189 { 190 FIXME("Resize the bitmap\n"); 191 192 lError = ERROR_INVALID_PARAMETER; 193 goto done; 194 } 195 196 /* Calculate the byte index and a mask for the affected bit */ 197 dwByteIndex = dwBitIndex / BITS_PER_BYTE; 198 cMask = 1 << (dwBitIndex % BITS_PER_BYTE); 199 200 lError = ERROR_SHARING_VIOLATION; 201 202 /* Check if the bit is not set */ 203 if ((pBitmap[dwByteIndex] & cMask) == 0) 204 { 205 /* Set the bit */ 206 pBitmap[dwByteIndex] |= cMask; 207 lError = ERROR_SUCCESS; 208 } 209 210 /* Save the bitmap if it was modified */ 211 if (lError == ERROR_SUCCESS) 212 { 213 lError = RegSetValueExW(pComDB->hKey, 214 L"ComDB", 215 0, 216 REG_BINARY, 217 pBitmap, 218 dwSize); 219 } 220 221 done: 222 /* Release the mutex */ 223 ReleaseMutex(pComDB->hMutex); 224 225 /* Release the bitmap */ 226 if (pBitmap != NULL) 227 HeapFree(GetProcessHeap(), 0, pBitmap); 228 229 return lError; 230 } 231 232 233 LONG 234 WINAPI 235 ComDBClose(IN HCOMDB hComDB) 236 { 237 PCOMDB pComDB; 238 239 TRACE("ComDBClose(%p)\n", hComDB); 240 241 if (hComDB == HCOMDB_INVALID_HANDLE_VALUE || 242 hComDB == NULL) 243 return ERROR_INVALID_PARAMETER; 244 245 pComDB = (PCOMDB)hComDB; 246 247 /* Close the registry key */ 248 if (pComDB->hKey != NULL) 249 RegCloseKey(pComDB->hKey); 250 251 /* Close the mutex */ 252 if (pComDB->hMutex != NULL) 253 CloseHandle(pComDB->hMutex); 254 255 /* Release the database */ 256 HeapFree(GetProcessHeap(), 0, pComDB); 257 258 return ERROR_SUCCESS; 259 } 260 261 262 LONG 263 WINAPI 264 ComDBGetCurrentPortUsage(IN HCOMDB hComDB, 265 OUT PBYTE Buffer, 266 IN DWORD BufferSize, 267 IN DWORD ReportType, 268 OUT LPDWORD MaxPortsReported) 269 { 270 PCOMDB pComDB; 271 DWORD dwBitIndex; 272 DWORD dwByteIndex; 273 DWORD dwType; 274 DWORD dwSize; 275 PBYTE pBitmap = NULL; 276 BYTE cMask; 277 LONG lError = ERROR_SUCCESS; 278 279 TRACE("ComDBGetCurrentPortUsage(%p %p %lu %lu %p)\n", 280 hComDB, Buffer, BufferSize, ReportType, MaxPortsReported); 281 282 if (hComDB == INVALID_HANDLE_VALUE || 283 hComDB == NULL || 284 (Buffer == NULL && MaxPortsReported == NULL) || 285 (ReportType != CDB_REPORT_BITS && ReportType != CDB_REPORT_BYTES)) 286 return ERROR_INVALID_PARAMETER; 287 288 pComDB = (PCOMDB)hComDB; 289 290 /* Wait for the mutex */ 291 WaitForSingleObject(pComDB->hMutex, INFINITE); 292 293 /* Get the required bitmap size */ 294 lError = RegQueryValueExW(pComDB->hKey, 295 L"ComDB", 296 NULL, 297 &dwType, 298 NULL, 299 &dwSize); 300 if (lError != ERROR_SUCCESS) 301 { 302 ERR("Failed to query the bitmap size!\n"); 303 goto done; 304 } 305 306 /* Allocate the bitmap */ 307 pBitmap = HeapAlloc(GetProcessHeap(), 308 HEAP_ZERO_MEMORY, 309 dwSize); 310 if (pBitmap == NULL) 311 { 312 ERR("Failed to allocate the bitmap!\n"); 313 lError = ERROR_NOT_ENOUGH_MEMORY; 314 goto done; 315 } 316 317 /* Read the bitmap */ 318 lError = RegQueryValueExW(pComDB->hKey, 319 L"ComDB", 320 NULL, 321 &dwType, 322 pBitmap, 323 &dwSize); 324 if (lError != ERROR_SUCCESS) 325 goto done; 326 327 if (Buffer == NULL) 328 { 329 *MaxPortsReported = dwSize * BITS_PER_BYTE; 330 } 331 else 332 { 333 if (ReportType == CDB_REPORT_BITS) 334 { 335 /* Clear the buffer */ 336 memset(Buffer, 0, BufferSize); 337 338 memcpy(Buffer, 339 pBitmap, 340 min(dwSize, BufferSize)); 341 342 if (MaxPortsReported != NULL) 343 *MaxPortsReported = min(dwSize, BufferSize) * BITS_PER_BYTE; 344 } 345 else if (ReportType == CDB_REPORT_BYTES) 346 { 347 /* Clear the buffer */ 348 memset(Buffer, 0, BufferSize); 349 350 for (dwBitIndex = 0; dwBitIndex < min(dwSize * BITS_PER_BYTE, BufferSize); dwBitIndex++) 351 { 352 /* Calculate the byte index and a mask for the affected bit */ 353 dwByteIndex = dwBitIndex / BITS_PER_BYTE; 354 cMask = 1 << (dwBitIndex % BITS_PER_BYTE); 355 356 if ((pBitmap[dwByteIndex] & cMask) != 0) 357 Buffer[dwBitIndex] = 1; 358 } 359 } 360 } 361 362 done:; 363 /* Release the mutex */ 364 ReleaseMutex(pComDB->hMutex); 365 366 /* Release the bitmap */ 367 HeapFree(GetProcessHeap(), 0, pBitmap); 368 369 return lError; 370 } 371 372 373 LONG 374 WINAPI 375 ComDBOpen(OUT HCOMDB *phComDB) 376 { 377 PCOMDB pComDB; 378 DWORD dwDisposition; 379 DWORD dwType; 380 DWORD dwSize; 381 PBYTE pBitmap; 382 LONG lError; 383 384 TRACE("ComDBOpen(%p)\n", phComDB); 385 386 /* Allocate a new database */ 387 pComDB = HeapAlloc(GetProcessHeap(), 388 HEAP_ZERO_MEMORY, 389 sizeof(COMDB)); 390 if (pComDB == NULL) 391 { 392 ERR("Failed to allocate the database!\n"); 393 *phComDB = HCOMDB_INVALID_HANDLE_VALUE; 394 return ERROR_ACCESS_DENIED; 395 } 396 397 /* Create a mutex to protect the database */ 398 pComDB->hMutex = CreateMutexW(NULL, 399 FALSE, 400 L"ComDBMutex"); 401 if (pComDB->hMutex == NULL) 402 { 403 ERR("Failed to create the mutex!\n"); 404 HeapFree(GetProcessHeap(), 0, pComDB); 405 *phComDB = HCOMDB_INVALID_HANDLE_VALUE; 406 return ERROR_ACCESS_DENIED; 407 } 408 409 /* Wait for the mutex */ 410 WaitForSingleObject(pComDB->hMutex, INFINITE); 411 412 /* Create or open the database key */ 413 lError = RegCreateKeyExW(HKEY_LOCAL_MACHINE, 414 L"System\\CurrentControlSet\\Control\\COM Name Arbiter", 415 0, 416 NULL, 417 0, 418 KEY_ALL_ACCESS, 419 NULL, 420 &pComDB->hKey, 421 &dwDisposition); 422 if (lError != ERROR_SUCCESS) 423 goto done; 424 425 /* Get the required bitmap size */ 426 lError = RegQueryValueExW(pComDB->hKey, 427 L"ComDB", 428 NULL, 429 &dwType, 430 NULL, 431 &dwSize); 432 if (lError == ERROR_FILE_NOT_FOUND) 433 { 434 /* Allocate a new bitmap */ 435 dwSize = COMDB_MIN_PORTS_ARBITRATED / BITS_PER_BYTE; 436 pBitmap = HeapAlloc(GetProcessHeap(), 437 HEAP_ZERO_MEMORY, 438 dwSize); 439 if (pBitmap == NULL) 440 { 441 ERR("Failed to allocate the bitmap!\n"); 442 lError = ERROR_ACCESS_DENIED; 443 goto done; 444 } 445 446 /* Write the bitmap to the registry */ 447 lError = RegSetValueExW(pComDB->hKey, 448 L"ComDB", 449 0, 450 REG_BINARY, 451 pBitmap, 452 dwSize); 453 454 HeapFree(GetProcessHeap(), 0, pBitmap); 455 } 456 457 done:; 458 /* Release the mutex */ 459 ReleaseMutex(pComDB->hMutex); 460 461 if (lError != ERROR_SUCCESS) 462 { 463 /* Clean up in case of failure */ 464 if (pComDB->hKey != NULL) 465 RegCloseKey(pComDB->hKey); 466 467 if (pComDB->hMutex != NULL) 468 CloseHandle(pComDB->hMutex); 469 470 HeapFree(GetProcessHeap(), 0, pComDB); 471 472 *phComDB = HCOMDB_INVALID_HANDLE_VALUE; 473 } 474 else 475 { 476 /* Return the database handle */ 477 *phComDB = (HCOMDB)pComDB; 478 } 479 480 TRACE("done (Error %lu)\n", lError); 481 482 return lError; 483 } 484 485 486 LONG 487 WINAPI 488 ComDBReleasePort(IN HCOMDB hComDB, 489 IN DWORD ComNumber) 490 { 491 PCOMDB pComDB; 492 DWORD dwByteIndex; 493 DWORD dwBitIndex; 494 DWORD dwType; 495 DWORD dwSize; 496 PBYTE pBitmap = NULL; 497 BYTE cMask; 498 LONG lError; 499 500 TRACE("ComDBReleasePort(%p %lu)\n", hComDB, ComNumber); 501 502 if (hComDB == INVALID_HANDLE_VALUE || 503 ComNumber == 0 || 504 ComNumber > COMDB_MAX_PORTS_ARBITRATED) 505 return ERROR_INVALID_PARAMETER; 506 507 pComDB = (PCOMDB)hComDB; 508 509 /* Wait for the mutex */ 510 WaitForSingleObject(pComDB->hMutex, INFINITE); 511 512 /* Get the required bitmap size */ 513 lError = RegQueryValueExW(pComDB->hKey, 514 L"ComDB", 515 NULL, 516 &dwType, 517 NULL, 518 &dwSize); 519 if (lError != ERROR_SUCCESS) 520 { 521 ERR("Failed to query the bitmap size!\n"); 522 goto done; 523 } 524 525 /* Allocate the bitmap */ 526 pBitmap = HeapAlloc(GetProcessHeap(), 527 HEAP_ZERO_MEMORY, 528 dwSize); 529 if (pBitmap == NULL) 530 { 531 ERR("Failed to allocate the bitmap!\n"); 532 lError = ERROR_NOT_ENOUGH_MEMORY; 533 goto done; 534 } 535 536 /* Read the bitmap */ 537 lError = RegQueryValueExW(pComDB->hKey, 538 L"ComDB", 539 NULL, 540 &dwType, 541 pBitmap, 542 &dwSize); 543 if (lError != ERROR_SUCCESS) 544 goto done; 545 546 /* Get the bit index */ 547 dwBitIndex = ComNumber - 1; 548 549 /* Check if the bit to set fits into the bitmap */ 550 if (dwBitIndex >= (dwSize * BITS_PER_BYTE)) 551 { 552 lError = ERROR_INVALID_PARAMETER; 553 goto done; 554 } 555 556 /* Calculate the byte index and a mask for the affected bit */ 557 dwByteIndex = dwBitIndex / BITS_PER_BYTE; 558 cMask = 1 << (dwBitIndex % BITS_PER_BYTE); 559 560 /* Release the port */ 561 pBitmap[dwByteIndex] &= ~cMask; 562 563 lError = RegSetValueExW(pComDB->hKey, 564 L"ComDB", 565 0, 566 REG_BINARY, 567 pBitmap, 568 dwSize); 569 570 done:; 571 /* Release the mutex */ 572 ReleaseMutex(pComDB->hMutex); 573 574 /* Release the bitmap */ 575 if (pBitmap != NULL) 576 HeapFree(GetProcessHeap(), 0, pBitmap); 577 578 return lError; 579 } 580 581 582 LONG 583 WINAPI 584 ComDBResizeDatabase(IN HCOMDB hComDB, 585 IN DWORD NewSize) 586 { 587 PCOMDB pComDB; 588 PBYTE pBitmap = NULL; 589 DWORD dwSize; 590 DWORD dwNewSize; 591 DWORD dwType; 592 LONG lError; 593 594 TRACE("ComDBResizeDatabase(%p %lu)\n", hComDB, NewSize); 595 596 if (hComDB == INVALID_HANDLE_VALUE || 597 hComDB == NULL || 598 (NewSize & BITMAP_SIZE_INVALID_BITS)) 599 return ERROR_INVALID_PARAMETER; 600 601 pComDB = (PCOMDB)hComDB; 602 603 /* Wait for the mutex */ 604 WaitForSingleObject(pComDB->hMutex, INFINITE); 605 606 /* Get the required bitmap size */ 607 lError = RegQueryValueExW(pComDB->hKey, 608 L"ComDB", 609 NULL, 610 &dwType, 611 NULL, 612 &dwSize); 613 if (lError != ERROR_SUCCESS) 614 goto done; 615 616 /* Check the size limits */ 617 if (NewSize > COMDB_MAX_PORTS_ARBITRATED || 618 NewSize <= dwSize * BITS_PER_BYTE) 619 { 620 lError = ERROR_BAD_LENGTH; 621 goto done; 622 } 623 624 /* Calculate the new bitmap size */ 625 dwNewSize = NewSize / BITS_PER_BYTE; 626 627 /* Allocate the new bitmap */ 628 pBitmap = HeapAlloc(GetProcessHeap(), 629 HEAP_ZERO_MEMORY, 630 dwSize); 631 if (pBitmap == NULL) 632 { 633 ERR("Failed to allocate the bitmap!\n"); 634 lError = ERROR_ACCESS_DENIED; 635 goto done; 636 } 637 638 /* Read the current bitmap */ 639 lError = RegQueryValueExW(pComDB->hKey, 640 L"ComDB", 641 NULL, 642 &dwType, 643 pBitmap, 644 &dwSize); 645 if (lError != ERROR_SUCCESS) 646 goto done; 647 648 /* Write the new bitmap */ 649 lError = RegSetValueExW(pComDB->hKey, 650 L"ComDB", 651 0, 652 REG_BINARY, 653 pBitmap, 654 dwNewSize); 655 656 done:; 657 /* Release the mutex */ 658 ReleaseMutex(pComDB->hMutex); 659 660 if (pBitmap != NULL) 661 HeapFree(GetProcessHeap(), 0, pBitmap); 662 663 return lError; 664 } 665 666 /* EOF */ 667