413b85fce3b6d5fd72d802072caa2d1468da2533
[reactos.git] / 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 _IRQL_requires_max_(PASSIVE_LEVEL)
138 NTSTATUS
139 FLTAPI
140 FltClose(_In_ HANDLE FileHandle)
141 {
142 PAGED_CODE();
143
144 return ZwClose(FileHandle);
145 }
146
147 _Must_inspect_result_
148 _IRQL_requires_max_(PASSIVE_LEVEL)
149 NTSTATUS
150 FLTAPI
151 FltCreateFileEx(_In_ PFLT_FILTER Filter,
152 _In_opt_ PFLT_INSTANCE Instance,
153 _Out_ PHANDLE FileHandle,
154 _Outptr_opt_ PFILE_OBJECT *FileObject,
155 _In_ ACCESS_MASK DesiredAccess,
156 _In_ POBJECT_ATTRIBUTES ObjectAttributes,
157 _Out_ PIO_STATUS_BLOCK IoStatusBlock,
158 _In_opt_ PLARGE_INTEGER AllocationSize,
159 _In_ ULONG FileAttributes,
160 _In_ ULONG ShareAccess,
161 _In_ ULONG CreateDisposition,
162 _In_ ULONG CreateOptions,
163 _In_reads_bytes_opt_(EaLength) PVOID EaBuffer,
164 _In_ ULONG EaLength,
165 _In_ ULONG Flags)
166 {
167 UNIMPLEMENTED;
168 return STATUS_NOT_IMPLEMENTED;
169 }
170
171
172
173 /* INTERNAL FUNCTIONS ******************************************************/
174
175 VOID
176 FltpExInitializeRundownProtection(_Out_ PEX_RUNDOWN_REF RundownRef)
177 {
178 ExInitializeRundownProtection(RundownRef);
179 }
180
181 BOOLEAN
182 FltpExAcquireRundownProtection(_Inout_ PEX_RUNDOWN_REF RundownRef)
183 {
184 return ExAcquireRundownProtection(RundownRef);
185 }
186
187 BOOLEAN
188 FltpExReleaseRundownProtection(_Inout_ PEX_RUNDOWN_REF RundownRef)
189 {
190 ExReleaseRundownProtection(RundownRef);
191 return TRUE;
192 }
193
194 BOOLEAN
195 FltpExRundownCompleted(_Inout_ PEX_RUNDOWN_REF RundownRef)
196 {
197 return _InterlockedExchange((PLONG)RundownRef, 1);
198 }
199
200 NTSTATUS
201 NTAPI
202 FltpObjectRundownWait(_Inout_ PEX_RUNDOWN_REF RundownRef)
203 {
204 //return FltpExWaitForRundownProtectionRelease(RundownRef);
205 return 0;
206 }
207
208 NTSTATUS
209 FltpGetBaseDeviceObjectName(_In_ PDEVICE_OBJECT DeviceObject,
210 _Inout_ PUNICODE_STRING ObjectName)
211 {
212 PDEVICE_OBJECT BaseDeviceObject;
213 NTSTATUS Status;
214
215 /*
216 * Get the lowest device object on the stack, which may be the
217 * object we were passed, and lookup the name for that object
218 */
219 BaseDeviceObject = IoGetDeviceAttachmentBaseRef(DeviceObject);
220 Status = FltpGetObjectName(BaseDeviceObject, ObjectName);
221 ObDereferenceObject(BaseDeviceObject);
222
223 return Status;
224 }
225
226 NTSTATUS
227 FltpGetObjectName(_In_ PVOID Object,
228 _Inout_ PUNICODE_STRING ObjectName)
229 {
230 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
231 OBJECT_NAME_INFORMATION LocalNameInfo;
232 ULONG ReturnLength;
233 NTSTATUS Status;
234
235 if (ObjectName == NULL)
236 return STATUS_INVALID_PARAMETER;
237
238 /* Get the size of the buffer required to hold the nameinfo */
239 Status = ObQueryNameString(Object,
240 &LocalNameInfo,
241 sizeof(LocalNameInfo),
242 &ReturnLength);
243 if (Status == STATUS_INFO_LENGTH_MISMATCH)
244 {
245 ObjectNameInfo = ExAllocatePoolWithTag(PagedPool,
246 ReturnLength,
247 FM_TAG_UNICODE_STRING);
248 if (ObjectNameInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES;
249
250 /* Get the actual name info now we have the buffer to hold it */
251 Status = ObQueryNameString(Object,
252 ObjectNameInfo,
253 ReturnLength,
254 &ReturnLength);
255 }
256
257
258 if (NT_SUCCESS(Status))
259 {
260 /* Make sure the buffer we were passed is large enough to hold the string */
261 if (ObjectName->MaximumLength < ObjectNameInfo->Name.Length)
262 {
263 /* It wasn't, let's enlarge the buffer */
264 Status = FltpReallocateUnicodeString(ObjectName,
265 ObjectNameInfo->Name.Length,
266 FALSE);
267
268 }
269
270 if (NT_SUCCESS(Status))
271 {
272 /* Copy the object name into the callers buffer */
273 RtlCopyUnicodeString(ObjectName, &ObjectNameInfo->Name);
274 }
275 }
276
277 if (ObjectNameInfo)
278 {
279 ExFreePoolWithTag(ObjectNameInfo, FM_TAG_UNICODE_STRING);
280 }
281
282 return Status;
283 }
284
285 ULONG
286 FltpObjectPointerReference(_In_ PFLT_OBJECT Object)
287 {
288 PULONG Result;
289
290 /* Store the old count and increment */
291 Result = &Object->PointerCount;
292 InterlockedIncrementSizeT(&Object->PointerCount);
293
294 /* Return the initial value */
295 return *Result;
296 }
297
298 VOID
299 FltpObjectPointerDereference(_In_ PFLT_OBJECT Object)
300 {
301 if (InterlockedDecrementSizeT(&Object->PointerCount) == 0)
302 {
303 // Cleanup
304 FLT_ASSERT(FALSE);
305 }
306 }