xref: /reactos/dll/win32/msports/comdb.c (revision c2c66aff)
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
ComDBClaimNextFreePort(IN HCOMDB hComDB,OUT LPDWORD ComNumber)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
ComDBClaimPort(IN HCOMDB hComDB,IN DWORD ComNumber,IN BOOL ForceClaim,OUT PBOOL Forced)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
ComDBClose(IN HCOMDB hComDB)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
ComDBGetCurrentPortUsage(IN HCOMDB hComDB,OUT PBYTE Buffer,IN DWORD BufferSize,IN DWORD ReportType,OUT LPDWORD MaxPortsReported)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
ComDBOpen(OUT HCOMDB * phComDB)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
ComDBReleasePort(IN HCOMDB hComDB,IN DWORD ComNumber)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
ComDBResizeDatabase(IN HCOMDB hComDB,IN DWORD NewSize)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