VOID Ext2OplockComplete ( IN PVOID Context, IN PIRP Irp ) { // // Check on the return value in the Irp. // if (Irp->IoStatus.Status == STATUS_SUCCESS) { // // queue the Irp context in the workqueue. // Ext2QueueRequest((PEXT2_IRP_CONTEXT)Context); } else { // // complete the request in case of failure // Ext2CompleteIrpContext( (PEXT2_IRP_CONTEXT) Context, Irp->IoStatus.Status ); } return; }
VOID Ext2DeferWrite(IN PEXT2_IRP_CONTEXT IrpContext, PIRP Irp) { ASSERT(IrpContext->Irp == Irp); Ext2QueueRequest(IrpContext); }
NTSTATUS Ext2ReadVolume (IN PEXT2_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb = NULL; PEXT2_CCB Ccb = NULL; PEXT2_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; PUCHAR Buffer = NULL; EXT2_EXTENT BlockArray; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); FileObject = IrpContext->FileObject; FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext; ASSERT(FcbOrVcb); if (!(FcbOrVcb->Identifier.Type == EXT2VCB && (PVOID)FcbOrVcb == (PVOID)Vcb)) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } Ccb = (PEXT2_CCB) FileObject->FsContext2; Irp = IrpContext->Irp; Irp->IoStatus.Information = 0; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Read.Length; ByteOffset = IoStackLocation->Parameters.Read.ByteOffset; PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO); Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE) || (Ccb != NULL); SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); if (PagingIo) { ASSERT(Nocache); } if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __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 (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart) { Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); } /* * User direct volume access */ if (Ccb != NULL && !PagingIo) { if (!ExAcquireResourceExclusiveLite( &Vcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; if (!FlagOn(Ccb->Flags, CCB_VOLUME_DASD_PURGE)) { if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { Ext2FlushVolume(IrpContext, Vcb, FALSE); } SetFlag(Ccb->Flags, CCB_VOLUME_DASD_PURGE); } ExReleaseResourceLite(&Vcb->MainResource); MainResourceAcquired = FALSE; /* will do Nocache i/o */ } /* * I/O to volume StreamObject */ if (!Nocache) { if (IsFlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcMdlRead( Vcb->Volume, &ByteOffset, Length, &Irp->MdlAddress, &Irp->IoStatus ); Status = Irp->IoStatus.Status; } else { Buffer = Ext2GetUserBuffer(Irp); if (Buffer == NULL) { DbgBreak(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (!CcCopyRead( Vcb->Volume, &ByteOffset, Length, Ext2CanIWait(), Buffer, &Irp->IoStatus )) { Status = STATUS_PENDING; __leave; } Status = Irp->IoStatus.Status; } } else { Length &= ~((ULONG)SECTOR_SIZE - 1); Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoWriteAccess ); if (!NT_SUCCESS(Status)) { __leave; } BlockArray.Irp = NULL; BlockArray.Lba = ByteOffset.QuadPart; BlockArray.Offset = 0; BlockArray.Length = Length; BlockArray.Next = NULL; Status = Ext2ReadWriteBlocks(IrpContext, Vcb, &BlockArray, Length ); Irp = IrpContext->Irp; if (!Irp) { __leave; } } } __finally { if (MainResourceAcquired) { ExReleaseResourceLite(&Vcb->MainResource); } if (!IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING && !IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED)) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoWriteAccess ); if (NT_SUCCESS(Status)) { Status = Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } else { if (NT_SUCCESS(Status)) { if (!PagingIo) { if (SynchronousIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } FileObject->Flags |= FO_FILE_FAST_IO_READ; } } Ext2CompleteIrpContext(IrpContext, Status);; } } else { Ext2FreeIrpContext(IrpContext); } } } return Status; }
NTSTATUS Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb = NULL; PEXT2_FCB Fcb = NULL; PEXT2_CCB Ccb = NULL; PFILE_OBJECT FileObject = NULL; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; ULONG Length; ULONG ReturnedLength = 0; LARGE_INTEGER ByteOffset; BOOLEAN OpPostIrp = FALSE; BOOLEAN PagingIo; BOOLEAN Nocache; BOOLEAN SynchronousIo; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; PUCHAR Buffer; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); FileObject = IrpContext->FileObject; Fcb = (PEXT2_FCB) FileObject->FsContext; ASSERT(Fcb); ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); Ccb = (PEXT2_CCB) FileObject->FsContext2; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Read.Length; ByteOffset = IoStackLocation->Parameters.Read.ByteOffset; PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO); Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE); SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); if (PagingIo) { ASSERT(Nocache); } DEBUG(DL_INF, ("Ext2ReadFile: reading %wZ Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n", &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache)); if ((IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) || IsFileDeleted(Fcb->Mcb)) { Status = STATUS_FILE_DELETED; __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; DbgBreak(); __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; DbgBreak(); __leave; } if (!PagingIo && Nocache && (FileObject->SectionObjectPointer->DataSectionObject != NULL)) { CcFlushCache( FileObject->SectionObjectPointer, &ByteOffset, Length, &Irp->IoStatus ); if (!NT_SUCCESS(Irp->IoStatus.Status)) { __leave; } } ReturnedLength = Length; if (PagingIo) { if (!ExAcquireResourceSharedLite( &Fcb->PagingIoResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; } else { if (Nocache) { if (!ExAcquireResourceExclusiveLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } else { if (!ExAcquireResourceSharedLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } if (!FsRtlCheckLockForReadAccess( &Fcb->FileLockAnchor, Irp )) { Status = STATUS_FILE_LOCK_CONFLICT; __leave; } } if ((ByteOffset.QuadPart + (LONGLONG)Length) > Fcb->Header.FileSize.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.FileSize.QuadPart) { Irp->IoStatus.Information = 0; Status = STATUS_END_OF_FILE; __leave; } ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); } if (!IsDirectory(Fcb) && Ccb != NULL) { Status = FsRtlCheckOplock( &Fcb->Oplock, Irp, IrpContext, Ext2OplockComplete, Ext2LockIrp ); if (Status != STATUS_SUCCESS) { OpPostIrp = TRUE; __leave; } // // Set the flag indicating if Fast I/O is possible // Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb); } if (!Nocache) { if (IsDirectory(Fcb)) { __leave; } if (FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap( FileObject, (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize), FALSE, &Ext2Global->CacheManagerCallbacks, Fcb ); CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY ); } if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcMdlRead( FileObject, (&ByteOffset), ReturnedLength, &Irp->MdlAddress, &Irp->IoStatus ); Status = Irp->IoStatus.Status; } else { Buffer = Ext2GetUserBuffer(Irp); if (Buffer == NULL) { Status = STATUS_INVALID_USER_BUFFER; DbgBreak(); __leave; } if (!CcCopyRead(FileObject, &ByteOffset, ReturnedLength, Ext2CanIWait(), Buffer, &Irp->IoStatus)) { if (Ext2CanIWait() || !CcCopyRead(FileObject, &ByteOffset, ReturnedLength, TRUE, Buffer, &Irp->IoStatus)) { Status = STATUS_PENDING; DbgBreak(); __leave; } } Status = Irp->IoStatus.Status; } } else { ULONG BytesRead = ReturnedLength; PUCHAR SystemVA = Ext2GetUserBuffer(IrpContext->Irp); if (ByteOffset.QuadPart + BytesRead > Fcb->Header.ValidDataLength.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.ValidDataLength.QuadPart) { if (SystemVA) { SafeZeroMemory(SystemVA, Length); } Irp->IoStatus.Information = ReturnedLength; Status = STATUS_SUCCESS; __leave; } else { BytesRead = (ULONG)(Fcb->Header.ValidDataLength.QuadPart - ByteOffset.QuadPart); if (SystemVA) { SafeZeroMemory(SystemVA + BytesRead, Length - BytesRead); } } } Status = Ext2LockUserBuffer( IrpContext->Irp, BytesRead, IoReadAccess ); if (!NT_SUCCESS(Status)) { __leave; } Status = Ext2ReadInode( IrpContext, Vcb, Fcb->Mcb, ByteOffset.QuadPart, NULL, BytesRead, TRUE, NULL ); /* we need re-queue this request in case STATUS_CANT_WAIT and fail it in other failure cases */ if (!NT_SUCCESS(Status)) { __leave; } /* pended by low level device */ if (Status == STATUS_PENDING) { IrpContext->Irp = Irp = NULL; __leave; } Irp = IrpContext->Irp; ASSERT(Irp); Status = Irp->IoStatus.Status; if (!NT_SUCCESS(Status)) { Ext2NormalizeAndRaiseStatus(IrpContext, Status); } } Irp->IoStatus.Information = ReturnedLength; } __finally { if (Irp) { if (PagingIoResourceAcquired) { ExReleaseResourceLite(&Fcb->PagingIoResource); } if (MainResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); } } if (!OpPostIrp && !IrpContext->ExceptionInProgress) { if (Irp) { if ( Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoWriteAccess ); if (NT_SUCCESS(Status)) { Status = Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } else { if (NT_SUCCESS(Status)) { if (!PagingIo) { if (SynchronousIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } FileObject->Flags |= FO_FILE_FAST_IO_READ; } } Ext2CompleteIrpContext(IrpContext, Status); } } else { Ext2FreeIrpContext(IrpContext); } } } DEBUG(DL_IO, ("Ext2ReadFile: %wZ fetch at Off=%I64xh Len=%xh Paging=%xh Nocache=%xh Returned=%xh Status=%xh\n", &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache, ReturnedLength, Status)); return Status; }
NTSTATUS Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext) { PEXT2_VCB Vcb = NULL; PEXT2_FCB Fcb = NULL; PEXT2_CCB Ccb = NULL; PFILE_OBJECT FileObject = NULL; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; PUCHAR Buffer = NULL; LARGE_INTEGER ByteOffset; ULONG ReturnedLength = 0; ULONG Length; NTSTATUS Status = STATUS_UNSUCCESSFUL; BOOLEAN OpPostIrp = FALSE; BOOLEAN PagingIo = FALSE; BOOLEAN Nocache = FALSE; BOOLEAN SynchronousIo = FALSE; BOOLEAN RecursiveWriteThrough = FALSE; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; BOOLEAN bDeferred = FALSE; BOOLEAN UpdateFileValidSize = FALSE; BOOLEAN FileSizesChanged = FALSE; BOOLEAN rc; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); FileObject = IrpContext->FileObject; Fcb = (PEXT2_FCB) FileObject->FsContext; Ccb = (PEXT2_CCB) FileObject->FsContext2; ASSERT(Fcb); ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Write.Length; ByteOffset = IoStackLocation->Parameters.Write.ByteOffset; PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO); Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE); SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); if (PagingIo) { ASSERT(Nocache); } DEBUG(DL_INF, ("Ext2WriteFile: %wZ Offset=%I64xh Length=%xh Paging=%xh Nocache=%xh\n", &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache)); if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } if (IsFileDeleted(Fcb->Mcb) || (IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) ) { Status = STATUS_FILE_DELETED; __leave; } if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } if (ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION && ByteOffset.HighPart == -1) { ByteOffset = FileObject->CurrentByteOffset; } else if (IsWritingToEof(ByteOffset)) { ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart; } if (Nocache && !PagingIo && ( (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 (!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 ) ) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); CcDeferWrite( FileObject, (PCC_POST_DEFERRED_WRITE)Ext2DeferWrite, IrpContext, Irp, Length, bAgain ); bDeferred = TRUE; Status = STATUS_PENDING; __leave; } } } if (IsDirectory(Fcb) && !PagingIo) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } if (IsFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) && !IrpContext->IsTopLevel) { PIRP TopIrp; TopIrp = IoGetTopLevelIrp(); if ( (ULONG_PTR)TopIrp > FSRTL_MAX_TOP_LEVEL_IRP_FLAG && NodeType(TopIrp) == IO_TYPE_IRP) { PIO_STACK_LOCATION IrpStack; IrpStack = IoGetCurrentIrpStackLocation(TopIrp); if ((IrpStack->MajorFunction == IRP_MJ_WRITE) && (IrpStack->FileObject->FsContext == FileObject->FsContext) && !FlagOn(TopIrp->Flags, IRP_NOCACHE) ) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH); RecursiveWriteThrough = TRUE; } } } if (PagingIo) { if (!ExAcquireResourceSharedLite(&Fcb->PagingIoResource, TRUE)) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; if ( (ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) { Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; __leave; } else { ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart) Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart); } } else { ReturnedLength = Length; } } else { if (!Ext2CheckFileAccess(Vcb, Fcb->Mcb, Ext2FileCanWrite)) { Status = STATUS_ACCESS_DENIED; __leave; } if (IsDirectory(Fcb)) { __leave; } if (!ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE)) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; // // Do flushing for such cases // if (Nocache && Ccb != NULL && Fcb->SectionObject.DataSectionObject != NULL) { ExAcquireSharedStarveExclusive( &Fcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Fcb->PagingIoResource); CcFlushCache( &(Fcb->SectionObject), &ByteOffset, CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE), &(Irp->IoStatus)); ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED); if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; __leave; } ExAcquireSharedStarveExclusive( &Fcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Fcb->PagingIoResource); CcPurgeCacheSection( &(Fcb->SectionObject), &(ByteOffset), CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE), FALSE ); } if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLockAnchor, Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; __leave; } if (Ccb != NULL) { Status = FsRtlCheckOplock( &Fcb->Oplock, Irp, IrpContext, Ext2OplockComplete, Ext2LockIrp ); if (Status != STATUS_SUCCESS) { OpPostIrp = TRUE; __leave; } // // Set the flag indicating if Fast I/O is possible // Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb); } // // Extend the inode size when the i/o is beyond the file end ? // if ((ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) { LARGE_INTEGER AllocationSize, Last; if (!ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE)) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; /* let this irp wait, since it has to be synchronous */ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); Last.QuadPart = Fcb->Header.AllocationSize.QuadPart; AllocationSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length); AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG, (ULONGLONG)AllocationSize.QuadPart, (ULONGLONG)BLOCK_SIZE); /* tell Ext2ExpandFile to allocate unwritten extent or NULL blocks for indirect files, otherwise we might get gabage data in holes */ IrpContext->MajorFunction += IRP_MJ_MAXIMUM_FUNCTION; Status = Ext2ExpandFile(IrpContext, Vcb, Fcb->Mcb, &AllocationSize); IrpContext->MajorFunction -= IRP_MJ_MAXIMUM_FUNCTION; if (AllocationSize.QuadPart > Last.QuadPart) { Fcb->Header.AllocationSize.QuadPart = AllocationSize.QuadPart; SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_WRITE); } ExReleaseResourceLite(&Fcb->PagingIoResource); PagingIoResourceAcquired = FALSE; if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) { if (NT_SUCCESS(Status)) { DbgBreak(); Status = STATUS_UNSUCCESSFUL; } __leave; } if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart) { Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart); } Fcb->Header.FileSize.QuadPart = Fcb->Inode->i_size = ByteOffset.QuadPart + Length; Ext2SaveInode(IrpContext, Vcb, Fcb->Inode); if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); } FileObject->Flags |= FO_FILE_SIZE_CHANGED | FO_FILE_MODIFIED; FileSizesChanged = TRUE; if (Fcb->Header.FileSize.QuadPart >= 0x80000000 && !IsFlagOn(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { SetFlag(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE); Ext2SaveSuper(IrpContext, Vcb); } DEBUG(DL_IO, ("Ext2WriteFile: expanding %wZ to FS: %I64xh FA: %I64xh\n", &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart, Fcb->Header.AllocationSize.QuadPart)); } ReturnedLength = Length; } if (!Nocache) { if (FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap( FileObject, (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize), FALSE, &Ext2Global->CacheManagerCallbacks, Fcb ); CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY ); } if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcPrepareMdlWrite( FileObject, &ByteOffset, Length, &Irp->MdlAddress, &Irp->IoStatus ); Status = Irp->IoStatus.Status; } else { Buffer = Ext2GetUserBuffer(Irp); if (Buffer == NULL) { DbgBreak(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) { /* let this irp wait, since it has to be synchronous */ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); rc = Ext2ZeroData(IrpContext, Vcb, FileObject, &Fcb->Header.ValidDataLength, &ByteOffset); if (!rc) { Status = STATUS_PENDING; DbgBreak(); __leave; } } if (!CcCopyWrite(FileObject, &ByteOffset, Length, Ext2CanIWait(), Buffer)) { if (Ext2CanIWait() || !CcCopyWrite(FileObject, &ByteOffset, Length, TRUE, Buffer)) { Status = STATUS_PENDING; DbgBreak(); __leave; } } if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) { if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) { Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; } else { if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length) Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length; } CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); FileSizesChanged = TRUE; } Status = STATUS_SUCCESS; } if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { DEBUG(DL_FLP, ("Ext2WriteFile is starting FlushingDpc...\n")); Ext2StartFloppyFlushDpc(Vcb, Fcb, FileObject); } } } else { if (!PagingIo && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) { if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) { /* let this irp wait, since it has to be synchronous */ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); rc = Ext2ZeroData(IrpContext, Vcb, FileObject, &Fcb->Header.ValidDataLength, &ByteOffset); if (!rc) { Status = STATUS_PENDING; DbgBreak(); __leave; } } } Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoReadAccess ); if (!NT_SUCCESS(Status)) { __leave; } Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = ReturnedLength; Status = Ext2WriteInode( IrpContext, Vcb, Fcb->Mcb, (ULONGLONG)(ByteOffset.QuadPart), NULL, ReturnedLength, TRUE, &Length ); Irp = IrpContext->Irp; if (NT_SUCCESS(Status) && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) { if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) { FileSizesChanged = TRUE; if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) { if (!PagingIo) Fcb->Header.FileSize.QuadPart = ByteOffset.QuadPart + Length; Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; } else { if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length) Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length; } if (!PagingIo && CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); } DEBUG(DL_IO, ("Ext2WriteFile: %wZ written FS: %I64xh FA: %I64xh BO: %I64xh LEN: %u\n", &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart, Fcb->Header.AllocationSize.QuadPart, ByteOffset.QuadPart, Length)); } } } if (FileSizesChanged) { FileObject->Flags |= FO_FILE_SIZE_CHANGED | FO_FILE_MODIFIED; Ext2NotifyReportChange( IrpContext, Vcb, Fcb->Mcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED ); } } __finally { /* * in case we got excpetions, we need revert MajorFunction * back to IRP_MJ_WRITE. The reason we do this, is to tell * Ext2ExpandFile to allocate unwritten extent or don't add * new blocks for indirect files. */ if (IrpContext->MajorFunction > IRP_MJ_MAXIMUM_FUNCTION) IrpContext->MajorFunction -= IRP_MJ_MAXIMUM_FUNCTION; if (Irp) { if (PagingIoResourceAcquired) { ExReleaseResourceLite(&Fcb->PagingIoResource); } if (MainResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); } } if (!OpPostIrp && !IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT ) { if (!bDeferred) { Status = Ext2QueueRequest(IrpContext); } } else { if (NT_SUCCESS(Status) && !PagingIo) { if (SynchronousIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } SetFlag(FileObject->Flags, FO_FILE_MODIFIED); SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED); } Ext2CompleteIrpContext(IrpContext, Status); } } else { Ext2FreeIrpContext(IrpContext); } } } DEBUG(DL_IO, ("Ext2WriteFile: %wZ written at Offset=%I64xh Length=%xh PagingIo=%d Nocache=%d " "RetLen=%xh VDL=%I64xh FileSize=%I64xh i_size=%I64xh Status=%xh\n", &Fcb->Mcb->ShortName, ByteOffset, Length, PagingIo, Nocache, ReturnedLength, Fcb->Header.ValidDataLength.QuadPart,Fcb->Header.FileSize.QuadPart, Fcb->Inode->i_size, Status)); return Status; }
NTSTATUS Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb = NULL; PEXT2_CCB Ccb = NULL; PEXT2_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 = FALSE; BOOLEAN Nocache = FALSE; BOOLEAN SynchronousIo = FALSE; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN bDeferred = FALSE; PUCHAR Buffer = NULL; PEXT2_EXTENT Chain = NULL; EXT2_EXTENT BlockArray; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); FileObject = IrpContext->FileObject; FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext; ASSERT(FcbOrVcb); if (!(FcbOrVcb->Identifier.Type == EXT2VCB && (PVOID)FcbOrVcb == (PVOID)Vcb)) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } Ccb = (PEXT2_CCB) FileObject->FsContext2; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Write.Length; ByteOffset = IoStackLocation->Parameters.Write.ByteOffset; PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO); Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE) || (Ccb != NULL); SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); if (PagingIo) { ASSERT(Nocache); } DEBUG(DL_INF, ("Ext2WriteVolume: 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; } 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 (!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 ) ) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); CcDeferWrite( FileObject, (PCC_POST_DEFERRED_WRITE)Ext2DeferWrite, IrpContext, Irp, Length, bAgain ); bDeferred = TRUE; Status = STATUS_PENDING; __leave; } } } /* * User direct volume access */ if (Ccb != NULL && !PagingIo) { if (!FlagOn(Ccb->Flags, CCB_VOLUME_DASD_PURGE)) { if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { Status = Ext2PurgeVolume( Vcb, TRUE); } SetFlag(Ccb->Flags, CCB_VOLUME_DASD_PURGE); } 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); } } } else if (Nocache && !PagingIo && (Vcb->SectionObject.DataSectionObject != NULL)) { ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE); MainResourceAcquired = TRUE; ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Vcb->PagingIoResource); CcFlushCache( &(Vcb->SectionObject), &ByteOffset, Length, &(Irp->IoStatus)); if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; __leave; } ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Vcb->PagingIoResource); CcPurgeCacheSection( &(Vcb->SectionObject), (PLARGE_INTEGER)&(ByteOffset), Length, FALSE ); ExReleaseResourceLite(&Vcb->MainResource); MainResourceAcquired = FALSE; } if ( (ByteOffset.QuadPart + Length) > Vcb->Header.FileSize.QuadPart) { Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); } if (!Nocache) { if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcPrepareMdlWrite ( Vcb->Volume, &ByteOffset, Length, &Irp->MdlAddress, &Irp->IoStatus ); Status = Irp->IoStatus.Status; } else { Buffer = Ext2GetUserBuffer(Irp); if (Buffer == NULL) { DbgBreak(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (!CcCopyWrite( Vcb->Volume, (PLARGE_INTEGER)(&ByteOffset), Length, TRUE, Buffer )) { Status = STATUS_PENDING; __leave; } Status = Irp->IoStatus.Status; Ext2AddVcbExtent(Vcb, ByteOffset.QuadPart, (LONGLONG)Length); } if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; } } else if (PagingIo) { LONGLONG DirtyStart; LONGLONG DirtyLba; LONGLONG DirtyLength; LONGLONG RemainLength; PEXT2_EXTENT Extent = NULL; PEXT2_EXTENT List = NULL; Length &= ~((ULONG)SECTOR_SIZE - 1); Status = Ext2LockUserBuffer(IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { __leave; } DirtyLba = ByteOffset.QuadPart; RemainLength = (LONGLONG) Length; ASSERT(Length >= SECTOR_SIZE); while (RemainLength > 0) { DirtyStart = DirtyLba; ASSERT(DirtyStart >= ByteOffset.QuadPart); ASSERT(DirtyStart <= ByteOffset.QuadPart + Length); if (Ext2LookupVcbExtent(Vcb, DirtyStart, &DirtyLba, &DirtyLength)) { if (DirtyLba == -1) { DirtyLba = DirtyStart + DirtyLength; if (ByteOffset.QuadPart + Length > DirtyLba) { RemainLength = ByteOffset.QuadPart + Length - DirtyLba; ASSERT(DirtyStart >= ByteOffset.QuadPart); ASSERT(DirtyStart <= ByteOffset.QuadPart + Length); } else { RemainLength = 0; } continue; } ASSERT(DirtyLba <= DirtyStart); Extent = Ext2AllocateExtent(); if (!Extent) { DEBUG(DL_ERR, ( "Ex2WriteVolume: failed to allocate Extent\n")); Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } Extent->Irp = NULL; Extent->Lba = DirtyLba; Extent->Offset = (ULONG)( DirtyStart + Length - RemainLength - DirtyLba ); ASSERT(Extent->Offset <= Length); if (DirtyLba + DirtyLength >= DirtyStart + RemainLength) { Extent->Length = (ULONG)( DirtyLba + RemainLength - DirtyStart ); ASSERT(Extent->Length <= Length); RemainLength = 0; } else { Extent->Length = (ULONG)(DirtyLength + DirtyLba - DirtyStart); RemainLength = (DirtyStart + RemainLength) - (DirtyLba + DirtyLength); ASSERT(RemainLength <= (LONGLONG)Length); ASSERT(Extent->Length <= Length); } ASSERT(Extent->Length >= SECTOR_SIZE); DirtyLba = DirtyStart + DirtyLength; if (List) { List->Next = Extent; List = Extent; } else { Chain = List = Extent; } } else { if (RemainLength > SECTOR_SIZE) { DirtyLba = DirtyStart + SECTOR_SIZE; RemainLength -= SECTOR_SIZE; } else { RemainLength = 0; } } } if (Chain) { Status = Ext2ReadWriteBlocks(IrpContext, Vcb, Chain, Length ); Irp = IrpContext->Irp; if (NT_SUCCESS(Status)) { for (Extent = Chain; Extent != NULL; Extent = Extent->Next) { Ext2RemoveVcbExtent(Vcb, Extent->Lba, Extent->Length); } } if (!Irp) { __leave; } } else { Irp->IoStatus.Information = Length; Status = STATUS_SUCCESS; __leave; } } else { Length &= ~((ULONG)SECTOR_SIZE - 1); Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoWriteAccess ); if (!NT_SUCCESS(Status)) { __leave; } BlockArray.Irp = NULL; BlockArray.Lba = ByteOffset.QuadPart; BlockArray.Offset = 0; BlockArray.Length = Length; BlockArray.Next = NULL; Status = Ext2ReadWriteBlocks(IrpContext, Vcb, &BlockArray, Length ); if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; } Irp = IrpContext->Irp; if (!Irp) { __leave; } } } __finally { if (MainResourceAcquired) { ExReleaseResourceLite(&Vcb->MainResource); } if (!IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING) { if (!bDeferred) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoReadAccess ); if (NT_SUCCESS(Status)) { Status = Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(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); } } Ext2CompleteIrpContext(IrpContext, Status); } } else { Ext2FreeIrpContext(IrpContext); } } if (Chain) { Ext2DestroyExtentChain(Chain); } } return Status; }
NTSTATUS Ext2ShutDown (IN PEXT2_IRP_CONTEXT IrpContext) { NTSTATUS Status; PIRP Irp; PIO_STACK_LOCATION IrpSp; PEXT2_VCB Vcb; PLIST_ENTRY ListEntry; BOOLEAN GlobalResourceAcquired = FALSE; __try { Status = STATUS_SUCCESS; ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); Irp = IrpContext->Irp; IrpSp = IoGetCurrentIrpStackLocation(Irp); if (!ExAcquireResourceExclusiveLite( &Ext2Global->Resource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } GlobalResourceAcquired = TRUE; for (ListEntry = Ext2Global->VcbList.Flink; ListEntry != &(Ext2Global->VcbList); ListEntry = ListEntry->Flink ) { Vcb = CONTAINING_RECORD(ListEntry, EXT2_VCB, Next); if (ExAcquireResourceExclusiveLite( &Vcb->MainResource, TRUE )) { if (IsMounted(Vcb)) { /* update mount count */ Vcb->SuperBlock->s_mnt_count++; if (Vcb->SuperBlock->s_mnt_count > Vcb->SuperBlock->s_max_mnt_count ) { Vcb->SuperBlock->s_mnt_count = Vcb->SuperBlock->s_max_mnt_count; } Ext2SaveSuper(IrpContext, Vcb); /* flush dirty cache for all files */ Status = Ext2FlushFiles(IrpContext, Vcb, TRUE); if (!NT_SUCCESS(Status)) { DbgBreak(); } /* flush volume stream's cache to disk */ Status = Ext2FlushVolume(IrpContext, Vcb, TRUE); if (!NT_SUCCESS(Status) && Status != STATUS_MEDIA_WRITE_PROTECTED) { DbgBreak(); } /* send shutdown request to underlying disk */ Ext2DiskShutDown(Vcb); } ExReleaseResourceLite(&Vcb->MainResource); } } /* IoUnregisterFileSystem(Ext2Global->DiskdevObject); IoUnregisterFileSystem(Ext2Global->CdromdevObject); */ } __finally { if (GlobalResourceAcquired) { ExReleaseResourceLite(&Ext2Global->Resource); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } } return Status; }
NTSTATUS Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_SUCCESS; PEXT2_VCB Vcb; PFILE_OBJECT FileObject; PEXT2_FCB Fcb; PEXT2_CCB Ccb; PIRP Irp; PEXT2_MCB Mcb; BOOLEAN VcbResourceAcquired = FALSE; BOOLEAN FcbResourceAcquired = FALSE; BOOLEAN FcbPagingIoResourceAcquired = FALSE; __try { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; if (IsExt2FsDevice(DeviceObject)) { Status = STATUS_SUCCESS; __leave; } Irp = IrpContext->Irp; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); if (!IsVcbInited(Vcb)) { Status = STATUS_SUCCESS; __leave; } FileObject = IrpContext->FileObject; Fcb = (PEXT2_FCB) FileObject->FsContext; if (!Fcb || (Fcb->Identifier.Type != EXT2VCB && Fcb->Identifier.Type != EXT2FCB)) { Status = STATUS_SUCCESS; __leave; } Mcb = Fcb->Mcb; Ccb = (PEXT2_CCB) FileObject->FsContext2; if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) { Status = STATUS_SUCCESS; __leave; } VcbResourceAcquired = ExAcquireResourceExclusiveLite( &Vcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (Fcb->Identifier.Type == EXT2VCB) { if (IsFlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) && (Vcb->LockFile == FileObject) ) { ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED); Vcb->LockFile = NULL; Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED); } if (Ccb) { Ext2DerefXcb(&Vcb->OpenHandleCount); Ext2DerefXcb(&Vcb->OpenVolumeCount); } IoRemoveShareAccess(FileObject, &Vcb->ShareAccess); Status = STATUS_SUCCESS; __leave; } ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); 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 = Ext2FlushFile(IrpContext, Fcb, Ccb); } __leave; } if (Ccb == NULL) { Status = STATUS_SUCCESS; __leave; } if (IsDirectory(Fcb)) { if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) { SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING); FsRtlNotifyFullChangeDirectory( Vcb->NotifySync, &Vcb->NotifyList, Ccb, NULL, FALSE, FALSE, 0, NULL, NULL, NULL ); } FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb); } ExReleaseResourceLite(&Vcb->MainResource); VcbResourceAcquired = FALSE; FcbResourceAcquired = ExAcquireResourceExclusiveLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); ASSERT((Ccb->Identifier.Type == EXT2CCB) && (Ccb->Identifier.Size == sizeof(EXT2_CCB))); Ext2DerefXcb(&Vcb->OpenHandleCount); Ext2DerefXcb(&Fcb->OpenHandleCount); if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) { Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE; } if (IsDirectory(Fcb)) { ext3_release_dir(Fcb->Inode, &Ccb->filp); } else { if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) && !IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) { LARGE_INTEGER SysTime; KeQuerySystemTime(&SysTime); Fcb->Inode->i_atime = Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime); Fcb->Mcb->LastAccessTime = Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_atime); Ext2SaveInode(IrpContext, Vcb, Fcb->Inode); Ext2NotifyReportChange( IrpContext, Vcb, Fcb->Mcb, FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS, FILE_ACTION_MODIFIED ); } FsRtlCheckOplock( &Fcb->Oplock, Irp, IrpContext, NULL, NULL ); Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb); if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) { Fcb->NonCachedOpenCount--; } if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) { SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING); } // // 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) { #if EXT2_DEBUG DEBUG(DL_INF, (": %-16.16s %-31s %wZ\n", Ext2GetCurrentProcessName(), "FastIoIsPossible", &Fcb->Mcb->FullName )); #endif Fcb->Header.IsFastIoPossible = FastIoIsPossible; } } if (Fcb->OpenHandleCount == 0 && (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE) || IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_WRITE)) ) { LARGE_INTEGER Size; ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE); FcbPagingIoResourceAcquired = TRUE; Size.QuadPart = CEILING_ALIGNED(ULONGLONG, (ULONGLONG)Fcb->Mcb->Inode.i_size, (ULONGLONG)BLOCK_SIZE); if (!IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size); Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart = Fcb->Mcb->Inode.i_size; Fcb->Header.AllocationSize = Size; if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); } } ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE|FCB_ALLOC_IN_WRITE); ExReleaseResourceLite(&Fcb->PagingIoResource); FcbPagingIoResourceAcquired = FALSE; } } if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { if (Fcb->OpenHandleCount == 0 || (Mcb = Ccb->SymLink)) { // // Ext2DeleteFile will acquire these lock inside // if (FcbResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); FcbResourceAcquired = FALSE; } // // this file is to be deleted ... // if (Ccb->SymLink) { Mcb = Ccb->SymLink; FileObject->DeletePending = FALSE; } Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb); if (NT_SUCCESS(Status)) { if (IsMcbDirectory(Mcb)) { Ext2NotifyReportChange( IrpContext, Vcb, Mcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_REMOVED ); } else { Ext2NotifyReportChange( IrpContext, Vcb, Mcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED ); } } // // re-acquire the main resource lock // FcbResourceAcquired = ExAcquireResourceExclusiveLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); SetFlag(FileObject->Flags, FO_FILE_MODIFIED); } } } if (!IsDirectory(Fcb)) { if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) && (Fcb->NonCachedOpenCount + 1 == 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); } if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) { ExReleaseResourceLite(&(Fcb->PagingIoResource)); } CcPurgeCacheSection( &Fcb->SectionObject, NULL, 0, FALSE ); } CcUninitializeCacheMap(FileObject, NULL, NULL); } IoRemoveShareAccess(FileObject, &Fcb->ShareAccess); DEBUG(DL_INF, ( "Ext2Cleanup: OpenCount=%u ReferCount=%u NonCahcedCount=%xh %wZ\n", Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName)); Status = STATUS_SUCCESS; if (FileObject) { SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE); } } __finally { if (FcbPagingIoResourceAcquired) { ExReleaseResourceLite(&Fcb->PagingIoResource); } if (FcbResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); } if (VcbResourceAcquired) { ExReleaseResourceLite(&Vcb->MainResource); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { Ext2QueueRequest(IrpContext); } else { IrpContext->Irp->IoStatus.Status = Status; Ext2CompleteIrpContext(IrpContext, Status); } } } return Status; }
NTSTATUS Ext2SetVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb; PIRP Irp; PIO_STACK_LOCATION IoStackLocation; FS_INFORMATION_CLASS FsInformationClass; BOOLEAN VcbResourceAcquired = FALSE; __try { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (IsExt2FsDevice(DeviceObject)) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); ASSERT(IsMounted(Vcb)); if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY)) { Status = STATUS_MEDIA_WRITE_PROTECTED; __leave; } if (!ExAcquireResourceExclusiveLite( &Vcb->MainResource, TRUE)) { Status = STATUS_PENDING; __leave; } VcbResourceAcquired = TRUE; Ext2VerifyVcb(IrpContext, Vcb); Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); //Notes: SetVolume is not defined in ntddk.h of win2k ddk, // But it's same to QueryVolume .... FsInformationClass = IoStackLocation->Parameters./*SetVolume*/QueryVolume.FsInformationClass; switch (FsInformationClass) { case FileFsLabelInformation: { PFILE_FS_LABEL_INFORMATION VolLabelInfo = NULL; ULONG VolLabelLen; UNICODE_STRING LabelName ; OEM_STRING OemName; VolLabelInfo = (PFILE_FS_LABEL_INFORMATION) Irp->AssociatedIrp.SystemBuffer; VolLabelLen = VolLabelInfo->VolumeLabelLength; if (VolLabelLen > (16 * sizeof(WCHAR))) { Status = STATUS_INVALID_VOLUME_LABEL; __leave; } RtlCopyMemory( Vcb->Vpb->VolumeLabel, VolLabelInfo->VolumeLabel, VolLabelLen ); RtlZeroMemory(Vcb->SuperBlock->s_volume_name, 16); LabelName.Buffer = VolLabelInfo->VolumeLabel; LabelName.MaximumLength = (USHORT)16 * sizeof(WCHAR); LabelName.Length = (USHORT)VolLabelLen; OemName.Buffer = SUPER_BLOCK->s_volume_name; OemName.Length = 0; OemName.MaximumLength = 16; Ext2UnicodeToOEM(Vcb, &OemName, &LabelName); Vcb->Vpb->VolumeLabelLength = (USHORT) VolLabelLen; if (Ext2SaveSuper(IrpContext, Vcb)) { Status = STATUS_SUCCESS; } Irp->IoStatus.Information = 0; } break; default: Status = STATUS_INVALID_INFO_CLASS; } } __finally { if (VcbResourceAcquired) { ExReleaseResourceLite(&Vcb->MainResource); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } } return Status; }
NTSTATUS Ext2QueryVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb; PIRP Irp; PIO_STACK_LOCATION IoStackLocation; FS_INFORMATION_CLASS FsInformationClass; ULONG Length; PVOID Buffer; BOOLEAN VcbResourceAcquired = FALSE; __try { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (IsExt2FsDevice(DeviceObject)) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); if (!IsMounted(Vcb)) { Status = STATUS_VOLUME_DISMOUNTED; __leave; } if (!ExAcquireResourceSharedLite( &Vcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } VcbResourceAcquired = TRUE; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); FsInformationClass = IoStackLocation->Parameters.QueryVolume.FsInformationClass; Length = IoStackLocation->Parameters.QueryVolume.Length; Buffer = Irp->AssociatedIrp.SystemBuffer; RtlZeroMemory(Buffer, Length); switch (FsInformationClass) { case FileFsVolumeInformation: { PFILE_FS_VOLUME_INFORMATION FsVolInfo; ULONG VolumeLabelLength; ULONG RequiredLength; if (Length < sizeof(FILE_FS_VOLUME_INFORMATION)) { Status = STATUS_BUFFER_OVERFLOW; __leave; } FsVolInfo = (PFILE_FS_VOLUME_INFORMATION) Buffer; FsVolInfo->VolumeCreationTime.QuadPart = 0; FsVolInfo->VolumeSerialNumber = Vcb->Vpb->SerialNumber; VolumeLabelLength = Vcb->Vpb->VolumeLabelLength; FsVolInfo->VolumeLabelLength = VolumeLabelLength; /* We don't support ObjectId */ FsVolInfo->SupportsObjects = FALSE; RequiredLength = sizeof(FILE_FS_VOLUME_INFORMATION) + VolumeLabelLength - sizeof(WCHAR); if (Length < RequiredLength) { Irp->IoStatus.Information = sizeof(FILE_FS_VOLUME_INFORMATION); Status = STATUS_BUFFER_OVERFLOW; __leave; } RtlCopyMemory(FsVolInfo->VolumeLabel, Vcb->Vpb->VolumeLabel, Vcb->Vpb->VolumeLabelLength); Irp->IoStatus.Information = RequiredLength; Status = STATUS_SUCCESS; } break; case FileFsSizeInformation: { PFILE_FS_SIZE_INFORMATION FsSizeInfo; if (Length < sizeof(FILE_FS_SIZE_INFORMATION)) { Status = STATUS_BUFFER_OVERFLOW; __leave; } FsSizeInfo = (PFILE_FS_SIZE_INFORMATION) Buffer; FsSizeInfo->TotalAllocationUnits.QuadPart = ext3_blocks_count(SUPER_BLOCK); FsSizeInfo->AvailableAllocationUnits.QuadPart = ext3_free_blocks_count(SUPER_BLOCK); FsSizeInfo->SectorsPerAllocationUnit = Vcb->BlockSize / Vcb->DiskGeometry.BytesPerSector; FsSizeInfo->BytesPerSector = Vcb->DiskGeometry.BytesPerSector; Irp->IoStatus.Information = sizeof(FILE_FS_SIZE_INFORMATION); Status = STATUS_SUCCESS; } break; case FileFsDeviceInformation: { PFILE_FS_DEVICE_INFORMATION FsDevInfo; if (Length < sizeof(FILE_FS_DEVICE_INFORMATION)) { Status = STATUS_BUFFER_OVERFLOW; __leave; } FsDevInfo = (PFILE_FS_DEVICE_INFORMATION) Buffer; FsDevInfo->DeviceType = Vcb->TargetDeviceObject->DeviceType; if (FsDevInfo->DeviceType != FILE_DEVICE_DISK) { DbgBreak(); } FsDevInfo->Characteristics = Vcb->TargetDeviceObject->Characteristics; if (FlagOn(Vcb->Flags, VCB_READ_ONLY)) { SetFlag( FsDevInfo->Characteristics, FILE_READ_ONLY_DEVICE ); } Irp->IoStatus.Information = sizeof(FILE_FS_DEVICE_INFORMATION); Status = STATUS_SUCCESS; } break; case FileFsAttributeInformation: { PFILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo; ULONG RequiredLength; if (Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) { Status = STATUS_BUFFER_OVERFLOW; __leave; } FsAttrInfo = (PFILE_FS_ATTRIBUTE_INFORMATION) Buffer; FsAttrInfo->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES; FsAttrInfo->MaximumComponentNameLength = EXT2_NAME_LEN; FsAttrInfo->FileSystemNameLength = 8; RequiredLength = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8 - sizeof(WCHAR); if (Length < RequiredLength) { Irp->IoStatus.Information = sizeof(FILE_FS_ATTRIBUTE_INFORMATION); Status = STATUS_BUFFER_OVERFLOW; __leave; } if (Vcb->IsExt3fs) { RtlCopyMemory(FsAttrInfo->FileSystemName, L"EXT3\0", 10); } else { RtlCopyMemory(FsAttrInfo->FileSystemName, L"EXT2\0", 10); } Irp->IoStatus.Information = RequiredLength; Status = STATUS_SUCCESS; } break; #if (_WIN32_WINNT >= 0x0500) case FileFsFullSizeInformation: { PFILE_FS_FULL_SIZE_INFORMATION PFFFSI; if (Length < sizeof(FILE_FS_FULL_SIZE_INFORMATION)) { Status = STATUS_BUFFER_OVERFLOW; __leave; } PFFFSI = (PFILE_FS_FULL_SIZE_INFORMATION) Buffer; /* typedef struct _FILE_FS_FULL_SIZE_INFORMATION { LARGE_INTEGER TotalAllocationUnits; LARGE_INTEGER CallerAvailableAllocationUnits; LARGE_INTEGER ActualAvailableAllocationUnits; ULONG SectorsPerAllocationUnit; ULONG BytesPerSector; } FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION; */ { PFFFSI->TotalAllocationUnits.QuadPart = ext3_blocks_count(SUPER_BLOCK); PFFFSI->CallerAvailableAllocationUnits.QuadPart = ext3_free_blocks_count(SUPER_BLOCK); /* - Vcb->SuperBlock->s_r_blocks_count; */ PFFFSI->ActualAvailableAllocationUnits.QuadPart = ext3_free_blocks_count(SUPER_BLOCK); } PFFFSI->SectorsPerAllocationUnit = Vcb->BlockSize / Vcb->DiskGeometry.BytesPerSector; PFFFSI->BytesPerSector = Vcb->DiskGeometry.BytesPerSector; Irp->IoStatus.Information = sizeof(FILE_FS_FULL_SIZE_INFORMATION); Status = STATUS_SUCCESS; } break; #endif // (_WIN32_WINNT >= 0x0500) default: Status = STATUS_INVALID_INFO_CLASS; break; } } __finally { if (VcbResourceAcquired) { ExReleaseResourceLite(&Vcb->MainResource); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } } return Status; }