work on registry
[reactos.git] / reactos / ntoskrnl / ob / object.c
1 /* $Id: object.c,v 1.27 2000/09/29 15:03:21 jean Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/object.c
6 * PURPOSE: Implements generic object managment functions
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * 10/06/98: Created
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <wchar.h>
15 #include <ddk/ntddk.h>
16 #include <internal/ob.h>
17 #include <internal/string.h>
18 #include <internal/ps.h>
19 #include <internal/id.h>
20 #include <internal/ke.h>
21
22 #define NDEBUG
23 #include <internal/debug.h>
24
25 /* FUNCTIONS ************************************************************/
26
27 /**********************************************************************
28 * NAME PRIVATE
29 * ObInitializeObject
30 *
31 * DESCRIPTION
32 *
33 * ARGUMENTS
34 *
35 * RETURN VALUE
36 */
37 VOID ObInitializeObject(POBJECT_HEADER ObjectHeader,
38 PHANDLE Handle,
39 ACCESS_MASK DesiredAccess,
40 POBJECT_TYPE Type,
41 POBJECT_ATTRIBUTES ObjectAttributes)
42 {
43 ObjectHeader->HandleCount = 0;
44 ObjectHeader->RefCount = 1;
45 ObjectHeader->ObjectType = Type;
46 if (ObjectAttributes != NULL &&
47 ObjectAttributes->Attributes & OBJ_PERMANENT)
48 {
49 ObjectHeader->Permanent = TRUE;
50 }
51 else
52 {
53 ObjectHeader->Permanent = FALSE;
54 }
55 RtlInitUnicodeString(&(ObjectHeader->Name),NULL);
56 if (Handle != NULL)
57 {
58 ObCreateHandle(PsGetCurrentProcess(),
59 HEADER_TO_BODY(ObjectHeader),
60 DesiredAccess,
61 FALSE,
62 Handle);
63 }
64 }
65
66
67 /**********************************************************************
68 * NAME PRIVATE
69 * ObFindObject@16
70 *
71 * DESCRIPTION
72 *
73 * ARGUMENTS
74 * ObjectAttributes
75 *
76 * ReturnedObject
77 *
78 * RemainigPath
79 * Pointer to a unicode string that will contain the
80 * remaining path if the function returns successfully.
81 * The caller must free the buffer after use by calling
82 * RtlFreeUnicodeString ().
83 *
84 * ObjectType
85 * Optional pointer to an object type. This is used to
86 * descide if a symbolic link object will be parsed or not.
87 *
88 * RETURN VALUE
89 */
90 NTSTATUS ObFindObject(POBJECT_ATTRIBUTES ObjectAttributes,
91 PVOID* ReturnedObject,
92 PUNICODE_STRING RemainingPath,
93 POBJECT_TYPE ObjectType)
94 {
95 PVOID NextObject;
96 PVOID CurrentObject;
97 PVOID RootObject;
98 POBJECT_HEADER CurrentHeader;
99 NTSTATUS Status;
100 PWSTR Path;
101 PWSTR current;
102 UNICODE_STRING PathString;
103
104 DPRINT("ObFindObject(ObjectAttributes %x, ReturnedObject %x, "
105 "RemainingPath %x)\n",ObjectAttributes,ReturnedObject,RemainingPath);
106 DPRINT("ObjectAttributes->ObjectName->Buffer %x\n",
107 ObjectAttributes->ObjectName->Buffer);
108
109 RtlInitUnicodeString (RemainingPath, NULL);
110
111 if (ObjectAttributes->RootDirectory == NULL)
112 {
113 ObReferenceObjectByPointer(NameSpaceRoot,
114 DIRECTORY_TRAVERSE,
115 NULL,
116 UserMode);
117 CurrentObject = NameSpaceRoot;
118 }
119 else
120 {
121 Status = ObReferenceObjectByHandle(ObjectAttributes->RootDirectory,
122 DIRECTORY_TRAVERSE,
123 NULL,
124 UserMode,
125 &CurrentObject,
126 NULL);
127 if (!NT_SUCCESS(Status))
128 {
129 return(Status);
130 }
131 }
132
133 Path = ObjectAttributes->ObjectName->Buffer;
134
135 if (Path[0] == 0)
136 {
137 *ReturnedObject = CurrentObject;
138 return(STATUS_SUCCESS);
139 }
140
141 if ((ObjectAttributes->RootDirectory == NULL) && (Path[0] != '\\'))
142 {
143 return(STATUS_UNSUCCESSFUL);
144 }
145
146 if (Path)
147 {
148 // if ( Path[0] != '\\' )
149 // {
150 // RtlCreateUnicodeString (&PathString, L"\\");
151 // RtlAppendUnicodeToString (&PathString, Path);
152 // }
153 // else
154 RtlCreateUnicodeString (&PathString, Path);
155 current = PathString.Buffer;
156 }
157 else
158 {
159 RtlInitUnicodeString (&PathString, NULL);
160 current = NULL;
161 }
162
163 RootObject = CurrentObject;
164
165 while (TRUE)
166 {
167 DPRINT("current %S\n",current);
168 CurrentHeader = BODY_TO_HEADER(CurrentObject);
169 if (CurrentHeader->ObjectType->Parse == NULL)
170 {
171 DPRINT("Current object can't parse\n");
172 break;
173 }
174 Status = CurrentHeader->ObjectType->Parse(CurrentObject,
175 &NextObject,
176 &PathString,
177 &current,
178 ObjectType);
179 if (Status == STATUS_REPARSE)
180 {
181 /* reparse the object path */
182 NextObject = RootObject;
183 current = PathString.Buffer;
184
185 ObReferenceObjectByPointer(NextObject,
186 DIRECTORY_TRAVERSE,
187 NULL,
188 UserMode);
189 }
190
191 if (NextObject == NULL)
192 {
193 break;
194 }
195 ObDereferenceObject(CurrentObject);
196 CurrentObject = NextObject;
197 }
198
199 if (current)
200 RtlCreateUnicodeString (RemainingPath, current);
201 RtlFreeUnicodeString (&PathString);
202 *ReturnedObject = CurrentObject;
203
204 return(STATUS_SUCCESS);
205 }
206
207
208 /**********************************************************************
209 * NAME EXPORTED
210 * ObCreateObject@36
211 *
212 * DESCRIPTION
213 *
214 * ARGUMENTS
215 *
216 * RETURN VALUE
217 */
218 PVOID STDCALL ObCreateObject(PHANDLE Handle,
219 ACCESS_MASK DesiredAccess,
220 POBJECT_ATTRIBUTES ObjectAttributes,
221 POBJECT_TYPE Type)
222 {
223 PVOID Parent = NULL;
224 UNICODE_STRING RemainingPath;
225 POBJECT_HEADER Header;
226 NTSTATUS Status;
227
228 assert_irql(APC_LEVEL);
229
230 DPRINT("ObCreateObject(Handle %x, ObjectAttributes %x, Type %x)\n");
231 if (ObjectAttributes != NULL &&
232 ObjectAttributes->ObjectName != NULL)
233 {
234 DPRINT("ObjectAttributes->ObjectName->Buffer %S\n",
235 ObjectAttributes->ObjectName->Buffer);
236 }
237
238 if (ObjectAttributes != NULL &&
239 ObjectAttributes->ObjectName != NULL)
240 {
241 ObFindObject(ObjectAttributes,
242 &Parent,
243 &RemainingPath,
244 NULL);
245 }
246 else
247 {
248 RtlInitUnicodeString (&RemainingPath, NULL);
249 }
250 Header = (POBJECT_HEADER)ExAllocatePool(NonPagedPool,
251 OBJECT_ALLOC_SIZE(Type));
252 ObInitializeObject(Header,
253 Handle,
254 DesiredAccess,
255 Type,
256 ObjectAttributes);
257 if (Header->ObjectType != NULL &&
258 Header->ObjectType->Create != NULL)
259 {
260 DPRINT("Calling %x\n", Header->ObjectType);
261 DPRINT("Calling %x\n", Header->ObjectType->Create);
262 Status = Header->ObjectType->Create(HEADER_TO_BODY(Header),
263 Parent,
264 RemainingPath.Buffer,
265 ObjectAttributes);
266 if (!NT_SUCCESS(Status))
267 {
268 ObDereferenceObject( Parent );
269 RtlFreeUnicodeString( &Header->Name );
270 RtlFreeUnicodeString( &RemainingPath );
271 ExFreePool( Header );
272 return(NULL);
273 }
274 }
275 RtlFreeUnicodeString( &RemainingPath );
276 return(HEADER_TO_BODY(Header));
277 }
278
279 NTSTATUS STDCALL ObReferenceObjectByPointer(PVOID ObjectBody,
280 ACCESS_MASK DesiredAccess,
281 POBJECT_TYPE ObjectType,
282 KPROCESSOR_MODE AccessMode)
283 /*
284 * FUNCTION: Increments the pointer reference count for a given object
285 * ARGUMENTS:
286 * ObjectBody = Object's body
287 * DesiredAccess = Desired access to the object
288 * ObjectType = Points to the object type structure
289 * AccessMode = Type of access check to perform
290 * RETURNS: Status
291 */
292 {
293 POBJECT_HEADER ObjectHeader;
294
295 // DPRINT("ObReferenceObjectByPointer(ObjectBody %x, ObjectType %x)\n",
296 // ObjectBody,ObjectType);
297
298 ObjectHeader = BODY_TO_HEADER(ObjectBody);
299
300 if (ObjectType != NULL && ObjectHeader->ObjectType != ObjectType)
301 {
302 DPRINT("Failed %x (type was %x %S) should %x\n",
303 ObjectHeader,
304 ObjectHeader->ObjectType,
305 ObjectHeader->ObjectType->TypeName.Buffer,
306 ObjectType);
307 KeBugCheck(0);
308 return(STATUS_UNSUCCESSFUL);
309 }
310 if (ObjectHeader->ObjectType == PsProcessType)
311 {
312 DPRINT("Ref p 0x%x refcount %d type %x ",
313 ObjectBody, ObjectHeader->RefCount, PsProcessType);
314 DPRINT("eip %x\n", ((PULONG)&ObjectBody)[-1]);
315 }
316 if (ObjectHeader->ObjectType == PsThreadType)
317 {
318 DPRINT("Deref t 0x%x with refcount %d type %x ",
319 ObjectBody, ObjectHeader->RefCount, PsThreadType);
320 DPRINT("eip %x\n", ((PULONG)&ObjectBody)[-1]);
321 }
322
323 ObjectHeader->RefCount++;
324
325 return(STATUS_SUCCESS);
326 }
327
328 NTSTATUS ObPerformRetentionChecks(POBJECT_HEADER Header)
329 {
330 // DPRINT("ObPerformRetentionChecks(Header %x), RefCount %d, HandleCount %d\n",
331 // Header,Header->RefCount,Header->HandleCount);
332
333 if (Header->RefCount < 0)
334 {
335 DbgPrint("Object %x/%x has invalid reference count (%d)\n",
336 Header, HEADER_TO_BODY(Header), Header->RefCount);
337 KeBugCheck(0);
338 }
339 if (Header->HandleCount < 0)
340 {
341 DbgPrint("Object %x/%x has invalid handle count (%d)\n",
342 Header, HEADER_TO_BODY(Header), Header->HandleCount);
343 KeBugCheck(0);
344 }
345
346 if (Header->RefCount == 0 && Header->HandleCount == 0 &&
347 !Header->Permanent)
348 {
349 if (Header->ObjectType != NULL &&
350 Header->ObjectType->Delete != NULL)
351 {
352 Header->ObjectType->Delete(HEADER_TO_BODY(Header));
353 }
354 if (Header->Name.Buffer != NULL)
355 {
356 ObRemoveEntry(Header);
357 RtlFreeUnicodeString( &Header->Name );
358 }
359 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
360 ExFreePool(Header);
361 }
362 return(STATUS_SUCCESS);
363 }
364
365 ULONG ObGetReferenceCount(PVOID ObjectBody)
366 {
367 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
368
369 return(Header->RefCount);
370 }
371
372 ULONG ObGetHandleCount(PVOID ObjectBody)
373 {
374 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
375
376 return(Header->HandleCount);
377 }
378
379
380 /**********************************************************************
381 * NAME EXPORTED
382 * @ObfReferenceObject@0
383 *
384 * DESCRIPTION
385 * Increments a given object's reference count and performs
386 * retention checks.
387 *
388 * ARGUMENTS
389 * ObjectBody
390 * Body of the object.
391 *
392 * RETURN VALUE
393 * The current value of the reference counter.
394 */
395 ULONG FASTCALL ObfReferenceObject(PVOID ObjectBody)
396 {
397 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
398 ULONG ReferenceCount;
399
400 ReferenceCount = Header->RefCount++;
401
402 ObPerformRetentionChecks (Header);
403
404 return(ReferenceCount);
405 }
406
407
408 VOID FASTCALL ObfDereferenceObject (PVOID ObjectBody)
409 /*
410 * FUNCTION: Decrements a given object's reference count and performs
411 * retention checks
412 * ARGUMENTS:
413 * ObjectBody = Body of the object
414 */
415 {
416 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
417 extern POBJECT_TYPE PsProcessType;
418
419 // DPRINT("ObDeferenceObject(ObjectBody %x) RefCount %d\n",ObjectBody,
420 // Header->RefCount);
421
422 if (Header->ObjectType == PsProcessType)
423 {
424 DPRINT("Deref p 0x%x with refcount %d type %x ",
425 ObjectBody, Header->RefCount, PsProcessType);
426 DPRINT("eip %x\n", ((PULONG)&ObjectBody)[-1]);
427 }
428 if (Header->ObjectType == PsThreadType)
429 {
430 DPRINT("Deref t 0x%x with refcount %d type %x ",
431 ObjectBody, Header->RefCount, PsThreadType);
432 DPRINT("eip %x\n", ((PULONG)&ObjectBody)[-1]);
433 }
434
435 Header->RefCount--;
436
437 ObPerformRetentionChecks(Header);
438 }
439
440
441 VOID STDCALL ObDereferenceObject (PVOID ObjectBody)
442 {
443 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
444 extern POBJECT_TYPE PsProcessType;
445
446 if (Header->ObjectType == PsProcessType)
447 {
448 DPRINT("Deref p 0x%x with refcount %d type %x ",
449 ObjectBody, Header->RefCount, PsProcessType);
450 DPRINT("eip %x\n", ((PULONG)&ObjectBody)[-1]);
451 }
452
453 ObfDereferenceObject (ObjectBody);
454 }
455
456
457 /* EOF */