NTSTATUS FAT32FindAndMarkAvailableCluster (PDEVICE_EXTENSION DeviceExt, PULONG Cluster) /* * FUNCTION: Finds the first available cluster in a FAT32 table */ { ULONG FatLength; ULONG StartCluster; ULONG i, j; PVOID BaseAddress; ULONG ChunkSize; PVOID Context; LARGE_INTEGER Offset; PULONG Block; PULONG BlockEnd; ChunkSize = CACHEPAGESIZE(DeviceExt); FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2); *Cluster = 0; StartCluster = DeviceExt->LastAvailableCluster; for (j = 0; j < 2; j++) { for (i = StartCluster; i < FatLength;) { Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize); if(!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress)) { DPRINT1("CcMapData(Offset %x, Length %d) failed\n", (ULONG)Offset.QuadPart, ChunkSize); return STATUS_UNSUCCESSFUL; } Block = (PULONG)((ULONG_PTR)BaseAddress + (i * 4) % ChunkSize); BlockEnd = (PULONG)((ULONG_PTR)BaseAddress + ChunkSize); /* Now process the whole block */ while (Block < BlockEnd && i < FatLength) { if ((*Block & 0x0fffffff) == 0) { DPRINT("Found available cluster 0x%x\n", i); DeviceExt->LastAvailableCluster = *Cluster = i; *Block = 0x0fffffff; CcSetDirtyPinnedData(Context, NULL); CcUnpinData(Context); if (DeviceExt->AvailableClustersValid) InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters); return(STATUS_SUCCESS); } Block++; i++; } CcUnpinData(Context); } FatLength = StartCluster; StartCluster = 2; } return (STATUS_DISK_FULL); }
/* * FUNCTION: Finds the first available cluster in a FAT12 table */ NTSTATUS FAT12FindAndMarkAvailableCluster( PDEVICE_EXTENSION DeviceExt, PULONG Cluster) { ULONG FatLength; ULONG StartCluster; ULONG Entry; PUSHORT CBlock; ULONG i, j; PVOID BaseAddress; PVOID Context; LARGE_INTEGER Offset; FatLength = DeviceExt->FatInfo.NumberOfClusters + 2; *Cluster = 0; StartCluster = DeviceExt->LastAvailableCluster; Offset.QuadPart = 0; if (!CcPinRead(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress)) { DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector); return STATUS_UNSUCCESSFUL; } for (j = 0; j < 2; j++) { for (i = StartCluster; i < FatLength; i++) { CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8); if ((i % 2) == 0) { Entry = *CBlock & 0xfff; } else { Entry = *CBlock >> 4; } if (Entry == 0) { DPRINT("Found available cluster 0x%x\n", i); DeviceExt->LastAvailableCluster = *Cluster = i; if ((i % 2) == 0) *CBlock = (*CBlock & 0xf000) | 0xfff; else *CBlock = (*CBlock & 0xf) | 0xfff0; CcSetDirtyPinnedData(Context, NULL); CcUnpinData(Context); if (DeviceExt->AvailableClustersValid) InterlockedDecrement((PLONG)&DeviceExt->AvailableClusters); return STATUS_SUCCESS; } } FatLength = StartCluster; StartCluster = 2; } CcUnpinData(Context); return STATUS_DISK_FULL; }
/* * update an existing FAT entry */ NTSTATUS VfatUpdateEntry( IN PVFATFCB pFcb) { PVOID Context; PDIR_ENTRY PinEntry; LARGE_INTEGER Offset; ULONG SizeDirEntry; ULONG dirIndex; ASSERT(pFcb); if (pFcb->Flags & FCB_IS_FATX_ENTRY) { SizeDirEntry = sizeof(FATX_DIR_ENTRY); dirIndex = pFcb->startIndex; } else { SizeDirEntry = sizeof(FAT_DIR_ENTRY); dirIndex = pFcb->dirIndex; } DPRINT("updEntry dirIndex %u, PathName \'%wZ\'\n", dirIndex, &pFcb->PathNameU); if (vfatFCBIsRoot(pFcb) || (pFcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME))) { return STATUS_SUCCESS; } ASSERT(pFcb->parentFcb); Offset.u.HighPart = 0; Offset.u.LowPart = dirIndex * SizeDirEntry; _SEH2_TRY { CcPinRead(pFcb->parentFcb->FileObject, &Offset, SizeDirEntry, PIN_WAIT, &Context, (PVOID*)&PinEntry); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { DPRINT1("Failed write to \'%wZ\'.\n", &pFcb->parentFcb->PathNameU); _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; pFcb->Flags &= ~FCB_IS_DIRTY; RtlCopyMemory(PinEntry, &pFcb->entry, SizeDirEntry); CcSetDirtyPinnedData(Context, NULL); CcUnpinData(Context); return STATUS_SUCCESS; }
static NTSTATUS FsdSetFsLabelInformation( PDEVICE_OBJECT DeviceObject, PFILE_FS_LABEL_INFORMATION FsLabelInfo) { PDEVICE_EXTENSION DeviceExt; PVOID Context = NULL; ULONG DirIndex = 0; PDIR_ENTRY Entry; PVFATFCB pRootFcb; LARGE_INTEGER FileOffset; BOOLEAN LabelFound = FALSE; DIR_ENTRY VolumeLabelDirEntry; ULONG VolumeLabelDirIndex; ULONG LabelLen; NTSTATUS Status = STATUS_UNSUCCESSFUL; OEM_STRING StringO; UNICODE_STRING StringW; CHAR cString[43]; ULONG SizeDirEntry; ULONG EntriesPerPage; DPRINT("FsdSetFsLabelInformation()\n"); DeviceExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; if (sizeof(DeviceObject->Vpb->VolumeLabel) < FsLabelInfo->VolumeLabelLength) { return STATUS_NAME_TOO_LONG; } if (DeviceExt->Flags & VCB_IS_FATX) { if (FsLabelInfo->VolumeLabelLength / sizeof(WCHAR) > 42) return STATUS_NAME_TOO_LONG; SizeDirEntry = sizeof(FATX_DIR_ENTRY); EntriesPerPage = FATX_ENTRIES_PER_PAGE; } else { if (FsLabelInfo->VolumeLabelLength / sizeof(WCHAR) > 11) return STATUS_NAME_TOO_LONG; SizeDirEntry = sizeof(FAT_DIR_ENTRY); EntriesPerPage = FAT_ENTRIES_PER_PAGE; } /* Create Volume label dir entry */ LabelLen = FsLabelInfo->VolumeLabelLength / sizeof(WCHAR); RtlZeroMemory(&VolumeLabelDirEntry, SizeDirEntry); StringW.Buffer = FsLabelInfo->VolumeLabel; StringW.Length = StringW.MaximumLength = (USHORT)FsLabelInfo->VolumeLabelLength; StringO.Buffer = cString; StringO.Length = 0; StringO.MaximumLength = 42; Status = RtlUnicodeStringToOemString(&StringO, &StringW, FALSE); if (!NT_SUCCESS(Status)) return Status; if (DeviceExt->Flags & VCB_IS_FATX) { RtlCopyMemory(VolumeLabelDirEntry.FatX.Filename, cString, LabelLen); memset(&VolumeLabelDirEntry.FatX.Filename[LabelLen], ' ', 42 - LabelLen); VolumeLabelDirEntry.FatX.Attrib = _A_VOLID; } else { RtlCopyMemory(VolumeLabelDirEntry.Fat.Filename, cString, max(sizeof(VolumeLabelDirEntry.Fat.Filename), LabelLen)); if (LabelLen > sizeof(VolumeLabelDirEntry.Fat.Filename)) { memset(VolumeLabelDirEntry.Fat.Ext, ' ', sizeof(VolumeLabelDirEntry.Fat.Ext)); RtlCopyMemory(VolumeLabelDirEntry.Fat.Ext, cString + sizeof(VolumeLabelDirEntry.Fat.Filename), LabelLen - sizeof(VolumeLabelDirEntry.Fat.Filename)); } else { memset(&VolumeLabelDirEntry.Fat.Filename[LabelLen], ' ', sizeof(VolumeLabelDirEntry.Fat.Filename) - LabelLen); } VolumeLabelDirEntry.Fat.Attrib = _A_VOLID; } pRootFcb = vfatOpenRootFCB(DeviceExt); /* Search existing volume entry on disk */ FileOffset.QuadPart = 0; if (CcPinRead(pRootFcb->FileObject, &FileOffset, SizeDirEntry, TRUE, &Context, (PVOID*)&Entry)) { while (TRUE) { if (ENTRY_VOLUME(DeviceExt, Entry)) { /* Update entry */ LabelFound = TRUE; RtlCopyMemory(Entry, &VolumeLabelDirEntry, SizeDirEntry); CcSetDirtyPinnedData(Context, NULL); Status = STATUS_SUCCESS; break; } if (ENTRY_END(DeviceExt, Entry)) { break; } DirIndex++; Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry); if ((DirIndex % EntriesPerPage) == 0) { CcUnpinData(Context); FileOffset.u.LowPart += PAGE_SIZE; if (!CcPinRead(pRootFcb->FileObject, &FileOffset, SizeDirEntry, TRUE, &Context, (PVOID*)&Entry)) { Context = NULL; break; } } } if (Context) { CcUnpinData(Context); } } if (!LabelFound) { /* Add new entry for label */ if (!vfatFindDirSpace(DeviceExt, pRootFcb, 1, &VolumeLabelDirIndex)) Status = STATUS_DISK_FULL; else { FileOffset.u.HighPart = 0; FileOffset.u.LowPart = VolumeLabelDirIndex * SizeDirEntry; if (!CcPinRead(pRootFcb->FileObject, &FileOffset, SizeDirEntry, TRUE, &Context, (PVOID*)&Entry)) { Status = STATUS_UNSUCCESSFUL; } else { RtlCopyMemory(Entry, &VolumeLabelDirEntry, SizeDirEntry); CcSetDirtyPinnedData(Context, NULL); CcUnpinData(Context); Status = STATUS_SUCCESS; } } } vfatReleaseFCB(DeviceExt, pRootFcb); if (!NT_SUCCESS(Status)) { return Status; } /* Update volume label in memory */ DeviceObject->Vpb->VolumeLabelLength = (USHORT)FsLabelInfo->VolumeLabelLength; RtlCopyMemory(DeviceObject->Vpb->VolumeLabel, FsLabelInfo->VolumeLabel, DeviceObject->Vpb->VolumeLabelLength); return Status; }
BOOLEAN FFSCheckSetBlock( PFFS_IRP_CONTEXT IrpContext, PFFS_VCB Vcb, ULONG Block) { #if 0 ULONG Group, dwBlk, Length; RTL_BITMAP BlockBitmap; PVOID BitmapCache; PBCB BitmapBcb; LARGE_INTEGER Offset; BOOLEAN bModified = FALSE; //Group = (Block - FFS_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP; dwBlk = (Block - FFS_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP; Offset.QuadPart = (LONGLONG) Vcb->BlockSize; Offset.QuadPart = Offset.QuadPart * Vcb->ffs_group_desc[Group].bg_block_bitmap; if (Group == Vcb->ffs_groups - 1) { Length = TOTAL_BLOCKS % BLOCKS_PER_GROUP; /* s_blocks_count is integer multiple of s_blocks_per_group */ if (Length == 0) Length = BLOCKS_PER_GROUP; } else { Length = BLOCKS_PER_GROUP; } if (dwBlk >= Length) return FALSE; if (!CcPinRead(Vcb->StreamObj, &Offset, Vcb->BlockSize, PIN_WAIT, &BitmapBcb, &BitmapCache)) { FFSPrint((DBG_ERROR, "FFSDeleteBlock: PinReading error ...\n")); return FALSE; } RtlInitializeBitMap(&BlockBitmap, BitmapCache, Length); if (RtlCheckBit(&BlockBitmap, dwBlk) == 0) { FFSBreakPoint(); RtlSetBits(&BlockBitmap, dwBlk, 1); bModified = TRUE; } if (bModified) { CcSetDirtyPinnedData(BitmapBcb, NULL); FFSRepinBcb(IrpContext, BitmapBcb); FFSAddMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize); } { CcUnpinData(BitmapBcb); BitmapBcb = NULL; BitmapCache = NULL; RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP)); } return (!bModified); #endif return FALSE; }
VOID FatPrepareWriteDirectoryFile ( IN PIRP_CONTEXT IrpContext, IN PDCB Dcb, IN VBO StartingVbo, IN ULONG ByteCount, OUT PBCB *Bcb, OUT PVOID *Buffer, IN BOOLEAN Zero, IN BOOLEAN Reversible, OUT PNTSTATUS Status ) /*++ Routine Description: This routine first looks to see if the specified range of sectors is already in the cache. If so, it increments the BCB PinCount, sets the BCB dirty, and returns TRUE with the location of the sectors. The IrpContext->Flags .. Wait == TRUE/FALSE actions of this routine are identical to FatPrepareWriteVolumeFile() above. Arguments: Dcb - Pointer to the DCB for the directory StartingVbo - The virtual offset of the first byte to be written ByteCount - Number of bytes to be written Bcb - Returns a pointer to the BCB which is valid until unpinned Buffer - Returns a pointer to the sectors, which is valid until unpinned Zero - Supplies TRUE if the specified range of bytes should be zeroed Reversible - Supplies TRUE if the specified range of modification should be repinned so that the operation can be reversed in a controlled fashion if errors are encountered. Status - Returns the status of the operation. --*/ { LARGE_INTEGER Vbo; ULONG InitialAllocation; BOOLEAN UnwindWeAllocatedDiskSpace = FALSE; ULONG ClusterSize; PVOID LocalBuffer; PAGED_CODE(); DebugTrace(+1, Dbg, "FatPrepareWriteDirectoryFile\n", 0); DebugTrace( 0, Dbg, "Dcb = %08lx\n", Dcb); DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", (ULONG)StartingVbo); DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount); DebugTrace( 0, Dbg, "Zero = %08lx\n", Zero); *Bcb = NULL; *Buffer = NULL; // // If we need to create a directory file and initialize the // cachemap, do so. // FatOpenDirectoryFile( IrpContext, Dcb ); // // If the transfer is beyond the allocation size we need to // extend the directory's allocation. The call to // AddFileAllocation will raise a condition if // it runs out of disk space. Note that the root directory // cannot be extended. // Vbo.QuadPart = StartingVbo; try { if (StartingVbo + ByteCount > Dcb->Header.AllocationSize.LowPart) { if (NodeType(Dcb) == FAT_NTC_ROOT_DCB && !FatIsFat32(Dcb->Vcb)) { FatRaiseStatus( IrpContext, STATUS_DISK_FULL ); } DebugTrace(0, Dbg, "Try extending normal directory\n", 0); InitialAllocation = Dcb->Header.AllocationSize.LowPart; FatAddFileAllocation( IrpContext, Dcb, Dcb->Specific.Dcb.DirectoryFile, StartingVbo + ByteCount ); UnwindWeAllocatedDiskSpace = TRUE; // // Inform the cache manager of the new allocation // Dcb->Header.FileSize.LowPart = Dcb->Header.AllocationSize.LowPart; CcSetFileSizes( Dcb->Specific.Dcb.DirectoryFile, (PCC_FILE_SIZES)&Dcb->Header.AllocationSize ); // // Set up the Bitmap buffer if it is not big enough already // FatCheckFreeDirentBitmap( IrpContext, Dcb ); // // The newly allocated clusters should be zeroed starting at // the previous allocation size // Zero = TRUE; Vbo.QuadPart = InitialAllocation; ByteCount = Dcb->Header.AllocationSize.LowPart - InitialAllocation; } // // Call the Cache Manager to attempt the transfer, going one cluster // at a time to avoid pinning across a page boundary. // ClusterSize = 1 << Dcb->Vcb->AllocationSupport.LogOfBytesPerCluster; while (ByteCount > 0) { ULONG BytesToPin; *Bcb = NULL; if (ByteCount > ClusterSize) { BytesToPin = ClusterSize; } else { BytesToPin = ByteCount; } ASSERT( (Vbo.QuadPart / ClusterSize) == (Vbo.QuadPart + BytesToPin - 1)/ClusterSize ); if (!CcPinRead( Dcb->Specific.Dcb.DirectoryFile, &Vbo, BytesToPin, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT), Bcb, &LocalBuffer )) { // // Could not read the data without waiting (cache miss). // FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } // // Update our caller with the beginning of their request. // if (*Buffer == NULL) { *Buffer = LocalBuffer; } DbgDoit( IrpContext->PinCount += 1 ) if (Zero) { // // We set this guy dirty right now so that we can raise CANT_WAIT when // it needs to be done. It'd be beautiful if we could noop the read IO // since we know we don't care about it. // RtlZeroMemory( LocalBuffer, BytesToPin ); CcSetDirtyPinnedData( *Bcb, NULL ); } ByteCount -= BytesToPin; Vbo.QuadPart += BytesToPin; if (ByteCount > 0) { FatUnpinBcb( IrpContext, *Bcb ); } } // // This lets us get the data pinned until we complete the request // and writes the dirty bit through to the disk. // FatSetDirtyBcb( IrpContext, *Bcb, Dcb->Vcb, Reversible ); *Status = STATUS_SUCCESS; } finally { DebugUnwind( FatPrepareWriteDirectoryFile ); if (AbnormalTermination()) { // // These steps are carefully arranged - FatTruncateFileAllocation can raise. // Make sure we unpin the buffer. If FTFA raises, the effect should be benign. // FatUnpinBcb(IrpContext, *Bcb); if (UnwindWeAllocatedDiskSpace == TRUE) { // // Inform the cache manager of the change. // FatTruncateFileAllocation( IrpContext, Dcb, InitialAllocation ); Dcb->Header.FileSize.LowPart = Dcb->Header.AllocationSize.LowPart; CcSetFileSizes( Dcb->Specific.Dcb.DirectoryFile, (PCC_FILE_SIZES)&Dcb->Header.AllocationSize ); } } DebugTrace(-1, Dbg, "FatPrepareWriteDirectoryFile -> (VOID), *Bcb = %08lx\n", *Bcb); } return; }
BOOLEAN CmpFileWriteThroughCache( PHHIVE Hive, ULONG FileType, PCMP_OFFSET_ARRAY offsetArray, ULONG offsetArrayCount ) /*++ Routine Description: This is routine writes dirty ranges of data using Cc mapped views. The benefit is that writes don't go through Cc Lazy Writer, so there is no danger to be throttled or deferred. It also flushes the cache for the written ranges, guaranteeing that the data was commited to the disk upon return. Arguments: Hive - Hive we are doing I/O for FileType - which supporting file to use offsetArray - array of structures where each structure holds a 32bit offset into the Hive file and pointer the a buffer written to that file offset. offsetArrayCount - number of elements in the offsetArray. Return Value: FALSE if failure TRUE if success Note: This routine is intended to deal only with paged bins (i.e. bins crossing the CM_VIEW_SIZE boundary or bins that were added after the last sync) Assumption: We work on the assumption that the data to be written at one iteration never spans over the CM_VIEW_SIZE boundary. HvpFindNextDirtyBlock takes care of that !!! --*/ { ULONG i; PVOID DataBuffer; ULONG DataLength; ULONG FileOffset; PCMHIVE CmHive; PVOID Bcb; PVOID FileBuffer; LARGE_INTEGER Offset; IO_STATUS_BLOCK IoStatus; ASSERT_PASSIVE_LEVEL(); #if !DBG UNREFERENCED_PARAMETER (FileType); #endif CmHive = (PCMHIVE)CONTAINING_RECORD(Hive, CMHIVE, Hive); ASSERT( ((FileType == HFILE_TYPE_EXTERNAL) && (CmHive->FileObject != NULL)) || HiveWritesThroughCache(Hive,FileType) ); Offset.HighPart = 0; // // iterate through the array of data // for(i=0;i<offsetArrayCount;i++) { DataBuffer = offsetArray[i].DataBuffer; DataLength = offsetArray[i].DataLength; FileOffset = offsetArray[i].FileOffset; // // data should never span over CM_VIEW_SIZE boundary // ASSERT( (FileOffset & (~(CM_VIEW_SIZE - 1))) == ((FileOffset + DataLength - 1) & (~(CM_VIEW_SIZE - 1))) ); // // unmap any possible mapped view that could overlap with this range ; not needed !!!! // // // map and pin data // Offset.LowPart = FileOffset; try { if( !CcPinRead (CmHive->FileObject,&Offset,DataLength,PIN_WAIT,&Bcb,&FileBuffer) ) { CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpFileWriteThroughCache - could not pin read view i= %lu\n",i)); #if DBG DbgBreakPoint(); #endif //DBG return FALSE; } // // copy data to pinned view; we need to do it inside try except, to protect against devices/volumes // dismounting from under us. // RtlCopyMemory(FileBuffer,DataBuffer, DataLength); } except (EXCEPTION_EXECUTE_HANDLER) { // // in low-memory scenarios, CcPinRead throws a STATUS_INSUFFICIENT_RESOURCES // We want to catch this and treat as a "not enough resources" problem, // rather than letting it to surface the kernel call // CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpFileWriteThroughCache : CcPinRead has raised :%08lx\n",GetExceptionCode())); return FALSE; } // // dirty, unpin and flush // CcSetDirtyPinnedData (Bcb,NULL); CcUnpinData( Bcb ); CcFlushCache (CmHive->FileObject->SectionObjectPointer,(PLARGE_INTEGER)(((ULONG_PTR)(&Offset)) + 1)/*we are private writers*/,DataLength,&IoStatus); if(!NT_SUCCESS(IoStatus.Status) ) { return FALSE; } } return TRUE; }
/* * rename an existing FAT entry */ NTSTATUS vfatRenameEntry( IN PDEVICE_EXTENSION DeviceExt, IN PVFATFCB pFcb, IN PUNICODE_STRING FileName, IN BOOLEAN CaseChangeOnly) { OEM_STRING NameA; ULONG StartIndex; PVOID Context = NULL; LARGE_INTEGER Offset; PFATX_DIR_ENTRY pDirEntry; NTSTATUS Status; DPRINT("vfatRenameEntry(%p, %p, %wZ, %d)\n", DeviceExt, pFcb, FileName, CaseChangeOnly); if (pFcb->Flags & FCB_IS_FATX_ENTRY) { VFAT_DIRENTRY_CONTEXT DirContext; /* Open associated dir entry */ StartIndex = pFcb->startIndex; Offset.u.HighPart = 0; Offset.u.LowPart = (StartIndex * sizeof(FATX_DIR_ENTRY) / PAGE_SIZE) * PAGE_SIZE; _SEH2_TRY { CcPinRead(pFcb->parentFcb->FileObject, &Offset, PAGE_SIZE, PIN_WAIT, &Context, (PVOID*)&pDirEntry); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { DPRINT1("CcPinRead(Offset %x:%x, Length %d) failed\n", Offset.u.HighPart, Offset.u.LowPart, PAGE_SIZE); _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; pDirEntry = &pDirEntry[StartIndex % (PAGE_SIZE / sizeof(FATX_DIR_ENTRY))]; /* Set file name */ NameA.Buffer = (PCHAR)pDirEntry->Filename; NameA.Length = 0; NameA.MaximumLength = 42; RtlUnicodeStringToOemString(&NameA, FileName, FALSE); pDirEntry->FilenameLength = (unsigned char)NameA.Length; /* Update FCB */ DirContext.ShortNameU.Length = 0; DirContext.ShortNameU.MaximumLength = 0; DirContext.ShortNameU.Buffer = NULL; DirContext.LongNameU = *FileName; DirContext.DirEntry.FatX = *pDirEntry; CcSetDirtyPinnedData(Context, NULL); CcUnpinData(Context); Status = vfatUpdateFCB(DeviceExt, pFcb, &DirContext, pFcb->parentFcb); if (NT_SUCCESS(Status)) { CcPurgeCacheSection(&pFcb->parentFcb->SectionObjectPointers, NULL, 0, FALSE); } return Status; }
NTSTATUS Ext2TruncateBlock( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Base, IN ULONG Start, IN ULONG Layer, IN ULONG SizeArray, IN PULONG BlockArray, IN PULONG Extra ) { NTSTATUS Status = STATUS_SUCCESS; ULONG i = 0; ULONG Slot = 0; ULONG Skip = 0; LONGLONG Offset; PBCB Bcb = NULL; PULONG pData = NULL; ASSERT(Mcb != NULL); for (i = 0; i < SizeArray; i++) { if (Layer == 0) { ULONG Number = 1; while (Extra && SizeArray > i + 1 && Number < *Extra) { if (BlockArray[SizeArray - i - 1] == BlockArray[SizeArray - i - 2] + 1) { BlockArray[SizeArray - i - 1] = 0; Number++; SizeArray--; } else { break; } } if (BlockArray[SizeArray - i - 1]) { Status = Ext2FreeBlock(IrpContext, Vcb, BlockArray[SizeArray - i - 1], Number); if (NT_SUCCESS(Status)) { ASSERT(Mcb->Inode.i_blocks >= (Number << (BLOCK_BITS - 9))); if (Mcb->Inode.i_blocks < (Number << (BLOCK_BITS - 9))) { Mcb->Inode.i_blocks = 0; DbgBreak(); } else { Mcb->Inode.i_blocks -= (Number << (BLOCK_BITS - 9)); } BlockArray[SizeArray - i - 1] = 0; } } if (Extra) { /* dec blocks count */ ASSERT(*Extra >= Number); *Extra = *Extra - Number; /* remove block mapping frm Mcb Extents */ if (!Ext2RemoveBlockExtent(Vcb, Mcb, Base + SizeArray - 1 - i, Number)) { DbgBreak(); ClearFlag(Mcb->Flags, MCB_ZONE_INITED); Ext2ClearAllExtents(&Mcb->Extents); } } } else { ASSERT(Layer <= 3); if (BlockArray[SizeArray - i - 1] >= TOTAL_BLOCKS) { DbgBreak(); BlockArray[SizeArray - i - 1] = 0; } if (i == 0) { if (Layer > 1) { Slot = Start / Vcb->max_blocks_per_layer[Layer - 1]; Start = Start % Vcb->max_blocks_per_layer[Layer - 1]; } else { Slot = Start; Start = (BLOCK_SIZE / 4) - 1; } } else { Slot = Start = (BLOCK_SIZE / 4) - 1; } Skip = (SizeArray - i - 1) * Vcb->max_blocks_per_layer[Layer]; if (BlockArray[SizeArray - i - 1]) { Offset = (LONGLONG) (BlockArray[SizeArray - i - 1]); Offset = Offset << BLOCK_BITS; if (!CcPinRead( Vcb->Volume, (PLARGE_INTEGER) (&Offset), BLOCK_SIZE, PIN_WAIT, &Bcb, (void **)&pData )) { DEBUG(DL_ERR, ( "Ext2TruncateBlock: PinLock failed on block %xh ...\n", BlockArray[SizeArray - i - 1])); Status = STATUS_CANT_WAIT; DbgBreak(); goto errorout; } Status = Ext2TruncateBlock( IrpContext, Vcb, Mcb, Base + Skip, Start, Layer - 1, Slot + 1, &pData[0], Extra ); if (!NT_SUCCESS(Status)) { break; } CcSetDirtyPinnedData(Bcb, NULL); Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)BLOCK_SIZE); if (*Extra || Ext2IsBlockEmpty(pData, BLOCK_SIZE/4)) { Ext2TruncateBlock( IrpContext, Vcb, Mcb, Base + Skip, /* base */ 0, /* start */ 0, /* layer */ 1, &BlockArray[SizeArray - i - 1], NULL ); if (!Ext2RemoveMcbMetaExts(Vcb, Mcb, BlockArray[SizeArray - i - 1], 1)) { DbgBreak(); Ext2Sleep(500); Ext2RemoveMcbMetaExts(Vcb, Mcb, BlockArray[SizeArray - i - 1], 1); } } if (pData) { CcUnpinData(Bcb); Bcb = NULL; pData = NULL; } } else { if (Layer > 1) { if (*Extra > Slot * Vcb->max_blocks_per_layer[Layer - 1] + Start + 1) { *Extra -= (Slot * Vcb->max_blocks_per_layer[Layer - 1] + Start + 1); } else { *Extra = 0; } } else { if (*Extra > Slot + 1) { *Extra -= (Slot + 1); } else { *Extra = 0; } } if (!Ext2RemoveBlockExtent(Vcb, Mcb, Base + Skip, (Start + 1))) { DbgBreak(); ClearFlag(Mcb->Flags, MCB_ZONE_INITED); Ext2ClearAllExtents(&Mcb->Extents); } } } if (Extra && *Extra == 0) { break; } } errorout: if (pData) { CcUnpinData(Bcb); } return Status; }
NTSTATUS Ext2ExpandBlock( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Base, IN ULONG Layer, IN ULONG Start, IN ULONG SizeArray, IN PULONG BlockArray, IN PULONG Hint, IN PULONG Extra ) { ULONG i = 0; ULONG j; ULONG Slot; ULONG Block = 0; LARGE_INTEGER Offset; PBCB Bcb = NULL; PULONG pData = NULL; ULONG Skip = 0; ULONG Number; ULONG Wanted; NTSTATUS Status = STATUS_SUCCESS; if (Layer == 1) { /* * try to make all leaf block continuous to avoid fragments */ Number = min(SizeArray, ((*Extra + (Start & (BLOCK_SIZE/4 - 1))) * 4 / BLOCK_SIZE)); Wanted = 0; DEBUG(DL_BLK, ("Ext2ExpandBlock: SizeArray=%xh Extra=%xh Start=%xh %xh\n", SizeArray, *Extra, Start, Number )); for (i=0; i < Number; i++) { if (BlockArray[i] == 0) { Wanted += 1; } } i = 0; while (Wanted > 0) { Number = Wanted; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, NULL, Hint, &Block, &Number ); if (!NT_SUCCESS(Status)) { goto errorout; } ASSERT(Number > 0); Wanted -= Number; while (Number) { if (BlockArray[i] == 0) { BlockArray[i] = Block++; Number--; } i++; } } } else if (Layer == 0) { /* * bulk allocation for inode data blocks */ i = 0; while (*Extra && i < SizeArray) { Wanted = 0; Number = 1; for (j = i; j < SizeArray && j < i + *Extra; j++) { if (BlockArray[j] >= TOTAL_BLOCKS) { DbgBreak(); BlockArray[j] = 0; } if (BlockArray[j] == 0) { Wanted += 1; } else { break; } } if (Wanted == 0) { /* add block extent into Mcb */ ASSERT(BlockArray[i] != 0); if (!Ext2AddBlockExtent(Vcb, Mcb, Base + i, BlockArray[i], 1)) { DbgBreak(); ClearFlag(Mcb->Flags, MCB_ZONE_INITED); Ext2ClearAllExtents(&Mcb->Extents); } } else { Number = Wanted; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base + i, 0, NULL, Hint, &Block, &Number ); if (!NT_SUCCESS(Status)) { goto errorout; } ASSERT(Number > 0); for (j = 0; j < Number; j++) { BlockArray[i + j] = Block++; } } *Extra -= Number; i += Number; } goto errorout; } /* * only for meta blocks allocation */ for (i = 0; *Extra && i < SizeArray; i++) { if (Layer <= 3) { if (BlockArray[i] >= TOTAL_BLOCKS) { DbgBreak(); BlockArray[i] = 0; } if (BlockArray[i] == 0) { Number = 1; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, &pData, Hint, &BlockArray[i], &Number ); if (!NT_SUCCESS(Status)) { goto errorout; } } else { Offset.QuadPart = (((LONGLONG)BlockArray[i]) << BLOCK_BITS); if (!CcPinRead( Vcb->Volume, &Offset, BLOCK_SIZE, PIN_WAIT, &Bcb, (void **)&pData )) { DEBUG(DL_ERR, ( "Ext2ExpandInode: failed to PinLock offset :%I64xh...\n", Offset.QuadPart)); Status = STATUS_CANT_WAIT; DbgBreak(); goto errorout; } /* add block to meta extents */ if (!Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[i], 1)) { DbgBreak(); Ext2Sleep(500); Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[i], 1); } } Skip = Vcb->max_blocks_per_layer[Layer] * i; if (i == 0) { if (Layer > 1) { Slot = Start / Vcb->max_blocks_per_layer[Layer - 1]; Start = Start % Vcb->max_blocks_per_layer[Layer - 1]; Skip += Slot * Vcb->max_blocks_per_layer[Layer - 1]; } else { Slot = Start; Start = 0; Skip += Slot; } } else { Start = 0; Slot = 0; } Status = Ext2ExpandBlock( IrpContext, Vcb, Mcb, Base + Skip, Layer - 1, Start, BLOCK_SIZE/4 - Slot, &pData[Slot], Hint, Extra ); if (Bcb) { CcSetDirtyPinnedData(Bcb, NULL); if (!Ext2AddBlockExtent(Vcb, NULL, BlockArray[i], BlockArray[i], 1)) { DbgBreak(); Ext2Sleep(500); if (!Ext2AddBlockExtent(Vcb, NULL, BlockArray[i], BlockArray[i], 1)) { } } } else { Ext2SaveBlock(IrpContext, Vcb, BlockArray[i], (PVOID)pData); } if (pData) { if (Bcb) { CcUnpinData(Bcb); Bcb = NULL; } else { Ext2FreePool(pData, EXT2_DATA_MAGIC); DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); } pData = NULL; } if (!NT_SUCCESS(Status)) { DbgBreak(); break; } } } errorout: return Status; }
NTSTATUS Ext2GetBlock( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Base, IN ULONG Layer, IN ULONG Start, IN ULONG SizeArray, IN PULONG BlockArray, IN BOOLEAN bAlloc, IN OUT PULONG Hint, OUT PULONG Block, OUT PULONG Number ) { NTSTATUS Status = STATUS_SUCCESS; PBCB Bcb = NULL; PULONG pData = NULL; ULONG Slot = 0, i = 0; ULONG Unit = 1; LARGE_INTEGER Offset; if (Layer == 0) { *Number = 1; if (BlockArray[0] == 0 && bAlloc) { /* now allocate new block */ Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, NULL, Hint, &BlockArray[0], Number ); if (!NT_SUCCESS(Status)) { goto errorout; } } else { /* check the block is valid or not */ if (BlockArray[0] >= TOTAL_BLOCKS) { DbgBreak(); Status = STATUS_DISK_CORRUPT_ERROR; goto errorout; } } *Block = BlockArray[0]; for (i=1; i < SizeArray; i++) { if (BlockArray[i] == BlockArray[i-1] + 1) { *Number = *Number + 1; } else { break; } } *Hint = BlockArray[*Number - 1]; } else if (Layer <= 3) { /* check the block is valid or not */ if (BlockArray[0] == 0 || BlockArray[0] >= TOTAL_BLOCKS) { DbgBreak(); Status = STATUS_DISK_CORRUPT_ERROR; goto errorout; } /* add block to meta extents */ if (!Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[0], 1)) { DbgBreak(); Ext2Sleep(500); Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[0], 1); } /* map memory in cache for the index block */ Offset.QuadPart = ((LONGLONG)BlockArray[0]) << BLOCK_BITS; if ( !CcPinRead( Vcb->Volume, (PLARGE_INTEGER) (&Offset), BLOCK_SIZE, PIN_WAIT, &Bcb, (void **)&pData )) { DEBUG(DL_ERR, ( "Ext2GetBlock: Failed to PinLock block: %xh ...\n", BlockArray[0] )); Status = STATUS_CANT_WAIT; goto errorout; } if (Layer > 1) { Unit = Vcb->max_blocks_per_layer[Layer - 1]; } else { Unit = 1; } Slot = Start / Unit; Start = Start % Unit; if (pData[Slot] == 0) { if (bAlloc) { /* we need allocate new block and zero all data in case it's an in-direct block. Index stores the new block no. */ ULONG Count = 1; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, NULL, Hint, &pData[Slot], &Count ); if (!NT_SUCCESS(Status)) { goto errorout; } /* refresh hint block */ *Hint = pData[Slot]; /* set dirty bit to notify system to flush */ CcSetDirtyPinnedData(Bcb, NULL ); SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); if (!Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)BLOCK_SIZE)) { DbgBreak(); Ext2Sleep(100); if (!Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)BLOCK_SIZE)) { Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } } /* save inode information here */ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); } else { *Number = 1; if (Layer == 1) { for (i = Slot + 1; i < BLOCK_SIZE/4; i++) { if (pData[i] == 0) { *Number = *Number + 1; } else { break; } } } else if (Layer == 2) { *Number = BLOCK_SIZE/4 - Start; } else { *Number = BLOCK_SIZE/4; } goto errorout; } } /* transfer to next recursion call */ Status = Ext2GetBlock( IrpContext, Vcb, Mcb, Base, Layer - 1, Start, BLOCK_SIZE/4 - Slot, &pData[Slot], bAlloc, Hint, Block, Number ); if (!NT_SUCCESS(Status)) { goto errorout; } } errorout: /* free the memory of pData */ if (Bcb) { CcUnpinData(Bcb); } if (!NT_SUCCESS(Status)) { *Block = 0; } return Status; }