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