[FLTMGR}
[reactos.git] / reactos / drivers / filters / fltmgr / Object.c
1 /*
2 * PROJECT: Filesystem Filter Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/filters/fltmgr/Object.c
5 * PURPOSE: Miscellaneous library functions
6 * PROGRAMMERS: Ged Murphy (gedmurphy@reactos.org)
7 */
8
9 // NOTE: Split this file into filter object and device object functions
10 // when the code base grows sufficiently
11
12 /* INCLUDES ******************************************************************/
13
14 #include "fltmgr.h"
15 #include "fltmgrint.h"
16
17 #define NDEBUG
18 #include <debug.h>
19
20
21 /* DATA *********************************************************************/
22
23 #define ExpChangePushlock(x, y, z) InterlockedCompareExchangePointer((PVOID*)x, (PVOID)y, (PVOID)z)
24
25 //
26 // Pushlock bits
27 //
28 #define EX_PUSH_LOCK_LOCK_V ((ULONG_PTR)0x0)
29 #define EX_PUSH_LOCK_LOCK ((ULONG_PTR)0x1)
30 #define EX_PUSH_LOCK_WAITING ((ULONG_PTR)0x2)
31 #define EX_PUSH_LOCK_WAKING ((ULONG_PTR)0x4)
32 #define EX_PUSH_LOCK_MULTIPLE_SHARED ((ULONG_PTR)0x8)
33 #define EX_PUSH_LOCK_SHARE_INC ((ULONG_PTR)0x10)
34 #define EX_PUSH_LOCK_PTR_BITS ((ULONG_PTR)0xf)
35
36 /* EXPORTED FUNCTIONS ******************************************************/
37
38
39 NTSTATUS
40 FLTAPI
41 FltObjectReference(_Inout_ PVOID Object)
42 {
43 if (!FltpExAcquireRundownProtection(&((PFLT_OBJECT)Object)->RundownRef))
44 {
45 return STATUS_FLT_DELETING_OBJECT;
46 }
47
48 return STATUS_SUCCESS;
49 }
50
51 VOID
52 FLTAPI
53 FltObjectDereference(_Inout_ PVOID Object)
54 {
55 FltpExReleaseRundownProtection(&((PFLT_OBJECT)Object)->RundownRef);
56 }
57
58
59 _Acquires_lock_(_Global_critical_region_)
60 _IRQL_requires_max_(APC_LEVEL)
61 VOID
62 FLTAPI
63 FltAcquirePushLockExclusive(_Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_) PEX_PUSH_LOCK PushLock)
64 {
65 KeEnterCriticalRegion();
66
67 /* Try acquiring the lock */
68 if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
69 {
70 /* Someone changed it, use the slow path */
71 ExfAcquirePushLockExclusive(PushLock);
72 }
73
74 /* Sanity check */
75 FLT_ASSERT(PushLock->Locked);
76 }
77
78
79 _Acquires_lock_(_Global_critical_region_)
80 _IRQL_requires_max_(APC_LEVEL)
81 VOID
82 FLTAPI
83 FltAcquirePushLockShared(_Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_) PEX_PUSH_LOCK PushLock)
84 {
85 EX_PUSH_LOCK NewValue;
86
87 KeEnterCriticalRegion();
88
89 /* Try acquiring the lock */
90 NewValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
91 if (ExpChangePushlock(PushLock, NewValue.Ptr, 0))
92 {
93 /* Someone changed it, use the slow path */
94 ExfAcquirePushLockShared(PushLock);
95 }
96
97 /* Sanity checks */
98 ASSERT(PushLock->Locked);
99 }
100
101 _Releases_lock_(_Global_critical_region_)
102 _IRQL_requires_max_(APC_LEVEL)
103 VOID
104 FLTAPI
105 FltReleasePushLock(_Inout_ _Requires_lock_held_(*_Curr_) _Releases_lock_(*_Curr_) PEX_PUSH_LOCK PushLock)
106 {
107 EX_PUSH_LOCK OldValue = *PushLock;
108 EX_PUSH_LOCK NewValue;
109
110 /* Sanity checks */
111 FLT_ASSERT(OldValue.Locked);
112
113 /* Check if the pushlock is shared */
114 if (OldValue.Shared > 1)
115 {
116 /* Decrease the share count */
117 NewValue.Value = OldValue.Value - EX_PUSH_LOCK_SHARE_INC;
118 }
119 else
120 {
121 /* Clear the pushlock entirely */
122 NewValue.Value = 0;
123 }
124
125 /* Check if nobody is waiting on us and try clearing the lock here */
126 if ((OldValue.Waiting) ||
127 (ExpChangePushlock(PushLock, NewValue.Ptr, OldValue.Ptr) !=
128 OldValue.Ptr))
129 {
130 /* We have waiters, use the long path */
131 ExfReleasePushLock(PushLock);
132 }
133
134 KeLeaveCriticalRegion();
135 }
136
137
138
139 /* INTERNAL FUNCTIONS ******************************************************/
140
141 VOID
142 FltpExInitializeRundownProtection(_Out_ PEX_RUNDOWN_REF RundownRef)
143 {
144 ExInitializeRundownProtection(RundownRef);
145 }
146
147 BOOLEAN
148 FltpExAcquireRundownProtection(_Inout_ PEX_RUNDOWN_REF RundownRef)
149 {
150 return ExAcquireRundownProtection(RundownRef);
151 }
152
153 BOOLEAN
154 FltpExReleaseRundownProtection(_Inout_ PEX_RUNDOWN_REF RundownRef)
155 {
156 ExReleaseRundownProtection(RundownRef);
157 return TRUE;
158 }
159
160 BOOLEAN
161 FltpExRundownCompleted(_Inout_ PEX_RUNDOWN_REF RundownRef)
162 {
163 return _InterlockedExchange((PLONG)RundownRef, 1);
164 }
165
166 NTSTATUS
167 NTAPI
168 FltpObjectRundownWait(_Inout_ PEX_RUNDOWN_REF RundownRef)
169 {
170 //return FltpExWaitForRundownProtectionRelease(RundownRef);
171 return 0;
172 }
173
174 NTSTATUS
175 FltpGetBaseDeviceObjectName(_In_ PDEVICE_OBJECT DeviceObject,
176 _Inout_ PUNICODE_STRING ObjectName)
177 {
178 PDEVICE_OBJECT BaseDeviceObject;
179 NTSTATUS Status;
180
181 /*
182 * Get the lowest device object on the stack, which may be the
183 * object we were passed, and lookup the name for that object
184 */
185 BaseDeviceObject = IoGetDeviceAttachmentBaseRef(DeviceObject);
186 Status = FltpGetObjectName(BaseDeviceObject, ObjectName);
187 ObDereferenceObject(BaseDeviceObject);
188
189 return Status;
190 }
191
192 NTSTATUS
193 FltpGetObjectName(_In_ PVOID Object,
194 _Inout_ PUNICODE_STRING ObjectName)
195 {
196 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
197 OBJECT_NAME_INFORMATION LocalNameInfo;
198 ULONG ReturnLength;
199 NTSTATUS Status;
200
201 if (ObjectName == NULL)
202 return STATUS_INVALID_PARAMETER;
203
204 /* Get the size of the buffer required to hold the nameinfo */
205 Status = ObQueryNameString(Object,
206 &LocalNameInfo,
207 sizeof(LocalNameInfo),
208 &ReturnLength);
209 if (Status == STATUS_INFO_LENGTH_MISMATCH)
210 {
211 ObjectNameInfo = ExAllocatePoolWithTag(PagedPool,
212 ReturnLength,
213 FM_TAG_UNICODE_STRING);
214 if (ObjectNameInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES;
215
216 /* Get the actual name info now we have the buffer to hold it */
217 Status = ObQueryNameString(Object,
218 ObjectNameInfo,
219 ReturnLength,
220 &ReturnLength);
221 }
222
223
224 if (NT_SUCCESS(Status))
225 {
226 /* Make sure the buffer we were passed is large enough to hold the string */
227 if (ObjectName->MaximumLength < ObjectNameInfo->Name.Length)
228 {
229 /* It wasn't, let's enlarge the buffer */
230 Status = FltpReallocateUnicodeString(ObjectName,
231 ObjectNameInfo->Name.Length,
232 FALSE);
233
234 }
235
236 if (NT_SUCCESS(Status))
237 {
238 /* Copy the object name into the callers buffer */
239 RtlCopyUnicodeString(ObjectName, &ObjectNameInfo->Name);
240 }
241 }
242
243 if (ObjectNameInfo)
244 {
245 ExFreePoolWithTag(ObjectNameInfo, FM_TAG_UNICODE_STRING);
246 }
247
248 return Status;
249 }
250
251 ULONG
252 FltpObjectPointerReference(_In_ PFLT_OBJECT Object)
253 {
254 PULONG Result;
255
256 /* Store the old count and increment */
257 Result = &Object->PointerCount;
258 InterlockedIncrement((PLONG)&Object->PointerCount);
259
260 /* Return the initial value */
261 return *Result;
262 }
263
264 VOID
265 FltpObjectPointerDereference(_In_ PFLT_OBJECT Object)
266 {
267 if (!InterlockedDecrement((PLONG)Object->PointerCount))
268 {
269 // Cleanup
270 FLT_ASSERT(FALSE);
271 }
272 }