VOID FFSFreeCcb( IN PFFS_CCB Ccb) { ASSERT(Ccb != NULL); ASSERT((Ccb->Identifier.Type == FFSCCB) && (Ccb->Identifier.Size == sizeof(FFS_CCB))); if (Ccb->DirectorySearchPattern.Buffer != NULL) { ExFreePool(Ccb->DirectorySearchPattern.Buffer); } if (FlagOn(Ccb->Flags, CCB_FROM_POOL)) { ExFreePool(Ccb); } else { ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); ExFreeToNPagedLookasideList(&(FFSGlobal->FFSCcbLookasideList), Ccb); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); } }
__drv_mustHoldCriticalRegion NTSTATUS RfsdPnpCancelRemove ( PRFSD_IRP_CONTEXT IrpContext, PRFSD_VCB Vcb ) { NTSTATUS Status; PAGED_CODE(); RfsdPrint((DBG_PNP, "RfsdPnpCancelRemove by RfsdPnp ...\n")); ExAcquireResourceExclusiveLite( &Vcb->MainResource, TRUE ); Status = RfsdUnlockVcb(Vcb, IrpContext->FileObject); ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread()); IoSkipCurrentIrpStackLocation(IrpContext->Irp); Status = IoCallDriver(Vcb->TargetDeviceObject, IrpContext->Irp); IrpContext->Irp = NULL; return Status; }
__drv_mustHoldCriticalRegion VOID FFSFreeMcb( IN PFFS_MCB Mcb) { #ifndef __REACTOS__ PFFS_MCB Parent = Mcb->Parent; #endif PAGED_CODE(); ASSERT(Mcb != NULL); ASSERT((Mcb->Identifier.Type == FFSMCB) && (Mcb->Identifier.Size == sizeof(FFS_MCB))); FFSPrint((DBG_INFO, "FFSFreeMcb: Mcb %S will be freed.\n", Mcb->ShortName.Buffer)); if (Mcb->ShortName.Buffer) ExFreePool(Mcb->ShortName.Buffer); if (FlagOn(Mcb->Flags, MCB_FROM_POOL)) { ExFreePool(Mcb); } else { ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); ExFreeToPagedLookasideList(&(FFSGlobal->FFSMcbLookasideList), Mcb); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); } ExAcquireResourceExclusiveLite( &FFSGlobal->CountResource, TRUE); FFSGlobal->McbAllocated--; ExReleaseResourceForThreadLite( &FFSGlobal->CountResource, ExGetCurrentResourceThread()); }
__drv_mustHoldCriticalRegion PFFS_CCB FFSAllocateCcb( VOID) { PFFS_CCB Ccb; PAGED_CODE(); ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); Ccb = (PFFS_CCB)(ExAllocateFromNPagedLookasideList(&(FFSGlobal->FFSCcbLookasideList))); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); if (Ccb == NULL) { Ccb = (PFFS_CCB)ExAllocatePoolWithTag(NonPagedPool, sizeof(FFS_CCB), FFS_POOL_TAG); RtlZeroMemory(Ccb, sizeof(FFS_CCB)); SetFlag(Ccb->Flags, CCB_FROM_POOL); } else { RtlZeroMemory(Ccb, sizeof(FFS_CCB)); } if (!Ccb) { return NULL; } Ccb->Identifier.Type = FFSCCB; Ccb->Identifier.Size = sizeof(FFS_CCB); Ccb->CurrentByteOffset = 0; Ccb->DirectorySearchPattern.Length = 0; Ccb->DirectorySearchPattern.MaximumLength = 0; Ccb->DirectorySearchPattern.Buffer = 0; return Ccb; }
__drv_mustHoldCriticalRegion VOID FFSFreeIrpContext( IN PFFS_IRP_CONTEXT IrpContext) { PAGED_CODE(); ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); FFSUnpinRepinnedBcbs(IrpContext); // Return the Irp context record to the region or to pool depending on // its flag if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_FROM_POOL)) { IrpContext->Identifier.Type = 0; IrpContext->Identifier.Size = 0; ExFreePool(IrpContext); } else { IrpContext->Identifier.Type = 0; IrpContext->Identifier.Size = 0; ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); ExFreeToNPagedLookasideList(&(FFSGlobal->FFSIrpContextLookasideList), IrpContext); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); } }
__drv_mustHoldCriticalRegion NTSTATUS RfsdPurgeVolume (IN PRFSD_VCB Vcb, IN BOOLEAN FlushBeforePurge ) { PRFSD_FCB Fcb; LIST_ENTRY FcbList; PLIST_ENTRY ListEntry; PFCB_LIST_ENTRY FcbListEntry; PAGED_CODE(); _SEH2_TRY { ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == RFSDVCB) && (Vcb->Identifier.Size == sizeof(RFSD_VCB))); if ( IsFlagOn(Vcb->Flags, VCB_READ_ONLY) || IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) { FlushBeforePurge = FALSE; } FcbListEntry= NULL; InitializeListHead(&FcbList); for (ListEntry = Vcb->FcbList.Flink; ListEntry != &Vcb->FcbList; ListEntry = ListEntry->Flink ) { Fcb = CONTAINING_RECORD(ListEntry, RFSD_FCB, Next); Fcb->ReferenceCount++; RfsdPrint((DBG_INFO, "RfsdPurgeVolume: %s refercount=%xh\n", Fcb->AnsiFileName.Buffer, Fcb->ReferenceCount)); FcbListEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FCB_LIST_ENTRY), RFSD_POOL_TAG); if (FcbListEntry) { FcbListEntry->Fcb = Fcb; InsertTailList(&FcbList, &FcbListEntry->Next); } else { RfsdPrint((DBG_ERROR, "RfsdPurgeVolume: Error allocating FcbListEntry ...\n")); } } while (!IsListEmpty(&FcbList)) { ListEntry = RemoveHeadList(&FcbList); FcbListEntry = CONTAINING_RECORD(ListEntry, FCB_LIST_ENTRY, Next); Fcb = FcbListEntry->Fcb; if (ExAcquireResourceExclusiveLite( &Fcb->MainResource, TRUE )) { RfsdPurgeFile(Fcb, FlushBeforePurge); if (!Fcb->OpenHandleCount && Fcb->ReferenceCount == 1) { RemoveEntryList(&Fcb->Next); RfsdFreeFcb(Fcb); } else { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread()); } } ExFreePool(FcbListEntry); } if (FlushBeforePurge) { ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Vcb->PagingIoResource); CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL); } if (Vcb->SectionObject.ImageSectionObject) { MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite); } if (Vcb->SectionObject.DataSectionObject) { CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE); } RfsdPrint((DBG_INFO, "RfsdPurgeVolume: Volume flushed and purged.\n")); } _SEH2_FINALLY { // Nothing } _SEH2_END; return STATUS_SUCCESS; }
__drv_mustHoldCriticalRegion BOOLEAN RfsdCheckDismount ( IN PRFSD_IRP_CONTEXT IrpContext, IN PRFSD_VCB Vcb, IN BOOLEAN bForce ) { KIRQL Irql; PVPB Vpb = Vcb->Vpb; BOOLEAN bDeleted = FALSE; ULONG UnCleanCount = 0; PAGED_CODE(); ExAcquireResourceExclusiveLite( &RfsdGlobal->Resource, TRUE ); ExAcquireResourceExclusiveLite( &Vcb->MainResource, TRUE ); if ((IrpContext->MajorFunction == IRP_MJ_CREATE) && (IrpContext->RealDevice == Vcb->RealDevice)) { UnCleanCount = 3; } else { UnCleanCount = 2; } IoAcquireVpbSpinLock (&Irql); if ((Vpb->ReferenceCount == UnCleanCount) || bForce) { if ((Vpb->ReferenceCount != UnCleanCount) && bForce) { KdPrint(("RfsdCheckDismount: force dismount ...\n")); } ClearFlag( Vpb->Flags, VPB_MOUNTED ); ClearFlag( Vpb->Flags, VPB_LOCKED ); #ifdef _MSC_VER #pragma prefast( suppress: 28175, "allowed in file system drivers" ) #endif if ((Vcb->RealDevice != Vpb->RealDevice) && (Vcb->RealDevice->Vpb == Vpb)) { SetFlag( Vcb->RealDevice->Flags, DO_DEVICE_INITIALIZING ); SetFlag( Vpb->Flags, VPB_PERSISTENT ); } RfsdRemoveVcb(Vcb); ClearFlag(Vpb->Flags, VPB_MOUNTED); SetFlag(Vcb->Flags, VCB_DISMOUNT_PENDING); Vpb->DeviceObject = NULL; bDeleted = TRUE; } IoReleaseVpbSpinLock(Irql); ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread() ); ExReleaseResourceForThreadLite( &RfsdGlobal->Resource, ExGetCurrentResourceThread() ); if (bDeleted) { KdPrint(("RfsdCheckDismount: now free the vcb ...\n")); RfsdFreeVcb(Vcb); } return bDeleted; }
BOOLEAN ExAcquireResourceExclusive( IN PNTDDK_ERESOURCE Resource, IN BOOLEAN Wait ) /*++ Routine Description: The routine acquires the resource for exclusive access. Upon return from the procedure the resource is acquired for exclusive access. Arguments: Resource - Supplies the resource to acquire Wait - Indicates if the call is allowed to wait for the resource to become available for must return immediately Return Value: BOOLEAN - TRUE if the resource is acquired and FALSE otherwise --*/ { KIRQL OldIrql; ERESOURCE_THREAD OurThread; ASSERTMSG("Routine cannot be called at DPC ", !KeIsExecutingDpc() ); ASSERT((Resource->Flag & ResourceNeverExclusive) == 0); OurThread = (ULONG_PTR)ExGetCurrentResourceThread(); // // Get exclusive access to this resource structure // AcquireResourceLock( Resource, &OldIrql ); // // Loop until the resource is ours or exit if we cannot wait. // while (TRUE) { if (Resource->ActiveCount == 0) { // // Resource is un-owned, obtain it exclusive // Resource->InitialOwnerThreads[0] = OurThread; Resource->OwnerThreads[0] = OurThread; Resource->OwnerCounts[0] = 1; Resource->ActiveCount = 1; Resource->Flag |= ResourceOwnedExclusive; ReleaseResourceLock ( Resource, OldIrql ); return TRUE; } if (IsOwnedExclusive(Resource) && Resource->OwnerThreads[0] == OurThread) { // // Our thread is already the exclusive resource owner // Resource->OwnerCounts[0] += 1; ReleaseResourceLock( Resource, OldIrql ); return TRUE; } // // Check if we are allowed to wait or must return immediately, and // indicate that we didn't acquire the resource // if (!Wait) { ReleaseResourceLock( Resource, OldIrql ); return FALSE; } // // Otherwise we need to wait to acquire the resource. // WaitForResourceExclusive ( Resource, OldIrql ); } }
__drv_mustHoldCriticalRegion NTSTATUS RfsdDismountVolume (IN PRFSD_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PRFSD_VCB Vcb = 0; BOOLEAN VcbResourceAcquired = FALSE; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == RFSDICX) && (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (DeviceObject == RfsdGlobal->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == RFSDVCB) && (Vcb->Identifier.Size == sizeof(RFSD_VCB))); ASSERT(IsMounted(Vcb)); ExAcquireResourceExclusiveLite( &Vcb->MainResource, TRUE ); VcbResourceAcquired = TRUE; if ( IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) { Status = STATUS_VOLUME_DISMOUNTED; _SEH2_LEAVE; } /* if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { RfsdPrint((DBG_ERROR, "RfsdDismount: Volume is not locked.\n")); Status = STATUS_ACCESS_DENIED; _SEH2_LEAVE; } */ #if DISABLED RfsdFlushFiles(Vcb, FALSE); RfsdFlushVolume(Vcb, FALSE); RfsdPurgeVolume(Vcb, TRUE); #endif ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread() ); VcbResourceAcquired = FALSE; RfsdCheckDismount(IrpContext, Vcb, TRUE); RfsdPrint((DBG_INFO, "RfsdDismount: Volume dismount pending.\n")); Status = STATUS_SUCCESS; } _SEH2_FINALLY { if (VcbResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread() ); } if (!IrpContext->ExceptionInProgress) { RfsdCompleteIrpContext(IrpContext, Status); } } _SEH2_END; return Status; }
__drv_mustHoldCriticalRegion NTSTATUS RfsdMountVolume (IN PRFSD_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT MainDeviceObject; BOOLEAN GlobalDataResourceAcquired = FALSE; PIRP Irp; PIO_STACK_LOCATION IoStackLocation; PDEVICE_OBJECT TargetDeviceObject; NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME; PDEVICE_OBJECT VolumeDeviceObject = NULL; PRFSD_VCB Vcb; PRFSD_SUPER_BLOCK RfsdSb = NULL; ULONG dwBytes; DISK_GEOMETRY DiskGeometry; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == RFSDICX) && (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT))); MainDeviceObject = IrpContext->DeviceObject; // // Make sure we can wait. // SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); // // This request is only allowed on the main device object // if (MainDeviceObject != RfsdGlobal->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } ExAcquireResourceExclusiveLite( &(RfsdGlobal->Resource), TRUE ); GlobalDataResourceAcquired = TRUE; if (FlagOn(RfsdGlobal->Flags, RFSD_UNLOAD_PENDING)) { Status = STATUS_UNRECOGNIZED_VOLUME; _SEH2_LEAVE; } Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); TargetDeviceObject = IoStackLocation->Parameters.MountVolume.DeviceObject; dwBytes = sizeof(DISK_GEOMETRY); Status = RfsdDiskIoControl( TargetDeviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DiskGeometry, &dwBytes ); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } Status = IoCreateDevice( MainDeviceObject->DriverObject, sizeof(RFSD_VCB), NULL, FILE_DEVICE_DISK_FILE_SYSTEM, 0, FALSE, &VolumeDeviceObject ); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1); if (TargetDeviceObject->AlignmentRequirement > VolumeDeviceObject->AlignmentRequirement) { VolumeDeviceObject->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement; } (IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject = VolumeDeviceObject; Vcb = (PRFSD_VCB) VolumeDeviceObject->DeviceExtension; RtlZeroMemory(Vcb, sizeof(RFSD_VCB)); Vcb->Identifier.Type = RFSDVCB; Vcb->Identifier.Size = sizeof(RFSD_VCB); Vcb->TargetDeviceObject = TargetDeviceObject; Vcb->DiskGeometry = DiskGeometry; RfsdSb = RfsdLoadSuper(Vcb, FALSE); if (RfsdSb) { if ( SuperblockContainsMagicKey(RfsdSb) ) { RfsdPrint((DBG_INFO, "Volume of ReiserFS rfsd file system is found.\n")); Status = STATUS_SUCCESS; } else { Status = STATUS_UNRECOGNIZED_VOLUME; } } if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } Vcb->BlockSize = RfsdSb->s_blocksize; // NOTE: FFS also does this here, since LoadGroup is not called in the non-ext2 drivers Vcb->GroupDesc = NULL; // NOTE: GroupDesc is not used for ReiserFS. Setting it to NULL will keep other code from barfing. // Vcb->SectorBits = RFSDLog(SECTOR_SIZE); // NOTE: SectorBits are unused for ReiserFS Status = RfsdInitializeVcb(IrpContext, Vcb, RfsdSb, TargetDeviceObject, VolumeDeviceObject, IoStackLocation->Parameters.MountVolume.Vpb); if (NT_SUCCESS(Status)) { if (RfsdIsMediaWriteProtected(IrpContext, TargetDeviceObject)) { SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED); } else { ClearFlag(Vcb->Flags, VCB_WRITE_PROTECTED); } SetFlag(Vcb->Flags, VCB_MOUNTED); RfsdInsertVcb(Vcb); ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING); } } _SEH2_FINALLY { if (GlobalDataResourceAcquired) { ExReleaseResourceForThreadLite( &RfsdGlobal->Resource, ExGetCurrentResourceThread() ); } if (!NT_SUCCESS(Status)) { if (RfsdSb) { ExFreePool(RfsdSb); } if (VolumeDeviceObject) { IoDeleteDevice(VolumeDeviceObject); } } if (!IrpContext->ExceptionInProgress) { if (NT_SUCCESS(Status)) { ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING); } RfsdCompleteIrpContext(IrpContext, Status); } } _SEH2_END; return Status; }
PFFS_IRP_CONTEXT FFSAllocateIrpContext( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION IoStackLocation; PFFS_IRP_CONTEXT IrpContext; ASSERT(DeviceObject != NULL); ASSERT(Irp != NULL); IoStackLocation = IoGetCurrentIrpStackLocation(Irp); ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); IrpContext = (PFFS_IRP_CONTEXT)(ExAllocateFromNPagedLookasideList(&(FFSGlobal->FFSIrpContextLookasideList))); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); if (IrpContext == NULL) { IrpContext = ExAllocatePool(NonPagedPool, sizeof(FFS_IRP_CONTEXT)); // // Zero out the irp context and indicate that it is from pool and // not region allocated // RtlZeroMemory(IrpContext, sizeof(FFS_IRP_CONTEXT)); SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_FROM_POOL); } else { // // Zero out the irp context and indicate that it is from zone and // not pool allocated // RtlZeroMemory(IrpContext, sizeof(FFS_IRP_CONTEXT)); } if (!IrpContext) { return NULL; } IrpContext->Identifier.Type = FFSICX; IrpContext->Identifier.Size = sizeof(FFS_IRP_CONTEXT); IrpContext->Irp = Irp; IrpContext->MajorFunction = IoStackLocation->MajorFunction; IrpContext->MinorFunction = IoStackLocation->MinorFunction; IrpContext->DeviceObject = DeviceObject; IrpContext->FileObject = IoStackLocation->FileObject; if (IrpContext->FileObject != NULL) { IrpContext->RealDevice = IrpContext->FileObject->DeviceObject; } else if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) { if (IoStackLocation->Parameters.MountVolume.Vpb) { IrpContext->RealDevice = IoStackLocation->Parameters.MountVolume.Vpb->RealDevice; } } if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL || IrpContext->MajorFunction == IRP_MJ_DEVICE_CONTROL || IrpContext->MajorFunction == IRP_MJ_SHUTDOWN) { IrpContext->IsSynchronous = TRUE; } else if (IrpContext->MajorFunction == IRP_MJ_CLEANUP || IrpContext->MajorFunction == IRP_MJ_CLOSE) { IrpContext->IsSynchronous = FALSE; } #if (_WIN32_WINNT >= 0x0500) else if (IrpContext->MajorFunction == IRP_MJ_PNP) { if (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL) { IrpContext->IsSynchronous = TRUE; } else { IrpContext->IsSynchronous = IoIsOperationSynchronous(Irp); } } #endif //(_WIN32_WINNT >= 0x0500) else { IrpContext->IsSynchronous = IoIsOperationSynchronous(Irp); } #if 0 // // Temporary workaround for a bug in close that makes it reference a // fileobject when it is no longer valid. // if (IrpContext->MajorFunction == IRP_MJ_CLOSE) { IrpContext->IsSynchronous = TRUE; } #endif IrpContext->IsTopLevel = (IoGetTopLevelIrp() == Irp); IrpContext->ExceptionInProgress = FALSE; return IrpContext; }
__drv_mustHoldCriticalRegion NTSTATUS FFSNotifyChangeDirectory( IN PFFS_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; BOOLEAN CompleteRequest; NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_VCB Vcb; PFILE_OBJECT FileObject; PFFS_FCB Fcb = 0; PIRP Irp; PIO_STACK_LOCATION IrpSp; ULONG CompletionFilter; BOOLEAN WatchTree; BOOLEAN bFcbAcquired = FALSE; PUNICODE_STRING FullName; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); // // Always set the wait flag in the Irp context for the original request. // SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); DeviceObject = IrpContext->DeviceObject; if (DeviceObject == FFSGlobal->DeviceObject) { CompleteRequest = TRUE; 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); if (Fcb->Identifier.Type == FFSVCB) { FFSBreakPoint(); CompleteRequest = TRUE; Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } ASSERT((Fcb->Identifier.Type == FFSFCB) && (Fcb->Identifier.Size == sizeof(FFS_FCB))); if (!IsDirectory(Fcb)) { FFSBreakPoint(); CompleteRequest = TRUE; Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } if (ExAcquireResourceExclusiveLite( &Fcb->MainResource, TRUE)) { bFcbAcquired = TRUE; } else { Status = STATUS_PENDING; _SEH2_LEAVE; } Irp = IrpContext->Irp; IrpSp = IoGetCurrentIrpStackLocation(Irp); #if !defined(_GNU_NTIFS_) || defined(__REACTOS__) CompletionFilter = IrpSp->Parameters.NotifyDirectory.CompletionFilter; #else // _GNU_NTIFS_ CompletionFilter = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.NotifyDirectory.CompletionFilter; #endif // _GNU_NTIFS_ WatchTree = IsFlagOn(IrpSp->Flags, SL_WATCH_TREE); if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { Status = STATUS_DELETE_PENDING; _SEH2_LEAVE; } FullName = &Fcb->LongName; if (FullName->Buffer == NULL) { if (!FFSGetFullFileName(Fcb->FFSMcb, FullName)) { Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } } FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->NotifyList, FileObject->FsContext2, (PSTRING)FullName, WatchTree, FALSE, CompletionFilter, Irp, NULL, NULL); CompleteRequest = FALSE; Status = STATUS_PENDING; /* Currently the driver is read-only but here is an example on how to use the FsRtl-functions to report a change: ANSI_STRING TestString; USHORT FileNamePartLength; RtlInitAnsiString(&TestString, "\\ntifs.h"); FileNamePartLength = 7; FsRtlNotifyReportChange( Vcb->NotifySync, // PNOTIFY_SYNC NotifySync &Vcb->NotifyList, // PLIST_ENTRY NotifyList &TestString, // PSTRING FullTargetName &FileNamePartLength, // PUSHORT FileNamePartLength FILE_NOTIFY_CHANGE_NAME // ULONG FilterMatch ); or ANSI_STRING TestString; RtlInitAnsiString(&TestString, "\\ntifs.h"); FsRtlNotifyFullReportChange( Vcb->NotifySync, // PNOTIFY_SYNC NotifySync &Vcb->NotifyList, // PLIST_ENTRY NotifyList &TestString, // PSTRING FullTargetName 1, // USHORT TargetNameOffset NULL, // PSTRING StreamName OPTIONAL NULL, // PSTRING NormalizedParentName OPTIONAL FILE_NOTIFY_CHANGE_NAME, // ULONG FilterMatch 0, // ULONG Action NULL // PVOID TargetContext ); */ } _SEH2_FINALLY { if (bFcbAcquired) { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { if (!CompleteRequest) { IrpContext->Irp = NULL; } FFSCompleteIrpContext(IrpContext, Status); } } _SEH2_END; return Status; }
__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; }
PLBCB LfsGetLbcb ( IN PLFCB Lfcb ) /*++ Routine Description: This routine is called to add a Lbcb to the active queue. Arguments: Lfcb - This is the file control block for the log file. Return Value: PLBCB - Pointer to the Lbcb allocated. --*/ { PLBCB Lbcb = NULL; PVOID PageHeader; PBCB PageHeaderBcb = NULL; BOOLEAN WrappedOrUsaError; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsGetLbcb: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); // // Use a try-finally to facilitate cleanup. // try { // // Pin the desired record page. // LfsPreparePinWriteData( Lfcb, Lfcb->NextLogPage, (ULONG)Lfcb->LogPageSize, &PageHeader, &PageHeaderBcb ); // // Put our signature into the page so we won't fail if we // see a previous 'BAAD' signature. // *((PULONG) PageHeader) = LFS_SIGNATURE_RECORD_PAGE_ULONG; // // Now allocate an Lbcb. // LfsAllocateLbcb( Lfcb, &Lbcb ); // // If we are at the beginning of the file we test that the // sequence number won't wrap to 0. // if (!FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN | LFCB_REUSE_TAIL ) && ( Lfcb->NextLogPage == Lfcb->FirstLogPage )) { Lfcb->SeqNumber = Lfcb->SeqNumber + 1; // // If the sequence number is going from 0 to 1, then // this is the first time the log file has wrapped. We want // to remember this because it means that we can now do // large spiral writes. // if (Int64ShllMod32( Lfcb->SeqNumber, Lfcb->FileDataBits ) == 0) { LfsDebugTrace( 0, Dbg, "Log sequence number about to wrap: Lfcb -> %08lx\n", Lfcb ); KeBugCheck( FILE_SYSTEM ); } // // If this number is greater or equal to the wrap sequence number in // the Lfcb, set the wrap flag in the Lbcb. // if (!FlagOn( Lfcb->Flags, LFCB_LOG_WRAPPED ) && ( Lfcb->SeqNumber >= Lfcb->SeqNumberForWrap )) { SetFlag( Lbcb->LbcbFlags, LBCB_LOG_WRAPPED ); SetFlag( Lfcb->Flags, LFCB_LOG_WRAPPED ); } } // // Now initialize the rest of the Lbcb fields. // Lbcb->FileOffset = Lfcb->NextLogPage; Lbcb->SeqNumber = Lfcb->SeqNumber; Lbcb->BufferOffset = Lfcb->LogPageDataOffset; // // Store the next page in the Lfcb. // LfsNextLogPageOffset( Lfcb, Lfcb->NextLogPage, &Lfcb->NextLogPage, &WrappedOrUsaError ); Lbcb->Length = Lfcb->LogPageSize; Lbcb->PageHeader = PageHeader; Lbcb->LogPageBcb = PageHeaderBcb; Lbcb->ResourceThread = ExGetCurrentResourceThread(); // // If we are reusing a previous page then set a flag in // the Lbcb to indicate that we should flush a copy // first. // if (FlagOn( Lfcb->Flags, LFCB_REUSE_TAIL )) { SetFlag( Lbcb->LbcbFlags, LBCB_FLUSH_COPY ); ClearFlag( Lfcb->Flags, LFCB_REUSE_TAIL ); (ULONG)Lbcb->BufferOffset = Lfcb->ReusePageOffset; Lbcb->Flags = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Flags; Lbcb->LastLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Copy.LastLsn; Lbcb->LastEndLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Header.Packed.LastEndLsn; } // // Put the Lbcb on the active queue // InsertTailList( &Lfcb->LbcbActive, &Lbcb->ActiveLinks ); SetFlag( Lbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE ); } finally { DebugUnwind( LfsGetLbcb ); // // If an error occurred, we need to clean up any blocks which // have not been added to the active queue. // if (AbnormalTermination()) { if (Lbcb != NULL) { LfsDeallocateLbcb( Lfcb, Lbcb ); Lbcb = NULL; } // // Unpin the system page if pinned. // if (PageHeaderBcb != NULL) { CcUnpinData( PageHeaderBcb ); } } LfsDebugTrace( -1, Dbg, "LfsGetLbcb: Exit\n", 0 ); } return Lbcb; }
NTSTATUS FatCommonRead ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common read routine for NtReadFile, called from both the Fsd, or from the Fsp if a request could not be completed without blocking in the Fsd. This routine has no code where it determines whether it is running in the Fsd or Fsp. Instead, its actions are conditionalized by the Wait input parameter, which determines whether it is allowed to block or not. If a blocking condition is encountered with Wait == FALSE, however, the request is posted to the Fsp, who always calls with WAIT == TRUE. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { PVCB Vcb; PFCB FcbOrDcb; PCCB Ccb; VBO StartingVbo; ULONG ByteCount; ULONG RequestedByteCount; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfRead; BOOLEAN PostIrp = FALSE; BOOLEAN OplockPostIrp = FALSE; BOOLEAN FcbOrDcbAcquired = FALSE; BOOLEAN Wait; BOOLEAN PagingIo; BOOLEAN NonCachedIo; BOOLEAN SynchronousIo; NTSTATUS Status; FAT_IO_CONTEXT StackFatIoContext; // // A system buffer is only used if we have to access the // buffer directly from the Fsp to clear a portion or to // do a synchronous I/O, or a cached transfer. It is // possible that our caller may have already mapped a // system buffer, in which case we must remember this so // we do not unmap it on the way out. // PVOID SystemBuffer = NULL; LARGE_INTEGER StartingByte; // // Get current Irp stack location. // IrpSp = IoGetCurrentIrpStackLocation( Irp ); FileObject = IrpSp->FileObject; // // Initialize the appropriate local variables. // Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); NonCachedIo = BooleanFlagOn(Irp->Flags,IRP_NOCACHE); SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); DebugTrace(+1, Dbg, "CommonRead\n", 0); DebugTrace( 0, Dbg, " Irp = %8lx\n", Irp); DebugTrace( 0, Dbg, " ->ByteCount = %8lx\n", IrpSp->Parameters.Read.Length); DebugTrace( 0, Dbg, " ->ByteOffset.LowPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.LowPart); DebugTrace( 0, Dbg, " ->ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.HighPart); // // Extract starting Vbo and offset. // StartingByte = IrpSp->Parameters.Read.ByteOffset; StartingVbo = StartingByte.LowPart; ByteCount = IrpSp->Parameters.Read.Length; RequestedByteCount = ByteCount; // // Check for a null request, and return immediately // if (ByteCount == 0) { Irp->IoStatus.Information = 0; FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); return STATUS_SUCCESS; } // // Check for a non-zero high part offset // if ( StartingByte.HighPart != 0 ) { Irp->IoStatus.Information = 0; FatCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE ); return STATUS_END_OF_FILE; } // // Extract the nature of the read from the file object, and case on it // TypeOfRead = FatDecodeFileObject(FileObject, &Vcb, &FcbOrDcb, &Ccb); // // Collect interesting statistics. The FLAG_USER_IO bit will indicate // what type of io we're doing in the FatNonCachedIo function. // if (PagingIo) { CollectReadStats(Vcb, TypeOfRead, ByteCount); if (TypeOfRead == UserFileOpen) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO); } else { ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO); } } // // If there is a previous STACK FatIoContext pointer, NULL it. // if ((IrpContext->FatIoContext != NULL) && FlagOn(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT)) { IrpContext->FatIoContext = NULL; } // // Allocate if necessary and initialize a FAT_IO_CONTEXT block for // all non cached Io, except Cvf file Io. For synchronous Io // we use stack storage, otherwise we allocate pool. // if (NonCachedIo && !(FcbOrDcb && FlagOn(FcbOrDcb->FcbState, FCB_STATE_COMPRESSED_VOLUME_FILE))) { if (IrpContext->FatIoContext == NULL) { if (!Wait) { IrpContext->FatIoContext = FsRtlAllocatePool( NonPagedPool, sizeof(FAT_IO_CONTEXT) ); } else { IrpContext->FatIoContext = &StackFatIoContext; SetFlag( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT ); } } RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) ); if (Wait) { KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent, NotificationEvent, FALSE ); } else { IrpContext->FatIoContext->Wait.Async.ResourceThreadId = ExGetCurrentResourceThread(); IrpContext->FatIoContext->Wait.Async.RequestedByteCount = ByteCount; IrpContext->FatIoContext->Wait.Async.FileObject = FileObject; } } // // These two cases correspond to either a general opened volume, ie. // open ("a:"), or a read of the volume file (boot sector + fat(s)) // if ((TypeOfRead == VirtualVolumeFile) || (TypeOfRead == UserVolumeOpen)) { DebugTrace(0, Dbg, "Type of read is User Volume or virtual volume file\n", 0); if (TypeOfRead == UserVolumeOpen) { // // Verify that the volume for this handle is still valid // FatQuickVerifyVcb( IrpContext, Vcb ); if (!FlagOn( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE )) { (VOID)ExAcquireResourceExclusive( &Vcb->Resource, TRUE ); try { // // If the volume isn't locked, flush it. // if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) { FatFlushVolume( IrpContext, Vcb ); } } finally { ExReleaseResource( &Vcb->Resource ); } SetFlag( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE ); }
NTSTATUS NtfsCompleteMdl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This routine performs the function of completing Mdl read and write requests. It should be called only from NtfsFsdRead and NtfsFsdWrite. Arguments: Irp - Supplies the originating Irp. Return Value: NTSTATUS - Will always be STATUS_PENDING or STATUS_SUCCESS. --*/ { PFILE_OBJECT FileObject; PIO_STACK_LOCATION IrpSp; PNTFS_ADVANCED_FCB_HEADER Header; ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL )); PAGED_CODE(); DebugTrace( +1, Dbg, ("NtfsCompleteMdl\n") ); DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) ); DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) ); // // Do completion processing. // FileObject = IoGetCurrentIrpStackLocation( Irp )->FileObject; switch( IrpContext->MajorFunction ) { case IRP_MJ_READ: CcMdlReadComplete( FileObject, Irp->MdlAddress ); break; case IRP_MJ_WRITE: try { PSCB Scb; VBO StartingVbo; LONGLONG ByteCount; LONGLONG ByteRange; BOOLEAN DoingIoAtEof = FALSE; ASSERT( FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT )); IrpSp = IoGetCurrentIrpStackLocation( Irp ); Scb = (PSCB)(IrpSp->FileObject->FsContext); Header = &(Scb->Header); // // Now synchronize with the FsRtl Header and Scb. // if (Header->PagingIoResource != NULL) { StartingVbo = IrpSp->Parameters.Write.ByteOffset.QuadPart; ByteCount = (LONGLONG) IrpSp->Parameters.Write.Length; ByteRange = StartingVbo + ByteCount + PAGE_SIZE - 1; ClearFlag( ((ULONG) ByteRange), PAGE_SIZE - 1 ); ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE ); NtfsAcquireFsrtlHeader( Scb ); // // Now see if this is at EOF. // Recursive flush will generate IO which ends on page boundary // which is why we rounded the range // if (ByteRange > Header->ValidDataLength.QuadPart) { // // Mark that we are writing to EOF. If someone else is currently // writing to EOF, wait for them. // ASSERT( ByteRange - StartingVbo < MAXULONG ); DoingIoAtEof = !FlagOn( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ) || NtfsWaitForIoAtEof( Header, (PLARGE_INTEGER)&StartingVbo, (ULONG)(ByteRange - StartingVbo) ); if (DoingIoAtEof) { SetFlag( Header->Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE ); #if (DBG || defined( NTFS_FREE_ASSERTS )) ((PSCB) Header)->IoAtEofThread = (PERESOURCE_THREAD) ExGetCurrentResourceThread(); #endif // // Store this in the IrpContext until commit or post. // IrpContext->CleanupStructure = Scb; } } NtfsReleaseFsrtlHeader( Scb ); } CcMdlWriteComplete( FileObject, &IrpSp->Parameters.Write.ByteOffset, Irp->MdlAddress ); } finally { if (Header->PagingIoResource != NULL) { ExReleaseResourceLite( Header->PagingIoResource ); } } break; default: DebugTrace( DEBUG_TRACE_ERROR, 0, ("Illegal Mdl Complete.\n") ); ASSERTMSG("Illegal Mdl Complete, About to bugcheck ", FALSE); NtfsBugCheck( IrpContext->MajorFunction, 0, 0 ); } // // Mdl is now deallocated. // Irp->MdlAddress = NULL; // // Ignore errors. CC has already cleaned up his structures. // IrpContext->ExceptionStatus = STATUS_SUCCESS; NtfsMinimumExceptionProcessing( IrpContext ); // // Complete the request and exit right away. // NtfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); DebugTrace( -1, Dbg, ("NtfsCompleteMdl -> STATUS_SUCCESS\n") ); return STATUS_SUCCESS; }
__drv_mustHoldCriticalRegion NTSTATUS FFSMountVolume( IN PFFS_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT MainDeviceObject; BOOLEAN GlobalDataResourceAcquired = FALSE; PIRP Irp; PIO_STACK_LOCATION IoStackLocation; PDEVICE_OBJECT TargetDeviceObject; NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME; PDEVICE_OBJECT VolumeDeviceObject = NULL; PFFS_VCB Vcb; PFFS_SUPER_BLOCK FFSSb = NULL; ULONG dwBytes; DISK_GEOMETRY DiskGeometry; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); MainDeviceObject = IrpContext->DeviceObject; // // Make sure we can wait. // SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); // // This request is only allowed on the main device object // if (MainDeviceObject != FFSGlobal->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } ExAcquireResourceExclusiveLite( &(FFSGlobal->Resource), TRUE); GlobalDataResourceAcquired = TRUE; if (FlagOn(FFSGlobal->Flags, FFS_UNLOAD_PENDING)) { Status = STATUS_UNRECOGNIZED_VOLUME; _SEH2_LEAVE; } Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); TargetDeviceObject = IoStackLocation->Parameters.MountVolume.DeviceObject; dwBytes = sizeof(DISK_GEOMETRY); Status = FFSDiskIoControl( TargetDeviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DiskGeometry, &dwBytes); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } Status = IoCreateDevice( MainDeviceObject->DriverObject, sizeof(FFS_VCB), NULL, FILE_DEVICE_DISK_FILE_SYSTEM, 0, FALSE, &VolumeDeviceObject); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1); if (TargetDeviceObject->AlignmentRequirement > VolumeDeviceObject->AlignmentRequirement) { VolumeDeviceObject->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement; } (IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject = VolumeDeviceObject; Vcb = (PFFS_VCB)VolumeDeviceObject->DeviceExtension; RtlZeroMemory(Vcb, sizeof(FFS_VCB)); Vcb->Identifier.Type = FFSVCB; Vcb->Identifier.Size = sizeof(FFS_VCB); Vcb->TargetDeviceObject = TargetDeviceObject; Vcb->DiskGeometry = DiskGeometry; Status = FFSLoadDiskLabel(TargetDeviceObject, Vcb); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } FFSSb = Vcb->ffs_super_block; Vcb->BlockSize = FFSSb->fs_bsize; Vcb->SectorBits = FFSLog2(SECTOR_SIZE); Status = FFSInitializeVcb(IrpContext, Vcb, FFSSb, TargetDeviceObject, VolumeDeviceObject, IoStackLocation->Parameters.MountVolume.Vpb); if (NT_SUCCESS(Status)) { if (FFSIsMediaWriteProtected(IrpContext, TargetDeviceObject)) { SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED); } else { ClearFlag(Vcb->Flags, VCB_WRITE_PROTECTED); } SetFlag(Vcb->Flags, VCB_MOUNTED); FFSInsertVcb(Vcb); ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING); } } _SEH2_FINALLY { if (GlobalDataResourceAcquired) { ExReleaseResourceForThreadLite( &FFSGlobal->Resource, ExGetCurrentResourceThread()); } if (!NT_SUCCESS(Status)) { if (FFSSb) { ExFreePool(FFSSb); } if (VolumeDeviceObject) { IoDeleteDevice(VolumeDeviceObject); } } if (!IrpContext->ExceptionInProgress) { if (NT_SUCCESS(Status)) { ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING); } FFSCompleteIrpContext(IrpContext, Status); } } _SEH2_END; return Status; }
__drv_mustHoldCriticalRegion NTSTATUS RfsdUnlockVolume ( IN PRFSD_IRP_CONTEXT IrpContext ) { PIO_STACK_LOCATION IrpSp; PDEVICE_OBJECT DeviceObject; NTSTATUS Status; PRFSD_VCB Vcb = 0; BOOLEAN VcbResourceAcquired = FALSE; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == RFSDICX) && (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (DeviceObject == RfsdGlobal->DeviceObject) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == RFSDVCB) && (Vcb->Identifier.Size == sizeof(RFSD_VCB))); ASSERT(IsMounted(Vcb)); IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp); ExAcquireResourceExclusiveLite( &Vcb->MainResource, TRUE ); VcbResourceAcquired = TRUE; Status = RfsdUnlockVcb(Vcb, IrpSp->FileObject); } _SEH2_FINALLY { if (VcbResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread() ); } if (!IrpContext->ExceptionInProgress) { RfsdCompleteIrpContext(IrpContext, Status); } } _SEH2_END; return Status; }
__drv_mustHoldCriticalRegion NTSTATUS RfsdInvalidateVolumes ( IN PRFSD_IRP_CONTEXT IrpContext ) { NTSTATUS Status; PIRP Irp; PIO_STACK_LOCATION IrpSp; HANDLE Handle; PLIST_ENTRY ListEntry; PFILE_OBJECT FileObject; PDEVICE_OBJECT DeviceObject; BOOLEAN GlobalResourceAcquired = FALSE; LUID Privilege = {SE_TCB_PRIVILEGE, 0}; _SEH2_TRY { Irp = IrpContext->Irp; IrpSp = IoGetCurrentIrpStackLocation(Irp); if (!SeSinglePrivilegeCheck(Privilege, Irp->RequestorMode)) { Status = STATUS_PRIVILEGE_NOT_HELD; _SEH2_LEAVE; } if ( #ifndef _GNU_NTIFS_ IrpSp->Parameters.FileSystemControl.InputBufferLength #else ((PEXTENDED_IO_STACK_LOCATION)(IrpSp))-> Parameters.FileSystemControl.InputBufferLength #endif != sizeof(HANDLE)) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer; Status = ObReferenceObjectByHandle( Handle, 0, *IoFileObjectType, KernelMode, (void **)&FileObject, NULL ); if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } else { ObDereferenceObject(FileObject); DeviceObject = FileObject->DeviceObject; } RfsdPrint((DBG_INFO, "RfsdInvalidateVolumes: FileObject=%xh ...\n", FileObject)); ExAcquireResourceExclusiveLite( &RfsdGlobal->Resource, TRUE ); GlobalResourceAcquired = TRUE; ListEntry = RfsdGlobal->VcbList.Flink; while (ListEntry != &RfsdGlobal->VcbList) { PRFSD_VCB Vcb; Vcb = CONTAINING_RECORD(ListEntry, RFSD_VCB, Next); ListEntry = ListEntry->Flink; RfsdPrint((DBG_INFO, "RfsdInvalidateVolumes: Vcb=%xh Vcb->Vpb=%xh...\n", Vcb, Vcb->Vpb)); if (Vcb->Vpb && (Vcb->Vpb->RealDevice == DeviceObject)) { ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE); RfsdPrint((DBG_INFO, "RfsdInvalidateVolumes: RfsdPurgeVolume...\n")); RfsdPurgeVolume(Vcb, FALSE); ClearFlag(Vcb->Flags, VCB_MOUNTED); ExReleaseResourceLite(&Vcb->MainResource); // // Vcb is still attached on the list ...... // if (ListEntry->Blink == &Vcb->Next) { RfsdPrint((DBG_INFO, "RfsdInvalidateVolumes: RfsdCheckDismount...\n")); RfsdCheckDismount(IrpContext, Vcb, FALSE); } } } } _SEH2_FINALLY { if (GlobalResourceAcquired) { ExReleaseResourceForThreadLite( &RfsdGlobal->Resource, ExGetCurrentResourceThread() ); } RfsdCompleteIrpContext(IrpContext, Status); } _SEH2_END; return Status; }
PFFS_FCB FFSv2AllocateFcb( IN PFFS_VCB Vcb, IN PFFS_MCB FFSMcb, IN PFFSv2_INODE dinode2) { PFFS_FCB Fcb; ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); Fcb = (PFFS_FCB)(ExAllocateFromNPagedLookasideList(&(FFSGlobal->FFSFcbLookasideList))); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); if (Fcb == NULL) { Fcb = (PFFS_FCB)ExAllocatePool(NonPagedPool, sizeof(FFS_FCB)); RtlZeroMemory(Fcb, sizeof(FFS_FCB)); SetFlag(Fcb->Flags, FCB_FROM_POOL); } else { RtlZeroMemory(Fcb, sizeof(FFS_FCB)); } if (!Fcb) { return NULL; } Fcb->Identifier.Type = FFSFCB; Fcb->Identifier.Size = sizeof(FFS_FCB); FsRtlInitializeFileLock( &Fcb->FileLockAnchor, NULL, NULL); Fcb->OpenHandleCount = 0; Fcb->ReferenceCount = 0; Fcb->Vcb = Vcb; #if DBG Fcb->AnsiFileName.MaximumLength = (USHORT) RtlxUnicodeStringToOemSize(&(FFSMcb->ShortName)) + 1; Fcb->AnsiFileName.Buffer = (PUCHAR) ExAllocatePool(PagedPool, Fcb->AnsiFileName.MaximumLength); if (!Fcb->AnsiFileName.Buffer) { goto errorout; } RtlZeroMemory(Fcb->AnsiFileName.Buffer, Fcb->AnsiFileName.MaximumLength); FFSUnicodeToOEM(&(Fcb->AnsiFileName), &(FFSMcb->ShortName)); #endif FFSMcb->FileAttr = FILE_ATTRIBUTE_NORMAL; if ((dinode2->di_mode & IFMT) == IFDIR) { SetFlag(FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY); } if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY) || FFSIsReadOnly(dinode2->di_mode)) { SetFlag(FFSMcb->FileAttr, FILE_ATTRIBUTE_READONLY); } Fcb->dinode2 = dinode2; Fcb->FFSMcb = FFSMcb; FFSMcb->FFSFcb = Fcb; RtlZeroMemory(&Fcb->Header, sizeof(FSRTL_COMMON_FCB_HEADER)); Fcb->Header.NodeTypeCode = (USHORT)FFSFCB; Fcb->Header.NodeByteSize = sizeof(FFS_FCB); Fcb->Header.IsFastIoPossible = FastIoIsNotPossible; Fcb->Header.Resource = &(Fcb->MainResource); Fcb->Header.PagingIoResource = &(Fcb->PagingIoResource); { ULONG Totalblocks = (ULONG)(Fcb->dinode2->di_blocks); Fcb->Header.AllocationSize.QuadPart = (((LONGLONG)FFSDataBlocks(Vcb, Totalblocks)) << BLOCK_BITS); } Fcb->Header.FileSize.QuadPart = (LONGLONG)(Fcb->dinode2->di_size); Fcb->Header.ValidDataLength.QuadPart = (LONGLONG)(0x7fffffffffffffff); Fcb->SectionObject.DataSectionObject = NULL; Fcb->SectionObject.SharedCacheMap = NULL; Fcb->SectionObject.ImageSectionObject = NULL; ExInitializeResourceLite(&(Fcb->MainResource)); ExInitializeResourceLite(&(Fcb->PagingIoResource)); InsertTailList(&Vcb->FcbList, &Fcb->Next); #if DBG ExAcquireResourceExclusiveLite( &FFSGlobal->CountResource, TRUE); FFSGlobal->FcbAllocated++; ExReleaseResourceForThreadLite( &FFSGlobal->CountResource, ExGetCurrentResourceThread()); #endif return Fcb; #if DBG errorout: #endif if (Fcb) { #if DBG if (Fcb->AnsiFileName.Buffer) ExFreePool(Fcb->AnsiFileName.Buffer); #endif if (FlagOn(Fcb->Flags, FCB_FROM_POOL)) { ExFreePool(Fcb); } else { ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); ExFreeToNPagedLookasideList(&(FFSGlobal->FFSFcbLookasideList), Fcb); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); } } return NULL; }
__drv_mustHoldCriticalRegion NTSTATUS RfsdVerifyVolume (IN PRFSD_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PRFSD_SUPER_BLOCK rfsd_sb = NULL; PRFSD_VCB Vcb = 0; BOOLEAN VcbResourceAcquired = FALSE; BOOLEAN GlobalResourceAcquired = FALSE; PIRP Irp; PIO_STACK_LOCATION IoStackLocation; ULONG ChangeCount; ULONG dwReturn; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == RFSDICX) && (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (DeviceObject == RfsdGlobal->DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } ExAcquireResourceExclusiveLite( &RfsdGlobal->Resource, TRUE ); GlobalResourceAcquired = TRUE; Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == RFSDVCB) && (Vcb->Identifier.Size == sizeof(RFSD_VCB))); ExAcquireResourceExclusiveLite( &Vcb->MainResource, TRUE ); VcbResourceAcquired = TRUE; if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } if (!IsMounted(Vcb)) { Status = STATUS_WRONG_VOLUME; _SEH2_LEAVE; } dwReturn = sizeof(ULONG); Status = RfsdDiskIoControl( Vcb->TargetDeviceObject, IOCTL_DISK_CHECK_VERIFY, NULL, 0, &ChangeCount, &dwReturn ); if (ChangeCount != Vcb->ChangeCount) { Status = STATUS_WRONG_VOLUME; _SEH2_LEAVE; } Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); rfsd_sb = RfsdLoadSuper(Vcb, TRUE); // FUTURE: use the volume name and uuid from the extended superblock to make this happen. // NOTE: The magic check will have to use the same thing as mount did! if ((rfsd_sb != NULL) /*&& (rfsd_sb->s_magic == RFSD_SUPER_MAGIC) && (memcmp(rfsd_sb->s_uuid, SUPER_BLOCK->s_uuid, 16) == 0) && (memcmp(rfsd_sb->s_volume_name, SUPER_BLOCK->s_volume_name, 16) ==0)*/) { ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME); if (RfsdIsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) { SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED); } else { ClearFlag(Vcb->Flags, VCB_WRITE_PROTECTED); } RfsdPrint((DBG_INFO, "RfsdVerifyVolume: Volume verify succeeded.\n")); Status = STATUS_SUCCESS; } else { Status = STATUS_WRONG_VOLUME; RfsdPurgeVolume(Vcb, FALSE); SetFlag(Vcb->Flags, VCB_DISMOUNT_PENDING); ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME); RfsdPrint((DBG_INFO, "RfsdVerifyVolume: Volume verify failed.\n")); } } _SEH2_FINALLY { if (rfsd_sb) ExFreePool(rfsd_sb); if (VcbResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread() ); } if (GlobalResourceAcquired) { ExReleaseResourceForThreadLite( &RfsdGlobal->Resource, ExGetCurrentResourceThread() ); } if (!IrpContext->ExceptionInProgress) { RfsdCompleteIrpContext(IrpContext, Status); } } _SEH2_END; return Status; }
VOID FFSFreeFcb( IN PFFS_FCB Fcb) { PFFS_VCB Vcb; ASSERT(Fcb != NULL); ASSERT((Fcb->Identifier.Type == FFSFCB) && (Fcb->Identifier.Size == sizeof(FFS_FCB))); Vcb = Fcb->Vcb; FsRtlUninitializeFileLock(&Fcb->FileLockAnchor); ExDeleteResourceLite(&Fcb->MainResource); ExDeleteResourceLite(&Fcb->PagingIoResource); Fcb->FFSMcb->FFSFcb = NULL; if(IsFlagOn(Fcb->Flags, FCB_FILE_DELETED)) { if (Fcb->FFSMcb) { FFSDeleteMcbNode(Vcb, Fcb->FFSMcb->Parent, Fcb->FFSMcb); FFSFreeMcb(Fcb->FFSMcb); } } if (Fcb->LongName.Buffer) { ExFreePool(Fcb->LongName.Buffer); Fcb->LongName.Buffer = NULL; } #if DBG ExFreePool(Fcb->AnsiFileName.Buffer); #endif if (FS_VERSION == 1) { ExFreePool(Fcb->dinode1); } else { ExFreePool(Fcb->dinode2); } Fcb->Header.NodeTypeCode = (SHORT)0xCCCC; Fcb->Header.NodeByteSize = (SHORT)0xC0C0; if (FlagOn(Fcb->Flags, FCB_FROM_POOL)) { ExFreePool(Fcb); } else { ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); ExFreeToNPagedLookasideList(&(FFSGlobal->FFSFcbLookasideList), Fcb); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); } #if DBG ExAcquireResourceExclusiveLite( &FFSGlobal->CountResource, TRUE); FFSGlobal->FcbAllocated--; ExReleaseResourceForThreadLite( &FFSGlobal->CountResource, ExGetCurrentResourceThread()); #endif }
NTSTATUS Ext2ReadWriteBlocks( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_EXTENT Chain, IN ULONG Length ) { PIRP Irp; PIRP MasterIrp = IrpContext->Irp; PIO_STACK_LOCATION IrpSp; PMDL Mdl; PEXT2_RW_CONTEXT pContext = NULL; PEXT2_EXTENT Extent; KEVENT Wait; NTSTATUS Status = STATUS_SUCCESS; BOOLEAN bMasterCompleted = FALSE; BOOLEAN bBugCheck = FALSE; ASSERT(MasterIrp); __try { pContext = Ext2AllocatePool(NonPagedPool, sizeof(EXT2_RW_CONTEXT), EXT2_RWC_MAGIC); if (!pContext) { DEBUG(DL_ERR, ( "Ex2ReadWriteBlocks: failed to allocate pContext.\n")); Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } INC_MEM_COUNT(PS_RW_CONTEXT, pContext, sizeof(EXT2_RW_CONTEXT)); RtlZeroMemory(pContext, sizeof(EXT2_RW_CONTEXT)); pContext->Wait = Ext2CanIWait(); pContext->MasterIrp = MasterIrp; pContext->Length = Length; if (IrpContext->MajorFunction == IRP_MJ_WRITE) { SetFlag(pContext->Flags, EXT2_RW_CONTEXT_WRITE); } if (pContext->Wait) { KeInitializeEvent(&(pContext->Event), NotificationEvent, FALSE); } else if (IrpContext->Fcb->Identifier.Type == EXT2FCB) { if (IsFlagOn(MasterIrp->Flags, IRP_PAGING_IO)) { pContext->Resource = &IrpContext->Fcb->PagingIoResource; } else { pContext->Resource = &IrpContext->Fcb->MainResource; } pContext->FileObject = IrpContext->FileObject; pContext->ThreadId = ExGetCurrentResourceThread(); } if (NULL == Chain->Next && 0 == Chain->Offset) { /* we get only 1 extent to dispatch, then don't bother allocating new irps */ /* setup the Stack location to do a read from the disk driver. */ IrpSp = IoGetNextIrpStackLocation(MasterIrp); IrpSp->MajorFunction = IrpContext->MajorFunction; IrpSp->Parameters.Read.Length = Chain->Length; IrpSp->Parameters.Read.ByteOffset.QuadPart = Chain->Lba; if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) { SetFlag(IrpSp->Flags, SL_WRITE_THROUGH); } if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) { SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME); } IoSetCompletionRoutine( MasterIrp, Ext2CanIWait() ? Ext2ReadWriteBlockSyncCompletionRoutine : Ext2ReadWriteBlockAsyncCompletionRoutine, (PVOID) pContext, TRUE, TRUE, TRUE ); /* intialize context block */ Chain->Irp = MasterIrp; pContext->Blocks = 1; } else { for (Extent = Chain; Extent != NULL; Extent = Extent->Next) { Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(Vcb->TargetDeviceObject->StackSize + 1) ); if (!Irp) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } Mdl = IoAllocateMdl( (PCHAR)MasterIrp->UserBuffer + Extent->Offset, Extent->Length, FALSE, FALSE, Irp ); if (!Mdl) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } IoBuildPartialMdl( MasterIrp->MdlAddress, Mdl, (PCHAR)MasterIrp->UserBuffer +Extent->Offset, Extent->Length ); IoSetNextIrpStackLocation(Irp); IrpSp = IoGetCurrentIrpStackLocation(Irp); IrpSp->MajorFunction = IrpContext->MajorFunction; IrpSp->Parameters.Read.Length = Extent->Length; IrpSp->Parameters.Read.ByteOffset.QuadPart = Extent->Lba; IoSetCompletionRoutine( Irp, Ext2CanIWait() ? Ext2ReadWriteBlockSyncCompletionRoutine : Ext2ReadWriteBlockAsyncCompletionRoutine, (PVOID) pContext, TRUE, TRUE, TRUE ); IrpSp = IoGetNextIrpStackLocation(Irp); IrpSp->MajorFunction = IrpContext->MajorFunction; IrpSp->Parameters.Read.Length =Extent->Length; IrpSp->Parameters.Read.ByteOffset.QuadPart = Extent->Lba; /* set write through flag */ if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) { SetFlag( IrpSp->Flags, SL_WRITE_THROUGH ); } /* set verify flag */ if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) { SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME); } Extent->Irp = Irp; pContext->Blocks += 1; } MasterIrp->AssociatedIrp.IrpCount = pContext->Blocks; if (Ext2CanIWait()) { MasterIrp->AssociatedIrp.IrpCount += 1; } } if (!Ext2CanIWait()) { /* mark MasterIrp pending */ IoMarkIrpPending(pContext->MasterIrp); } bBugCheck = TRUE; for (Extent = Chain; Extent != NULL; Extent = Extent->Next) { Status = IoCallDriver ( Vcb->TargetDeviceObject, Extent->Irp); Extent->Irp = NULL; } if (Ext2CanIWait()) { KeWaitForSingleObject( &(pContext->Event), Executive, KernelMode, FALSE, NULL ); KeClearEvent( &(pContext->Event) ); } else { bMasterCompleted = TRUE; } } __finally { for (Extent = Chain; Extent != NULL; Extent = Extent->Next) { if (Extent->Irp != NULL ) { if (Extent->Irp->MdlAddress != NULL) { IoFreeMdl(Extent->Irp->MdlAddress ); } IoFreeIrp(Extent->Irp); } } if (IrpContext->ExceptionInProgress) { if (bBugCheck) { Ext2BugCheck(EXT2_BUGCHK_BLOCK, 0, 0, 0); } } else { if (Ext2CanIWait()) { if (MasterIrp) { Status = MasterIrp->IoStatus.Status; } if (pContext) { Ext2FreePool(pContext, EXT2_RWC_MAGIC); DEC_MEM_COUNT(PS_RW_CONTEXT, pContext, sizeof(EXT2_RW_CONTEXT)); } } else { if (bMasterCompleted) { IrpContext->Irp = NULL; Status = STATUS_PENDING; } } } } return Status; }
NTSTATUS Ext2FsdQueryVolumeInformation (IN PFSD_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; PFSD_VCB Vcb = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IrpSp = NULL; FS_INFORMATION_CLASS FsInformationClass; ULONG Length; PVOID SystemBuffer = NULL; BOOLEAN VcbResourceAcquired = FALSE; __try { ASSERT (IrpContext != NULL); ASSERT ((IrpContext->Identifier.Type == ICX) && (IrpContext->Identifier.Size == sizeof (FSD_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; ASSERT (DeviceObject); if (DeviceObject == FsdGlobalData.DeviceObject) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } Vcb = (PFSD_VCB) DeviceObject->DeviceExtension; ASSERT (Vcb != NULL); ASSERT ((Vcb->Identifier.Type == VCB) && (Vcb->Identifier.Size == sizeof (FSD_VCB))); if (!ExAcquireResourceSharedLite (&Vcb->MainResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } VcbResourceAcquired = TRUE; Irp = IrpContext->Irp; ASSERT (Irp); IrpSp = IoGetCurrentIrpStackLocation (Irp); ASSERT (IrpSp); FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass; Length = IrpSp->Parameters.QueryVolume.Length; SystemBuffer = Irp->AssociatedIrp.SystemBuffer; ASSERT (SystemBuffer); RtlZeroMemory (SystemBuffer, Length); switch (FsInformationClass) { case FileFsVolumeInformation: { PFILE_FS_VOLUME_INFORMATION Buffer; ULONG VolumeLabelLength; ULONG RequiredLength; if (Length < sizeof (FILE_FS_VOLUME_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; __leave; } #ifdef TRACE DbgPrint ("Ext2FsdQueryVolumeInformation : FileFsVolumeInformation\n"); #endif Buffer = (PFILE_FS_VOLUME_INFORMATION) SystemBuffer; Buffer->VolumeCreationTime.QuadPart = 0; Buffer->VolumeSerialNumber = 0xAFFE; //It's a joke! VolumeLabelLength = 4 + 1; //Ext2 doesn't have a volume label, so we take 'ext2' Buffer->VolumeLabelLength = VolumeLabelLength * 2; // I don't know what this means. Buffer->SupportsObjects = FALSE; RequiredLength = sizeof (FILE_FS_VOLUME_INFORMATION) + VolumeLabelLength * 2 - sizeof (WCHAR); if (Length < RequiredLength) { DbgPrint ("Ext2FsdQueryVolumeInformation[1] : L=%i RL=%i\n", Length, RequiredLength); Irp->IoStatus.Information = sizeof (FILE_FS_VOLUME_INFORMATION); Status = STATUS_BUFFER_OVERFLOW; __leave; } FsdCharToWchar (Buffer->VolumeLabel, "ext2", VolumeLabelLength); Irp->IoStatus.Information = RequiredLength; Status = STATUS_SUCCESS; __leave; } case FileFsSizeInformation: { PFILE_FS_SIZE_INFORMATION Buffer; #ifdef TRACE DbgPrint ("Ext2FsdQueryVolumeInformation : FileFsSizeInformation\n"); #endif if (Length < sizeof (FILE_FS_SIZE_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; __leave; } Buffer = (PFILE_FS_SIZE_INFORMATION) SystemBuffer; // On a readonly filesystem total size is the size of the // contents and available size is zero Buffer->TotalAllocationUnits.QuadPart = 0; //Vcb->ext2->superblock.s_blocks_count; Buffer->AvailableAllocationUnits.QuadPart = 0; //Vcb->ext2->block_size; Buffer->SectorsPerAllocationUnit = Vcb->ext2->block_size / Vcb->DiskGeometry.BytesPerSector; Buffer->BytesPerSector = Vcb->DiskGeometry.BytesPerSector; Irp->IoStatus.Information = sizeof (FILE_FS_SIZE_INFORMATION); Status = STATUS_SUCCESS; __leave; } case FileFsDeviceInformation: { PFILE_FS_DEVICE_INFORMATION Buffer; #ifdef TRACE DbgPrint ("Ext2FsdQueryVolumeInformation : FileFsDeviceInformation\n"); #endif if (Length < sizeof (FILE_FS_DEVICE_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; __leave; } Buffer = (PFILE_FS_DEVICE_INFORMATION) SystemBuffer; Buffer->DeviceType = Vcb->TargetDeviceObject->DeviceType; Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics; SetFlag (Buffer->Characteristics, FILE_READ_ONLY_DEVICE); Irp->IoStatus.Information = sizeof (FILE_FS_DEVICE_INFORMATION); Status = STATUS_SUCCESS; __leave; } case FileFsAttributeInformation: { PFILE_FS_ATTRIBUTE_INFORMATION Buffer; ULONG RequiredLength; #ifdef TRACE DbgPrint ("Ext2FsdQueryVolumeInformation : FileFsAttributeInformation\n"); #endif if (Length < sizeof (FILE_FS_ATTRIBUTE_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; __leave; } Buffer = (PFILE_FS_ATTRIBUTE_INFORMATION) SystemBuffer; Buffer->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_READ_ONLY_VOLUME; Buffer->MaximumComponentNameLength = EXT2_NAME_LEN; RequiredLength = sizeof (FILE_FS_ATTRIBUTE_INFORMATION) + sizeof (DRIVER_NAME) * 2 - sizeof (WCHAR); if (Length < RequiredLength) { Buffer->FileSystemNameLength = 0; Irp->IoStatus.Information = sizeof (FILE_FS_ATTRIBUTE_INFORMATION); DbgPrint ("Ext2FsdQueryVolumeInformation[1] : L=%i RL=%i\n", Length, RequiredLength); //Status = STATUS_BUFFER_OVERFLOW; //__leave; } else { Buffer->FileSystemNameLength = sizeof (DRIVER_NAME) * 2; FsdCharToWchar (Buffer->FileSystemName, DRIVER_NAME, sizeof (DRIVER_NAME)); Irp->IoStatus.Information = RequiredLength; } Status = STATUS_SUCCESS; __leave; } case FileFsFullSizeInformation: { PFILE_FS_FULL_SIZE_INFORMATION Buffer; #ifdef TRACE DbgPrint ("Ext2FsdQueryVolumeInformation : FileFsFullSizeInformation\n"); #endif if (Length < sizeof (FILE_FS_FULL_SIZE_INFORMATION)) { Status = STATUS_INFO_LENGTH_MISMATCH; __leave; } Buffer = (PFILE_FS_FULL_SIZE_INFORMATION) SystemBuffer; // On a readonly filesystem total size is the size of the // contents and available size is zero Buffer->TotalAllocationUnits.QuadPart = 0; //Vcb->ext2->superblock.s_blocks_count; Buffer->CallerAvailableAllocationUnits.QuadPart = 0; Buffer->ActualAvailableAllocationUnits.QuadPart = 0; Buffer->SectorsPerAllocationUnit = Vcb->ext2->block_size / Vcb->DiskGeometry.BytesPerSector; Buffer->BytesPerSector = Vcb->DiskGeometry.BytesPerSector; Irp->IoStatus.Information = sizeof (FILE_FS_FULL_SIZE_INFORMATION); Status = STATUS_SUCCESS; __leave; } default: Status = STATUS_INVALID_INFO_CLASS; } } __finally { if (VcbResourceAcquired) { ExReleaseResourceForThreadLite (&Vcb->MainResource, ExGetCurrentResourceThread ()); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { FsdQueueRequest (IrpContext); } else { IrpContext->Irp->IoStatus.Status = Status; FsdCompleteRequest (IrpContext->Irp, (CCHAR) (NT_SUCCESS (Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT)); Ext2FsdFreeIrpContext (IrpContext); } } } return Status; }
__drv_mustHoldCriticalRegion NTSTATUS RfsdCleanup (IN PRFSD_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_SUCCESS; PRFSD_VCB Vcb = 0; BOOLEAN VcbResourceAcquired = FALSE; PFILE_OBJECT FileObject; PRFSD_FCB Fcb = 0; BOOLEAN FcbResourceAcquired = FALSE; BOOLEAN FcbPagingIoAcquired = FALSE; PRFSD_CCB Ccb; PIRP Irp; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == RFSDICX) && (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; if (DeviceObject == RfsdGlobal->DeviceObject) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == RFSDVCB) && (Vcb->Identifier.Size == sizeof(RFSD_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 = (PRFSD_FCB) FileObject->FsContext; if (!Fcb) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } if (Fcb->Identifier.Type == RFSDVCB) { if (IsFlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) && (Vcb->LockFile == FileObject) ) { ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED); Vcb->LockFile = NULL; RfsdClearVpbFlag(Vcb->Vpb, VPB_LOCKED); } Vcb->OpenHandleCount--; if (!Vcb->OpenHandleCount) { IoRemoveShareAccess(FileObject, &Vcb->ShareAccess); } Status = STATUS_SUCCESS; _SEH2_LEAVE; } ASSERT((Fcb->Identifier.Type == RFSDFCB) && (Fcb->Identifier.Size == sizeof(RFSD_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 = (PRFSD_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 = RfsdFlushFile(Fcb); } _SEH2_LEAVE; } ASSERT((Ccb->Identifier.Type == RFSDCCB) && (Ccb->Identifier.Size == sizeof(RFSD_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) { RfsdPrint(( DBG_INFO, ": %-16.16s %-31s %s\n", RfsdGetCurrentProcessName(), "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 (Fcb->OpenHandleCount == 0) { if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { // // 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; DbgBreak(); #if DISABLED Status = RfsdDeleteFile(IrpContext, Vcb, Fcb); if (NT_SUCCESS(Status)) { if (IsDirectory(Fcb)) { RfsdNotifyReportChange( IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_REMOVED ); } else { RfsdNotifyReportChange( IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED ); } } #endif if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); SetFlag(FileObject->Flags, FO_FILE_MODIFIED); } if (FcbPagingIoAcquired) { ExReleaseResourceForThreadLite( &Fcb->PagingIoResource, ExGetCurrentResourceThread() ); FcbPagingIoAcquired = FALSE; } } } if (!IsDirectory(Fcb) && FileObject->PrivateCacheMap) { RfsdPrint((DBG_INFO, "RfsdCleanup: CcUninitializeCacheMap is called for %s.\n", Fcb->AnsiFileName.Buffer )); CcUninitializeCacheMap( FileObject, (PLARGE_INTEGER)(&(Fcb->Header.FileSize)), NULL ); } if (!Fcb->OpenHandleCount) { IoRemoveShareAccess(FileObject, &Fcb->ShareAccess); } RfsdPrint((DBG_INFO, "RfsdCleanup: 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) { RfsdQueueRequest(IrpContext); } else { IrpContext->Irp->IoStatus.Status = Status; RfsdCompleteIrpContext(IrpContext, Status); } } } _SEH2_END; return Status; }
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; }
NTSTATUS FatCommonRead ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common read routine for NtReadFile, called from both the Fsd, or from the Fsp if a request could not be completed without blocking in the Fsd. This routine has no code where it determines whether it is running in the Fsd or Fsp. Instead, its actions are conditionalized by the Wait input parameter, which determines whether it is allowed to block or not. If a blocking condition is encountered with Wait == FALSE, however, the request is posted to the Fsp, who always calls with WAIT == TRUE. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { PVCB Vcb; PFCB FcbOrDcb; PCCB Ccb; VBO StartingVbo; ULONG ByteCount; ULONG RequestedByteCount; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfOpen; BOOLEAN PostIrp = FALSE; BOOLEAN OplockPostIrp = FALSE; BOOLEAN FcbOrDcbAcquired = FALSE; BOOLEAN Wait; BOOLEAN PagingIo; BOOLEAN NonCachedIo; BOOLEAN SynchronousIo; NTSTATUS Status; FAT_IO_CONTEXT StackFatIoContext; // // A system buffer is only used if we have to access the // buffer directly from the Fsp to clear a portion or to // do a synchronous I/O, or a cached transfer. It is // possible that our caller may have already mapped a // system buffer, in which case we must remember this so // we do not unmap it on the way out. // PVOID SystemBuffer = NULL; LARGE_INTEGER StartingByte; PAGED_CODE(); // // Get current Irp stack location. // IrpSp = IoGetCurrentIrpStackLocation( Irp ); FileObject = IrpSp->FileObject; // // Initialize the appropriate local variables. // Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); NonCachedIo = BooleanFlagOn(Irp->Flags,IRP_NOCACHE); SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); DebugTrace(+1, Dbg, "CommonRead\n", 0); DebugTrace( 0, Dbg, " Irp = %8lx\n", Irp); DebugTrace( 0, Dbg, " ->ByteCount = %8lx\n", IrpSp->Parameters.Read.Length); DebugTrace( 0, Dbg, " ->ByteOffset.LowPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.LowPart); DebugTrace( 0, Dbg, " ->ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.HighPart); // // Extract starting Vbo and offset. // StartingByte = IrpSp->Parameters.Read.ByteOffset; StartingVbo = StartingByte.LowPart; ByteCount = IrpSp->Parameters.Read.Length; RequestedByteCount = ByteCount; // // Check for a null request, and return immediately // if (ByteCount == 0) { Irp->IoStatus.Information = 0; FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); return STATUS_SUCCESS; } // // Extract the nature of the read from the file object, and case on it // TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &FcbOrDcb, &Ccb); ASSERT( Vcb != NULL ); // // Save callers who try to do cached IO to the raw volume from themselves. // if (TypeOfOpen == UserVolumeOpen) { NonCachedIo = TRUE; } ASSERT(!(NonCachedIo == FALSE && TypeOfOpen == VirtualVolumeFile)); // // Collect interesting statistics. The FLAG_USER_IO bit will indicate // what type of io we're doing in the FatNonCachedIo function. // if (PagingIo) { CollectReadStats(Vcb, TypeOfOpen, ByteCount); if (TypeOfOpen == UserFileOpen) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO); } else { ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO); } } ASSERT(!FlagOn( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT )); // // Allocate if necessary and initialize a FAT_IO_CONTEXT block for // all non cached Io. For synchronous Io we use stack storage, // otherwise we allocate pool. // if (NonCachedIo) { if (IrpContext->FatIoContext == NULL) { if (!Wait) { IrpContext->FatIoContext = FsRtlAllocatePoolWithTag( NonPagedPool, sizeof(FAT_IO_CONTEXT), TAG_FAT_IO_CONTEXT ); } else { IrpContext->FatIoContext = &StackFatIoContext; SetFlag( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT ); } } RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) ); if (Wait) { KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent, NotificationEvent, FALSE ); } else { IrpContext->FatIoContext->Wait.Async.ResourceThreadId = ExGetCurrentResourceThread(); IrpContext->FatIoContext->Wait.Async.RequestedByteCount = ByteCount; IrpContext->FatIoContext->Wait.Async.FileObject = FileObject; } } // // These two cases correspond to either a general opened volume, ie. // open ("a:"), or a read of the volume file (boot sector + fat(s)) // if ((TypeOfOpen == VirtualVolumeFile) || (TypeOfOpen == UserVolumeOpen)) { LBO StartingLbo; StartingLbo = StartingByte.QuadPart; DebugTrace(0, Dbg, "Type of read is User Volume or virtual volume file\n", 0); if (TypeOfOpen == UserVolumeOpen) { // // Verify that the volume for this handle is still valid // // // Verify that the volume for this handle is still valid, permitting // operations to proceed on dismounted volumes via the handle which // performed the dismount. // if (!FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT | CCB_FLAG_SENT_FORMAT_UNIT )) { FatQuickVerifyVcb( IrpContext, Vcb ); } // // If the caller previously sent a format unit command, then we will allow // their read/write requests to ignore the verify flag on the device, since some // devices send a media change event after format unit, but we don't want to // process it yet since we're probably in the process of formatting the // media. // if (FlagOn( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT )) { SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_OVERRIDE_VERIFY ); } if (!FlagOn( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE )) { (VOID)ExAcquireResourceExclusiveLite( &Vcb->Resource, TRUE ); try { // // If the volume isn't locked, flush it. // if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) { FatFlushVolume( IrpContext, Vcb, Flush ); } } finally { ExReleaseResourceLite( &Vcb->Resource ); } SetFlag( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE ); } if (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO )) { LBO VolumeSize; // // Make sure we don't try to read past end of volume, // reducing the byte count if necessary. // VolumeSize = (LBO) Vcb->Bpb.BytesPerSector * (Vcb->Bpb.Sectors != 0 ? Vcb->Bpb.Sectors : Vcb->Bpb.LargeSectors); if (StartingLbo >= VolumeSize) { Irp->IoStatus.Information = 0; FatCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE ); return STATUS_END_OF_FILE; } if (ByteCount > VolumeSize - StartingLbo) { ByteCount = RequestedByteCount = (ULONG) (VolumeSize - StartingLbo); // // For async reads we had set the byte count in the FatIoContext // above, so fix that here. // if (!Wait) { IrpContext->FatIoContext->Wait.Async.RequestedByteCount = ByteCount; } } } // // For DASD we have to probe and lock the user's buffer // FatLockUserBuffer( IrpContext, Irp, IoWriteAccess, ByteCount ); } else {
PFFS_MCB FFSAllocateMcb( PFFS_VCB Vcb, PUNICODE_STRING FileName, ULONG FileAttr) { PFFS_MCB Mcb = NULL; PLIST_ENTRY List = NULL; ULONG Extra = 0; #define MCB_NUM_SHIFT 0x04 if (FFSGlobal->McbAllocated > (FFSGlobal->MaxDepth << MCB_NUM_SHIFT)) Extra = FFSGlobal->McbAllocated - (FFSGlobal->MaxDepth << MCB_NUM_SHIFT) + FFSGlobal->MaxDepth; FFSPrint((DBG_INFO, "FFSAllocateMcb: CurrDepth=%xh/%xh/%xh FileName=%S\n", FFSGlobal->McbAllocated, FFSGlobal->MaxDepth << MCB_NUM_SHIFT, FFSGlobal->FcbAllocated, FileName->Buffer)); List = Vcb->McbList.Flink; while ((List != &(Vcb->McbList)) && (Extra > 0)) { Mcb = CONTAINING_RECORD(List, FFS_MCB, Link); List = List->Flink; if ((Mcb->Inode != 2) && (Mcb->Child == NULL) && (Mcb->FFSFcb == NULL) && (!IsMcbUsed(Mcb))) { FFSPrint((DBG_INFO, "FFSAllocateMcb: Mcb %S will be freed.\n", Mcb->ShortName.Buffer)); if (FFSDeleteMcbNode(Vcb, Vcb->McbTree, Mcb)) { FFSFreeMcb(Mcb); Extra--; } } } ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); Mcb = (PFFS_MCB)(ExAllocateFromPagedLookasideList( &(FFSGlobal->FFSMcbLookasideList))); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); if (Mcb == NULL) { Mcb = (PFFS_MCB)ExAllocatePool(PagedPool, sizeof(FFS_MCB)); RtlZeroMemory(Mcb, sizeof(FFS_MCB)); SetFlag(Mcb->Flags, MCB_FROM_POOL); } else { RtlZeroMemory(Mcb, sizeof(FFS_MCB)); } if (!Mcb) { return NULL; } Mcb->Identifier.Type = FFSMCB; Mcb->Identifier.Size = sizeof(FFS_MCB); if (FileName && FileName->Length) { Mcb->ShortName.Length = FileName->Length; Mcb->ShortName.MaximumLength = Mcb->ShortName.Length + 2; Mcb->ShortName.Buffer = ExAllocatePool(PagedPool, Mcb->ShortName.MaximumLength); if (!Mcb->ShortName.Buffer) goto errorout; RtlZeroMemory(Mcb->ShortName.Buffer, Mcb->ShortName.MaximumLength); RtlCopyMemory(Mcb->ShortName.Buffer, FileName->Buffer, Mcb->ShortName.Length); } Mcb->FileAttr = FileAttr; ExAcquireResourceExclusiveLite( &FFSGlobal->CountResource, TRUE); FFSGlobal->McbAllocated++; ExReleaseResourceForThreadLite( &FFSGlobal->CountResource, ExGetCurrentResourceThread()); return Mcb; errorout: if (Mcb) { if (Mcb->ShortName.Buffer) ExFreePool(Mcb->ShortName.Buffer); if (FlagOn(Mcb->Flags, MCB_FROM_POOL)) { ExFreePool(Mcb); } else { ExAcquireResourceExclusiveLite( &FFSGlobal->LAResource, TRUE); ExFreeToPagedLookasideList(&(FFSGlobal->FFSMcbLookasideList), Mcb); ExReleaseResourceForThreadLite( &FFSGlobal->LAResource, ExGetCurrentResourceThread()); } } return NULL; }
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; }
NTSTATUS CdCommonWrite ( _Inout_ PIRP_CONTEXT IrpContext, _Inout_ PIRP Irp ) /*++ Routine Description: This is the common entry point for NtWriteFile calls. For synchronous requests, CommonWrite will complete the request in the current thread. If not synchronous the request will be passed to the Fsp if there is a need to block. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The result of this operation. --*/ { NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); TYPE_OF_OPEN TypeOfOpen; PFCB Fcb; PCCB Ccb; BOOLEAN Wait; ULONG SynchronousIo; PVOID UserBuffer; LONGLONG StartingOffset; LONGLONG ByteRange; ULONG ByteCount; ULONG WriteByteCount; ULONG OriginalByteCount; BOOLEAN ReleaseFile = TRUE; CD_IO_CONTEXT LocalIoContext; PAGED_CODE(); // // If this is a zero length write then return SUCCESS immediately. // if (IrpSp->Parameters.Write.Length == 0) { CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); return STATUS_SUCCESS; } // // Decode the file object and verify we support write on this. It // must be a volume file. // TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ); // Internal lock object is acquired if return status is STATUS_PENDING _Analysis_suppress_lock_checking_(Fcb->Resource); if (TypeOfOpen != UserVolumeOpen) { CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); return STATUS_INVALID_DEVICE_REQUEST; } // // Examine our input parameters to determine if this is noncached and/or // a paging io operation. // Wait = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); SynchronousIo = FlagOn( IrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO ); // // Extract the range of the Io. // StartingOffset = IrpSp->Parameters.Write.ByteOffset.QuadPart; OriginalByteCount = ByteCount = IrpSp->Parameters.Write.Length; ByteRange = StartingOffset + ByteCount; // // Acquire the file shared to perform the write. // CdAcquireFileShared( IrpContext, Fcb ); // // Use a try-finally to facilitate cleanup. // try { // // Verify the Fcb. Allow writes if this is a DASD handle that is // dismounting the volume. // if (!FlagOn( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE )) { CdVerifyFcbOperation( IrpContext, Fcb ); } if (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO )) { // // Complete the request if it begins beyond the end of file. // if (StartingOffset >= Fcb->FileSize.QuadPart) { try_return( Status = STATUS_END_OF_FILE ); } // // Truncate the write if it extends beyond the end of the file. // if (ByteRange > Fcb->FileSize.QuadPart) { ByteCount = (ULONG) (Fcb->FileSize.QuadPart - StartingOffset); ByteRange = Fcb->FileSize.QuadPart; } } // // If we have an unaligned transfer then post this request if // we can't wait. Unaligned means that the starting offset // is not on a sector boundary or the write is not integral // sectors. // WriteByteCount = BlockAlign( Fcb->Vcb, ByteCount ); if (SectorOffset( StartingOffset ) || SectorOffset( WriteByteCount ) || (WriteByteCount > OriginalByteCount)) { if (!Wait) { CdRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } // // Make sure we don't overwrite the buffer. // WriteByteCount = ByteCount; } // // Initialize the IoContext for the write. // If there is a context pointer, we need to make sure it was // allocated and not a stale stack pointer. // if (IrpContext->IoContext == NULL || !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) { // // If we can wait, use the context on the stack. Otherwise // we need to allocate one. // if (Wait) { IrpContext->IoContext = &LocalIoContext; ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO ); } else { IrpContext->IoContext = CdAllocateIoContext(); SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO ); } } RtlZeroMemory( IrpContext->IoContext, sizeof( CD_IO_CONTEXT ) ); // // Store whether we allocated this context structure in the structure // itself. // IrpContext->IoContext->AllocatedContext = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO ); if (Wait) { KeInitializeEvent( &IrpContext->IoContext->SyncEvent, NotificationEvent, FALSE ); } else { IrpContext->IoContext->ResourceThreadId = ExGetCurrentResourceThread(); IrpContext->IoContext->Resource = Fcb->Resource; IrpContext->IoContext->RequestedByteCount = ByteCount; } Irp->IoStatus.Information = WriteByteCount; // // Set the FO_MODIFIED flag here to trigger a verify when this // handle is closed. Note that we can err on the conservative // side with no problem, i.e. if we accidently do an extra // verify there is no problem. // SetFlag( IrpSp->FileObject->Flags, FO_FILE_MODIFIED ); // // Dasd access is always non-cached. Call the Dasd write routine to // perform the actual write. // Status = CdVolumeDasdWrite( IrpContext, Fcb, StartingOffset, WriteByteCount ); // // Don't complete this request now if STATUS_PENDING was returned. // if (Status == STATUS_PENDING) { Irp = NULL; ReleaseFile = FALSE; // // Test is we should zero part of the buffer or update the // synchronous file position. // } else { // // Convert any unknown error code to IO_ERROR. // if (!NT_SUCCESS( Status )) { // // Set the information field to zero. // Irp->IoStatus.Information = 0; // // Raise if this is a user induced error. // if (IoIsErrorUserInduced( Status )) { CdRaiseStatus( IrpContext, Status ); } Status = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR ); // // Check if there is any portion of the user's buffer to zero. // } else if (WriteByteCount != ByteCount) { CdMapUserBuffer( IrpContext, &UserBuffer ); SafeZeroMemory( IrpContext, Add2Ptr( UserBuffer, ByteCount, PVOID ), WriteByteCount - ByteCount ); Irp->IoStatus.Information = ByteCount; } // // Update the file position if this is a synchronous request. // if (SynchronousIo && NT_SUCCESS( Status )) { IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange; } } try_exit: NOTHING; } finally { // // Release the Fcb. // if (ReleaseFile) { CdReleaseFile( IrpContext, Fcb ); } } // // Post the request if we got CANT_WAIT. // if (Status == STATUS_CANT_WAIT) { Status = CdFsdPostRequest( IrpContext, Irp ); // // Otherwise complete the request. // } else { CdCompleteRequest( IrpContext, Irp, Status ); } return Status; }