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