[FLTMGR] Implement FltCreateFile()
[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 _Must_inspect_result_
172 _IRQL_requires_max_(PASSIVE_LEVEL)
173 NTSTATUS
174 FLTAPI
175 FltCreateFile(_In_ PFLT_FILTER Filter,
176 _In_opt_ PFLT_INSTANCE Instance,
177 _Out_ PHANDLE FileHandle,
178 _In_ ACCESS_MASK DesiredAccess,
179 _In_ POBJECT_ATTRIBUTES ObjectAttributes,
180 _Out_ PIO_STATUS_BLOCK IoStatusBlock,
181 _In_opt_ PLARGE_INTEGER AllocationSize,
182 _In_ ULONG FileAttributes,
183 _In_ ULONG ShareAccess,
184 _In_ ULONG CreateDisposition,
185 _In_ ULONG CreateOptions,
186 _In_reads_bytes_opt_(EaLength)PVOID EaBuffer,
187 _In_ ULONG EaLength,
188 _In_ ULONG Flags)
189 {
190 return FltCreateFileEx(Filter,
191 Instance,
192 FileHandle,
193 NULL,
194 DesiredAccess,
195 ObjectAttributes,
196 IoStatusBlock,
197 AllocationSize,
198 FileAttributes,
199 ShareAccess,
200 CreateDisposition,
201 CreateOptions,
202 EaBuffer,
203 EaLength,
204 Flags);
205 }
206
207
208
209 /* INTERNAL FUNCTIONS ******************************************************/
210
211 VOID
212 FltpExInitializeRundownProtection(_Out_ PEX_RUNDOWN_REF RundownRef)
213 {
214 ExInitializeRundownProtection(RundownRef);
215 }
216
217 BOOLEAN
218 FltpExAcquireRundownProtection(_Inout_ PEX_RUNDOWN_REF RundownRef)
219 {
220 return ExAcquireRundownProtection(RundownRef);
221 }
222
223 BOOLEAN
224 FltpExReleaseRundownProtection(_Inout_ PEX_RUNDOWN_REF RundownRef)
225 {
226 ExReleaseRundownProtection(RundownRef);
227 return TRUE;
228 }
229
230 BOOLEAN
231 FltpExRundownCompleted(_Inout_ PEX_RUNDOWN_REF RundownRef)
232 {
233 return _InterlockedExchange((PLONG)RundownRef, 1);
234 }
235
236 NTSTATUS
237 NTAPI
238 FltpObjectRundownWait(_Inout_ PEX_RUNDOWN_REF RundownRef)
239 {
240 //return FltpExWaitForRundownProtectionRelease(RundownRef);
241 return 0;
242 }
243
244 NTSTATUS
245 FltpGetBaseDeviceObjectName(_In_ PDEVICE_OBJECT DeviceObject,
246 _Inout_ PUNICODE_STRING ObjectName)
247 {
248 PDEVICE_OBJECT BaseDeviceObject;
249 NTSTATUS Status;
250
251 /*
252 * Get the lowest device object on the stack, which may be the
253 * object we were passed, and lookup the name for that object
254 */
255 BaseDeviceObject = IoGetDeviceAttachmentBaseRef(DeviceObject);
256 Status = FltpGetObjectName(BaseDeviceObject, ObjectName);
257 ObDereferenceObject(BaseDeviceObject);
258
259 return Status;
260 }
261
262 NTSTATUS
263 FltpGetObjectName(_In_ PVOID Object,
264 _Inout_ PUNICODE_STRING ObjectName)
265 {
266 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
267 OBJECT_NAME_INFORMATION LocalNameInfo;
268 ULONG ReturnLength;
269 NTSTATUS Status;
270
271 if (ObjectName == NULL)
272 return STATUS_INVALID_PARAMETER;
273
274 /* Get the size of the buffer required to hold the nameinfo */
275 Status = ObQueryNameString(Object,
276 &LocalNameInfo,
277 sizeof(LocalNameInfo),
278 &ReturnLength);
279 if (Status == STATUS_INFO_LENGTH_MISMATCH)
280 {
281 ObjectNameInfo = ExAllocatePoolWithTag(PagedPool,
282 ReturnLength,
283 FM_TAG_UNICODE_STRING);
284 if (ObjectNameInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES;
285
286 /* Get the actual name info now we have the buffer to hold it */
287 Status = ObQueryNameString(Object,
288 ObjectNameInfo,
289 ReturnLength,
290 &ReturnLength);
291 }
292
293
294 if (NT_SUCCESS(Status))
295 {
296 /* Make sure the buffer we were passed is large enough to hold the string */
297 if (ObjectName->MaximumLength < ObjectNameInfo->Name.Length)
298 {
299 /* It wasn't, let's enlarge the buffer */
300 Status = FltpReallocateUnicodeString(ObjectName,
301 ObjectNameInfo->Name.Length,
302 FALSE);
303
304 }
305
306 if (NT_SUCCESS(Status))
307 {
308 /* Copy the object name into the callers buffer */
309 RtlCopyUnicodeString(ObjectName, &ObjectNameInfo->Name);
310 }
311 }
312
313 if (ObjectNameInfo)
314 {
315 ExFreePoolWithTag(ObjectNameInfo, FM_TAG_UNICODE_STRING);
316 }
317
318 return Status;
319 }
320
321 ULONG
322 FltpObjectPointerReference(_In_ PFLT_OBJECT Object)
323 {
324 PULONG Result;
325
326 /* Store the old count and increment */
327 Result = &Object->PointerCount;
328 InterlockedIncrementSizeT(&Object->PointerCount);
329
330 /* Return the initial value */
331 return *Result;
332 }
333
334 VOID
335 FltpObjectPointerDereference(_In_ PFLT_OBJECT Object)
336 {
337 if (InterlockedDecrementSizeT(&Object->PointerCount) == 0)
338 {
339 // Cleanup
340 FLT_ASSERT(FALSE);
341 }
342 }