Implemented ObOpenObjectByName()
[reactos.git] / reactos / ntoskrnl / ob / object.c
1 /* $Id: object.c,v 1.30 2001/01/20 18:33:05 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 ObCreateObject(PHANDLE Handle,
224 ACCESS_MASK DesiredAccess,
225 POBJECT_ATTRIBUTES ObjectAttributes,
226 POBJECT_TYPE Type)
227 {
228 PVOID Parent = NULL;
229 UNICODE_STRING RemainingPath;
230 POBJECT_HEADER Header;
231 NTSTATUS Status;
232
233 assert_irql(APC_LEVEL);
234
235 DPRINT("ObCreateObject(Handle %x, ObjectAttributes %x, Type %x)\n");
236 if (ObjectAttributes != NULL &&
237 ObjectAttributes->ObjectName != NULL)
238 {
239 DPRINT("ObjectAttributes->ObjectName->Buffer %S\n",
240 ObjectAttributes->ObjectName->Buffer);
241 }
242
243 if (ObjectAttributes != NULL &&
244 ObjectAttributes->ObjectName != NULL)
245 {
246 ObFindObject(ObjectAttributes,
247 &Parent,
248 &RemainingPath,
249 NULL);
250 }
251 else
252 {
253 RtlInitUnicodeString (&RemainingPath, NULL);
254 }
255 Header = (POBJECT_HEADER)ExAllocatePool(NonPagedPool,
256 OBJECT_ALLOC_SIZE(Type));
257 ObInitializeObject(Header,
258 Handle,
259 DesiredAccess,
260 Type,
261 ObjectAttributes);
262 if (Header->ObjectType != NULL &&
263 Header->ObjectType->Create != NULL)
264 {
265 DPRINT("Calling %x\n", Header->ObjectType);
266 DPRINT("Calling %x\n", Header->ObjectType->Create);
267 Status = Header->ObjectType->Create(HEADER_TO_BODY(Header),
268 Parent,
269 RemainingPath.Buffer,
270 ObjectAttributes);
271 if (!NT_SUCCESS(Status))
272 {
273 ObDereferenceObject( Parent );
274 RtlFreeUnicodeString( &Header->Name );
275 RtlFreeUnicodeString( &RemainingPath );
276 ExFreePool( Header );
277 return(NULL);
278 }
279 }
280 RtlFreeUnicodeString( &RemainingPath );
281 return(HEADER_TO_BODY(Header));
282 }
283
284 NTSTATUS STDCALL ObReferenceObjectByPointer(PVOID ObjectBody,
285 ACCESS_MASK DesiredAccess,
286 POBJECT_TYPE ObjectType,
287 KPROCESSOR_MODE AccessMode)
288 /*
289 * FUNCTION: Increments the pointer reference count for a given object
290 * ARGUMENTS:
291 * ObjectBody = Object's body
292 * DesiredAccess = Desired access to the object
293 * ObjectType = Points to the object type structure
294 * AccessMode = Type of access check to perform
295 * RETURNS: Status
296 */
297 {
298 POBJECT_HEADER ObjectHeader;
299
300 // DPRINT("ObReferenceObjectByPointer(ObjectBody %x, ObjectType %x)\n",
301 // ObjectBody,ObjectType);
302
303 ObjectHeader = BODY_TO_HEADER(ObjectBody);
304
305 if (ObjectType != NULL && ObjectHeader->ObjectType != ObjectType)
306 {
307 DPRINT("Failed %x (type was %x %S) should %x\n",
308 ObjectHeader,
309 ObjectHeader->ObjectType,
310 ObjectHeader->ObjectType->TypeName.Buffer,
311 ObjectType);
312 KeBugCheck(0);
313 return(STATUS_UNSUCCESSFUL);
314 }
315 if (ObjectHeader->ObjectType == PsProcessType)
316 {
317 DPRINT("Ref p 0x%x refcount %d type %x ",
318 ObjectBody, ObjectHeader->RefCount, PsProcessType);
319 DPRINT("eip %x\n", ((PULONG)&ObjectBody)[-1]);
320 }
321 if (ObjectHeader->ObjectType == PsThreadType)
322 {
323 DPRINT("Deref t 0x%x with refcount %d type %x ",
324 ObjectBody, ObjectHeader->RefCount, PsThreadType);
325 DPRINT("eip %x\n", ((PULONG)&ObjectBody)[-1]);
326 }
327
328 ObjectHeader->RefCount++;
329
330 return(STATUS_SUCCESS);
331 }
332
333 NTSTATUS ObPerformRetentionChecks(POBJECT_HEADER Header)
334 {
335 // DPRINT("ObPerformRetentionChecks(Header %x), RefCount %d, HandleCount %d\n",
336 // Header,Header->RefCount,Header->HandleCount);
337
338 if (Header->RefCount < 0)
339 {
340 DbgPrint("Object %x/%x has invalid reference count (%d)\n",
341 Header, HEADER_TO_BODY(Header), Header->RefCount);
342 KeBugCheck(0);
343 }
344 if (Header->HandleCount < 0)
345 {
346 DbgPrint("Object %x/%x has invalid handle count (%d)\n",
347 Header, HEADER_TO_BODY(Header), Header->HandleCount);
348 KeBugCheck(0);
349 }
350
351 if (Header->RefCount == 0 && Header->HandleCount == 0 &&
352 !Header->Permanent)
353 {
354 if (Header->ObjectType != NULL &&
355 Header->ObjectType->Delete != NULL)
356 {
357 Header->ObjectType->Delete(HEADER_TO_BODY(Header));
358 }
359 if (Header->Name.Buffer != NULL)
360 {
361 ObRemoveEntry(Header);
362 RtlFreeUnicodeString( &Header->Name );
363 }
364 DPRINT("ObPerformRetentionChecks() = Freeing object\n");
365 ExFreePool(Header);
366 }
367 return(STATUS_SUCCESS);
368 }
369
370 ULONG ObGetReferenceCount(PVOID ObjectBody)
371 {
372 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
373
374 return(Header->RefCount);
375 }
376
377 ULONG ObGetHandleCount(PVOID ObjectBody)
378 {
379 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
380
381 return(Header->HandleCount);
382 }
383
384
385 /**********************************************************************
386 * NAME EXPORTED
387 * @ObfReferenceObject@0
388 *
389 * DESCRIPTION
390 * Increments a given object's reference count and performs
391 * retention checks.
392 *
393 * ARGUMENTS
394 * ObjectBody
395 * Body of the object.
396 *
397 * RETURN VALUE
398 * The current value of the reference counter.
399 */
400 ULONG FASTCALL ObfReferenceObject(PVOID ObjectBody)
401 {
402 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
403 ULONG ReferenceCount;
404
405 ReferenceCount = Header->RefCount++;
406
407 ObPerformRetentionChecks (Header);
408
409 return(ReferenceCount);
410 }
411
412
413 VOID FASTCALL ObfDereferenceObject (PVOID ObjectBody)
414 /*
415 * FUNCTION: Decrements a given object's reference count and performs
416 * retention checks
417 * ARGUMENTS:
418 * ObjectBody = Body of the object
419 */
420 {
421 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
422 extern POBJECT_TYPE PsProcessType;
423
424 // DPRINT("ObDeferenceObject(ObjectBody %x) RefCount %d\n",ObjectBody,
425 // Header->RefCount);
426
427 if (Header->ObjectType == PsProcessType)
428 {
429 DPRINT("Deref p 0x%x with refcount %d type %x ",
430 ObjectBody, Header->RefCount, PsProcessType);
431 DPRINT("eip %x\n", ((PULONG)&ObjectBody)[-1]);
432 }
433 if (Header->ObjectType == PsThreadType)
434 {
435 DPRINT("Deref t 0x%x with refcount %d type %x ",
436 ObjectBody, Header->RefCount, PsThreadType);
437 DPRINT("eip %x\n", ((PULONG)&ObjectBody)[-1]);
438 }
439
440 Header->RefCount--;
441
442 ObPerformRetentionChecks(Header);
443 }
444
445
446 VOID STDCALL ObDereferenceObject (PVOID ObjectBody)
447 {
448 POBJECT_HEADER Header = BODY_TO_HEADER(ObjectBody);
449 extern POBJECT_TYPE PsProcessType;
450
451 if (Header->ObjectType == PsProcessType)
452 {
453 DPRINT("Deref p 0x%x with refcount %d type %x ",
454 ObjectBody, Header->RefCount, PsProcessType);
455 DPRINT("eip %x\n", ((PULONG)&ObjectBody)[-1]);
456 }
457
458 ObfDereferenceObject (ObjectBody);
459 }
460
461
462 /* EOF */