xref: /reactos/drivers/filesystems/ext2/src/misc.c (revision 25720d75)
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 NTAPI 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 }
2122