xref: /reactos/sdk/lib/rtl/handle.c (revision 321bcc05)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * PURPOSE:         Handle table
5  * FILE:            lib/rtl/handle.c
6  * PROGRAMMER:      Eric Kohl
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include <rtl.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ******************************************************************/
17 
18 VOID
19 NTAPI
20 RtlInitializeHandleTable(
21     ULONG TableSize,
22     ULONG HandleSize,
23     PRTL_HANDLE_TABLE HandleTable)
24 {
25     /* Initialize handle table */
26     memset(HandleTable, 0, sizeof(RTL_HANDLE_TABLE));
27     HandleTable->MaximumNumberOfHandles = TableSize;
28     HandleTable->SizeOfHandleTableEntry = HandleSize;
29 }
30 
31 
32 /*
33  * @implemented
34  */
35 VOID
36 NTAPI
37 RtlDestroyHandleTable(
38     PRTL_HANDLE_TABLE HandleTable)
39 {
40     PVOID ArrayPointer;
41     SIZE_T ArraySize = 0;
42 
43     /* free handle array */
44     if (HandleTable->CommittedHandles)
45     {
46         ArrayPointer = (PVOID)HandleTable->CommittedHandles;
47         NtFreeVirtualMemory(NtCurrentProcess(),
48                             &ArrayPointer,
49                             &ArraySize,
50                             MEM_RELEASE);
51     }
52 }
53 
54 
55 /*
56  * @implemented
57  */
58 PRTL_HANDLE_TABLE_ENTRY
59 NTAPI
60 RtlAllocateHandle(
61     PRTL_HANDLE_TABLE HandleTable,
62     PULONG Index)
63 {
64     PRTL_HANDLE_TABLE_ENTRY CurrentEntry, NextEntry;
65     NTSTATUS Status;
66     PRTL_HANDLE_TABLE_ENTRY HandleEntry;
67     PVOID ArrayPointer;
68     SIZE_T ArraySize;
69     ULONG i, NumberOfEntries;
70 
71     /* Check if we are out of free handles entries */
72     if (HandleTable->FreeHandles == NULL)
73     {
74         /* Check if we don't have uncomitted handle entries yet */
75         if (HandleTable->UnCommittedHandles == NULL)
76         {
77             /* Use the maximum number of handle entries */
78             ArraySize = HandleTable->SizeOfHandleTableEntry * HandleTable->MaximumNumberOfHandles;
79             ArrayPointer = NULL;
80 
81             /* Reserve memory */
82             Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
83                                              &ArrayPointer,
84                                              0,
85                                              &ArraySize,
86                                              MEM_RESERVE,
87                                              PAGE_READWRITE);
88             if (!NT_SUCCESS(Status))
89                 return NULL;
90 
91             /* Update handle array pointers */
92             HandleTable->UnCommittedHandles = (PRTL_HANDLE_TABLE_ENTRY)ArrayPointer;
93             HandleTable->MaxReservedHandles = (PRTL_HANDLE_TABLE_ENTRY)((ULONG_PTR)ArrayPointer + ArraySize);
94         }
95 
96         /* Commit one reserved handle entry page */
97         ArraySize = PAGE_SIZE;
98         ArrayPointer = HandleTable->UnCommittedHandles;
99         Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
100                                          &ArrayPointer,
101                                          0,
102                                          &ArraySize,
103                                          MEM_COMMIT,
104                                          PAGE_READWRITE);
105         if (!NT_SUCCESS(Status))
106             return NULL;
107 
108         /* Update handle array pointers */
109         HandleTable->FreeHandles = (PRTL_HANDLE_TABLE_ENTRY)ArrayPointer;
110         HandleTable->CommittedHandles = (PRTL_HANDLE_TABLE_ENTRY)ArrayPointer;
111         HandleTable->UnCommittedHandles = (PRTL_HANDLE_TABLE_ENTRY)((ULONG_PTR)ArrayPointer + ArraySize);
112 
113         /* Calculate the number of entries we can store in the array */
114         NumberOfEntries = ArraySize / HandleTable->SizeOfHandleTableEntry;
115 
116         /* Loop all entries, except the last one */
117         CurrentEntry = HandleTable->FreeHandles;
118         for (i = 0; i < NumberOfEntries - 1; i++)
119         {
120             /* Calculate the address of the next handle entry */
121             NextEntry = (PRTL_HANDLE_TABLE_ENTRY)((ULONG_PTR)CurrentEntry +
122                                                   HandleTable->SizeOfHandleTableEntry);
123 
124             /* Link the next entry */
125             CurrentEntry->NextFree = NextEntry;
126 
127             /* Continue with the next entry */
128             CurrentEntry = NextEntry;
129         }
130 
131         /* CurrentEntry now points to the last entry, terminate the list here */
132         CurrentEntry->NextFree = NULL;
133     }
134 
135     /* remove handle from free list */
136     HandleEntry = HandleTable->FreeHandles;
137     HandleTable->FreeHandles = HandleEntry->NextFree;
138     HandleEntry->NextFree = NULL;
139 
140     if (Index)
141     {
142         *Index = ((ULONG)((ULONG_PTR)HandleEntry - (ULONG_PTR)HandleTable->CommittedHandles) /
143                   HandleTable->SizeOfHandleTableEntry);
144     }
145 
146     return HandleEntry;
147 }
148 
149 
150 /*
151  * @implemented
152  */
153 BOOLEAN
154 NTAPI
155 RtlFreeHandle(
156     PRTL_HANDLE_TABLE HandleTable,
157     PRTL_HANDLE_TABLE_ENTRY Handle)
158 {
159 #if DBG
160     /* check if handle is valid */
161     if (!RtlIsValidHandle(HandleTable, Handle))
162     {
163         DPRINT1("Invalid Handle! HandleTable=0x%p, Handle=0x%p, Handle->Flags=0x%x\n",
164                 HandleTable, Handle, Handle ? Handle->Flags : 0);
165         return FALSE;
166     }
167 #endif
168 
169     /* clear handle */
170     memset(Handle, 0, HandleTable->SizeOfHandleTableEntry);
171 
172     /* add handle to free list */
173     Handle->NextFree = HandleTable->FreeHandles;
174     HandleTable->FreeHandles = Handle;
175 
176     return TRUE;
177 }
178 
179 
180 /*
181  * @implemented
182  */
183 BOOLEAN
184 NTAPI
185 RtlIsValidHandle(
186     PRTL_HANDLE_TABLE HandleTable,
187     PRTL_HANDLE_TABLE_ENTRY Handle)
188 {
189     if ((HandleTable != NULL)
190             && (Handle >= HandleTable->CommittedHandles)
191             && (Handle < HandleTable->MaxReservedHandles)
192             && (Handle->Flags & RTL_HANDLE_VALID))
193     {
194         return TRUE;
195     }
196     return FALSE;
197 }
198 
199 
200 /*
201  * @implemented
202  */
203 BOOLEAN
204 NTAPI
205 RtlIsValidIndexHandle(
206     IN PRTL_HANDLE_TABLE HandleTable,
207     IN ULONG Index,
208     OUT PRTL_HANDLE_TABLE_ENTRY *Handle)
209 {
210     PRTL_HANDLE_TABLE_ENTRY InternalHandle;
211 
212     DPRINT("RtlIsValidIndexHandle(HandleTable %p Index 0x%lx Handle %p)\n", HandleTable, Index, Handle);
213 
214     if (HandleTable == NULL)
215         return FALSE;
216 
217     DPRINT("Handles %p HandleSize 0x%lx\n",
218            HandleTable->CommittedHandles, HandleTable->SizeOfHandleTableEntry);
219 
220     InternalHandle = (PRTL_HANDLE_TABLE_ENTRY)((ULONG_PTR)HandleTable->CommittedHandles +
221                      (HandleTable->SizeOfHandleTableEntry * Index));
222     if (!RtlIsValidHandle(HandleTable, InternalHandle))
223         return FALSE;
224 
225     DPRINT("InternalHandle %p\n", InternalHandle);
226 
227     if (Handle != NULL)
228         *Handle = InternalHandle;
229 
230     return TRUE;
231 }
232 
233 /* EOF */
234