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