1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/fsrtl/filtrctx.c 5 * PURPOSE: File Stream Filter Context support for File System Drivers 6 * PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* PRIVATE FUNCTIONS *********************************************************/ 16 17 typedef struct _FILE_OBJECT_FILTER_CONTEXTS 18 { 19 FAST_MUTEX FilterContextsMutex; 20 LIST_ENTRY FilterContexts; 21 } FILE_OBJECT_FILTER_CONTEXTS, *PFILE_OBJECT_FILTER_CONTEXTS; 22 23 /* 24 * @implemented 25 */ 26 VOID 27 NTAPI 28 FsRtlPTeardownPerFileObjectContexts(IN PFILE_OBJECT FileObject) 29 { 30 PFILE_OBJECT_FILTER_CONTEXTS FOContext = NULL; 31 32 ASSERT(FileObject); 33 34 if (!(FOContext = IoGetFileObjectFilterContext(FileObject))) 35 { 36 return; 37 } 38 39 ASSERT(IoChangeFileObjectFilterContext(FileObject, FOContext, FALSE) == STATUS_SUCCESS); 40 ASSERT(IsListEmpty(&(FOContext->FilterContexts))); 41 42 ExFreePoolWithTag(FOContext, 'FOCX'); 43 } 44 45 46 /* PUBLIC FUNCTIONS **********************************************************/ 47 48 /*++ 49 * @name FsRtlIsPagingFile 50 * @implemented NT 5.2 51 * 52 * The FsRtlIsPagingFile routine checks if the FileObject is a Paging File. 53 * 54 * @param FileObject 55 * A pointer to the File Object to be tested. 56 * 57 * @return TRUE if the File is a Paging File, FALSE otherwise. 58 * 59 * @remarks None. 60 * 61 *--*/ 62 LOGICAL 63 NTAPI 64 FsRtlIsPagingFile(IN PFILE_OBJECT FileObject) 65 { 66 return MmIsFileObjectAPagingFile(FileObject); 67 } 68 69 /* 70 * @implemented 71 */ 72 PFSRTL_PER_FILEOBJECT_CONTEXT 73 NTAPI 74 FsRtlLookupPerFileObjectContext(IN PFILE_OBJECT FileObject, 75 IN PVOID OwnerId OPTIONAL, 76 IN PVOID InstanceId OPTIONAL) 77 { 78 PLIST_ENTRY NextEntry; 79 PFILE_OBJECT_FILTER_CONTEXTS FOContext = NULL; 80 PFSRTL_PER_FILEOBJECT_CONTEXT TmpPerFOContext, PerFOContext = NULL; 81 82 if (!FileObject || !(FOContext = IoGetFileObjectFilterContext(FileObject))) 83 { 84 return NULL; 85 } 86 87 ExAcquireFastMutex(&(FOContext->FilterContextsMutex)); 88 89 /* If list is empty, no need to browse it */ 90 if (!IsListEmpty(&(FOContext->FilterContexts))) 91 { 92 for (NextEntry = FOContext->FilterContexts.Flink; 93 NextEntry != &(FOContext->FilterContexts); 94 NextEntry = NextEntry->Flink) 95 { 96 /* If we don't have any criteria for search, first entry will be enough */ 97 if (!OwnerId && !InstanceId) 98 { 99 PerFOContext = (PFSRTL_PER_FILEOBJECT_CONTEXT)NextEntry; 100 break; 101 } 102 /* Else, we've to find something that matches with the parameters. */ 103 else 104 { 105 TmpPerFOContext = CONTAINING_RECORD(NextEntry, FSRTL_PER_FILEOBJECT_CONTEXT, Links); 106 if ((InstanceId && TmpPerFOContext->InstanceId == InstanceId && TmpPerFOContext->OwnerId == OwnerId) || 107 (OwnerId && TmpPerFOContext->OwnerId == OwnerId)) 108 { 109 PerFOContext = TmpPerFOContext; 110 break; 111 } 112 } 113 } 114 } 115 116 ExReleaseFastMutex(&(FOContext->FilterContextsMutex)); 117 118 return PerFOContext; 119 } 120 121 /* 122 * @implemented 123 */ 124 PFSRTL_PER_STREAM_CONTEXT 125 NTAPI 126 FsRtlLookupPerStreamContextInternal(IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader, 127 IN PVOID OwnerId OPTIONAL, 128 IN PVOID InstanceId OPTIONAL) 129 { 130 PLIST_ENTRY NextEntry; 131 PFSRTL_PER_STREAM_CONTEXT TmpPerStreamContext, PerStreamContext = NULL; 132 133 ASSERT(AdvFcbHeader); 134 ASSERT(FlagOn(AdvFcbHeader->Flags2, FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS)); 135 136 ExAcquireFastMutex(AdvFcbHeader->FastMutex); 137 138 /* If list is empty, no need to browse it */ 139 if (!IsListEmpty(&(AdvFcbHeader->FilterContexts))) 140 { 141 for (NextEntry = AdvFcbHeader->FilterContexts.Flink; 142 NextEntry != &(AdvFcbHeader->FilterContexts); 143 NextEntry = NextEntry->Flink) 144 { 145 /* If we don't have any criteria for search, first entry will be enough */ 146 if (!OwnerId && !InstanceId) 147 { 148 PerStreamContext = (PFSRTL_PER_STREAM_CONTEXT)NextEntry; 149 break; 150 } 151 /* Else, we've to find something that matches with the parameters. */ 152 else 153 { 154 TmpPerStreamContext = CONTAINING_RECORD(NextEntry, FSRTL_PER_STREAM_CONTEXT, Links); 155 if ((InstanceId && TmpPerStreamContext->InstanceId == InstanceId && TmpPerStreamContext->OwnerId == OwnerId) || 156 (OwnerId && TmpPerStreamContext->OwnerId == OwnerId)) 157 { 158 PerStreamContext = TmpPerStreamContext; 159 break; 160 } 161 } 162 } 163 } 164 165 ExReleaseFastMutex(AdvFcbHeader->FastMutex); 166 167 return PerStreamContext; 168 } 169 170 /* 171 * @implemented 172 */ 173 NTSTATUS 174 NTAPI 175 FsRtlInsertPerFileObjectContext(IN PFILE_OBJECT FileObject, 176 IN PFSRTL_PER_FILEOBJECT_CONTEXT Ptr) 177 { 178 PFILE_OBJECT_FILTER_CONTEXTS FOContext = NULL; 179 180 if (!FileObject) 181 { 182 return STATUS_INVALID_PARAMETER; 183 } 184 185 if (!(FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)) 186 { 187 return STATUS_INVALID_DEVICE_REQUEST; 188 } 189 190 /* Get filter contexts */ 191 FOContext = IoGetFileObjectFilterContext(FileObject); 192 if (!FOContext) 193 { 194 /* If there's none, allocate new structure */ 195 FOContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(FILE_OBJECT_FILTER_CONTEXTS), 'FOCX'); 196 if (!FOContext) 197 { 198 return STATUS_INSUFFICIENT_RESOURCES; 199 } 200 201 /* Initialize it */ 202 ExInitializeFastMutex(&(FOContext->FilterContextsMutex)); 203 InitializeListHead(&(FOContext->FilterContexts)); 204 205 /* Set it */ 206 if (!IoChangeFileObjectFilterContext(FileObject, FOContext, TRUE)) 207 { 208 /* If it fails, it means that someone else has set it in the meanwhile */ 209 ExFreePoolWithTag(FOContext, 'FOCX'); 210 211 /* So, we can get it */ 212 FOContext = IoGetFileObjectFilterContext(FileObject); 213 if (!FOContext) 214 { 215 /* If we fall down here, something went very bad. This shouldn't happen */ 216 ASSERT(FALSE); 217 return STATUS_UNSUCCESSFUL; 218 } 219 } 220 } 221 222 /* Finally, insert */ 223 ExAcquireFastMutex(&(FOContext->FilterContextsMutex)); 224 InsertHeadList(&(FOContext->FilterContexts), &(Ptr->Links)); 225 ExReleaseFastMutex(&(FOContext->FilterContextsMutex)); 226 227 return STATUS_SUCCESS; 228 } 229 230 /* 231 * @implemented 232 */ 233 NTSTATUS 234 NTAPI 235 FsRtlInsertPerStreamContext(IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader, 236 IN PFSRTL_PER_STREAM_CONTEXT PerStreamContext) 237 { 238 if (!(AdvFcbHeader) || !(AdvFcbHeader->Flags2 & FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS)) 239 { 240 return STATUS_INVALID_DEVICE_REQUEST; 241 } 242 243 ExAcquireFastMutex(AdvFcbHeader->FastMutex); 244 InsertHeadList(&(AdvFcbHeader->FilterContexts), &(PerStreamContext->Links)); 245 ExReleaseFastMutex(AdvFcbHeader->FastMutex); 246 return STATUS_SUCCESS; 247 } 248 249 /* 250 * @implemented 251 */ 252 PFSRTL_PER_FILEOBJECT_CONTEXT 253 NTAPI 254 FsRtlRemovePerFileObjectContext(IN PFILE_OBJECT FileObject, 255 IN PVOID OwnerId OPTIONAL, 256 IN PVOID InstanceId OPTIONAL) 257 { 258 PLIST_ENTRY NextEntry; 259 PFILE_OBJECT_FILTER_CONTEXTS FOContext = NULL; 260 PFSRTL_PER_FILEOBJECT_CONTEXT TmpPerFOContext, PerFOContext = NULL; 261 262 if (!FileObject || !(FOContext = IoGetFileObjectFilterContext(FileObject))) 263 { 264 return NULL; 265 } 266 267 ExAcquireFastMutex(&(FOContext->FilterContextsMutex)); 268 269 /* If list is empty, no need to browse it */ 270 if (!IsListEmpty(&(FOContext->FilterContexts))) 271 { 272 for (NextEntry = FOContext->FilterContexts.Flink; 273 NextEntry != &(FOContext->FilterContexts); 274 NextEntry = NextEntry->Flink) 275 { 276 /* If we don't have any criteria for search, first entry will be enough */ 277 if (!OwnerId && !InstanceId) 278 { 279 PerFOContext = (PFSRTL_PER_FILEOBJECT_CONTEXT)NextEntry; 280 break; 281 } 282 /* Else, we've to find something that matches with the parameters. */ 283 else 284 { 285 TmpPerFOContext = CONTAINING_RECORD(NextEntry, FSRTL_PER_FILEOBJECT_CONTEXT, Links); 286 if ((InstanceId && TmpPerFOContext->InstanceId == InstanceId && TmpPerFOContext->OwnerId == OwnerId) || 287 (OwnerId && TmpPerFOContext->OwnerId == OwnerId)) 288 { 289 PerFOContext = TmpPerFOContext; 290 break; 291 } 292 } 293 } 294 295 /* Finally remove entry from list */ 296 if (PerFOContext) 297 { 298 RemoveEntryList(&(PerFOContext->Links)); 299 } 300 } 301 302 ExReleaseFastMutex(&(FOContext->FilterContextsMutex)); 303 304 return PerFOContext; 305 } 306 307 /* 308 * @implemented 309 */ 310 PFSRTL_PER_STREAM_CONTEXT 311 NTAPI 312 FsRtlRemovePerStreamContext(IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader, 313 IN PVOID OwnerId OPTIONAL, 314 IN PVOID InstanceId OPTIONAL) 315 { 316 PLIST_ENTRY NextEntry; 317 PFSRTL_PER_STREAM_CONTEXT TmpPerStreamContext, PerStreamContext = NULL; 318 319 if (!(AdvFcbHeader) || !(AdvFcbHeader->Flags2 & FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS)) 320 { 321 return NULL; 322 } 323 324 ExAcquireFastMutex(AdvFcbHeader->FastMutex); 325 /* If list is empty, no need to browse it */ 326 if (!IsListEmpty(&(AdvFcbHeader->FilterContexts))) 327 { 328 for (NextEntry = AdvFcbHeader->FilterContexts.Flink; 329 NextEntry != &(AdvFcbHeader->FilterContexts); 330 NextEntry = NextEntry->Flink) 331 { 332 /* If we don't have any criteria for search, first entry will be enough */ 333 if (!OwnerId && !InstanceId) 334 { 335 PerStreamContext = (PFSRTL_PER_STREAM_CONTEXT)NextEntry; 336 break; 337 } 338 /* Else, we've to find something that matches with the parameters. */ 339 else 340 { 341 TmpPerStreamContext = CONTAINING_RECORD(NextEntry, FSRTL_PER_STREAM_CONTEXT, Links); 342 if ((InstanceId && TmpPerStreamContext->InstanceId == InstanceId && TmpPerStreamContext->OwnerId == OwnerId) || 343 (OwnerId && TmpPerStreamContext->OwnerId == OwnerId)) 344 { 345 PerStreamContext = TmpPerStreamContext; 346 break; 347 } 348 } 349 } 350 351 /* Finally remove entry from list */ 352 if (PerStreamContext) 353 { 354 RemoveEntryList(&(PerStreamContext->Links)); 355 } 356 } 357 ExReleaseFastMutex(AdvFcbHeader->FastMutex); 358 359 return PerStreamContext; 360 361 } 362 363 /* 364 * @implemented 365 */ 366 VOID 367 NTAPI 368 FsRtlTeardownPerStreamContexts(IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader) 369 { 370 PLIST_ENTRY NextEntry; 371 volatile BOOLEAN IsMutexLocked = FALSE; 372 PFSRTL_PER_STREAM_CONTEXT PerStreamContext; 373 374 _SEH2_TRY 375 { 376 /* Acquire mutex to deal with the list */ 377 ExAcquireFastMutex(AdvFcbHeader->FastMutex); 378 IsMutexLocked = TRUE; 379 380 /* While there are items... */ 381 while (!IsListEmpty(&(AdvFcbHeader->FilterContexts))) 382 { 383 /* ...remove one */ 384 NextEntry = RemoveHeadList(&(AdvFcbHeader->FilterContexts)); 385 PerStreamContext = CONTAINING_RECORD(NextEntry, FSRTL_PER_STREAM_CONTEXT, Links); 386 387 /* Release mutex before calling callback */ 388 ExReleaseFastMutex(AdvFcbHeader->FastMutex); 389 IsMutexLocked = FALSE; 390 391 /* Call the callback */ 392 ASSERT(PerStreamContext->FreeCallback); 393 (*PerStreamContext->FreeCallback)(PerStreamContext); 394 395 /* Relock the list to continue */ 396 ExAcquireFastMutex(AdvFcbHeader->FastMutex); 397 IsMutexLocked = TRUE; 398 } 399 } 400 _SEH2_FINALLY 401 { 402 /* If mutex was locked, release */ 403 if (IsMutexLocked) 404 { 405 ExReleaseFastMutex(AdvFcbHeader->FastMutex); 406 } 407 } 408 _SEH2_END; 409 } 410