Bring back ext2 code from branch
[reactos.git] / reactos / drivers / filesystems / ext2 / src / misc.c
1 /*************************************************************************
2 *
3 * File: misc.c
4 *
5 * Module: Ext2 File System Driver (Kernel mode execution only)
6 *
7 * Description:
8 * This file contains some miscellaneous support routines.
9 *
10 * Author: Manoj Paul Joseph
11 *
12 *
13 *************************************************************************/
14
15 #include "ext2fsd.h"
16
17 // define the file specific bug-check id
18 #define EXT2_BUG_CHECK_ID EXT2_FILE_MISC
19
20 #define DEBUG_LEVEL ( DEBUG_TRACE_MISC )
21
22 /*************************************************************************
23 *
24 * Function: Ext2InitializeZones()
25 *
26 * Description:
27 * Allocates some memory for global zones used to allocate FSD structures.
28 * Either all memory will be allocated or we will back out gracefully.
29 *
30 * Expected Interrupt Level (for execution) :
31 *
32 * IRQL_PASSIVE_LEVEL
33 *
34 * Return Value: STATUS_SUCCESS/Error
35 *
36 *************************************************************************/
37 NTSTATUS Ext2InitializeZones(
38 void)
39 {
40 NTSTATUS RC = STATUS_SUCCESS;
41 uint32 SizeOfZone = Ext2GlobalData.DefaultZoneSizeInNumStructs;
42 uint32 SizeOfObjectNameZone = 0;
43 uint32 SizeOfCCBZone = 0;
44 uint32 SizeOfFCBZone = 0;
45 uint32 SizeOfByteLockZone = 0;
46 uint32 SizeOfIrpContextZone = 0;
47
48 try {
49
50 // initialize the spinlock protecting the zones
51 KeInitializeSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock));
52
53 // determine memory requirements
54 switch (MmQuerySystemSize()) {
55 case MmSmallSystem:
56 // this is just for illustration purposes. I will multiply
57 // number of structures with some arbitrary amount depending
58 // upon available memory in the system ... You should choose a
59 // more intelligent method suitable to your memory consumption
60 // and the amount of memory available.
61 SizeOfObjectNameZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER);
62 SizeOfCCBZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER);
63 SizeOfFCBZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER);
64 SizeOfByteLockZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER);
65 SizeOfIrpContextZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER);
66 break;
67 case MmMediumSystem:
68 SizeOfObjectNameZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER);
69 SizeOfCCBZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER);
70 SizeOfFCBZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER);
71 SizeOfByteLockZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER);
72 SizeOfIrpContextZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER);
73 break;
74 case MmLargeSystem:
75 SizeOfObjectNameZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER);
76 SizeOfCCBZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER);
77 SizeOfFCBZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER);
78 SizeOfByteLockZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER);
79 SizeOfIrpContextZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER);
80 break;
81 }
82
83 // typical NT methodology (at least until *someone* exposed the "difference" between a server and workstation ;-)
84 if (MmIsThisAnNtAsSystem()) {
85 SizeOfObjectNameZone *= EXT2_NTAS_MULTIPLE;
86 SizeOfCCBZone *= EXT2_NTAS_MULTIPLE;
87 SizeOfFCBZone *= EXT2_NTAS_MULTIPLE;
88 SizeOfByteLockZone *= EXT2_NTAS_MULTIPLE;
89 SizeOfIrpContextZone *= EXT2_NTAS_MULTIPLE;
90 }
91
92 // allocate memory for each of the zones and initialize the zones ...
93 if (!(Ext2GlobalData.ObjectNameZone = Ext2AllocatePool(NonPagedPool, SizeOfObjectNameZone ))) {
94 RC = STATUS_INSUFFICIENT_RESOURCES;
95 try_return(RC);
96 }
97
98 if (!(Ext2GlobalData.CCBZone = Ext2AllocatePool(NonPagedPool, SizeOfCCBZone ))) {
99 RC = STATUS_INSUFFICIENT_RESOURCES;
100 try_return(RC);
101 }
102
103 if (!(Ext2GlobalData.FCBZone = Ext2AllocatePool(NonPagedPool, SizeOfFCBZone ))) {
104 RC = STATUS_INSUFFICIENT_RESOURCES;
105 try_return(RC);
106 }
107
108 if (!(Ext2GlobalData.ByteLockZone = Ext2AllocatePool(NonPagedPool, SizeOfByteLockZone ))) {
109 RC = STATUS_INSUFFICIENT_RESOURCES;
110 try_return(RC);
111 }
112
113 if (!(Ext2GlobalData.IrpContextZone = Ext2AllocatePool(NonPagedPool, SizeOfIrpContextZone ))) {
114 RC = STATUS_INSUFFICIENT_RESOURCES;
115 try_return(RC);
116 }
117
118 // initialize each of the zone headers ...
119 if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.ObjectNameZoneHeader),
120 Ext2QuadAlign(sizeof(Ext2ObjectName)),
121 Ext2GlobalData.ObjectNameZone, SizeOfObjectNameZone))) {
122 // failed the initialization, leave ...
123 try_return(RC);
124 }
125
126 if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.CCBZoneHeader),
127 Ext2QuadAlign(sizeof(Ext2CCB)),
128 Ext2GlobalData.CCBZone,
129 SizeOfCCBZone))) {
130 // failed the initialization, leave ...
131 try_return(RC);
132 }
133
134 if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.FCBZoneHeader),
135 Ext2QuadAlign(sizeof(Ext2FCB)),
136 Ext2GlobalData.FCBZone,
137 SizeOfFCBZone))) {
138 // failed the initialization, leave ...
139 try_return(RC);
140 }
141
142 if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.ByteLockZoneHeader),
143 Ext2QuadAlign(sizeof(Ext2FileLockInfo)),
144 Ext2GlobalData.ByteLockZone,
145 SizeOfByteLockZone))) {
146 // failed the initialization, leave ...
147 try_return(RC);
148 }
149
150 if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.IrpContextZoneHeader),
151 Ext2QuadAlign(sizeof(Ext2IrpContext)),
152 Ext2GlobalData.IrpContextZone,
153 SizeOfIrpContextZone))) {
154 // failed the initialization, leave ...
155 try_return(RC);
156 }
157
158 try_exit: NOTHING;
159
160 } finally {
161 if (!NT_SUCCESS(RC)) {
162 // invoke the destroy routine now ...
163 Ext2DestroyZones();
164 } else {
165 // mark the fact that we have allocated zones ...
166 Ext2SetFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_ZONES_INITIALIZED);
167 }
168 }
169
170 return(RC);
171 }
172
173
174 /*************************************************************************
175 *
176 * Function: Ext2DestroyZones()
177 *
178 * Description:
179 * Free up the previously allocated memory. NEVER do this once the
180 * driver has been successfully loaded.
181 *
182 * Expected Interrupt Level (for execution) :
183 *
184 * IRQL_PASSIVE_LEVEL
185 *
186 * Return Value: None
187 *
188 *************************************************************************/
189 void Ext2DestroyZones(
190 void)
191 {
192 try {
193 // free up each of the pools
194 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.ObjectNameZone);
195 ExFreePool(Ext2GlobalData.ObjectNameZone);
196
197 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.CCBZone);
198 ExFreePool(Ext2GlobalData.CCBZone);
199
200 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.FCBZone);
201 ExFreePool(Ext2GlobalData.FCBZone);
202
203 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.ByteLockZone);
204 ExFreePool(Ext2GlobalData.ByteLockZone);
205
206 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.IrpContextZone);
207 ExFreePool(Ext2GlobalData.IrpContextZone);
208
209 try_exit: NOTHING;
210
211 }
212 finally
213 {
214 Ext2ClearFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_ZONES_INITIALIZED);
215 }
216
217 return;
218 }
219
220
221 /*************************************************************************
222 *
223 * Function: Ext2IsIrpTopLevel()
224 *
225 * Description:
226 * Helps the FSD determine who the "top level" caller is for this
227 * request. A request can originate directly from a user process
228 * (in which case, the "top level" will be NULL when this routine
229 * is invoked), OR the user may have originated either from the NT
230 * Cache Manager/VMM ("top level" may be set), or this could be a
231 * recursion into our code in which we would have set the "top level"
232 * field the last time around.
233 *
234 * Expected Interrupt Level (for execution) :
235 *
236 * whatever level a particular dispatch routine is invoked at.
237 *
238 * Return Value: TRUE/FALSE (TRUE if top level was NULL when routine invoked)
239 *
240 *************************************************************************/
241 BOOLEAN Ext2IsIrpTopLevel(
242 PIRP Irp) // the IRP sent to our dispatch routine
243 {
244 BOOLEAN ReturnCode = FALSE;
245
246 if (IoGetTopLevelIrp() == NULL)
247 {
248 // OK, so we can set ourselves to become the "top level" component
249 IoSetTopLevelIrp( Irp );
250 ReturnCode = TRUE;
251 }
252
253 return(ReturnCode);
254 }
255
256
257 /*************************************************************************
258 *
259 * Function: Ext2ExceptionFilter()
260 *
261 * Description:
262 * This routines allows the driver to determine whether the exception
263 * is an "allowed" exception i.e. one we should not-so-quietly consume
264 * ourselves, or one which should be propagated onwards in which case
265 * we will most likely bring down the machine.
266 *
267 * This routine employs the services of FsRtlIsNtstatusExpected(). This
268 * routine returns a BOOLEAN result. A RC of FALSE will cause us to return
269 * EXCEPTION_CONTINUE_SEARCH which will probably cause a panic.
270 * The FsRtl.. routine returns FALSE iff exception values are (currently) :
271 * STATUS_DATATYPE_MISALIGNMENT || STATUS_ACCESS_VIOLATION ||
272 * STATUS_ILLEGAL_INSTRUCTION || STATUS_INSTRUCTION_MISALIGNMENT
273 *
274 * Expected Interrupt Level (for execution) :
275 *
276 * ?
277 *
278 * Return Value: EXCEPTION_EXECUTE_HANDLER/EXECEPTION_CONTINUE_SEARCH
279 *
280 *************************************************************************/
281 long Ext2ExceptionFilter(
282 PtrExt2IrpContext PtrIrpContext,
283 PEXCEPTION_POINTERS PtrExceptionPointers )
284 {
285 long ReturnCode = EXCEPTION_EXECUTE_HANDLER;
286 NTSTATUS ExceptionCode = STATUS_SUCCESS;
287
288 // figure out the exception code
289 ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionCode;
290
291 if ((ExceptionCode == STATUS_IN_PAGE_ERROR) && (PtrExceptionPointers->ExceptionRecord->NumberParameters >= 3))
292 {
293 ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionInformation[2];
294 }
295
296 if (PtrIrpContext)
297 {
298 PtrIrpContext->SavedExceptionCode = ExceptionCode;
299 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_EXCEPTION);
300 }
301
302 // check if we should propagate this exception or not
303 if (!(FsRtlIsNtstatusExpected(ExceptionCode)))
304 {
305 // we are not ok, propagate this exception.
306 // NOTE: we will bring down the machine ...
307 ReturnCode = EXCEPTION_CONTINUE_SEARCH;
308
309 // better free up the IrpContext now ...
310 if (PtrIrpContext)
311 {
312 Ext2ReleaseIrpContext(PtrIrpContext);
313 }
314 }
315
316 // if you wish to perform some special processing when
317 // not propagating the exception, set up the state for
318 // special processing now ...
319
320 // return the appropriate code
321 return(ReturnCode);
322 }
323
324 /*************************************************************************
325 *
326 * Function: Ext2ExceptionHandler()
327 *
328 * Description:
329 * One of the routines in the FSD or in the modules we invoked encountered
330 * an exception. We have decided that we will "handle" the exception.
331 * Therefore we will prevent the machine from a panic ...
332 * You can do pretty much anything you choose to in your commercial
333 * driver at this point to ensure a graceful exit. In the sample
334 * driver, I will simply free up the IrpContext (if any), set the
335 * error code in the IRP and complete the IRP at this time ...
336 *
337 * Expected Interrupt Level (for execution) :
338 *
339 * ?
340 *
341 * Return Value: Error code
342 *
343 *************************************************************************/
344 NTSTATUS Ext2ExceptionHandler(
345 PtrExt2IrpContext PtrIrpContext,
346 PIRP Irp)
347 {
348 NTSTATUS RC;
349
350 ASSERT(Irp);
351
352 if (PtrIrpContext)
353 {
354 RC = PtrIrpContext->SavedExceptionCode;
355 // Free irp context here
356 Ext2ReleaseIrpContext(PtrIrpContext);
357 }
358 else
359 {
360 // must be insufficient resources ...?
361 RC = STATUS_INSUFFICIENT_RESOURCES;
362 }
363
364 // set the error code in the IRP
365 Irp->IoStatus.Status = RC;
366 Irp->IoStatus.Information = 0;
367
368 // complete the IRP
369 IoCompleteRequest(Irp, IO_NO_INCREMENT);
370
371 return(RC);
372 }
373
374 /*************************************************************************
375 *
376 * Function: Ext2LogEvent()
377 *
378 * Description:
379 * Log a message in the NT Event Log. This is a rather simplistic log
380 * methodology since you can potentially utilize the event log to
381 * provide a lot of information to the user (and you should too!)
382 *
383 * Expected Interrupt Level (for execution) :
384 *
385 * IRQL_PASSIVE_LEVEL
386 *
387 * Return Value: None
388 *
389 *************************************************************************/
390 void Ext2LogEvent(
391 NTSTATUS Ext2EventLogId, // the Ext2 private message id
392 NTSTATUS RC) // any NT error code we wish to log ...
393 {
394 try
395 {
396
397 // Implement a call to IoAllocateErrorLogEntry() followed by a call
398 // to IoWriteErrorLogEntry(). You should note that the call to IoWriteErrorLogEntry()
399 // will free memory for the entry once the write completes (which in actuality
400 // is an asynchronous operation).
401
402 }
403 except (EXCEPTION_EXECUTE_HANDLER)
404 {
405 // nothing really we can do here, just do not wish to crash ...
406 NOTHING;
407 }
408
409 return;
410 }
411
412 /*************************************************************************
413 *
414 * Function: Ext2AllocateObjectName()
415 *
416 * Description:
417 * Allocate a new ObjectName structure to represent an open on-disk object.
418 * Also initialize the ObjectName structure to NULL.
419 *
420 * Expected Interrupt Level (for execution) :
421 *
422 * IRQL_PASSIVE_LEVEL
423 *
424 * Return Value: A pointer to the ObjectName structure OR NULL.
425 *
426 *************************************************************************/
427 PtrExt2ObjectName Ext2AllocateObjectName(
428 void)
429 {
430 PtrExt2ObjectName PtrObjectName = NULL;
431 BOOLEAN AllocatedFromZone = TRUE;
432 KIRQL CurrentIrql;
433 /*
434 // first, try to allocate out of the zone
435 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
436 if (!ExIsFullZone(&(Ext2GlobalData.ObjectNameZoneHeader))) {
437 // we have enough memory
438 PtrObjectName = (PtrExt2ObjectName)ExAllocateFromZone(&(Ext2GlobalData.ObjectNameZoneHeader));
439
440 // release the spinlock
441 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
442 } else {
443 // release the spinlock
444 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
445
446 // if we failed to obtain from the zone, get it directly from the VMM
447 */
448 PtrObjectName = (PtrExt2ObjectName)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2ObjectName)) );
449 AllocatedFromZone = FALSE;
450 /*
451 }
452 */
453 // if we could not obtain the required memory, bug-check.
454 // Do NOT do this in your commercial driver, instead handle the error gracefully ...
455 if (!PtrObjectName)
456 {
457 Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2ObjectName)), 0);
458 }
459
460 // zero out the allocated memory block
461 RtlZeroMemory( PtrObjectName, Ext2QuadAlign(sizeof(Ext2ObjectName)) );
462
463 // set up some fields ...
464 PtrObjectName->NodeIdentifier.NodeType = EXT2_NODE_TYPE_OBJECT_NAME;
465 PtrObjectName->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2ObjectName));
466
467
468 if (!AllocatedFromZone)
469 {
470 Ext2SetFlag(PtrObjectName->ObjectNameFlags, EXT2_OB_NAME_NOT_FROM_ZONE);
471 }
472
473 return(PtrObjectName);
474 }
475
476
477 /*************************************************************************
478 *
479 * Function: Ext2ReleaseObjectName()
480 *
481 * Description:
482 * Deallocate a previously allocated structure.
483 *
484 * Expected Interrupt Level (for execution) :
485 *
486 * IRQL_PASSIVE_LEVEL
487 *
488 * Return Value: None
489 *
490 *************************************************************************/
491 void Ext2ReleaseObjectName(
492 PtrExt2ObjectName PtrObjectName)
493 {
494 KIRQL CurrentIrql;
495
496 ASSERT(PtrObjectName);
497 PtrObjectName->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED;
498 #ifdef USE_ZONES
499
500 // give back memory either to the zone or to the VMM
501 if (!(PtrObjectName->ObjectNameFlags & EXT2_OB_NAME_NOT_FROM_ZONE))
502 {
503 // back to the zone
504 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
505 ExFreeToZone(&(Ext2GlobalData.ObjectNameZoneHeader), PtrObjectName);
506 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
507 }
508 else
509 {
510 #endif
511
512 Ext2DeallocateUnicodeString( & PtrObjectName->ObjectName );
513
514 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrObjectName);
515 ExFreePool(PtrObjectName);
516
517 #ifdef USE_ZONES
518 }
519 #endif
520 return;
521 }
522
523 /*************************************************************************
524 *
525 * Function: Ext2AllocateCCB()
526 *
527 * Description:
528 * Allocate a new CCB structure to represent an open on-disk object.
529 * Also initialize the CCB structure to NULL.
530 *
531 * Expected Interrupt Level (for execution) :
532 *
533 * IRQL_PASSIVE_LEVEL
534 *
535 * Return Value: A pointer to the CCB structure OR NULL.
536 *
537 *************************************************************************/
538 PtrExt2CCB Ext2AllocateCCB(
539 void)
540 {
541 PtrExt2CCB PtrCCB = NULL;
542 BOOLEAN AllocatedFromZone = TRUE;
543 KIRQL CurrentIrql;
544
545
546 #ifdef USE_ZONES
547 // first, try to allocate out of the zone
548 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
549 if (!ExIsFullZone(&(Ext2GlobalData.CCBZoneHeader)))
550 {
551 // we have enough memory
552 PtrCCB = (PtrExt2CCB)ExAllocateFromZone(&(Ext2GlobalData.CCBZoneHeader));
553
554 // release the spinlock
555 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
556 }
557 else
558 {
559 // release the spinlock
560 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
561 // if we failed to obtain from the zone, get it directly from the VMM
562 #endif
563
564 PtrCCB = (PtrExt2CCB)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2CCB)) );
565 AllocatedFromZone = FALSE;
566
567 #ifdef USE_ZONES
568 }
569 #endif
570
571 // if we could not obtain the required memory, bug-check.
572 // Do NOT do this in your commercial driver, instead handle the error gracefully ...
573 if (!PtrCCB)
574 {
575 Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2CCB)), 0);
576 }
577
578 // zero out the allocated memory block
579 RtlZeroMemory(PtrCCB, Ext2QuadAlign(sizeof(Ext2CCB)));
580
581 // set up some fields ...
582 PtrCCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_CCB;
583 PtrCCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2CCB));
584
585
586 if (!AllocatedFromZone)
587 {
588 Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_NOT_FROM_ZONE);
589 }
590
591 return(PtrCCB);
592 }
593
594 /*************************************************************************
595 *
596 * Function: Ext2ReleaseCCB()
597 *
598 * Description:
599 * Deallocate a previously allocated structure.
600 *
601 * Expected Interrupt Level (for execution) :
602 *
603 * IRQL_PASSIVE_LEVEL
604 *
605 * Return Value: None
606 *
607 *************************************************************************/
608 void Ext2ReleaseCCB(
609 PtrExt2CCB PtrCCB)
610 {
611 KIRQL CurrentIrql;
612
613 ASSERT( PtrCCB );
614 if(PtrCCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_CCB)
615 {
616 Ext2Panic( PtrCCB, PtrCCB->NodeIdentifier.NodeType, EXT2_NODE_TYPE_CCB ) ;
617 }
618
619 Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern );
620 Ext2DeallocateUnicodeString( &PtrCCB->AbsolutePathName );
621 Ext2DeallocateUnicodeString( &PtrCCB->RenameLinkTargetFileName );
622
623
624 #ifdef USE_ZONES
625
626 // give back memory either to the zone or to the VMM
627 if (!(PtrCCB->CCBFlags & EXT2_CCB_NOT_FROM_ZONE))
628 {
629 // back to the zone
630 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
631 ExFreeToZone(&(Ext2GlobalData.CCBZoneHeader), PtrCCB);
632 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
633 }
634 else
635 {
636 #endif
637 PtrCCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED;
638 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrCCB);
639 ExFreePool(PtrCCB);
640
641 #ifdef USE_ZONES
642 }
643 #endif
644
645 return;
646 }
647
648 /*************************************************************************
649 *
650 * Function: Ext2AllocateFCB()
651 *
652 * Description:
653 * Allocate a new FCB structure to represent an open on-disk object.
654 * Also initialize the FCB structure to NULL.
655 *
656 * Expected Interrupt Level (for execution) :
657 *
658 * IRQL_PASSIVE_LEVEL
659 *
660 * Return Value: A pointer to the FCB structure OR NULL.
661 *
662 *************************************************************************/
663 PtrExt2FCB Ext2AllocateFCB(
664 void)
665 {
666 PtrExt2FCB PtrFCB = NULL;
667 BOOLEAN AllocatedFromZone = TRUE;
668 KIRQL CurrentIrql;
669
670 // first, try to allocate out of the zone
671 #ifdef USE_ZONES
672
673 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
674 if (!ExIsFullZone(&(Ext2GlobalData.FCBZoneHeader))) {
675 // we have enough memory
676 PtrFCB = (PtrExt2FCB)ExAllocateFromZone(&(Ext2GlobalData.FCBZoneHeader));
677
678 // release the spinlock
679 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
680 } else {
681 // release the spinlock
682 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
683 #endif
684 // if we failed to obtain from the zone, get it directly from the VMM
685 PtrFCB = (PtrExt2FCB)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2FCB)) );
686 AllocatedFromZone = FALSE;
687
688 #ifdef USE_ZONES
689 }
690 #endif
691
692 // if we could not obtain the required memory, bug-check.
693 // Do NOT do this in your commercial driver, instead handle the error gracefully ...
694 if (!PtrFCB)
695 {
696 Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2FCB)), 0);
697 }
698
699 // zero out the allocated memory block
700 RtlZeroMemory(PtrFCB, Ext2QuadAlign(sizeof(Ext2FCB)));
701
702 // set up some fields ...
703 PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FCB;
704 PtrFCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2FCB));
705
706
707 if (!AllocatedFromZone)
708 {
709 Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE);
710 }
711
712 return(PtrFCB);
713 }
714
715
716 /*************************************************************************
717 *
718 * Function: Ext2CreateNewFCB()
719 *
720 * Description:
721 * We want to create a new FCB. We will also create a new CCB (presumably)
722 * later. Simply allocate a new FCB structure and initialize fields
723 * appropriately.
724 * This function also takes the file size values that the caller must
725 * have obtained and will set the file size fields appropriately in the
726 * CommonFCBHeader.
727 * Finally, this routine will initialize the FileObject structure passed
728 * in to this function. If you decide to fail the call later, remember
729 * to uninitialize the fields.
730 *
731 * Expected Interrupt Level (for execution) :
732 *
733 * IRQL_PASSIVE_LEVEL
734 *
735 * Return Value: A pointer to the FCB structure OR NULL.
736 *
737 *************************************************************************/
738 NTSTATUS Ext2CreateNewFCB(
739 PtrExt2FCB *ReturnedFCB,
740 LARGE_INTEGER AllocationSize,
741 LARGE_INTEGER EndOfFile,
742 PFILE_OBJECT PtrFileObject,
743 PtrExt2VCB PtrVCB,
744 PtrExt2ObjectName PtrObjectName)
745 {
746 NTSTATUS RC = STATUS_SUCCESS;
747
748 PtrExt2FCB PtrFCB = NULL;
749 PtrExt2NTRequiredFCB PtrReqdFCB = NULL;
750 PFSRTL_COMMON_FCB_HEADER PtrCommonFCBHeader = NULL;
751
752 ASSERT( PtrVCB );
753
754 try
755 {
756 if( !PtrFileObject )
757 {
758 PtrFCB = Ext2GetUsedFCB( PtrVCB );
759
760 }
761 else
762 {
763 // Obtain a new FCB structure.
764 // The function Ext2AllocateFCB() will obtain a new structure either
765 // from a zone or from memory requested directly from the VMM.
766 PtrFCB = Ext2AllocateFCB();
767 }
768 if (!PtrFCB)
769 {
770 // Assume lack of memory.
771 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
772 }
773
774 // Initialize fields required to interface with the NT Cache Manager.
775 // Note that the returned structure has already been zeroed. This means
776 // that the SectionObject structure has been zeroed which is a
777 // requirement for newly created FCB structures.
778 PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
779
780 // Initialize the MainResource and PagingIoResource structures now.
781 ExInitializeResourceLite(&(PtrReqdFCB->MainResource));
782 Ext2SetFlag(PtrFCB->FCBFlags, EXT2_INITIALIZED_MAIN_RESOURCE);
783
784 ExInitializeResourceLite(&(PtrReqdFCB->PagingIoResource));
785 Ext2SetFlag(PtrFCB->FCBFlags, EXT2_INITIALIZED_PAGING_IO_RESOURCE);
786
787 // Start initializing the fields contained in the CommonFCBHeader.
788 PtrCommonFCBHeader = &(PtrReqdFCB->CommonFCBHeader);
789
790 // Disallow fast-IO for now.
791 PtrCommonFCBHeader->IsFastIoPossible = FastIoIsNotPossible;
792
793 // Initialize the MainResource and PagingIoResource pointers in
794 // the CommonFCBHeader structure to point to the ERESOURCE structures we
795 // have allocated and already initialized above.
796 PtrCommonFCBHeader->Resource = &(PtrReqdFCB->MainResource);
797 PtrCommonFCBHeader->PagingIoResource = &(PtrReqdFCB->PagingIoResource);
798
799 // Ignore the Flags field in the CommonFCBHeader for now. Part 3
800 // of the book describes it in greater detail.
801
802 // Initialize the file size values here.
803 PtrCommonFCBHeader->AllocationSize = AllocationSize;
804 PtrCommonFCBHeader->FileSize = EndOfFile;
805
806 // The following will disable ValidDataLength support. However, your
807 // FSD may choose to support this concept.
808 PtrCommonFCBHeader->ValidDataLength.LowPart = 0xFFFFFFFF;
809 PtrCommonFCBHeader->ValidDataLength.HighPart = 0x7FFFFFFF;
810
811 // Initialize other fields for the FCB here ...
812 PtrFCB->PtrVCB = PtrVCB;
813
814 // caller MUST ensure that VCB has been acquired exclusively
815 InsertTailList(&(PtrVCB->FCBListHead), &(PtrFCB->NextFCB));
816
817
818 InitializeListHead(&(PtrFCB->CCBListHead));
819
820 // Initialize fields contained in the file object now.
821 if( PtrFileObject )
822 {
823 PtrFileObject->PrivateCacheMap = NULL;
824 // Note that we could have just as well taken the value of PtrReqdFCB
825 // directly below. The bottom line however is that the FsContext
826 // field must point to a FSRTL_COMMON_FCB_HEADER structure.
827 PtrFileObject->FsContext = (void *)(PtrCommonFCBHeader);
828 PtrFileObject->SectionObjectPointer = &(PtrFCB->NTRequiredFCB.SectionObject) ;
829 }
830
831 // Initialising the object name...
832 PtrFCB->FCBName = PtrObjectName;
833
834 // Returning the FCB...
835 *ReturnedFCB = PtrFCB;
836 try_exit: NOTHING;
837 }
838
839 finally
840 {
841
842 }
843
844 return(RC);
845 }
846
847
848 /*************************************************************************
849 *
850 * Function: Ext2ReleaseFCB()
851 *
852 * Description:
853 * Deallocate a previously allocated structure.
854 *
855 * Expected Interrupt Level (for execution) :
856 *
857 * IRQL_PASSIVE_LEVEL
858 *
859 * Return Value: None
860 *
861 *************************************************************************/
862 void Ext2ReleaseFCB(
863 PtrExt2FCB PtrFCB)
864 {
865 KIRQL CurrentIrql;
866
867 AssertFCB( PtrFCB );
868
869 if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB )
870 {
871 Ext2Panic( PtrFCB, PtrFCB->NodeIdentifier.NodeType, EXT2_NODE_TYPE_FCB ) ;
872 }
873
874
875 PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED;
876
877 /*
878 // give back memory either to the zone or to the VMM
879 if (!(PtrFCB->FCBFlags & EXT2_FCB_NOT_FROM_ZONE))
880 {
881 // back to the zone
882 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
883 ExFreeToZone(&(Ext2GlobalData.FCBZoneHeader), PtrFCB);
884 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
885 }
886 else
887 {
888 */
889
890 ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.MainResource );
891 ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.PagingIoResource );
892
893 if( PtrFCB->FCBName )
894 {
895 Ext2ReleaseObjectName( PtrFCB->FCBName );
896 }
897
898 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrFCB);
899 ExFreePool(PtrFCB);
900
901 /*
902 }
903 */
904
905 return;
906 }
907
908 /*************************************************************************
909 *
910 * Function: Ext2AllocateByteLocks()
911 *
912 * Description:
913 * Allocate a new byte range lock structure and initialize it to NULL.
914 *
915 * Expected Interrupt Level (for execution) :
916 *
917 * IRQL_PASSIVE_LEVEL
918 *
919 * Return Value: A pointer to the Ext2ByteLocks structure OR NULL.
920 *
921 *************************************************************************/
922 PtrExt2FileLockInfo Ext2AllocateByteLocks(
923 void)
924 {
925 PtrExt2FileLockInfo PtrByteLocks = NULL;
926 BOOLEAN AllocatedFromZone = TRUE;
927 KIRQL CurrentIrql;
928
929 // first, try to allocate out of the zone
930 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
931 if (!ExIsFullZone(&(Ext2GlobalData.ByteLockZoneHeader)))
932 {
933 // we have enough memory
934 PtrByteLocks = (PtrExt2FileLockInfo)ExAllocateFromZone(&(Ext2GlobalData.ByteLockZoneHeader));
935
936 // release the spinlock
937 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
938 }
939 else
940 {
941 // release the spinlock
942 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
943
944 // if we failed to obtain from the zone, get it directly from the VMM
945 PtrByteLocks = (PtrExt2FileLockInfo)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2FileLockInfo)) );
946 AllocatedFromZone = FALSE;
947 }
948
949 // if we could not obtain the required memory, bug-check.
950 // Do NOT do this in your commercial driver, instead handle the error gracefully ...
951 if (!PtrByteLocks)
952 {
953 Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2FileLockInfo)), 0);
954 }
955
956 // zero out the allocated memory block
957 RtlZeroMemory(PtrByteLocks, Ext2QuadAlign(sizeof(PtrExt2FileLockInfo)));
958
959 if (!AllocatedFromZone)
960 {
961 Ext2SetFlag(PtrByteLocks->FileLockFlags, EXT2_BYTE_LOCK_NOT_FROM_ZONE);
962 }
963
964 return(PtrByteLocks);
965 }
966
967 /*************************************************************************
968 *
969 * Function: Ext2ReleaseByteLocks()
970 *
971 * Description:
972 * Deallocate a previously allocated structure.
973 *
974 * Expected Interrupt Level (for execution) :
975 *
976 * IRQL_PASSIVE_LEVEL
977 *
978 * Return Value: None
979 *
980 *************************************************************************/
981 void Ext2ReleaseByteLocks(
982 PtrExt2FileLockInfo PtrByteLocks)
983 {
984 KIRQL CurrentIrql;
985
986 ASSERT(PtrByteLocks);
987
988 // give back memory either to the zone or to the VMM
989 if (!(PtrByteLocks->FileLockFlags & EXT2_BYTE_LOCK_NOT_FROM_ZONE)) {
990 // back to the zone
991 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
992 ExFreeToZone(&(Ext2GlobalData.ByteLockZoneHeader), PtrByteLocks);
993 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
994 }
995 else
996 {
997 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrByteLocks);
998 ExFreePool(PtrByteLocks);
999 }
1000
1001 return;
1002 }
1003
1004
1005 /*************************************************************************
1006 *
1007 * Function: Ext2AllocateIrpContext()
1008 *
1009 * Description:
1010 * The sample FSD creates an IRP context for each request received. This
1011 * routine simply allocates (and initializes to NULL) a Ext2IrpContext
1012 * structure.
1013 * Most of the fields in the context structure are then initialized here.
1014 *
1015 * Expected Interrupt Level (for execution) :
1016 *
1017 * IRQL_PASSIVE_LEVEL
1018 *
1019 * Return Value: A pointer to the IrpContext structure OR NULL.
1020 *
1021 *************************************************************************/
1022 PtrExt2IrpContext Ext2AllocateIrpContext(
1023 PIRP Irp,
1024 PDEVICE_OBJECT PtrTargetDeviceObject)
1025 {
1026 PtrExt2IrpContext PtrIrpContext = NULL;
1027 BOOLEAN AllocatedFromZone = TRUE;
1028 KIRQL CurrentIrql;
1029 PIO_STACK_LOCATION PtrIoStackLocation = NULL;
1030
1031 /*
1032 // Allocation from zone not done at present...
1033
1034 // first, try to allocate out of the zone
1035 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
1036 if (!ExIsFullZone(&(Ext2GlobalData.IrpContextZoneHeader))) {
1037 // we have enough memory
1038 PtrIrpContext = (PtrExt2IrpContext)ExAllocateFromZone(&(Ext2GlobalData.IrpContextZoneHeader));
1039
1040 // release the spinlock
1041 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
1042 } else {
1043 // release the spinlock
1044 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
1045
1046
1047
1048
1049 // if we failed to obtain from the zone, get it directly from the VMM
1050 PtrIrpContext = (PtrExt2IrpContext)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2IrpContext)) );
1051 AllocatedFromZone = FALSE;
1052 }
1053
1054 //No Zone handling for now
1055 */
1056
1057 PtrIrpContext = (PtrExt2IrpContext)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2IrpContext)) );
1058 AllocatedFromZone = FALSE;
1059
1060 // if we could not obtain the required memory, bug-check.
1061 // Do NOT do this in your commercial driver, instead handle the error gracefully ...
1062 if (!PtrIrpContext)
1063 {
1064 Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2IrpContext)), 0);
1065 }
1066
1067 // zero out the allocated memory block
1068 RtlZeroMemory(PtrIrpContext, Ext2QuadAlign(sizeof(Ext2IrpContext)));
1069
1070 // set up some fields ...
1071 PtrIrpContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IRP_CONTEXT;
1072 PtrIrpContext->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2IrpContext));
1073
1074
1075 PtrIrpContext->Irp = Irp;
1076 PtrIrpContext->TargetDeviceObject = PtrTargetDeviceObject;
1077
1078 // copy over some fields from the IRP and set appropriate flag values
1079 if (Irp)
1080 {
1081 PtrIoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1082 ASSERT(PtrIoStackLocation);
1083
1084 PtrIrpContext->MajorFunction = PtrIoStackLocation->MajorFunction;
1085 PtrIrpContext->MinorFunction = PtrIoStackLocation->MinorFunction;
1086
1087 // Often, a FSD cannot honor a request for asynchronous processing
1088 // of certain critical requests. For example, a "close" request on
1089 // a file object can typically never be deferred. Therefore, do not
1090 // be surprised if sometimes your FSD (just like all other FSD
1091 // implementations on the Windows NT system) has to override the flag
1092 // below.
1093 if( PtrIoStackLocation->FileObject )
1094 {
1095 if (IoIsOperationSynchronous(Irp) )
1096 {
1097 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK);
1098 }
1099 }
1100 else
1101 {
1102 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK);
1103 }
1104 }
1105
1106 if (!AllocatedFromZone)
1107 {
1108 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_NOT_FROM_ZONE);
1109 }
1110
1111 // Are we top-level ? This information is used by the dispatching code
1112 // later (and also by the FSD dispatch routine)
1113 if (IoGetTopLevelIrp() != Irp)
1114 {
1115 // We are not top-level. Note this fact in the context structure
1116 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_NOT_TOP_LEVEL);
1117 }
1118
1119 InitializeListHead( &PtrIrpContext->SavedBCBsListHead );
1120
1121 return(PtrIrpContext);
1122 }
1123
1124
1125 /*************************************************************************
1126 *
1127 * Function: Ext2ReleaseIrpContext()
1128 *
1129 * Description:
1130 * Deallocate a previously allocated structure.
1131 *
1132 * Expected Interrupt Level (for execution) :
1133 *
1134 * IRQL_PASSIVE_LEVEL
1135 *
1136 * Return Value: None
1137 *
1138 *************************************************************************/
1139 void Ext2ReleaseIrpContext(
1140 PtrExt2IrpContext PtrIrpContext)
1141 {
1142 KIRQL CurrentIrql;
1143
1144 ASSERT(PtrIrpContext);
1145
1146 // Flush the saved BCBs...
1147 Ext2FlushSavedBCBs( PtrIrpContext );
1148
1149 // give back memory either to the zone or to the VMM
1150 if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_NOT_FROM_ZONE))
1151 {
1152 // back to the zone
1153 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
1154 ExFreeToZone(&(Ext2GlobalData.IrpContextZoneHeader), PtrIrpContext);
1155 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
1156 }
1157 else
1158 {
1159 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrIrpContext);
1160 ExFreePool(PtrIrpContext);
1161 }
1162
1163 return;
1164 }
1165
1166 /*************************************************************************
1167 *
1168 * Function: Ext2PostRequest()
1169 *
1170 * Description:
1171 * Queue up a request for deferred processing (in the context of a system
1172 * worker thread). The caller must have locked the user buffer (if required)
1173 *
1174 * Expected Interrupt Level (for execution) :
1175 *
1176 * IRQL_PASSIVE_LEVEL
1177 *
1178 * Return Value: STATUS_PENDING
1179 *
1180 *************************************************************************/
1181 NTSTATUS Ext2PostRequest(
1182 PtrExt2IrpContext PtrIrpContext,
1183 PIRP PtrIrp)
1184 {
1185 NTSTATUS RC = STATUS_PENDING;
1186
1187 DebugTrace(DEBUG_TRACE_ASYNC, " === Asynchronous request. Deferring processing", 0);
1188
1189 // mark the IRP pending
1190 IoMarkIrpPending(PtrIrp);
1191
1192 // queue up the request
1193 ExInterlockedInsertTailList(
1194 &Ext2GlobalData.ThreadQueue.ThreadQueueListHead,
1195 &PtrIrpContext->ThreadQueueListEntry,
1196 &Ext2GlobalData.ThreadQueue.SpinLock );
1197
1198 KeSetEvent( &Ext2GlobalData.ThreadQueue.QueueEvent, 0, FALSE );
1199
1200
1201 /***************** not using system worker threads *****************
1202 ExInitializeWorkItem(&(PtrIrpContext->WorkQueueItem), Ext2CommonDispatch, PtrIrpContext);
1203 ExQueueWorkItem( &( PtrIrpContext->WorkQueueItem ), DelayedWorkQueue );
1204 // CriticalWorkQueue
1205 *****************************************************************************/
1206
1207 // return status pending
1208 return(RC);
1209 }
1210
1211
1212 /*************************************************************************
1213 *
1214 * Function: Ext2CommonDispatch()
1215 *
1216 * Description:
1217 * The common dispatch routine invoked in the context of a system worker
1218 * thread. All we do here is pretty much case off the major function
1219 * code and invoke the appropriate FSD dispatch routine for further
1220 * processing.
1221 *
1222 * Expected Interrupt Level (for execution) :
1223 *
1224 * IRQL PASSIVE_LEVEL
1225 *
1226 * Return Value: None
1227 *
1228 *************************************************************************/
1229 void Ext2CommonDispatch(
1230 void *Context ) // actually an IRPContext structure
1231 {
1232 NTSTATUS RC = STATUS_SUCCESS;
1233 PtrExt2IrpContext PtrIrpContext = NULL;
1234 PIRP PtrIrp = NULL;
1235
1236 // The context must be a pointer to an IrpContext structure
1237 PtrIrpContext = (PtrExt2IrpContext)Context;
1238 ASSERT(PtrIrpContext);
1239
1240 // Assert that the Context is legitimate
1241 if ((PtrIrpContext->NodeIdentifier.NodeType != EXT2_NODE_TYPE_IRP_CONTEXT) || (PtrIrpContext->NodeIdentifier.NodeSize != Ext2QuadAlign(sizeof(Ext2IrpContext))))
1242 {
1243 // This does not look good
1244 Ext2Panic(EXT2_ERROR_INTERNAL_ERROR, PtrIrpContext->NodeIdentifier.NodeType, PtrIrpContext->NodeIdentifier.NodeSize);
1245 }
1246
1247 // Get a pointer to the IRP structure
1248 PtrIrp = PtrIrpContext->Irp;
1249 ASSERT(PtrIrp);
1250
1251 // Now, check if the FSD was top level when the IRP was originally invoked
1252 // and set the thread context (for the worker thread) appropriately
1253 if (PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_NOT_TOP_LEVEL)
1254 {
1255 // The FSD is not top level for the original request
1256 // Set a constant value in TLS to reflect this fact
1257 IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP);
1258 }
1259
1260 // Since the FSD routine will now be invoked in the context of this worker
1261 // thread, we should inform the FSD that it is perfectly OK to block in
1262 // the context of this thread
1263 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK);
1264
1265 FsRtlEnterFileSystem();
1266
1267 try
1268 {
1269
1270 // Pre-processing has been completed; check the Major Function code value
1271 // either in the IrpContext (copied from the IRP), or directly from the
1272 // IRP itself (we will need a pointer to the stack location to do that),
1273 // Then, switch based on the value on the Major Function code
1274 switch (PtrIrpContext->MajorFunction)
1275 {
1276 case IRP_MJ_CREATE:
1277 // Invoke the common create routine
1278 DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_CREATE request asynchronously .", 0);
1279 (void)Ext2CommonCreate(PtrIrpContext, PtrIrp, FALSE);
1280 break;
1281 case IRP_MJ_READ:
1282 // Invoke the common read routine
1283 DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_READ request asynchronously .", 0);
1284 (void)Ext2CommonRead(PtrIrpContext, PtrIrp, FALSE);
1285 break;
1286 case IRP_MJ_WRITE:
1287 // Invoke the common write routine
1288 DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_WRITE request asynchronously .", 0);
1289 (void)Ext2CommonWrite(PtrIrpContext, PtrIrp );
1290 break;
1291
1292 case IRP_MJ_CLEANUP:
1293 // Invoke the common read routine
1294 DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_CLEANUP request asynchronously .", 0);
1295 (void)Ext2CommonCleanup(PtrIrpContext, PtrIrp, FALSE);
1296 break;
1297 case IRP_MJ_CLOSE:
1298 // Invoke the common read routine
1299 DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_CLOSE request asynchronously .", 0);
1300 (void)Ext2CommonClose ( PtrIrpContext, PtrIrp, FALSE );
1301 break;
1302
1303 // Continue with the remaining possible dispatch routines below ...
1304 default:
1305 // This is the case where we have an invalid major function
1306 DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing asynchronous request. \nUnable to recoganise the IRP!!! How can this be!!!", 0);
1307 PtrIrp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1308 PtrIrp->IoStatus.Information = 0;
1309
1310 Ext2BreakPoint();
1311
1312 IoCompleteRequest(PtrIrp, IO_NO_INCREMENT);
1313 break;
1314 }
1315 }
1316 except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation()))
1317 {
1318 RC = Ext2ExceptionHandler(PtrIrpContext, PtrIrp);
1319 Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
1320 }
1321
1322 // Enable preemption
1323 FsRtlExitFileSystem();
1324
1325 // Ensure that the "top-level" field is cleared
1326 IoSetTopLevelIrp(NULL);
1327
1328 PsTerminateSystemThread( RC );
1329
1330
1331 return;
1332 }
1333
1334 /*************************************************************************
1335 *
1336 * Function: Ext2InitializeVCB()
1337 *
1338 * Description:
1339 * Perform the initialization for a VCB structure.
1340 *
1341 * Expected Interrupt Level (for execution) :
1342 *
1343 * IRQL PASSIVE_LEVEL
1344 *
1345 * Return Value: None
1346 *
1347 *************************************************************************/
1348 void Ext2InitializeVCB(
1349 PDEVICE_OBJECT PtrVolumeDeviceObject,
1350 PDEVICE_OBJECT PtrTargetDeviceObject,
1351 PVPB PtrVPB,
1352 PLARGE_INTEGER AllocationSize )
1353 {
1354 NTSTATUS RC = STATUS_SUCCESS;
1355 PtrExt2VCB PtrVCB = NULL;
1356 BOOLEAN VCBResourceInitialized = FALSE;
1357
1358 PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension);
1359
1360 // Zero it out (typically this has already been done by the I/O
1361 // Manager but it does not hurt to do it again)!
1362 RtlZeroMemory(PtrVCB, sizeof(Ext2VCB));
1363
1364 // Initialize the signature fields
1365 PtrVCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_VCB;
1366 PtrVCB->NodeIdentifier.NodeSize = sizeof(Ext2VCB);
1367
1368 // Initialize the ERESOURCE objects.
1369 RC = ExInitializeResourceLite(&(PtrVCB->VCBResource));
1370 RC = ExInitializeResourceLite(&(PtrVCB->PagingIoResource));
1371
1372 ASSERT(NT_SUCCESS(RC));
1373 VCBResourceInitialized = TRUE;
1374
1375 PtrVCB->TargetDeviceObject = PtrTargetDeviceObject;
1376
1377 PtrVCB->VCBDeviceObject = PtrVolumeDeviceObject;
1378
1379 PtrVCB->PtrVPB = PtrVPB;
1380
1381 // Initialize the list anchor (head) for some lists in this VCB.
1382 InitializeListHead(&(PtrVCB->FCBListHead));
1383 InitializeListHead(&(PtrVCB->NextNotifyIRP));
1384 InitializeListHead(&(PtrVCB->VolumeOpenListHead));
1385 InitializeListHead(&(PtrVCB->ClosableFCBs.ClosableFCBListHead));
1386 PtrVCB->ClosableFCBs.Count = 0;
1387
1388 // Initialize the notify IRP list mutex
1389 KeInitializeMutex(&(PtrVCB->NotifyIRPMutex), 0);
1390
1391 // Set the initial file size values appropriately. Note that your FSD may
1392 // wish to guess at the initial amount of information you would like to
1393 // read from the disk until you have really determined that this a valid
1394 // logical volume (on disk) that you wish to mount.
1395 PtrVCB->CommonVCBHeader.AllocationSize.QuadPart = AllocationSize->QuadPart;
1396
1397 PtrVCB->CommonVCBHeader.FileSize.QuadPart = AllocationSize->QuadPart;
1398 // You typically do not want to bother with valid data length callbacks
1399 // from the Cache Manager for the file stream opened for volume metadata
1400 // information
1401 PtrVCB->CommonVCBHeader.ValidDataLength.LowPart = 0xFFFFFFFF;
1402 PtrVCB->CommonVCBHeader.ValidDataLength.HighPart = 0x7FFFFFFF;
1403
1404 PtrVCB->CommonVCBHeader.IsFastIoPossible = FastIoIsNotPossible;
1405
1406 PtrVCB->CommonVCBHeader.Resource = &(PtrVCB->VCBResource);
1407 PtrVCB->CommonVCBHeader.PagingIoResource = &(PtrVCB->PagingIoResource);;
1408
1409 // Create a stream file object for this volume.
1410 PtrVCB->PtrStreamFileObject = IoCreateStreamFileObject(NULL,
1411 PtrVCB->PtrVPB->RealDevice);
1412 ASSERT(PtrVCB->PtrStreamFileObject);
1413
1414 // Initialize some important fields in the newly created file object.
1415 PtrVCB->PtrStreamFileObject->FsContext = (void *)(&PtrVCB->CommonVCBHeader);
1416 PtrVCB->PtrStreamFileObject->FsContext2 = NULL;
1417 PtrVCB->PtrStreamFileObject->SectionObjectPointer = &(PtrVCB->SectionObject);
1418
1419 PtrVCB->PtrStreamFileObject->Vpb = PtrVPB;
1420 PtrVCB->PtrStreamFileObject->ReadAccess = TRUE;
1421 PtrVCB->PtrStreamFileObject->WriteAccess = TRUE;
1422
1423 // Link this chap onto the global linked list of all VCB structures.
1424 DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire Global Resource Exclusively [FileInfo]", 0);
1425 ExAcquireResourceExclusiveLite(&(Ext2GlobalData.GlobalDataResource), TRUE);
1426 InsertTailList(&(Ext2GlobalData.NextVCB), &(PtrVCB->NextVCB));
1427 DebugTrace(DEBUG_TRACE_MISC, "*** Global Resource Acquired [FileInfo]", 0);
1428
1429
1430
1431 // Initialize caching for the stream file object.
1432 CcInitializeCacheMap(PtrVCB->PtrStreamFileObject, (PCC_FILE_SIZES)(&(PtrVCB->CommonVCBHeader.AllocationSize)),
1433 TRUE, // We will use pinned access.
1434 &(Ext2GlobalData.CacheMgrCallBacks), PtrVCB );
1435
1436
1437 Ext2ReleaseResource(&(Ext2GlobalData.GlobalDataResource));
1438 DebugTrace(DEBUG_TRACE_MISC, "*** Global Resource Released[FileInfo]", 0);
1439
1440 // Mark the fact that this VCB structure is initialized.
1441 Ext2SetFlag(PtrVCB->VCBFlags, EXT2_VCB_FLAGS_VCB_INITIALIZED);
1442 PtrVCB->PtrGroupDescriptors = NULL;
1443 PtrVCB->NoOfGroups = 0;
1444 return;
1445 }
1446
1447
1448
1449 /*************************************************************************
1450 *
1451 * Function: Ext2CompleteRequest()
1452 *
1453 * Description:
1454 * This routine completes a Irp.
1455 *
1456 * Expected Interrupt Level (for execution) :
1457 *
1458 * ???
1459 *
1460 * Arguments:
1461 *
1462 * Irp - Supplies the Irp being processed
1463 *
1464 * Status - Supplies the status to complete the Irp with
1465 *
1466 * Return Value: none
1467 *
1468 *************************************************************************/
1469 void Ext2CompleteRequest(
1470 IN PIRP Irp OPTIONAL,
1471 IN NTSTATUS Status
1472 )
1473 {
1474 //
1475 // If we have an Irp then complete the irp.
1476 //
1477
1478 if (Irp != NULL)
1479 {
1480
1481 //
1482 // We got an error, so zero out the information field before
1483 // completing the request if this was an input operation.
1484 // Otherwise IopCompleteRequest will try to copy to the user's buffer.
1485 //
1486
1487 if ( NT_ERROR(Status) &&
1488 FlagOn(Irp->Flags, IRP_INPUT_OPERATION) ) {
1489
1490 Irp->IoStatus.Information = 0;
1491 }
1492
1493 Irp->IoStatus.Status = Status;
1494
1495 IoCompleteRequest( Irp, IO_DISK_INCREMENT );
1496 }
1497 return;
1498 }
1499
1500
1501 /*************************************************************************
1502 *
1503 * Function: Ext2CreateNewCCB()
1504 *
1505 * Description:
1506 * We want to create a new CCB.
1507 *
1508 * Expected Interrupt Level (for execution) :
1509 *
1510 * IRQL_PASSIVE_LEVEL
1511 *
1512 * Return Value: A pointer to the CCB structure OR NULL.
1513 *
1514 *************************************************************************/
1515 NTSTATUS Ext2CreateNewCCB(
1516 PtrExt2CCB *ReturnedCCB,
1517 PtrExt2FCB PtrFCB,
1518 PFILE_OBJECT PtrFileObject )
1519 {
1520 PtrExt2CCB PtrCCB;
1521 NTSTATUS RC = STATUS_SUCCESS;
1522
1523 try
1524 {
1525
1526 PtrCCB = Ext2AllocateCCB();
1527 if (!PtrFCB)
1528 {
1529 // Assume lack of memory.
1530 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
1531 }
1532 PtrCCB->PtrFCB = PtrFCB;
1533
1534 PtrCCB->PtrFileObject = PtrFileObject;
1535 PtrCCB->CurrentByteOffset.QuadPart = 0;
1536
1537 if( PtrFCB->ClosableFCBs.OnClosableFCBList )
1538 {
1539 // This FCB was on the Closable List...
1540 // Taking it off the list...
1541 //
1542 RemoveEntryList( &PtrFCB->ClosableFCBs.ClosableFCBList );
1543 PtrFCB->ClosableFCBs.OnClosableFCBList = FALSE;
1544 PtrFCB->PtrVCB->ClosableFCBs.Count --;
1545 }
1546
1547 InterlockedIncrement( &PtrFCB->ReferenceCount );
1548 InterlockedIncrement( &PtrFCB->OpenHandleCount );
1549
1550 InsertTailList( &( PtrFCB->CCBListHead ), &(PtrCCB->NextCCB));
1551
1552 *ReturnedCCB = PtrCCB;
1553 try_exit: NOTHING;
1554 }
1555 finally
1556 {
1557
1558 }
1559
1560 return(RC);
1561 }
1562
1563
1564 /*************************************************************************
1565 *
1566 * Function: Ext2DenyAccess()
1567 *
1568 * Description:
1569 * We want to deny access to an IRP
1570 *
1571 * Expected Interrupt Level (for execution) :
1572 *
1573 * IRQL_PASSIVE_LEVEL
1574 *
1575 * Return Value: NTSTATUS - STATUS_ACCESS_DENIED (always)
1576 *
1577 *************************************************************************/
1578 NTSTATUS Ext2DenyAccess( IN PIRP Irp )
1579 {
1580 ASSERT( Irp );
1581
1582 // Just return Access Denied
1583 Irp->IoStatus.Information = 0;
1584 Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
1585 IoCompleteRequest( Irp, IO_DISK_INCREMENT );
1586
1587 DebugTrace(DEBUG_TRACE_MISC, "DENYING ACCESS (this will do for now!)...", 0);
1588
1589 return STATUS_ACCESS_DENIED;
1590 }
1591
1592
1593
1594 /*************************************************************************
1595 *
1596 * Function: Ext2GetFCB_CCB_VCB_FromFileObject()
1597 *
1598 * Description:
1599 * This routine retrieves the FCB, CCB and VCB from the File Object...
1600 *
1601 * Expected Interrupt Level (for execution) :
1602 *
1603 * ?
1604 *
1605 * Return Value: NTSTATUS - STATUS_SUCCESS(always)
1606 *
1607 *************************************************************************/
1608 NTSTATUS Ext2GetFCB_CCB_VCB_FromFileObject (
1609 IN PFILE_OBJECT PtrFileObject,
1610 OUT PtrExt2FCB *PPtrFCB,
1611 OUT PtrExt2CCB *PPtrCCB,
1612 OUT PtrExt2VCB *PPtrVCB )
1613 {
1614 int Offset;
1615
1616 (*PPtrCCB) = (PtrExt2CCB)(PtrFileObject->FsContext2);
1617 if( *PPtrCCB )
1618 {
1619 ASSERT((*PPtrCCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB);
1620 (*PPtrFCB) = (*PPtrCCB)->PtrFCB;
1621
1622 ASSERT((*PPtrFCB));
1623
1624 if ((*PPtrFCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB)
1625 {
1626 (*PPtrVCB) = (PtrExt2VCB)(*PPtrFCB);
1627 AssertVCB( (*PPtrVCB) );
1628
1629 // No FCB
1630 (*PPtrFCB) = NULL;
1631 //found a VCB
1632 }
1633 else
1634 {
1635 AssertFCB( (*PPtrFCB) );
1636 (*PPtrVCB) = (*PPtrFCB)->PtrVCB;
1637 AssertVCB( (*PPtrVCB) );
1638
1639 }
1640 }
1641 else
1642 {
1643 // PtrFileObject->FsContext points to NTRequiredFCB
1644 (*PPtrFCB) = CONTAINING_RECORD( PtrFileObject->FsContext, Ext2FCB, NTRequiredFCB );
1645 ASSERT((*PPtrFCB));
1646 //(*PPtrFCB) = PtrFileObject->FsContext;
1647
1648 if ((*PPtrFCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB)
1649 {
1650 // Making sure I got it right...
1651 AssertFCB( *PPtrFCB );
1652 (*PPtrVCB) = (*PPtrFCB)->PtrVCB;
1653 AssertVCB( *PPtrVCB );
1654 }
1655 else
1656 {
1657 // This should be a VCB
1658
1659 (*PPtrVCB) = CONTAINING_RECORD( PtrFileObject->FsContext, Ext2VCB, CommonVCBHeader );
1660 AssertVCB( *PPtrVCB );
1661
1662 // No FCB
1663 (*PPtrFCB) = NULL;
1664 //found a VCB
1665 }
1666
1667 }
1668 return STATUS_SUCCESS;
1669 }
1670
1671
1672 void Ext2CopyUnicodeString( PUNICODE_STRING PtrDestinationString, PUNICODE_STRING PtrSourceString )
1673 {
1674 int Count;
1675 // Allcating space for Destination...
1676 PtrDestinationString->Length = PtrSourceString->Length;
1677 PtrDestinationString->MaximumLength = Ext2QuadAlign( PtrSourceString->Length + 2 );
1678 PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength );
1679
1680 // RtlCopyUnicodeString( PtrDestinationString, PtrSourceString );
1681
1682 for( Count = 0 ; Count < (PtrSourceString->Length/2) ; Count++ )
1683 {
1684 PtrDestinationString->Buffer[Count] = PtrSourceString->Buffer[Count];
1685 }
1686 PtrDestinationString->Buffer[Count] = 0;
1687
1688 }
1689
1690 void Ext2CopyWideCharToUnicodeString(
1691 PUNICODE_STRING PtrDestinationString,
1692 PCWSTR PtrSourceString )
1693 {
1694
1695 int Count;
1696
1697 // Determining length...
1698 for( Count = 0 ; PtrSourceString[Count] != 0 ; Count++ );
1699
1700 // Allcating space for Destination...
1701 PtrDestinationString->Length = Count * 2;
1702 PtrDestinationString->MaximumLength = Ext2QuadAlign( Count * 2 + 2 );
1703 PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength );
1704
1705 // Copying the string over...
1706 for( Count = 0 ; ; Count++ )
1707 {
1708 PtrDestinationString->Buffer[Count] = PtrSourceString[Count];
1709 if( PtrSourceString[Count] == 0 )
1710 break;
1711 }
1712 }
1713
1714
1715 void Ext2CopyCharToUnicodeString(
1716 PUNICODE_STRING PtrDestinationString,
1717 PCSTR PtrSourceString,
1718 USHORT SourceStringLength )
1719 {
1720 int Count;
1721 // Allcating space for Destination...
1722 PtrDestinationString->Length = SourceStringLength * 2;
1723 PtrDestinationString->MaximumLength = Ext2QuadAlign( SourceStringLength * 2 + 2 );
1724 PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength );
1725
1726 // Copying the string over...
1727 for( Count = 0 ; Count < SourceStringLength ; Count++ )
1728 {
1729 PtrDestinationString->Buffer[Count] = PtrSourceString[Count];
1730 }
1731 PtrDestinationString->Buffer[Count] = 0;
1732
1733 }
1734
1735 void Ext2CopyZCharToUnicodeString( PUNICODE_STRING PtrDestinationString, PCSTR PtrSourceString )
1736 {
1737
1738 int Count;
1739
1740 // Determining length...
1741 for( Count = 0 ; PtrSourceString[Count] != 0 ; Count++ );
1742
1743 // Allcating space for Destination...
1744 PtrDestinationString->Length = Count * 2;
1745 PtrDestinationString->MaximumLength = Ext2QuadAlign( Count * 2 + 2 );
1746 PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength );
1747
1748 // Copying the string over...
1749 for( Count = 0 ; ; Count++ )
1750 {
1751 PtrDestinationString->Buffer[Count] = PtrSourceString[Count];
1752 if( PtrSourceString[Count] == 0 )
1753 break;
1754 }
1755 }
1756
1757 void Ext2ZerooutUnicodeString( PUNICODE_STRING PtrUnicodeString )
1758 {
1759 PtrUnicodeString->Length = 0;
1760 PtrUnicodeString->MaximumLength =0;
1761 PtrUnicodeString->Buffer = 0;
1762 }
1763
1764 void Ext2DeallocateUnicodeString( PUNICODE_STRING PtrUnicodeString )
1765 {
1766 if( PtrUnicodeString && PtrUnicodeString->Buffer )
1767 {
1768 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrUnicodeString->Buffer );
1769 ExFreePool( PtrUnicodeString->Buffer );
1770 }
1771 PtrUnicodeString->Length = 0;
1772 PtrUnicodeString->MaximumLength =0;
1773 PtrUnicodeString->Buffer = 0;
1774 }
1775
1776 PtrExt2FCB Ext2GetUsedFCB(
1777 PtrExt2VCB PtrVCB )
1778 {
1779
1780 BOOLEAN AllocatedFromZone = FALSE;
1781 PLIST_ENTRY PtrEntry = NULL;
1782 PtrExt2FCB PtrFCB = NULL;
1783
1784 ASSERT( PtrVCB );
1785 if( PtrVCB->ClosableFCBs.Count < EXT2_MAXCLOSABLE_FCBS_LL )
1786 {
1787 //
1788 // Too few Closable FCBs
1789 // Will not reuse any FCBs
1790 // Allocating a new one
1791 //
1792 return Ext2AllocateFCB();
1793 }
1794 //
1795 // Obtaining a used FCB...
1796 //
1797
1798 // Retrieving the first entry in the closable FCB list...
1799
1800 PtrEntry = RemoveHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead );
1801
1802 PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, ClosableFCBs.ClosableFCBList );
1803
1804 // Remembering if the FCB was allocated from the Zone...
1805 AllocatedFromZone = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE );
1806
1807 //
1808 // Close this FCB
1809 //
1810 if( !Ext2CloseClosableFCB( PtrFCB ) )
1811 {
1812 // Couldn't close the FCB!!
1813 //
1814 InsertHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead,
1815 &PtrFCB->ClosableFCBs.ClosableFCBList );
1816 return Ext2AllocateFCB();
1817 }
1818
1819 PtrVCB->ClosableFCBs.Count--;
1820 DebugTrace( DEBUG_TRACE_SPECIAL, "Count = %ld [Ext2GetUsedFCB]", PtrVCB->ClosableFCBs.Count );
1821
1822 //
1823 // Getting the FCB ready for reuse by
1824 // zeroing it out...
1825 //
1826 RtlZeroMemory(PtrFCB, Ext2QuadAlign(sizeof(Ext2FCB)));
1827
1828 // set up some fields ...
1829 PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FCB;
1830 PtrFCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2FCB));
1831
1832
1833 if (!AllocatedFromZone)
1834 {
1835 Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE);
1836 }
1837
1838 return PtrFCB;
1839 }
1840
1841 BOOLEAN Ext2CloseClosableFCB(
1842 PtrExt2FCB PtrFCB)
1843 {
1844 KIRQL Irql = 0;
1845 PFILE_OBJECT PtrFileObject = NULL;
1846
1847 AssertFCB( PtrFCB );
1848
1849 // Attempting to acquire the FCB Exclusively...
1850 if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) )
1851 {
1852 Ext2BreakPoint();
1853 return FALSE;
1854 }
1855
1856 Irql = KeGetCurrentIrql( );
1857
1858 if( PtrFCB->ReferenceCount )
1859 {
1860 // How the hell can this happen!!!
1861 Ext2BreakPoint();
1862 }
1863 if( PtrFCB->OpenHandleCount )
1864 {
1865 // How the hell can this happen!!!
1866 Ext2BreakPoint();
1867 }
1868
1869 // Deleting entry from VCB's FCB list...
1870 RemoveEntryList( &PtrFCB->NextFCB );
1871
1872 PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED;
1873
1874 PtrFileObject = PtrFCB->DcbFcb.Dcb.PtrDirFileObject;
1875
1876 if ( PtrFileObject )
1877 {
1878 //
1879 // Clear the Cache Map...
1880 //
1881 if( PtrFileObject->PrivateCacheMap != NULL)
1882 {
1883 IO_STATUS_BLOCK Status;
1884 DebugTrace( DEBUG_TRACE_SPECIAL, ">>.........Flushing cache.........<<", 0 );
1885 CcFlushCache( PtrFileObject->SectionObjectPointer, NULL, 0, &Status );
1886 CcUninitializeCacheMap( PtrFileObject, NULL, NULL );
1887 }
1888 //
1889 // The File Object is no longer required...
1890 // Close it by dereferenceing it!!!
1891 //
1892 PtrFileObject->FsContext = NULL;
1893 PtrFileObject->FsContext2 = NULL;
1894 ObDereferenceObject( PtrFileObject );
1895
1896 PtrFCB->DcbFcb.Dcb.PtrDirFileObject = NULL;
1897 PtrFileObject = NULL;
1898 }
1899
1900 // Uninitialize the Resources...
1901 ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.MainResource );
1902 ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.PagingIoResource );
1903
1904 //
1905 // Releasing the FCB Name Object...
1906 //
1907 if( PtrFCB->FCBName )
1908 {
1909 DebugTrace( DEBUG_TRACE_SPECIAL, "Reusing FCB - File Name %S", PtrFCB->FCBName->ObjectName.Buffer );
1910 Ext2ReleaseObjectName( PtrFCB->FCBName );
1911 }
1912 else
1913 {
1914 DebugTrace( DEBUG_TRACE_SPECIAL, "Reusing FCB - File Name *Unknown*", 0 );
1915 }
1916 return TRUE;
1917 }
1918
1919
1920 BOOLEAN Ext2SaveBCB(
1921 PtrExt2IrpContext PtrIrpContext,
1922 PBCB PtrBCB,
1923 PFILE_OBJECT PtrFileObject)
1924 {
1925 PEXT2_SAVED_BCBS PtrSavedBCB;
1926 PLIST_ENTRY PtrEntry = NULL;
1927
1928 if( !PtrIrpContext )
1929 {
1930 //
1931 // NULL passed instead of the IRP Context
1932 // This call should be ignored...
1933 //
1934 return TRUE;
1935 }
1936
1937 if( !AssertBCB( PtrBCB ) )
1938 {
1939 DebugTrace( DEBUG_TRACE_MISC, "Not saving BCB!!! [Ext2SaveBCB]", 0 );
1940 return FALSE;
1941 }
1942
1943
1944 DebugTrace( DEBUG_TRACE_SPECIAL, "Saving BCB [Ext2SaveBCB]", 0 );
1945
1946 // Has the BCB been saved already?
1947 for( PtrEntry = PtrIrpContext->SavedBCBsListHead.Flink;
1948 PtrEntry != &PtrIrpContext->SavedBCBsListHead;
1949 PtrEntry = PtrEntry->Flink )
1950 {
1951 PtrSavedBCB = CONTAINING_RECORD( PtrEntry, EXT2_SAVED_BCBS, SavedBCBsListEntry );
1952 ASSERT( PtrSavedBCB );
1953 if( PtrSavedBCB->PtrBCB == PtrBCB )
1954 {
1955
1956 // A BCB for this file has already been saved for flushing...
1957 // Won't resave this one...
1958 return TRUE;
1959 }
1960 }
1961
1962
1963 // Reference the BCB
1964 CcRepinBcb( PtrBCB );
1965
1966 // Now allocate a EXT2_SAVED_BCBS
1967 PtrSavedBCB = Ext2AllocatePool( NonPagedPool,
1968 Ext2QuadAlign( sizeof( EXT2_SAVED_BCBS ) ) );
1969 if( !PtrSavedBCB )
1970 return FALSE;
1971 PtrSavedBCB->NodeIdentifier.NodeSize = sizeof( EXT2_SAVED_BCBS );
1972 PtrSavedBCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_SAVED_BCB;
1973
1974 PtrSavedBCB->PtrBCB = PtrBCB;
1975 // PtrSavedBCB->PtrFileObject = PtrFileObject;
1976
1977 // Now save it in the IRP Context
1978 InsertHeadList( &PtrIrpContext->SavedBCBsListHead, &PtrSavedBCB->SavedBCBsListEntry );
1979
1980 PtrIrpContext->SavedCount++;
1981 // Return success...
1982 return TRUE;
1983
1984 }
1985
1986
1987 BOOLEAN Ext2FlushSavedBCBs(
1988 PtrExt2IrpContext PtrIrpContext )
1989 {
1990
1991 PLIST_ENTRY PtrEntry = NULL;
1992 PEXT2_SAVED_BCBS PtrSavedBCB = NULL;
1993 IO_STATUS_BLOCK Status;
1994 BOOLEAN RC = TRUE;
1995
1996 if( !IsListEmpty( &PtrIrpContext->SavedBCBsListHead ) )
1997 {
1998 DebugTrace( DEBUG_TRACE_SPECIAL, "Flushing cache... - Ext2FlushSavedBCBs", 0 );
1999 }
2000 while( !IsListEmpty( &PtrIrpContext->SavedBCBsListHead ) )
2001 {
2002
2003 PtrEntry = RemoveTailList( &PtrIrpContext->SavedBCBsListHead );
2004 if( !PtrEntry )
2005 {
2006 // No more entries left...
2007 break;
2008 }
2009
2010 // Get the Saved BCB
2011 PtrSavedBCB = CONTAINING_RECORD( PtrEntry, EXT2_SAVED_BCBS, SavedBCBsListEntry );
2012 if( PtrSavedBCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_SAVED_BCB )
2013 {
2014 // Something is wrong...
2015 Ext2BreakPoint();
2016 return FALSE;
2017 }
2018
2019 if( !AssertBCB( PtrSavedBCB->PtrBCB ) )
2020 {
2021 // This BCB shouldn't have been saved in the first place...
2022 DebugTrace( DEBUG_TRACE_ERROR, "Unable to flush BCB - Skipping!!! [Ext2SaveBCB]", 0 );
2023 continue;
2024 }
2025
2026 // Unpin and Flush the cache...
2027 CcUnpinRepinnedBcb( PtrSavedBCB->PtrBCB, TRUE, &Status );
2028
2029 if( !NT_SUCCESS( Status.Status ) )
2030 {
2031 // Failure in flushing...
2032 DebugTrace( DEBUG_TRACE_SPECIAL, "Failure flushing cache - Ext2FlushSavedBCBs", 0 );
2033 RC = FALSE;
2034 }
2035
2036 // Release the Saved BCB
2037 PtrSavedBCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_INVALID;
2038
2039 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrSavedBCB );
2040 ExFreePool( PtrSavedBCB );
2041 PtrSavedBCB = NULL;
2042 PtrIrpContext->SavedCount--;
2043 }
2044
2045 return RC;
2046 }
2047
2048 BOOLEAN AssertBCB( PBCB PtrBCB )
2049 {
2050 PFILE_OBJECT PtrFileObject = NULL;
2051
2052 /*
2053 * This routine is simplified version of the original
2054 * AssertBCB and doesn't make any assumptions about
2055 * the layout of undocumented BCB structure.
2056 * -- Filip Navara, 18/08/2004
2057 */
2058
2059 PtrFileObject = CcGetFileObjectFromBcb ( PtrBCB );
2060 if( !PtrFileObject )
2061 {
2062 Ext2BreakPoint();
2063 return FALSE;
2064 }
2065 else
2066 {
2067 return TRUE;
2068 }
2069 }
2070
2071
2072 ULONG Ext2Align( ULONG NumberToBeAligned, ULONG Alignment )
2073 {
2074 if( Alignment & ( Alignment - 1 ) )
2075 {
2076 //
2077 // Alignment not a power of 2
2078 // Just returning
2079 //
2080 return NumberToBeAligned;
2081 }
2082 if( ( NumberToBeAligned & ( Alignment - 1 ) ) != 0 )
2083 {
2084 NumberToBeAligned = NumberToBeAligned + Alignment;
2085 NumberToBeAligned = NumberToBeAligned & ( ~ (Alignment-1) );
2086 }
2087 return NumberToBeAligned;
2088 }
2089
2090 LONGLONG Ext2Align64( LONGLONG NumberToBeAligned, LONGLONG Alignment )
2091 {
2092 if( Alignment & ( Alignment - 1 ) )
2093 {
2094 //
2095 // Alignment not a power of 2
2096 // Just returning
2097 //
2098 return NumberToBeAligned;
2099 }
2100 if( ( NumberToBeAligned & ( Alignment - 1 ) ) != 0 )
2101 {
2102 NumberToBeAligned = NumberToBeAligned + Alignment;
2103 NumberToBeAligned = NumberToBeAligned & ( ~ (Alignment-1) );
2104 }
2105 return NumberToBeAligned;
2106 }
2107
2108
2109 ULONG Ext2GetCurrentTime()
2110 {
2111 LARGE_INTEGER CurrentTime;
2112 ULONG Time;
2113 KeQuerySystemTime( &CurrentTime );
2114 Time = (ULONG) ( (CurrentTime.QuadPart - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
2115 return Time;
2116 }