xref: /reactos/dll/win32/msports/comdb.c (revision b09b5584)
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