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