NTSTATUS Ext2DoExtentExpand( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Index, IN OUT PULONG Block, IN OUT PULONG Number ) { EXT4_EXTENT_HEADER *eh; struct buffer_head bh_got; int rc, flags; if (IsMcbDirectory(Mcb) || IrpContext->MajorFunction == IRP_MJ_WRITE) { flags = EXT4_GET_BLOCKS_IO_CONVERT_EXT; } else { flags = EXT4_GET_BLOCKS_IO_CREATE_EXT; } memset(&bh_got, 0, sizeof(struct buffer_head)); eh = get_ext4_header(&Mcb->Inode); if (eh->eh_magic != EXT4_EXT_MAGIC) { ext4_ext_tree_init(IrpContext, NULL, &Mcb->Inode); } if ((rc = ext4_ext_get_blocks( IrpContext, NULL, &Mcb->Inode, Index, *Number, &bh_got, 1, flags)) < 0) { DEBUG(DL_ERR, ("Expand Block insufficient resources, Number: %u," " err: %d\n", *Number, rc)); DbgBreak(); return Ext2WinntError(rc); } if (Number) *Number = rc ? rc : 1; if (Block) *Block = (ULONG)bh_got.b_blocknr; Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); return STATUS_SUCCESS; }
NTSTATUS Ext2MapExtent( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Index, IN BOOLEAN Alloc, OUT PULONG Block, OUT PULONG Number ) { EXT4_EXTENT_HEADER *eh; struct buffer_head bh_got; int flags, rc; ULONG max_blocks = 0; memset(&bh_got, 0, sizeof(struct buffer_head)); eh = get_ext4_header(&Mcb->Inode); if (eh->eh_magic != EXT4_EXT_MAGIC) { if (Alloc) { /* now initialize inode extent root node */ ext4_ext_tree_init(IrpContext, NULL, &Mcb->Inode); } else { /* return empty-mapping when inode extent isn't initialized */ if (Block) *Block = 0; if (Number) { LONGLONG _len = _len = Mcb->Inode.i_size; if (Mcb->Fcb) _len = Mcb->Fcb->Header.AllocationSize.QuadPart; *Number = (ULONG)((_len + BLOCK_SIZE - 1) >> BLOCK_BITS); } return STATUS_SUCCESS; } } /* IrpContext is NULL when called during journal initialization */ if (IsMcbDirectory(Mcb) || IrpContext == NULL || IrpContext->MajorFunction == IRP_MJ_WRITE || !Alloc){ flags = EXT4_GET_BLOCKS_IO_CONVERT_EXT; max_blocks = EXT_INIT_MAX_LEN; } else { flags = EXT4_GET_BLOCKS_IO_CREATE_EXT; max_blocks = EXT_UNWRITTEN_MAX_LEN; } if ((rc = ext4_ext_get_blocks( IrpContext, NULL, &Mcb->Inode, Index, max_blocks, &bh_got, Alloc, flags)) < 0) { DEBUG(DL_ERR, ("Block insufficient resources, err: %d\n", rc)); return Ext2WinntError(rc); } if (Alloc) Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); if (Number) *Number = rc ? rc : 1; if (Block) *Block = (ULONG)bh_got.b_blocknr; return STATUS_SUCCESS; }
NTSTATUS Ext2WriteInode ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONGLONG Offset, IN PVOID Buffer, IN ULONG Size, IN BOOLEAN bDirectIo, OUT PULONG BytesWritten ) { PEXT2_EXTENT Chain = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; __try { if (BytesWritten) { *BytesWritten = 0; } Status = Ext2BuildExtents ( IrpContext, Vcb, Mcb, Offset, Size, IsMcbDirectory(Mcb) ? FALSE : TRUE, &Chain ); if (!NT_SUCCESS(Status)) { __leave; } if (Chain == NULL) { Status = STATUS_SUCCESS; __leave; } if (bDirectIo) { ASSERT(IrpContext != NULL); // // We assume the offset is aligned. // Status = Ext2ReadWriteBlocks( IrpContext, Vcb, Chain, Size ); } else { PEXT2_EXTENT Extent; for (Extent = Chain; Extent != NULL; Extent = Extent->Next) { if ( !Ext2SaveBuffer( IrpContext, Vcb, Extent->Lba, Extent->Length, (PVOID)((PUCHAR)Buffer + Extent->Offset) )) { __leave; } } if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { DEBUG(DL_FLP, ("Ext2WriteInode is starting FlushingDpc...\n")); Ext2StartFloppyFlushDpc(Vcb, NULL, NULL); } Status = STATUS_SUCCESS; } } __finally { if (Chain) { Ext2DestroyExtentChain(Chain); } if (NT_SUCCESS(Status) && BytesWritten) { *BytesWritten = Size; } } 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 Ext2ExpandLast( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Base, IN ULONG Layer, IN PULONG * Data, IN PULONG Hint, IN PULONG Block, IN OUT PULONG Number ) { PULONG pData = NULL; ULONG i; NTSTATUS Status = STATUS_SUCCESS; if (Layer > 0 || IsMcbDirectory(Mcb)) { /* allocate buffer for new block */ pData = (ULONG *) Ext2AllocatePool( PagedPool, BLOCK_SIZE, EXT2_DATA_MAGIC ); if (!pData) { DEBUG(DL_ERR, ( "Ex2ExpandBlock: failed to allocate memory for Data.\n")); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } RtlZeroMemory(pData, BLOCK_SIZE); INC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); } /* allocate block from disk */ Status = Ext2NewBlock( IrpContext, Vcb, (Mcb->Inode.i_ino - 1) / BLOCKS_PER_GROUP, *Hint, Block, Number ); if (!NT_SUCCESS(Status)) { goto errorout; } /* increase inode i_blocks */ Mcb->Inode.i_blocks += (*Number << (BLOCK_BITS - 9)); if (Layer == 0) { if (IsMcbDirectory(Mcb)) { /* for directory we need initialize it's entry structure */ PEXT2_DIR_ENTRY2 pEntry; pEntry = (PEXT2_DIR_ENTRY2) pData; pEntry->rec_len = (USHORT)(BLOCK_SIZE); ASSERT(*Number == 1); Ext2SaveBlock(IrpContext, Vcb, *Block, (PVOID)pData); } /* add new Extent into Mcb */ if (!Ext2AddBlockExtent(Vcb, Mcb, Base, (*Block), *Number)) { DbgBreak(); ClearFlag(Mcb->Flags, MCB_ZONE_INITED); Ext2ClearAllExtents(&Mcb->Extents); } } else { /* zero the content of all meta blocks */ for (i = 0; i < *Number; i++) { Ext2SaveBlock(IrpContext, Vcb, *Block + i, (PVOID)pData); /* add block to meta extents */ if (!Ext2AddMcbMetaExts(Vcb, Mcb, *Block + i, 1)) { DbgBreak(); Ext2Sleep(500); Ext2AddMcbMetaExts(Vcb, Mcb, *Block + i, 1); } } } errorout: if (NT_SUCCESS(Status)) { *Hint = *Block + *Number; if (Data) { *Data = pData; ASSERT(*Number == 1); } else { if (pData) { Ext2FreePool(pData, EXT2_DATA_MAGIC); DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); } } } else { if (pData) { Ext2FreePool(pData, EXT2_DATA_MAGIC); DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); } if (*Block) { Ext2FreeBlock(IrpContext, Vcb, *Block, *Number); Mcb->Inode.i_blocks -= (*Number << (BLOCK_BITS - 9)); *Block = 0; } } return Status; }