Esempio n. 1
0
VOID
FFSDeferWrite(
	IN PFFS_IRP_CONTEXT IrpContext,
	PIRP Irp)
{
	ASSERT(IrpContext->Irp == Irp);

	FFSQueueRequest(IrpContext);
}
Esempio n. 2
0
NTSTATUS
FFSWriteFile(
	IN PFFS_IRP_CONTEXT IrpContext)
{
	NTSTATUS            Status = STATUS_UNSUCCESSFUL;

	PFFS_VCB            Vcb  = NULL;
	PFFS_FCB            Fcb  = NULL;
	PFFS_CCB            Ccb =  NULL;
	PFILE_OBJECT        FileObject  = NULL;
	PFILE_OBJECT        CacheObject;

	PDEVICE_OBJECT      DeviceObject  = NULL;

	PIRP                Irp  = NULL;
	PIO_STACK_LOCATION  IoStackLocation  = NULL;

	ULONG               Length;
	ULONG               ReturnedLength = 0;
	LARGE_INTEGER       ByteOffset;

	BOOLEAN             PagingIo;
	BOOLEAN             Nocache;
	BOOLEAN             SynchronousIo;
	BOOLEAN             MainResourceAcquired = FALSE;
	BOOLEAN             PagingIoResourceAcquired = FALSE;

	BOOLEAN             bNeedExtending = FALSE;
	BOOLEAN             bAppendFile = FALSE;

	BOOLEAN             bDeferred = FALSE;

	PUCHAR              Buffer = NULL;

	__try
	{
		ASSERT(IrpContext);

		ASSERT((IrpContext->Identifier.Type == FFSICX) &&
				(IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));

		DeviceObject = IrpContext->DeviceObject;

		Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;

		ASSERT(Vcb != NULL);

		ASSERT((Vcb->Identifier.Type == FFSVCB) &&
				(Vcb->Identifier.Size == sizeof(FFS_VCB)));

		FileObject = IrpContext->FileObject;

		Fcb = (PFFS_FCB)FileObject->FsContext;

		ASSERT(Fcb);

		ASSERT((Fcb->Identifier.Type == FFSFCB) &&
				(Fcb->Identifier.Size == sizeof(FFS_FCB)));

		Ccb = (PFFS_CCB)FileObject->FsContext2;

		Irp = IrpContext->Irp;

		IoStackLocation = IoGetCurrentIrpStackLocation(Irp);

		Length = IoStackLocation->Parameters.Write.Length;
		ByteOffset = IoStackLocation->Parameters.Write.ByteOffset;

		PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE);
		Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE);
		SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE);

		FFSPrint((DBG_INFO, "FFSWriteFile: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
					ByteOffset.QuadPart, Length, PagingIo, Nocache));

		/*
		if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED))
		{
			Status = STATUS_FILE_DELETED;
			__leave;
		}

		if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING))
		{
			Status = STATUS_DELETE_PENDING;
			__leave;
		}
		*/

		if (Length == 0)
		{
			Irp->IoStatus.Information = 0;
			Status = STATUS_SUCCESS;
			__leave;
		}

		if (Nocache &&
				(ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
				 Length & (SECTOR_SIZE - 1)))
		{
			Status = STATUS_INVALID_PARAMETER;
			__leave;
		}

		if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC))
		{
			ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
			Status = STATUS_PENDING;
			__leave;
		}

#if FALSE
		if (!Nocache)
		{
			BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
			BOOLEAN bWait  = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
			BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);

			if (!CcCanIWrite(
						FileObject,
						Length,
						(bWait && bQueue),
						bAgain))
			{
				SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);

				CcDeferWrite(FileObject,
						(PCC_POST_DEFERRED_WRITE)FFSDeferWrite,
						IrpContext,
						Irp,
						Length,
						bAgain);

				bDeferred = TRUE;

				FFSBreakPoint();

				Status = STATUS_PENDING;
				__leave;
			}
		}

#endif

		if (IsEndOfFile(ByteOffset))
		{
			bAppendFile = TRUE;
			ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
		}

		if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY) && !PagingIo)
		{
			Status = STATUS_INVALID_DEVICE_REQUEST;
			__leave;
		}

		//
		//  Do flushing for such cases
		//
		if (Nocache && !PagingIo && (Fcb->SectionObject.DataSectionObject != NULL)) 
		{
			ExAcquireResourceExclusive(&Fcb->MainResource, 
					IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));

			MainResourceAcquired = TRUE;

			ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
			ExReleaseResource(&Fcb->PagingIoResource);

			CcFlushCache(&(Fcb->SectionObject),
					&ByteOffset,
					Length,
					&(Irp->IoStatus));
			ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);

			if (!NT_SUCCESS(Irp->IoStatus.Status)) 
			{
				Status = Irp->IoStatus.Status;
				__leave;
			}

			ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
			ExReleaseResource(&Fcb->PagingIoResource);

			CcPurgeCacheSection(&(Fcb->SectionObject),
					(PLARGE_INTEGER)&(ByteOffset),
					Length,
					FALSE);

			ExReleaseResource(&Fcb->MainResource);
			MainResourceAcquired = FALSE;
		}

		if (!PagingIo)
		{
			if (!ExAcquireResourceExclusiveLite(
						&Fcb->MainResource,
						IrpContext->IsSynchronous))
			{
				Status = STATUS_PENDING;
				__leave;
			}

			MainResourceAcquired = TRUE;
		}
		else
		{
			/*
			ULONG ResShCnt, ResExCnt; 
			ResShCnt = ExIsResourceAcquiredSharedLite(&Fcb->PagingIoResource);
			ResExCnt = ExIsResourceAcquiredExclusiveLite(&Fcb->PagingIoResource);

			FFSPrint((DBG_USER, "FFSWriteFile: Inode=%xh %S PagingIo: %xh:%xh Synchronous=%xh\n",
			Fcb->FFSMcb->Inode, Fcb->FFSMcb->ShortName.Buffer, ResShCnt, ResExCnt, IrpContext->IsSynchronous));
			*/
			if (!ExAcquireResourceSharedLite(
						&Fcb->PagingIoResource,
						IrpContext->IsSynchronous))
			{
				Status = STATUS_PENDING;
				__leave;
			}

			PagingIoResourceAcquired = TRUE;
		}

		if (!PagingIo)
		{
			if (!FsRtlCheckLockForWriteAccess(
						&Fcb->FileLockAnchor,
						Irp))
			{
				Status = STATUS_FILE_LOCK_CONFLICT;
				__leave;
			}
		}

		if (Nocache)
		{
			if ((ByteOffset.QuadPart + Length) >
					Fcb->Header.AllocationSize.QuadPart)
			{
				if (ByteOffset.QuadPart >= 
						Fcb->Header.AllocationSize.QuadPart)
				{
					Status = STATUS_SUCCESS;
					Irp->IoStatus.Information = 0;
					__leave;
				}
				else
				{
					if (Length > (ULONG)(Fcb->Header.AllocationSize.QuadPart
								- ByteOffset.QuadPart))
					{
						Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart
								- ByteOffset.QuadPart);
					}
				}
			}
		}

		if (!Nocache)
		{
			if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY))
			{
				__leave;
			}

			if (FileObject->PrivateCacheMap == NULL)
			{
				CcInitializeCacheMap(
						FileObject,
						(PCC_FILE_SIZES)(&Fcb->Header.AllocationSize),
						FALSE,
						&FFSGlobal->CacheManagerCallbacks,
						Fcb);

				CcSetReadAheadGranularity(
						FileObject,
						READ_AHEAD_GRANULARITY);

				CcSetFileSizes(
						FileObject, 
						(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
			}

			CacheObject = FileObject;

			//
			//  Need extending the size of inode ?
			//
			if ((bAppendFile) || ((ULONG)(ByteOffset.QuadPart + Length) >
						(ULONG)(Fcb->Header.FileSize.QuadPart)))
			{

				LARGE_INTEGER   ExtendSize;
				LARGE_INTEGER   FileSize;

				bNeedExtending = TRUE;
				FileSize = Fcb->Header.FileSize;
				ExtendSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length);

				if (ExtendSize.QuadPart > Fcb->Header.AllocationSize.QuadPart)
				{
					if (!FFSExpandFile(IrpContext, Vcb, Fcb, &ExtendSize))
					{
						Status = STATUS_INSUFFICIENT_RESOURCES;
						__leave;
					}
				}

				{
					Fcb->Header.FileSize.QuadPart = ExtendSize.QuadPart;
					Fcb->dinode1->di_size = (ULONG)ExtendSize.QuadPart;
				}

				if (FileObject->PrivateCacheMap)
				{
					CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));

					if (ByteOffset.QuadPart > FileSize.QuadPart)
					{
						FFSZeroHoles(IrpContext, Vcb, FileObject, FileSize.QuadPart, 
								ByteOffset.QuadPart - FileSize.QuadPart);
					}

					if (Fcb->Header.AllocationSize.QuadPart > ExtendSize.QuadPart)
					{
						FFSZeroHoles(IrpContext, Vcb, FileObject, ExtendSize.QuadPart, 
								Fcb->Header.AllocationSize.QuadPart - ExtendSize.QuadPart);
					}
				}

				if (FFSv1SaveInode(IrpContext, Vcb, Fcb->FFSMcb->Inode, Fcb->dinode1))
				{
					Status = STATUS_SUCCESS;
				}

				FFSNotifyReportChange(
						IrpContext,
						Vcb,
						Fcb,
						FILE_NOTIFY_CHANGE_SIZE,
						FILE_ACTION_MODIFIED);
			}

			if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL))
			{
				CcPrepareMdlWrite(
						CacheObject,
						(&ByteOffset),
						Length,
						&Irp->MdlAddress,
						&Irp->IoStatus);

				Status = Irp->IoStatus.Status;
			}
			else
			{
				Buffer = FFSGetUserBuffer(Irp);

				if (Buffer == NULL)
				{
					FFSBreakPoint();
					Status = STATUS_INVALID_USER_BUFFER;
					__leave;
				}

				if (!CcCopyWrite(
							CacheObject,
							(PLARGE_INTEGER)&ByteOffset,
							Length,
							IrpContext->IsSynchronous,
							Buffer))
				{
					Status = STATUS_PENDING;
					__leave;
				}

				Status = Irp->IoStatus.Status;
			}

			if (NT_SUCCESS(Status))
			{
				Irp->IoStatus.Information = Length;

				if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK))
				{
					FFSPrint((DBG_USER, "FFSWriteFile is starting FlushingDpc...\n"));
					FFSStartFloppyFlushDpc(Vcb, Fcb, FileObject);
				}
			}
		}
		else
		{
			ReturnedLength = Length;

			Status = FFSLockUserBuffer(
					IrpContext->Irp,
					Length,
					IoReadAccess);

			if (!NT_SUCCESS(Status))
			{
				__leave;
			}

			Irp->IoStatus.Status = STATUS_SUCCESS;
			Irp->IoStatus.Information = Length;

			Status = 
				FFSv1WriteInode(
						IrpContext,
						Vcb,
						Fcb->dinode1,
						(ULONGLONG)(ByteOffset.QuadPart),
						NULL,
						Length,
						TRUE,
						&ReturnedLength);

			Irp = IrpContext->Irp;

		}
	}

	__finally
	{
		if (PagingIoResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Fcb->PagingIoResource,
					ExGetCurrentResourceThread());
		}

		if (MainResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Fcb->MainResource,
					ExGetCurrentResourceThread());
		}

		if (!IrpContext->ExceptionInProgress)
		{
			if (Irp)
			{
				if (Status == STATUS_PENDING)
				{
					if (!bDeferred)
					{
						Status = FFSLockUserBuffer(
									IrpContext->Irp,
									Length,
									IoReadAccess);

						if (NT_SUCCESS(Status))
						{
							Status = FFSQueueRequest(IrpContext);
						}
						else
						{
							FFSCompleteIrpContext(IrpContext, Status);
						}
					}
				}
				else
				{
					if (NT_SUCCESS(Status))
					{
						if (SynchronousIo && !PagingIo)
						{
							FileObject->CurrentByteOffset.QuadPart =
								ByteOffset.QuadPart + Irp->IoStatus.Information;
						}

						if (!PagingIo)
						{
							SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
							SetFlag(Fcb->Flags, FCB_FILE_MODIFIED);
						}
					}

					FFSCompleteIrpContext(IrpContext, Status);
				}
			}
			else
			{
				FFSFreeIrpContext(IrpContext);
			}
		}
	}

	return Status;

}
Esempio n. 3
0
NTSTATUS
FFSWriteVolume(
	IN PFFS_IRP_CONTEXT IrpContext)
{
	NTSTATUS            Status = STATUS_UNSUCCESSFUL;

	PFFS_VCB            Vcb  = NULL;
	PFFS_CCB            Ccb = NULL;
	PFFS_FCBVCB         FcbOrVcb  = NULL;
	PFILE_OBJECT        FileObject  = NULL;

	PDEVICE_OBJECT      DeviceObject  = NULL;

	PIRP                Irp  = NULL;
	PIO_STACK_LOCATION  IoStackLocation  = NULL;

	ULONG               Length;
	LARGE_INTEGER       ByteOffset;

	BOOLEAN             PagingIo;
	BOOLEAN             Nocache;
	BOOLEAN             SynchronousIo;
	BOOLEAN             MainResourceAcquired = FALSE;
	BOOLEAN             PagingIoResourceAcquired = FALSE;

	BOOLEAN             bDeferred = FALSE;

	PUCHAR              Buffer = NULL;

	__try
	{
		ASSERT(IrpContext);

		ASSERT((IrpContext->Identifier.Type == FFSICX) &&
				(IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));

		DeviceObject = IrpContext->DeviceObject;

		Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;

		ASSERT(Vcb != NULL);

		ASSERT((Vcb->Identifier.Type == FFSVCB) &&
				(Vcb->Identifier.Size == sizeof(FFS_VCB)));

		FileObject = IrpContext->FileObject;

		FcbOrVcb = (PFFS_FCBVCB)FileObject->FsContext;

		ASSERT(FcbOrVcb);

		if (!(FcbOrVcb->Identifier.Type == FFSVCB && (PVOID)FcbOrVcb == (PVOID)Vcb))
		{
			Status = STATUS_INVALID_DEVICE_REQUEST;
			__leave;
		}

		Ccb = (PFFS_CCB)FileObject->FsContext2;

		Irp = IrpContext->Irp;

		IoStackLocation = IoGetCurrentIrpStackLocation(Irp);

		Length = IoStackLocation->Parameters.Write.Length;
		ByteOffset = IoStackLocation->Parameters.Write.ByteOffset;

		PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE);
		Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE);
		SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE);

		FFSPrint((DBG_INFO, "FFSWriteVolume: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
					ByteOffset.QuadPart, Length, PagingIo, Nocache));

		if (Length == 0)
		{
			Irp->IoStatus.Information = 0;
			Status = STATUS_SUCCESS;
			__leave;
		}

		// For the case of "Direct Access Storage Device", we
		// need flush/purge the cache

		if (Ccb != NULL)
		{
			ExAcquireResourceExclusive(&Vcb->MainResource, TRUE);
			MainResourceAcquired = TRUE;

			Status = FFSPurgeVolume(Vcb, TRUE);

			ExReleaseResource(&Vcb->MainResource);
			MainResourceAcquired = FALSE;

			if(!IsFlagOn(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO))
			{
				if (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart)
				{
					Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
				}
			}

			{
				FFS_BDL BlockArray;

				if ((ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
						(Length & (SECTOR_SIZE - 1)))
				{
					Status = STATUS_INVALID_PARAMETER;
					__leave;
				}

				Status = FFSLockUserBuffer(
							IrpContext->Irp,
							Length,
							IoReadAccess);

				if (!NT_SUCCESS(Status))
				{
					__leave;
				}

				BlockArray.Irp = NULL;
				BlockArray.Lba = ByteOffset.QuadPart;;
				BlockArray.Offset = 0;
				BlockArray.Length = Length;

				Status = FFSReadWriteBlocks(IrpContext,
							Vcb,
							&BlockArray,
							Length,
							1,
							FALSE);
				Irp = IrpContext->Irp;

				__leave;
			}
		}                    

		if (Nocache &&
				(ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
				 Length & (SECTOR_SIZE - 1)))
		{
			Status = STATUS_INVALID_PARAMETER;
			__leave;
		}

		if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC))
		{
			ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
			Status = STATUS_PENDING;
			__leave;
		}

		if (ByteOffset.QuadPart >=
				Vcb->PartitionInformation.PartitionLength.QuadPart)
		{
			Irp->IoStatus.Information = 0;
			Status = STATUS_END_OF_FILE;
			__leave;
		}

#if FALSE

		if (!Nocache)
		{
			BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
			BOOLEAN bWait  = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
			BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);

			if (!CcCanIWrite(
						FileObject,
						Length,
						(bWait && bQueue),
						bAgain))
			{
				SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);

				CcDeferWrite(FileObject,
						(PCC_POST_DEFERRED_WRITE)FFSDeferWrite,
						IrpContext,
						Irp,
						Length,
						bAgain);

				bDeferred = TRUE;

				FFSBreakPoint();

				Status = STATUS_PENDING;

				__leave;
			}
		}

#endif

		if (Nocache && !PagingIo && (Vcb->SectionObject.DataSectionObject != NULL)) 
		{
			ExAcquireResourceExclusive(&Vcb->MainResource, TRUE);
			MainResourceAcquired = TRUE;

			ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
			ExReleaseResource(&Vcb->PagingIoResource);

			CcFlushCache(&(Vcb->SectionObject),
					&ByteOffset,
					Length,
					&(Irp->IoStatus));

			if (!NT_SUCCESS(Irp->IoStatus.Status)) 
			{
				Status = Irp->IoStatus.Status;
				__leave;
			}

			ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
			ExReleaseResource(&Vcb->PagingIoResource);

			CcPurgeCacheSection(&(Vcb->SectionObject),
					(PLARGE_INTEGER)&(ByteOffset),
					Length,
					FALSE);

			ExReleaseResource(&Vcb->MainResource);
			MainResourceAcquired = FALSE;
		}

		if (!PagingIo)
		{
			if (!ExAcquireResourceExclusiveLite(
						&Vcb->MainResource,
						IrpContext->IsSynchronous))
			{
				Status = STATUS_PENDING;
				__leave;
			}

			MainResourceAcquired = TRUE;
		}
		else
		{
			/*
			ULONG ResShCnt, ResExCnt; 
			ResShCnt = ExIsResourceAcquiredSharedLite(&Vcb->PagingIoResource);
			ResExCnt = ExIsResourceAcquiredExclusiveLite(&Vcb->PagingIoResource);

			FFSPrint((DBG_USER, "PagingIoRes: %xh:%xh Synchronous=%xh\n", ResShCnt, ResExCnt, IrpContext->IsSynchronous));
			*/

			if (Ccb)
			{
				if (!ExAcquireResourceSharedLite(
							&Vcb->PagingIoResource,
							IrpContext->IsSynchronous))
				{
					Status = STATUS_PENDING;
					__leave;
				}

				PagingIoResourceAcquired = TRUE;
			}
		}

		if (!Nocache)
		{
			if ((ByteOffset.QuadPart + Length) >
					Vcb->PartitionInformation.PartitionLength.QuadPart
			)
			{
				Length = (ULONG) (
						Vcb->PartitionInformation.PartitionLength.QuadPart -
						ByteOffset.QuadPart);

				Length &= ~((ULONG)SECTOR_SIZE - 1);
			}

			if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL))
			{

				CcPrepareMdlWrite(
						Vcb->StreamObj,
						&ByteOffset,
						Length,
						&Irp->MdlAddress,
						&Irp->IoStatus);

				Status = Irp->IoStatus.Status;
			}
			else
			{
				Buffer = FFSGetUserBuffer(Irp);

				if (Buffer == NULL)
				{
					FFSBreakPoint();

					Status = STATUS_INVALID_USER_BUFFER;
					__leave;
				}

				if (!CcCopyWrite(Vcb->StreamObj,
							(PLARGE_INTEGER)(&ByteOffset),
							Length,
							TRUE,
							Buffer))
				{
					Status = STATUS_PENDING;
					__leave;
				}

				Status = Irp->IoStatus.Status;
				FFSAddMcbEntry(Vcb, ByteOffset.QuadPart, (LONGLONG)Length);
			}

			if (NT_SUCCESS(Status))
			{
				Irp->IoStatus.Information = Length;
			}
		}
		else
		{
			PFFS_BDL            ffs_bdl = NULL;
			ULONG               Blocks = 0;

			LONGLONG            DirtyStart;
			LONGLONG            DirtyLba;
			LONGLONG            DirtyLength;
			LONGLONG            RemainLength;

			if ((ByteOffset.QuadPart + Length) >
					Vcb->PartitionInformation.PartitionLength.QuadPart)
			{
				Length = (ULONG)(
						Vcb->PartitionInformation.PartitionLength.QuadPart -
						ByteOffset.QuadPart);

				Length &= ~((ULONG)SECTOR_SIZE - 1);
			}

			Status = FFSLockUserBuffer(
					IrpContext->Irp,
					Length,
					IoReadAccess);

			if (!NT_SUCCESS(Status))
			{
				__leave;
			}

			ffs_bdl = ExAllocatePool(PagedPool, 
					(Length / Vcb->BlockSize) *
					sizeof(FFS_BDL));

			if (!ffs_bdl)
			{
				Status = STATUS_INSUFFICIENT_RESOURCES;
				__leave;
			}

			DirtyLba = ByteOffset.QuadPart;
			RemainLength = (LONGLONG)Length;

			while (RemainLength > 0)
			{
				DirtyStart = DirtyLba;

				if (FFSLookupMcbEntry(Vcb, 
							DirtyStart,
							&DirtyLba,
							&DirtyLength,
							(PLONGLONG)NULL,
							(PLONGLONG)NULL,
							(PULONG)NULL))
				{

					if (DirtyLba == -1)
					{
						DirtyLba = DirtyStart + DirtyLength;

						RemainLength = ByteOffset.QuadPart + 
							(LONGLONG)Length -
							DirtyLba;
						continue;
					}

					ffs_bdl[Blocks].Irp = NULL;
					ffs_bdl[Blocks].Lba = DirtyLba;
					ffs_bdl[Blocks].Offset = (ULONG)((LONGLONG)Length +
							DirtyStart -
							RemainLength - 
							DirtyLba);

					if (DirtyLba + DirtyLength > DirtyStart + RemainLength)
					{
						ffs_bdl[Blocks].Length = (ULONG)(DirtyStart +
								RemainLength -
								DirtyLba);
						RemainLength = 0;
					}
					else
					{
						ffs_bdl[Blocks].Length = (ULONG)DirtyLength;
						RemainLength =  (DirtyStart + RemainLength) -
							(DirtyLba + DirtyLength);
					}

					DirtyLba = DirtyStart + DirtyLength;
					Blocks++;
				}
				else
				{
					if (Blocks == 0)
					{
						if (ffs_bdl)
							ExFreePool(ffs_bdl);

						//
						// Lookup fails at the first time, ie. 
						// no dirty blocks in the run
						//

						FFSBreakPoint();

						if (RemainLength == (LONGLONG)Length)
							Status = STATUS_SUCCESS;
						else
							Status = STATUS_UNSUCCESSFUL;

						__leave;
					}
					else
					{
						break;
					}
				}
			}

			if (Blocks > 0)
			{
				Status = FFSReadWriteBlocks(IrpContext,
							Vcb,
							ffs_bdl,
							Length,
							Blocks,
							FALSE);
				Irp = IrpContext->Irp;

				if (NT_SUCCESS(Status))
				{
					ULONG   i;

					for (i = 0; i < Blocks; i++)
					{
						FFSRemoveMcbEntry(Vcb,
								ffs_bdl[i].Lba,
								ffs_bdl[i].Length);
					}
				}

				if (ffs_bdl)
					ExFreePool(ffs_bdl);

				if (!Irp)
					__leave;

			}
			else
			{
				if (ffs_bdl)
					ExFreePool(ffs_bdl);

				Irp->IoStatus.Information = Length;

				Status = STATUS_SUCCESS;
				__leave;
			}
		}
	}

	__finally
	{
		if (PagingIoResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Vcb->PagingIoResource,
					ExGetCurrentResourceThread());
		}

		if (MainResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Vcb->MainResource,
					ExGetCurrentResourceThread());
		}

		if (!IrpContext->ExceptionInProgress)
		{
			if (Irp)
			{
				if (Status == STATUS_PENDING)
				{
					if(!bDeferred)
					{
						Status = FFSLockUserBuffer(
								IrpContext->Irp,
								Length,
								IoReadAccess);

						if (NT_SUCCESS(Status))
						{
							Status = FFSQueueRequest(IrpContext);
						}
						else
						{
							FFSCompleteIrpContext(IrpContext, Status);
						}
					}
				}
				else
				{
					if (NT_SUCCESS(Status))
					{
						if (SynchronousIo && !PagingIo)
						{
							FileObject->CurrentByteOffset.QuadPart =
								ByteOffset.QuadPart + Irp->IoStatus.Information;
						}

						if (!PagingIo)
						{
							SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
						}
					}

					FFSCompleteIrpContext(IrpContext, Status);
				}
			}
			else
			{
				FFSFreeIrpContext(IrpContext);
			}
		}
	}

	return Status;
}
Esempio n. 4
0
__drv_mustHoldCriticalRegion
NTSTATUS
FFSQueryDirectory(
	IN PFFS_IRP_CONTEXT IrpContext)
{
	PDEVICE_OBJECT          DeviceObject;
	NTSTATUS                Status = STATUS_UNSUCCESSFUL;
	PFFS_VCB                Vcb = 0;
	PFILE_OBJECT            FileObject;
	PFFS_FCB                Fcb = 0;
	PFFS_CCB                Ccb;
	PIRP                    Irp;
	PIO_STACK_LOCATION      IoStackLocation;
	FILE_INFORMATION_CLASS  FileInformationClass;
	ULONG                   Length;
	PUNICODE_STRING         FileName;
	ULONG                   FileIndex;
	BOOLEAN                 RestartScan;
	BOOLEAN                 ReturnSingleEntry;
	BOOLEAN                 IndexSpecified;
	PUCHAR                  Buffer;
	BOOLEAN                 FirstQuery;
	PFFSv1_INODE            dinode1 = NULL;
	PFFSv2_INODE            dinode2 = NULL;
	BOOLEAN                 FcbResourceAcquired = FALSE;
	ULONG                   UsedLength = 0;
	USHORT                  InodeFileNameLength;
	UNICODE_STRING          InodeFileName;
	PFFS_DIR_ENTRY          pDir = NULL;
	ULONG                   dwBytes;
	ULONG                   dwTemp = 0;
	ULONG                   dwSize = 0;
	ULONG                   dwReturn = 0;
	BOOLEAN                 bRun = TRUE;
	ULONG                   ByteOffset;

    PAGED_CODE();

	InodeFileName.Buffer = NULL;

	_SEH2_TRY
	{
		ASSERT(IrpContext);

		ASSERT((IrpContext->Identifier.Type == FFSICX) &&
				(IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));

		DeviceObject = IrpContext->DeviceObject;

		//
		// This request is not allowed on the main device object
		//
		if (DeviceObject == FFSGlobal->DeviceObject)
		{
			Status = STATUS_INVALID_DEVICE_REQUEST;
			_SEH2_LEAVE;
		}

		Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;

		ASSERT(Vcb != NULL);

		ASSERT((Vcb->Identifier.Type == FFSVCB) &&
				(Vcb->Identifier.Size == sizeof(FFS_VCB)));

		ASSERT(IsMounted(Vcb));

		FileObject = IrpContext->FileObject;

		Fcb = (PFFS_FCB)FileObject->FsContext;

		ASSERT(Fcb);

		//
		// This request is not allowed on volumes
		//
		if (Fcb->Identifier.Type == FFSVCB)
		{
			Status = STATUS_INVALID_PARAMETER;
			_SEH2_LEAVE;
		}

		ASSERT((Fcb->Identifier.Type == FFSFCB) &&
				(Fcb->Identifier.Size == sizeof(FFS_FCB)));

		if (!IsDirectory(Fcb))
		{
			Status = STATUS_INVALID_PARAMETER;
			_SEH2_LEAVE;
		}

		Ccb = (PFFS_CCB)FileObject->FsContext2;

		ASSERT(Ccb);

		ASSERT((Ccb->Identifier.Type == FFSCCB) &&
				(Ccb->Identifier.Size == sizeof(FFS_CCB)));

		Irp = IrpContext->Irp;

		IoStackLocation = IoGetCurrentIrpStackLocation(Irp);

#if !defined(_GNU_NTIFS_) || defined(__REACTOS__)

		FileInformationClass =
			IoStackLocation->Parameters.QueryDirectory.FileInformationClass;

		Length = IoStackLocation->Parameters.QueryDirectory.Length;

		FileName = IoStackLocation->Parameters.QueryDirectory.FileName;

		FileIndex = IoStackLocation->Parameters.QueryDirectory.FileIndex;

#else // _GNU_NTIFS_

		FileInformationClass = ((PEXTENDED_IO_STACK_LOCATION)
				IoStackLocation)->Parameters.QueryDirectory.FileInformationClass;

		Length = ((PEXTENDED_IO_STACK_LOCATION)
				IoStackLocation)->Parameters.QueryDirectory.Length;

		FileName = ((PEXTENDED_IO_STACK_LOCATION)
				IoStackLocation)->Parameters.QueryDirectory.FileName;

		FileIndex = ((PEXTENDED_IO_STACK_LOCATION)
				IoStackLocation)->Parameters.QueryDirectory.FileIndex;

#endif // _GNU_NTIFS_

		RestartScan = FlagOn(IoStackLocation->Flags, SL_RESTART_SCAN);
		ReturnSingleEntry = FlagOn(IoStackLocation->Flags, SL_RETURN_SINGLE_ENTRY);
		IndexSpecified = FlagOn(IoStackLocation->Flags, SL_INDEX_SPECIFIED);
		/*
		if (!Irp->MdlAddress && Irp->UserBuffer)
		{
			ProbeForWrite(Irp->UserBuffer, Length, 1);
		}
		*/
		Buffer = FFSGetUserBuffer(Irp);

		if (Buffer == NULL)
		{
			FFSBreakPoint();
			Status = STATUS_INVALID_USER_BUFFER;
			_SEH2_LEAVE;
		}

		if (!IrpContext->IsSynchronous)
		{
			Status = STATUS_PENDING;
			_SEH2_LEAVE;
		}

		if (!ExAcquireResourceSharedLite(
					&Fcb->MainResource,
					IrpContext->IsSynchronous))
		{
			Status = STATUS_PENDING;
			_SEH2_LEAVE;
		}

		FcbResourceAcquired = TRUE;

		if (FileName != NULL)
		{
			if (Ccb->DirectorySearchPattern.Buffer != NULL)
			{
				FirstQuery = FALSE;
			}
			else
			{
				FirstQuery = TRUE;

				Ccb->DirectorySearchPattern.Length =
					Ccb->DirectorySearchPattern.MaximumLength =
					FileName->Length;

				Ccb->DirectorySearchPattern.Buffer =
					ExAllocatePoolWithTag(PagedPool, FileName->Length, FFS_POOL_TAG);

				if (Ccb->DirectorySearchPattern.Buffer == NULL)
				{
					Status = STATUS_INSUFFICIENT_RESOURCES;
					_SEH2_LEAVE;
				}

				Status = RtlUpcaseUnicodeString(
						&(Ccb->DirectorySearchPattern),
						FileName,
						FALSE);

				if (!NT_SUCCESS(Status))
					_SEH2_LEAVE;
			}
		}
		else if (Ccb->DirectorySearchPattern.Buffer != NULL)
		{
			FirstQuery = FALSE;
			FileName = &Ccb->DirectorySearchPattern;
		}
		else
		{
			FirstQuery = TRUE;

			Ccb->DirectorySearchPattern.Length =
				Ccb->DirectorySearchPattern.MaximumLength = 2;

			Ccb->DirectorySearchPattern.Buffer =
				ExAllocatePoolWithTag(PagedPool, 2, FFS_POOL_TAG);

			if (Ccb->DirectorySearchPattern.Buffer == NULL)
			{
				Status = STATUS_INSUFFICIENT_RESOURCES;
				_SEH2_LEAVE;
			}

			RtlCopyMemory(
					Ccb->DirectorySearchPattern.Buffer,
					L"*\0", 2);
		}

		if (!IndexSpecified)
		{
			if (RestartScan || FirstQuery)
			{
				FileIndex = Fcb->FFSMcb->DeOffset = 0;
			}
			else
			{
				FileIndex = Ccb->CurrentByteOffset;
			}
		}

		if (FS_VERSION == 1)
		{
			dinode1 = (PFFSv1_INODE)ExAllocatePoolWithTag(
					PagedPool,
					DINODE1_SIZE, FFS_POOL_TAG);

			if (dinode1 == NULL)
			{
				Status = STATUS_INSUFFICIENT_RESOURCES;
				_SEH2_LEAVE;
			}

			RtlZeroMemory(Buffer, Length);

			if (Fcb->dinode1->di_size <= FileIndex)
			{
				Status = STATUS_NO_MORE_FILES;
				_SEH2_LEAVE;
			}
		}
		else
		{
			dinode2 = (PFFSv2_INODE)ExAllocatePoolWithTag(
					PagedPool,
					DINODE2_SIZE, FFS_POOL_TAG);

			if (dinode2 == NULL)
			{
				Status = STATUS_INSUFFICIENT_RESOURCES;
				_SEH2_LEAVE;
			}

			RtlZeroMemory(Buffer, Length);

			if (Fcb->dinode2->di_size <= FileIndex)
			{
				Status = STATUS_NO_MORE_FILES;
				_SEH2_LEAVE;
			}
		}

		pDir = ExAllocatePoolWithTag(PagedPool,
				sizeof(FFS_DIR_ENTRY), FFS_POOL_TAG);
		if (!pDir)
		{
			Status = STATUS_INSUFFICIENT_RESOURCES;
			_SEH2_LEAVE;
		}


		if (FS_VERSION == 1)
		{
			dwBytes = 0;
			dwSize = (ULONG)Fcb->dinode1->di_size - FileIndex -
				(sizeof(FFS_DIR_ENTRY) - FFS_NAME_LEN + 1);

			ByteOffset = FileIndex;

			dwTemp = 0;

			while (bRun && UsedLength < Length  && dwBytes < dwSize)
			{
				OEM_STRING  OemName;

				RtlZeroMemory(pDir, sizeof(FFS_DIR_ENTRY));

				Status = FFSv1ReadInode(
							NULL,
							Vcb,
							Fcb->dinode1,
							ByteOffset,
							(PVOID)pDir,
							sizeof(FFS_DIR_ENTRY),
							&dwReturn);

				if (!NT_SUCCESS(Status))
				{
					_SEH2_LEAVE;
				}

				if (!pDir->d_ino)
				{
					if (pDir->d_reclen == 0)
					{
						FFSBreakPoint();
						_SEH2_LEAVE;
					}

					goto ProcessNextEntryv1;
				}

				OemName.Buffer = pDir->d_name;
				OemName.Length = (pDir->d_namlen & 0xff);
				OemName.MaximumLength = OemName.Length;

#if 0
/*
				//
				// We could not filter the files: "." and ".."
				//

				if ((OemName.Length >) 1 && OemName.Buffer[0] == '.')
				{
					if ( OemName.Length == 2 && OemName.Buffer[1] == '.')
					{
					}
					else
					{
						goto ProcessNextEntry1;
					}
				}
*/
#endif

				InodeFileNameLength = (USHORT)
					RtlOemStringToUnicodeSize(&OemName);

				InodeFileName.Length = 0;
				InodeFileName.MaximumLength = InodeFileNameLength + 2;

				if (InodeFileNameLength <= 0)
				{
					break;
				}

				InodeFileName.Buffer = ExAllocatePoolWithTag(
						PagedPool,
						InodeFileNameLength + 2, FFS_POOL_TAG);

				if (!InodeFileName.Buffer)
				{
					Status = STATUS_INSUFFICIENT_RESOURCES;
					_SEH2_LEAVE;
				}

				RtlZeroMemory(
						InodeFileName.Buffer, 
						InodeFileNameLength + 2);

				Status = FFSOEMToUnicode(&InodeFileName,
						&OemName);

				if (!NT_SUCCESS(Status))
				{
					_SEH2_LEAVE;
				}

				if (FsRtlDoesNameContainWildCards(
							&(Ccb->DirectorySearchPattern)) ?
						FsRtlIsNameInExpression(
							&(Ccb->DirectorySearchPattern),
							&InodeFileName,
							TRUE,
							NULL) :
						!RtlCompareUnicodeString(
							&(Ccb->DirectorySearchPattern),
							&InodeFileName,
							TRUE))
				{
					dwReturn = FFSProcessDirEntry(
							Vcb, FileInformationClass,
							pDir->d_ino,
							Buffer,
							UsedLength, 
							Length - UsedLength,
							(FileIndex + dwBytes),
							&InodeFileName,
							ReturnSingleEntry);

					if (dwReturn <= 0)
					{
						bRun = FALSE;
					}
					else
					{
						dwTemp = UsedLength;
						UsedLength += dwReturn;
					}
				}

				if (InodeFileName.Buffer != NULL)
				{
					ExFreePool(InodeFileName.Buffer);
					InodeFileName.Buffer = NULL;
				}

ProcessNextEntryv1:

				if (bRun)
				{
					dwBytes +=pDir->d_reclen;
					Ccb->CurrentByteOffset = FileIndex + dwBytes;
				}

				if (UsedLength && ReturnSingleEntry)
				{
					Status = STATUS_SUCCESS;
					_SEH2_LEAVE;
				}

				ByteOffset = FileIndex + dwBytes;
			}
		}
		else
		{
			dwBytes = 0;
			dwSize = (ULONG)Fcb->dinode2->di_size - FileIndex -
				(sizeof(FFS_DIR_ENTRY) - FFS_NAME_LEN + 1);

			ByteOffset = FileIndex;

			dwTemp = 0;

			while (bRun && UsedLength < Length  && dwBytes < dwSize)
			{
				OEM_STRING  OemName;

				RtlZeroMemory(pDir, sizeof(FFS_DIR_ENTRY));

				Status = FFSv2ReadInode(
							NULL,
							Vcb,
							Fcb->dinode2,
							ByteOffset,
							(PVOID)pDir,
							sizeof(FFS_DIR_ENTRY),
							&dwReturn);

				if (!NT_SUCCESS(Status))
				{
					_SEH2_LEAVE;
				}

				if (!pDir->d_ino)
				{
					if (pDir->d_reclen == 0)
					{
						FFSBreakPoint();
						_SEH2_LEAVE;
					}

					goto ProcessNextEntryv2;
				}

				OemName.Buffer = pDir->d_name;
				OemName.Length = (pDir->d_namlen & 0xff);
				OemName.MaximumLength = OemName.Length;
#if 0
/*
				//
				// We could not filter the files: "." and ".."
				//

				if ((OemName.Length >) 1 && OemName.Buffer[0] == '.')
				{
					if ( OemName.Length == 2 && OemName.Buffer[1] == '.')
					{
					}
					else
					{
						goto ProcessNextEntry2;
					}
				}
*/
#endif

				InodeFileNameLength = (USHORT)
					RtlOemStringToUnicodeSize(&OemName);

				InodeFileName.Length = 0;
				InodeFileName.MaximumLength = InodeFileNameLength + 2;

				if (InodeFileNameLength <= 0)
				{
					break;
				}

				InodeFileName.Buffer = ExAllocatePoolWithTag(
						PagedPool,
						InodeFileNameLength + 2, FFS_POOL_TAG);

				if (!InodeFileName.Buffer)
				{
					Status = STATUS_INSUFFICIENT_RESOURCES;
					_SEH2_LEAVE;
				}

				RtlZeroMemory(
						InodeFileName.Buffer, 
						InodeFileNameLength + 2);

				Status = FFSOEMToUnicode(&InodeFileName,
						&OemName);

				if (!NT_SUCCESS(Status))
				{
					_SEH2_LEAVE;
				}

				if (FsRtlDoesNameContainWildCards(
							&(Ccb->DirectorySearchPattern)) ?
						FsRtlIsNameInExpression(
							&(Ccb->DirectorySearchPattern),
							&InodeFileName,
							TRUE,
							NULL) :
						!RtlCompareUnicodeString(
							&(Ccb->DirectorySearchPattern),
							&InodeFileName,
							TRUE))
				{
					dwReturn = FFSProcessDirEntry(
							Vcb, FileInformationClass,
							pDir->d_ino,
							Buffer,
							UsedLength, 
							Length - UsedLength,
							(FileIndex + dwBytes),
							&InodeFileName,
							ReturnSingleEntry);

					if (dwReturn <= 0)
					{
						bRun = FALSE;
					}
					else
					{
						dwTemp = UsedLength;
						UsedLength += dwReturn;
					}
				}

				if (InodeFileName.Buffer != NULL)
				{
					ExFreePool(InodeFileName.Buffer);
					InodeFileName.Buffer = NULL;
				}

ProcessNextEntryv2:

				if (bRun)
				{
					dwBytes +=pDir->d_reclen;
					Ccb->CurrentByteOffset = FileIndex + dwBytes;
				}

				if (UsedLength && ReturnSingleEntry)
				{
					Status = STATUS_SUCCESS;
					_SEH2_LEAVE;
				}

				ByteOffset = FileIndex + dwBytes;
			}
		}

		FileIndex += dwBytes;

		((PULONG)((PUCHAR)Buffer + dwTemp)) [0] = 0;

		if (!UsedLength)
		{
			if (FirstQuery)
			{
				Status = STATUS_NO_SUCH_FILE;
			}
			else
			{
				Status = STATUS_NO_MORE_FILES;
			}
		}
		else
		{
			Status = STATUS_SUCCESS;
		}
	}

	_SEH2_FINALLY
	{

		if (FcbResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Fcb->MainResource,
					ExGetCurrentResourceThread());
		}

		if (FS_VERSION == 1)
		{
			if (dinode1 != NULL)
			{
				ExFreePool(dinode1);
			}
		}
		else
		{
			if (dinode2 != NULL)
			{
				ExFreePool(dinode2);
			}
		}

		if (pDir != NULL)
		{
			ExFreePool(pDir);
			pDir = NULL;
		}

		if (InodeFileName.Buffer != NULL)
		{
			ExFreePool(InodeFileName.Buffer);
		}

		if (!IrpContext->ExceptionInProgress)
		{
			if (Status == STATUS_PENDING)
			{
				Status = FFSLockUserBuffer(
						IrpContext->Irp,
						Length,
						IoWriteAccess);

				if (NT_SUCCESS(Status))
				{
					Status = FFSQueueRequest(IrpContext);
				}
				else
				{
					FFSCompleteIrpContext(IrpContext, Status);
				}
			}
			else
			{
				IrpContext->Irp->IoStatus.Information = UsedLength;
				FFSCompleteIrpContext(IrpContext, Status);
			}
		}
	} _SEH2_END;

	return Status;
}
Esempio n. 5
0
__drv_mustHoldCriticalRegion
NTSTATUS
FFSCleanup(
	IN PFFS_IRP_CONTEXT IrpContext)
{
	PDEVICE_OBJECT  DeviceObject;
	NTSTATUS        Status = STATUS_SUCCESS;
	PFFS_VCB        Vcb = 0;
	BOOLEAN	        VcbResourceAcquired = FALSE;
	PFILE_OBJECT    FileObject;
	PFFS_FCB        Fcb = 0;
	BOOLEAN	        FcbResourceAcquired = FALSE;
	BOOLEAN	        FcbPagingIoAcquired = FALSE;
	PFFS_CCB        Ccb;
	PIRP            Irp;

    PAGED_CODE();

	_SEH2_TRY
	{
		ASSERT(IrpContext != NULL);

		ASSERT((IrpContext->Identifier.Type == FFSICX) &&
			(IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));

		DeviceObject = IrpContext->DeviceObject;
		
		if (DeviceObject == FFSGlobal->DeviceObject)
		{
			Status = STATUS_SUCCESS;
			_SEH2_LEAVE;
		}
		
		Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;

		ASSERT(Vcb != NULL);

		ASSERT((Vcb->Identifier.Type == FFSVCB) &&
			(Vcb->Identifier.Size == sizeof(FFS_VCB)));

		if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED))
		{
			Status = STATUS_SUCCESS;
			_SEH2_LEAVE;
		}

#ifdef _MSC_VER
#pragma prefast( suppress: 28137, "by design" )
#endif
		if (!ExAcquireResourceExclusiveLite(
				&Vcb->MainResource,
				IrpContext->IsSynchronous))
		{
			Status = STATUS_PENDING;
			_SEH2_LEAVE;
		}

		VcbResourceAcquired = TRUE;

		FileObject = IrpContext->FileObject;

		Fcb = (PFFS_FCB)FileObject->FsContext;

		if (!Fcb)
		{
			Status = STATUS_SUCCESS;
			_SEH2_LEAVE;
		}

		if (Fcb->Identifier.Type == FFSVCB)
		{
			if (IsFlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) &&
				(Vcb->LockFile == FileObject))
			{
				ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
				Vcb->LockFile = NULL;

				FFSClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
			}

			Vcb->OpenHandleCount--;

			if (!Vcb->OpenHandleCount)
			{
				IoRemoveShareAccess(FileObject, &Vcb->ShareAccess);
			}

			Status = STATUS_SUCCESS;
			_SEH2_LEAVE;
		}

		ASSERT((Fcb->Identifier.Type == FFSFCB) &&
			(Fcb->Identifier.Size == sizeof(FFS_FCB)));

/*
		if (!IsFlagOn(Vcb->Flags, VCB_READ_ONLY) &&
			 !IsFlagOn(Fcb->Flags, FCB_PAGE_FILE))
*/
		{
#ifdef _MSC_VER
#pragma prefast( suppress: 28137, "by design" )
#endif
			if (!ExAcquireResourceExclusiveLite(
					&Fcb->MainResource,
					IrpContext->IsSynchronous))
			{
				Status = STATUS_PENDING;
				_SEH2_LEAVE;
			}

			FcbResourceAcquired = TRUE;
		}
		
		Ccb = (PFFS_CCB)FileObject->FsContext2;

		if (!Ccb)
		{
			Status = STATUS_SUCCESS;
			_SEH2_LEAVE;
		}

		if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
		{
			if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
				 IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) &&
				 !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED))
			{
				Status = FFSFlushFile(Fcb);
			}

			_SEH2_LEAVE;
		}
		
		ASSERT((Ccb->Identifier.Type == FFSCCB) &&
			(Ccb->Identifier.Size == sizeof(FFS_CCB)));		
		Irp = IrpContext->Irp;

		Fcb->OpenHandleCount--;

		if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
		{
			Fcb->NonCachedOpenCount--;
		}

		Vcb->OpenFileHandleCount--;

		if (IsFlagOn(Fcb->Flags, FCB_DELETE_ON_CLOSE))
		{
			SetFlag(Fcb->Flags, FCB_DELETE_PENDING);

			if (IsDirectory(Fcb))
			{
				FsRtlNotifyFullChangeDirectory(
											Vcb->NotifySync,
											&Vcb->NotifyList,
											Fcb,
											NULL,
											FALSE,
											FALSE,
											0,
											NULL,
											NULL,
											NULL);
			}
		}

		if (IsDirectory(Fcb))
		{
			FsRtlNotifyCleanup(
				Vcb->NotifySync,
				&Vcb->NotifyList,
				Ccb);
		}
		else
		{
			//
			// Drop any byte range locks this process may have on the file.
			//
			FsRtlFastUnlockAll(
				&Fcb->FileLockAnchor,
				FileObject,
				IoGetRequestorProcess(Irp),
				NULL);

			//
			// If there are no byte range locks owned by other processes on the
			// file the fast I/O read/write functions doesn't have to check for
			// locks so we set IsFastIoPossible to FastIoIsPossible again.
			//
			if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE))
			{
				if (Fcb->Header.IsFastIoPossible != FastIoIsPossible)
				{
					FFSPrint((
						DBG_INFO, ": %-16.16s %-31s %s\n",
						FFSGetCurrentProcessName(),
						"FastIoIsPossible",
						Fcb->AnsiFileName.Buffer));

					Fcb->Header.IsFastIoPossible = FastIoIsPossible;
				}
			}
		}

		if (IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
			 (Fcb->NonCachedOpenCount != 0) &&
			 (Fcb->NonCachedOpenCount == Fcb->ReferenceCount) &&
			 (Fcb->SectionObject.DataSectionObject != NULL))
		{

			if(!IsFlagOn(Vcb->Flags, VCB_READ_ONLY) &&
				!IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED))
			{
				CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
			}

			ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE);
			ExReleaseResourceLite(&(Fcb->PagingIoResource));

			CcPurgeCacheSection(&Fcb->SectionObject,
								NULL,
								0,
								FALSE);
		}

#if !FFS_READ_ONLY
		if (Fcb->OpenHandleCount == 0)
		{
			if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING))
			{
				BOOLEAN	 bDeleted = FALSE;

				//
				//  Have to delete this file...
				//
#ifdef _MSC_VER
#pragma prefast( suppress: 28137, "by design" )
#endif
				if (!ExAcquireResourceExclusiveLite(
						 &Fcb->PagingIoResource,
						 IrpContext->IsSynchronous))
				{
					Status = STATUS_PENDING;
					_SEH2_LEAVE;
				}

				FcbPagingIoAcquired = TRUE;

				bDeleted = FFSDeleteFile(IrpContext, Vcb, Fcb);

				if (bDeleted)
				{
					if (IsDirectory(Fcb))
					{
						FFSNotifyReportChange(IrpContext, Vcb, Fcb,
												FILE_NOTIFY_CHANGE_DIR_NAME,
												FILE_ACTION_REMOVED);
					}
					else
					{
						FFSNotifyReportChange(IrpContext, Vcb, Fcb,
												FILE_NOTIFY_CHANGE_FILE_NAME,
												FILE_ACTION_REMOVED);
					}
				}

				if (FcbPagingIoAcquired)
				{
					ExReleaseResourceForThreadLite(
						&Fcb->PagingIoResource,
						ExGetCurrentResourceThread());

					FcbPagingIoAcquired = FALSE;
				}

/*
				if (bDeleted)
				{
					FFSPurgeFile(Fcb, FALSE);
				}
*/
			}
		}
#endif // !FFS_READ_ONLY

		if (!IsDirectory(Fcb) && FileObject->PrivateCacheMap)
		{
			FFSPrint((DBG_INFO, "FFSCleanup: CcUninitializeCacheMap is called for %s.\n",
								  Fcb->AnsiFileName.Buffer));

			CcUninitializeCacheMap(
					FileObject,
					(PLARGE_INTEGER)(&(Fcb->Header.FileSize)),
					NULL);
		}

		if (!Fcb->OpenHandleCount)
		{
			IoRemoveShareAccess(FileObject, &Fcb->ShareAccess);
		}

		FFSPrint((DBG_INFO, "FFSCleanup: OpenCount: %u ReferCount: %u %s\n",
			Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->AnsiFileName.Buffer));

		Status = STATUS_SUCCESS;

		if (FileObject)
		{
			SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
		}
	}

	_SEH2_FINALLY
	{
	   
		if (FcbPagingIoAcquired)
		{
			ExReleaseResourceForThreadLite(
				&Fcb->PagingIoResource,
				ExGetCurrentResourceThread());
		}

		if (FcbResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
				&Fcb->MainResource,
				ExGetCurrentResourceThread());
		}

		if (VcbResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
				&Vcb->MainResource,
				ExGetCurrentResourceThread());
		}

		if (!IrpContext->ExceptionInProgress)
		{
			if (Status == STATUS_PENDING)
			{
				FFSQueueRequest(IrpContext);
			}
			else
			{
				IrpContext->Irp->IoStatus.Status = Status;

				FFSCompleteIrpContext(IrpContext, Status);
			}
		}
	} _SEH2_END;

	return Status;
}