/* * FUNCTION: Retrieve the next FAT32 cluster from the FAT table via a physical * disk read */ NTSTATUS FAT32GetNextCluster( PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster, PULONG NextCluster) { PVOID BaseAddress; ULONG FATOffset; ULONG ChunkSize; PVOID Context; LARGE_INTEGER Offset; ChunkSize = CACHEPAGESIZE(DeviceExt); FATOffset = CurrentCluster * sizeof(ULONG); Offset.QuadPart = ROUND_DOWN(FATOffset, ChunkSize); if (!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress)) { return STATUS_UNSUCCESSFUL; } CurrentCluster = (*(PULONG)((char*)BaseAddress + (FATOffset % ChunkSize))) & 0x0fffffff; if (CurrentCluster >= 0xffffff8 && CurrentCluster <= 0xfffffff) CurrentCluster = 0xffffffff; CcUnpinData(Context); *NextCluster = CurrentCluster; return STATUS_SUCCESS; }
/* * 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 FAT32CountAvailableClusters(PDEVICE_EXTENSION DeviceExt) /* * FUNCTION: Counts free clusters in a FAT32 table */ { PULONG Block; PULONG BlockEnd; PVOID BaseAddress = NULL; ULONG ulCount = 0; ULONG i; ULONG ChunkSize; PVOID Context = NULL; LARGE_INTEGER Offset; ULONG FatLength; ChunkSize = CACHEPAGESIZE(DeviceExt); FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2); for (i = 2; i < FatLength; ) { Offset.QuadPart = ROUND_DOWN(i * 4, ChunkSize); if(!CcMapData(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) ulCount++; Block++; i++; } CcUnpinData(Context); } DeviceExt->AvailableClusters = ulCount; DeviceExt->AvailableClustersValid = TRUE; return(STATUS_SUCCESS); }
/* * FUNCTION: Counts free clusters in a FAT16 table */ static NTSTATUS FAT16CountAvailableClusters( PDEVICE_EXTENSION DeviceExt) { PUSHORT Block; PUSHORT BlockEnd; PVOID BaseAddress = NULL; ULONG ulCount = 0; ULONG i; ULONG ChunkSize; PVOID Context = NULL; LARGE_INTEGER Offset; ULONG FatLength; ChunkSize = CACHEPAGESIZE(DeviceExt); FatLength = (DeviceExt->FatInfo.NumberOfClusters + 2); for (i = 2; i < FatLength; ) { Offset.QuadPart = ROUND_DOWN(i * 2, ChunkSize); if (!CcMapData(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress)) { return STATUS_UNSUCCESSFUL; } Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize); BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize); /* Now process the whole block */ while (Block < BlockEnd && i < FatLength) { if (*Block == 0) ulCount++; Block++; i++; } CcUnpinData(Context); } DeviceExt->AvailableClusters = ulCount; DeviceExt->AvailableClustersValid = TRUE; return STATUS_SUCCESS; }
/* * FUNCTION: Counts free cluster in a FAT12 table */ static NTSTATUS FAT12CountAvailableClusters( PDEVICE_EXTENSION DeviceExt) { ULONG Entry; PVOID BaseAddress; ULONG ulCount = 0; ULONG i; ULONG numberofclusters; LARGE_INTEGER Offset; PVOID Context; PUSHORT CBlock; Offset.QuadPart = 0; if (!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress)) { return STATUS_UNSUCCESSFUL; } numberofclusters = DeviceExt->FatInfo.NumberOfClusters + 2; for (i = 2; i < numberofclusters; i++) { CBlock = (PUSHORT)((char*)BaseAddress + (i * 12) / 8); if ((i % 2) == 0) { Entry = *CBlock & 0x0fff; } else { Entry = *CBlock >> 4; } if (Entry == 0) ulCount++; } CcUnpinData(Context); DeviceExt->AvailableClusters = ulCount; DeviceExt->AvailableClustersValid = TRUE; return STATUS_SUCCESS; }
VOID NTAPI CcUnpinRepinnedBcb(IN PVOID Bcb, IN BOOLEAN WriteThrough, OUT PIO_STATUS_BLOCK IoStatus) { PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb; if (WriteThrough) { DPRINT("BCB #%x\n", RealBcb - CcCacheSections); CcpFlushCache(RealBcb->Map, &RealBcb->FileOffset, RealBcb->Length, IoStatus, RealBcb->Dirty); } CcUnpinData(Bcb); }
/* * FUNCTION: Retrieve the next FAT12 cluster from the FAT table */ NTSTATUS FAT12GetNextCluster( PDEVICE_EXTENSION DeviceExt, ULONG CurrentCluster, PULONG NextCluster) { PUSHORT CBlock; ULONG Entry; PVOID BaseAddress; PVOID Context; LARGE_INTEGER Offset; *NextCluster = 0; Offset.QuadPart = 0; if (!CcMapData(DeviceExt->FATFileObject, &Offset, DeviceExt->FatInfo.FATSectors * DeviceExt->FatInfo.BytesPerSector, 1, &Context, &BaseAddress)) { return STATUS_UNSUCCESSFUL; } CBlock = (PUSHORT)((char*)BaseAddress + (CurrentCluster * 12) / 8); if ((CurrentCluster % 2) == 0) { Entry = *CBlock & 0x0fff; } else { Entry = *CBlock >> 4; } // DPRINT("Entry %x\n",Entry); if (Entry >= 0xff8 && Entry <= 0xfff) Entry = 0xffffffff; // DPRINT("Returning %x\n",Entry); *NextCluster = Entry; CcUnpinData(Context); // return Entry == 0xffffffff ? STATUS_END_OF_FILE : STATUS_SUCCESS; return STATUS_SUCCESS; }
FF_T_SINT32 FatReadBlocks(FF_T_UINT8 *DestBuffer, FF_T_UINT32 SectorAddress, FF_T_UINT32 Count, void *pParam) { LARGE_INTEGER Offset; //PVOID Buffer; PVCB Vcb = (PVCB)pParam; //PBCB Bcb; ULONG SectorSize = 512; // FIXME: hardcoding 512 is bad IO_STATUS_BLOCK IoSb; DPRINT("FatReadBlocks %p %d %d %p\n", DestBuffer, SectorAddress, Count, pParam); /* Calculate the offset */ Offset.QuadPart = Int32x32To64(SectorAddress, SectorSize); #if 0 if (!CcMapData(Vcb->StreamFileObject, &Offset, Count * SectorSize, TRUE, &Bcb, &Buffer)) { ASSERT(FALSE); /* Mapping failed */ return 0; } /* Copy data to the buffer */ RtlCopyMemory(DestBuffer, Buffer, Count * SectorSize); /* Unpin unneeded data */ CcUnpinData(Bcb); #else CcCopyRead(Vcb->StreamFileObject, &Offset, Count * SectorSize, TRUE, DestBuffer, &IoSb); #endif /* Return amount of read data in sectors */ return Count; }
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 LfsReadNextLogRecord ( IN LFS_LOG_HANDLE LogHandle, IN OUT LFS_LOG_CONTEXT Context, OUT PLFS_RECORD_TYPE RecordType, OUT TRANSACTION_ID *TransactionId, OUT PLSN UndoNextLsn, OUT PLSN PreviousLsn, OUT PLSN Lsn, OUT PULONG BufferLength, OUT PVOID *Buffer ) /*++ Routine Description: This routine is called to continue a query operation. The Lfs uses private information stored in the context structure to determine the next log record to return to the caller. Arguments: LogHandle - Pointer to private Lfs structure used to identify this client. Context - Supplies the address to store a pointer to the Lfs created context structure. Lsn - Lsn for this log record. RecordType - Supplies the address to store the record type of this log record. TransactionId - Supplies the address to store the transaction Id of this log record. UndoNextLsn - Supplies the address to store the Undo Next Lsn for this log record. PreviousLsn - Supplies the address to store the Previous Lsn for this log record. BufferLength - This is the length of the log data. Buffer - This is a pointer to the start of the log data. Return Value: None --*/ { volatile NTSTATUS Status = STATUS_SUCCESS; PLCH Lch; PLFCB Lfcb; PLfsLCB Lcb; BOOLEAN FoundNextLsn; BOOLEAN UnwindRememberLcbFields; PBCB UnwindRecordHeaderBcb; PLFS_RECORD_HEADER UnwindRecordHeader; PVOID UnwindCurrentLogRecord; BOOLEAN UnwindAuxilaryBuffer; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsReadNextLogRecord: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle ); LfsDebugTrace( 0, Dbg, "Context -> %08lx\n", Context ); FoundNextLsn = FALSE; UnwindRememberLcbFields = FALSE; Lch = (PLCH) LogHandle; Lcb = (PLfsLCB) Context; // // Check that the structure is a valid log handle structure. // LfsValidateLch( Lch ); // // Use a try-except to catch errors. // try { // // Use a try-finally to facilitate cleanup. // try { // // Acquire the log file control block for this log file. // LfsAcquireLch( Lch ); Lfcb = Lch->Lfcb; // // If the Log file has been closed then refuse access. // if (Lfcb == NULL) { ExRaiseStatus( STATUS_ACCESS_DENIED ); } // // Check that the client Id is valid. // LfsValidateClientId( Lfcb, Lch ); // // Check that the context structure is valid. // LfsValidateLcb( Lcb, Lch ); // // Remember any context fields to be overwritten. // UnwindRememberLcbFields = TRUE; UnwindRecordHeaderBcb = Lcb->RecordHeaderBcb; Lcb->RecordHeaderBcb = NULL; UnwindRecordHeader = Lcb->RecordHeader; UnwindCurrentLogRecord = Lcb->CurrentLogRecord; UnwindAuxilaryBuffer = Lcb->AuxilaryBuffer; Lcb->AuxilaryBuffer = FALSE; // // Find the next Lsn number based on the current Lsn number in // the context block. // if (LfsFindClientNextLsn( Lfcb, Lcb, Lsn )) { // // We can give up the Lfcb as we know the Lsn is within the file. // LfsReleaseLfcb( Lfcb ); // // Cleanup the context block so we can do the next search. // Lcb->CurrentLogRecord = NULL; Lcb->AuxilaryBuffer = FALSE; // // Perform the work of getting the log record. // LfsFindLogRecord( Lfcb, Lcb, *Lsn, RecordType, TransactionId, UndoNextLsn, PreviousLsn, BufferLength, Buffer ); FoundNextLsn = TRUE; } } finally { DebugUnwind( LfsReadNextLogRecord ); // // If we exited due to an error, we have to restore the context // block. // if (UnwindRememberLcbFields) { if (AbnormalTermination()) { // // If the record header in the context block is not // the same as we started with. Then we unpin that // data. // if (Lcb->RecordHeaderBcb != NULL) { CcUnpinData( Lcb->RecordHeaderBcb ); } if (Lcb->CurrentLogRecord != NULL && Lcb->AuxilaryBuffer == TRUE) { ExFreePool( Lcb->CurrentLogRecord ); } Lcb->RecordHeaderBcb = UnwindRecordHeaderBcb; Lcb->RecordHeader = UnwindRecordHeader; Lcb->CurrentLogRecord = UnwindCurrentLogRecord; Lcb->AuxilaryBuffer = UnwindAuxilaryBuffer; // // Otherwise, if we have successfully found the next Lsn, // we free up any resources being held from the previous search. // } else if (FoundNextLsn ) { if (UnwindRecordHeaderBcb != NULL) { CcUnpinData( UnwindRecordHeaderBcb ); } if (UnwindCurrentLogRecord != NULL && UnwindAuxilaryBuffer == TRUE) { ExFreePool( UnwindCurrentLogRecord ); } // // Restore the Bcb and auxilary buffer field for the final // cleanup. // } else { if (UnwindRecordHeaderBcb != NULL) { if (Lcb->RecordHeaderBcb != NULL) { CcUnpinData( UnwindRecordHeaderBcb ); } else { Lcb->RecordHeaderBcb = UnwindRecordHeaderBcb; } } if (UnwindAuxilaryBuffer) { if (Lcb->CurrentLogRecord == UnwindCurrentLogRecord) { Lcb->AuxilaryBuffer = TRUE; } else { ExFreePool( UnwindCurrentLogRecord ); } } } } // // Release the log file control block if held. // LfsReleaseLch( Lch ); LfsDebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart ); LfsDebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart ); LfsDebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength ); LfsDebugTrace( 0, Dbg, "Buffer -> %08lx\n", *Buffer ); LfsDebugTrace( -1, Dbg, "LfsReadNextLogRecord: Exit\n", 0 ); } } except (LfsExceptionFilter( GetExceptionInformation() )) { Status = GetExceptionCode(); } if (Status != STATUS_SUCCESS) { ExRaiseStatus( Status ); } return FoundNextLsn; }
BOOLEAN LfsSearchForwardByClient ( IN PLFCB Lfcb, IN OUT PLfsLCB Lcb, OUT PLSN Lsn ) /*++ Routine Description: This routine will attempt to find the next Lsn for this client by searching forward in the file, looking for a match. Arguments: Lfcb - Pointer to the file control block for this log file. Lcb - Pointer to the context block for this query operation. Lsn - Points to the location to store the next Lsn if found. Return Value: BOOLEAN - TRUE if another Lsn for this client is found. FALSE otherwise. --*/ { PLFS_RECORD_HEADER CurrentRecordHeader; PBCB CurrentBcb; BOOLEAN FoundNextLsn; LSN CurrentLsn; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsSearchForwardByClient: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Lcb -> %08lx\n", Lcb ); // // The log record header is in the log context // block. We set the current Bcb to NULL so that we don't // unpin the log record in the context block until we're sure // of success. // CurrentRecordHeader = Lcb->RecordHeader; CurrentBcb = NULL; // // We use a try-finally to facilitate cleanup. // try { // // We assume we won't find another Lsn. // FoundNextLsn = FALSE; // // Loop as long as another Lsn can be found. // while (LfsFindNextLsn( Lfcb, CurrentRecordHeader, &CurrentLsn )) { BOOLEAN UsaError; // // Unpin the previous log record header. // if (CurrentBcb != NULL) { CcUnpinData( CurrentBcb ); CurrentBcb = NULL; } // // Pin the log record header for this Lsn. // LfsPinOrMapLogRecordHeader( Lfcb, CurrentLsn, FALSE, FALSE, &UsaError, &CurrentRecordHeader, &CurrentBcb ); // // If the client values match, then we update the // context block and exit. // if (LfsClientIdMatch( &CurrentRecordHeader->ClientId, &Lcb->ClientId ) && CurrentRecordHeader->RecordType == LfsClientRecord) { // // We remember this one. // Lcb->RecordHeader = CurrentRecordHeader; Lcb->RecordHeaderBcb = CurrentBcb; CurrentBcb = NULL; FoundNextLsn = TRUE; *Lsn = CurrentLsn; break; } } } finally { DebugUnwind( LfsSearchForwardByClient ); // // Unpin any log record headers still pinned for no reason. // if (CurrentBcb != NULL) { CcUnpinData( CurrentBcb ); } LfsDebugTrace( 0, Dbg, "NextLsn (Low) -> %08lx\n", Lsn->LowPart ); LfsDebugTrace( 0, Dbg, "NextLsn (High) -> %08lx\n", Lsn->HighPart ); LfsDebugTrace( -1, Dbg, "LfsSearchForwardByClient: Exit -> %08x\n", FoundNextLsn ); } return FoundNextLsn; }
static NTSTATUS NtfsDirFindFile(PNTFS_VCB Vcb, PNTFS_FCB DirectoryFcb, PWSTR FileToFind, PNTFS_FCB *FoundFCB) { #if 0 WCHAR TempName[2]; WCHAR Name[256]; PVOID Block; ULONG FirstSector; ULONG DirSize; PDIR_RECORD Record; ULONG Offset; ULONG BlockOffset; NTSTATUS Status; LARGE_INTEGER StreamOffset; PVOID Context; ASSERT(DeviceExt); ASSERT(DirectoryFcb); ASSERT(FileToFind); DPRINT("NtfsDirFindFile(VCB:%08x, dirFCB:%08x, File:%S)\n", DeviceExt, DirectoryFcb, FileToFind); DPRINT("Dir Path:%S\n", DirectoryFcb->PathName); /* default to '.' if no filename specified */ if (wcslen(FileToFind) == 0) { TempName[0] = L'.'; TempName[1] = 0; FileToFind = TempName; } DirSize = DirectoryFcb->Entry.DataLengthL; StreamOffset.QuadPart = (LONGLONG)DirectoryFcb->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE; if(!CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, TRUE, &Context, &Block)) { DPRINT("CcMapData() failed\n"); return(STATUS_UNSUCCESSFUL); } Offset = 0; BlockOffset = 0; Record = (PDIR_RECORD)Block; while(TRUE) { if (Record->RecordLength == 0) { DPRINT("RecordLength == 0 Stopped!\n"); break; } DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n", Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength); NtfsGetDirEntryName(DeviceExt, Record, Name); DPRINT("Name '%S'\n", Name); if (wstrcmpjoki(Name, FileToFind)) { DPRINT("Match found, %S\n", Name); Status = NtfsMakeFCBFromDirEntry(DeviceExt, DirectoryFcb, Name, Record, FoundFCB); CcUnpinData(Context); return(Status); } Offset += Record->RecordLength; BlockOffset += Record->RecordLength; Record = (PDIR_RECORD)(Block + BlockOffset); if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0) { DPRINT("Map next sector\n"); CcUnpinData(Context); StreamOffset.QuadPart += BLOCKSIZE; Offset = ROUND_UP(Offset, BLOCKSIZE); BlockOffset = 0; if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, TRUE, &Context, &Block)) { DPRINT("CcMapData() failed\n"); return(STATUS_UNSUCCESSFUL); } Record = (PDIR_RECORD)(Block + BlockOffset); } if (Offset >= DirSize) break; } CcUnpinData(Context); #else UNREFERENCED_PARAMETER(Vcb); UNREFERENCED_PARAMETER(DirectoryFcb); UNREFERENCED_PARAMETER(FileToFind); UNREFERENCED_PARAMETER(FoundFCB); #endif return STATUS_OBJECT_NAME_NOT_FOUND; }
NTSTATUS CdfsDirFindFile(PDEVICE_EXTENSION DeviceExt, PFCB DirectoryFcb, PUNICODE_STRING FileToFind, PFCB *FoundFCB) { UNICODE_STRING TempName; WCHAR Name[256]; PVOID Block; ULONG DirSize; PDIR_RECORD Record; ULONG Offset; ULONG BlockOffset; NTSTATUS Status; LARGE_INTEGER StreamOffset, OffsetOfEntry; PVOID Context; WCHAR ShortNameBuffer[13]; UNICODE_STRING ShortName; UNICODE_STRING LongName; UNICODE_STRING FileToFindUpcase; ASSERT(DeviceExt); ASSERT(DirectoryFcb); ASSERT(FileToFind); DPRINT("CdfsDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n", DeviceExt, DirectoryFcb, FileToFind); DPRINT("Dir Path:%S\n", DirectoryFcb->PathName); /* default to '.' if no filename specified */ if (FileToFind->Length == 0) { RtlInitUnicodeString(&TempName, L"."); FileToFind = &TempName; } DirSize = DirectoryFcb->Entry.DataLengthL; StreamOffset.QuadPart = (LONGLONG)DirectoryFcb->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE; if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, TRUE, &Context, &Block)) { DPRINT("CcMapData() failed\n"); return STATUS_UNSUCCESSFUL; } Offset = 0; BlockOffset = 0; Record = (PDIR_RECORD)Block; /* Upper case the expression for FsRtlIsNameInExpression */ Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFind, TRUE); if (!NT_SUCCESS(Status)) { return Status; } while(TRUE) { if (Record->RecordLength == 0) { DPRINT("RecordLength == 0 Stopped!\n"); break; } DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n", Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength); CdfsGetDirEntryName(DeviceExt, Record, Name); DPRINT ("Name '%S'\n", Name); DPRINT ("Sector %lu\n", DirectoryFcb->Entry.ExtentLocationL); DPRINT ("Offset %lu\n", Offset); RtlInitUnicodeString(&LongName, Name); ShortName.Length = 0; ShortName.MaximumLength = 26; ShortName.Buffer = ShortNameBuffer; memset(ShortNameBuffer, 0, 26); OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset; CdfsShortNameCacheGet(DirectoryFcb, &OffsetOfEntry, &LongName, &ShortName); DPRINT("ShortName '%wZ'\n", &ShortName); if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) || FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL)) { DPRINT("Match found, %S\n", Name); Status = CdfsMakeFCBFromDirEntry(DeviceExt, DirectoryFcb, Name, ShortNameBuffer, Record, DirectoryFcb->Entry.ExtentLocationL, Offset, FoundFCB); RtlFreeUnicodeString(&FileToFindUpcase); CcUnpinData(Context); return(Status); } Offset += Record->RecordLength; BlockOffset += Record->RecordLength; Record = (PDIR_RECORD)((ULONG_PTR)Block + BlockOffset); if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0) { DPRINT("Map next sector\n"); CcUnpinData(Context); StreamOffset.QuadPart += BLOCKSIZE; Offset = ROUND_UP(Offset, BLOCKSIZE); BlockOffset = 0; if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, TRUE, &Context, &Block)) { DPRINT("CcMapData() failed\n"); RtlFreeUnicodeString(&FileToFindUpcase); return(STATUS_UNSUCCESSFUL); } Record = (PDIR_RECORD)((ULONG_PTR)Block + BlockOffset); } if (Offset >= DirSize) break; } RtlFreeUnicodeString(&FileToFindUpcase); CcUnpinData(Context); return(STATUS_OBJECT_NAME_NOT_FOUND); }
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; }
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; }
/* * FUNCTION: Find a file */ static NTSTATUS CdfsFindFile(PDEVICE_EXTENSION DeviceExt, PFCB Fcb, PFCB Parent, PUNICODE_STRING FileToFind, PULONG pDirIndex, PULONG pOffset) { WCHAR name[256]; WCHAR ShortNameBuffer[13]; UNICODE_STRING TempString; UNICODE_STRING ShortName; UNICODE_STRING LongName; UNICODE_STRING FileToFindUpcase; PVOID Block; NTSTATUS Status; ULONG len; ULONG DirIndex; ULONG Offset = 0; BOOLEAN IsRoot; PVOID Context = NULL; ULONG DirSize; PDIR_RECORD Record; LARGE_INTEGER StreamOffset, OffsetOfEntry; DPRINT("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %u)\n", Parent, FileToFind, pDirIndex ? *pDirIndex : 0); DPRINT("FindFile: old Pathname %p, old Objectname %p)\n", Fcb->PathName, Fcb->ObjectName); IsRoot = FALSE; DirIndex = 0; if (FileToFind == NULL || FileToFind->Length == 0) { RtlInitUnicodeString(&TempString, L"."); FileToFind = &TempString; } if (Parent) { if (Parent->Entry.ExtentLocationL == DeviceExt->CdInfo.RootStart) { IsRoot = TRUE; } } else { IsRoot = TRUE; } if (IsRoot == TRUE) { StreamOffset.QuadPart = (LONGLONG)DeviceExt->CdInfo.RootStart * (LONGLONG)BLOCKSIZE; DirSize = DeviceExt->CdInfo.RootSize; if (FileToFind->Buffer[0] == 0 || (FileToFind->Buffer[0] == '\\' && FileToFind->Buffer[1] == 0) || (FileToFind->Buffer[0] == '.' && FileToFind->Buffer[1] == 0)) { /* it's root : complete essentials fields then return ok */ RtlZeroMemory(Fcb, sizeof(FCB)); RtlInitEmptyUnicodeString(&Fcb->PathName, Fcb->PathNameBuffer, sizeof(Fcb->PathNameBuffer)); Fcb->PathNameBuffer[0] = '\\'; Fcb->PathName.Length = sizeof(WCHAR); Fcb->ObjectName = &Fcb->PathNameBuffer[1]; Fcb->Entry.ExtentLocationL = DeviceExt->CdInfo.RootStart; Fcb->Entry.DataLengthL = DeviceExt->CdInfo.RootSize; Fcb->Entry.FileFlags = 0x02; //FILE_ATTRIBUTE_DIRECTORY; if (pDirIndex) *pDirIndex = 0; if (pOffset) *pOffset = 0; DPRINT("CdfsFindFile: new Pathname %wZ, new Objectname %S)\n",&Fcb->PathName, Fcb->ObjectName); return STATUS_SUCCESS; } } else { StreamOffset.QuadPart = (LONGLONG)Parent->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE; DirSize = Parent->Entry.DataLengthL; } DPRINT("StreamOffset %I64d DirSize %u\n", StreamOffset.QuadPart, DirSize); if (pDirIndex && (*pDirIndex)) DirIndex = *pDirIndex; if (pOffset && (*pOffset)) { Offset = *pOffset; StreamOffset.QuadPart += ROUND_DOWN(Offset, BLOCKSIZE); } if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, TRUE, &Context, &Block)) { DPRINT("CcMapData() failed\n"); return STATUS_UNSUCCESSFUL; } Record = (PDIR_RECORD) ((ULONG_PTR)Block + Offset % BLOCKSIZE); if (Offset) { Offset += Record->RecordLength; Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength); } /* Upper case the expression for FsRtlIsNameInExpression */ Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFind, TRUE); if (!NT_SUCCESS(Status)) { return Status; } while(TRUE) { DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n", Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength); Status = CdfsGetEntryName (DeviceExt, &Context, &Block, &StreamOffset, DirSize, (PVOID*)&Record, name, &DirIndex, &Offset); if (Status == STATUS_NO_MORE_ENTRIES) { break; } else if (Status == STATUS_UNSUCCESSFUL || Status == STATUS_DISK_CORRUPT_ERROR) { /* Note: the directory cache has already been unpinned */ RtlFreeUnicodeString(&FileToFindUpcase); return Status; } DPRINT("Name '%S'\n", name); RtlInitUnicodeString(&LongName, name); ShortName.Length = 0; ShortName.MaximumLength = 26; ShortName.Buffer = ShortNameBuffer; OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset; CdfsShortNameCacheGet(Parent, &OffsetOfEntry, &LongName, &ShortName); DPRINT("ShortName '%wZ'\n", &ShortName); if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) || FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL)) { if (Parent->PathName.Buffer[0]) { RtlCopyUnicodeString(&Fcb->PathName, &Parent->PathName); len = Parent->PathName.Length / sizeof(WCHAR); Fcb->ObjectName=&Fcb->PathName.Buffer[len]; if (len != 1 || Fcb->PathName.Buffer[0] != '\\') { Fcb->ObjectName[0] = '\\'; Fcb->ObjectName = &Fcb->ObjectName[1]; } } else { Fcb->ObjectName=Fcb->PathName.Buffer; Fcb->ObjectName[0]='\\'; Fcb->ObjectName=&Fcb->ObjectName[1]; } DPRINT("PathName '%wZ' ObjectName '%S'\n", &Fcb->PathName, Fcb->ObjectName); memcpy(&Fcb->Entry, Record, sizeof(DIR_RECORD)); wcsncpy(Fcb->ObjectName, name, min(wcslen(name) + 1, MAX_PATH - (Fcb->PathName.Length / sizeof(WCHAR)) + wcslen(Fcb->ObjectName))); /* Copy short name */ Fcb->ShortNameU.Length = ShortName.Length; Fcb->ShortNameU.MaximumLength = ShortName.Length; Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer; memcpy(Fcb->ShortNameBuffer, ShortName.Buffer, ShortName.Length); if (pDirIndex) *pDirIndex = DirIndex; if (pOffset) *pOffset = Offset; DPRINT("FindFile: new Pathname %wZ, new Objectname %S, DirIndex %u\n", &Fcb->PathName, Fcb->ObjectName, DirIndex); RtlFreeUnicodeString(&FileToFindUpcase); CcUnpinData(Context); return STATUS_SUCCESS; } Offset += Record->RecordLength; Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength); DirIndex++; } RtlFreeUnicodeString(&FileToFindUpcase); CcUnpinData(Context); if (pDirIndex) *pDirIndex = DirIndex; if (pOffset) *pOffset = Offset; return STATUS_UNSUCCESSFUL; }
NTSTATUS NTAPI FatMountVolume(PFAT_IRP_CONTEXT IrpContext, PDEVICE_OBJECT TargetDeviceObject, PVPB Vpb, PDEVICE_OBJECT FsDeviceObject) { NTSTATUS Status; DISK_GEOMETRY DiskGeometry; ULONG MediaChangeCount = 0; PVOLUME_DEVICE_OBJECT VolumeDevice; VCB *Vcb; FF_ERROR Error; PBCB BootBcb; PPACKED_BOOT_SECTOR BootSector; DPRINT1("FatMountVolume()\n"); /* Make sure this IRP is waitable */ ASSERT(IrpContext->Flags & IRPCONTEXT_CANWAIT); /* Request media changes count, mostly useful for removable devices */ Status = FatPerformDevIoCtrl(TargetDeviceObject, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &MediaChangeCount, sizeof(ULONG), TRUE); if (!NT_SUCCESS(Status)) return Status; /* TODO: Check if data-track present in case of a CD drive */ /* TODO: IOCTL_DISK_GET_PARTITION_INFO_EX */ /* Remove unmounted VCBs */ FatiCleanVcbs(IrpContext); /* Acquire the global exclusive lock */ FatAcquireExclusiveGlobal(IrpContext); /* Create a new volume device object */ Status = IoCreateDevice(FatGlobalData.DriverObject, sizeof(VOLUME_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT), NULL, FILE_DEVICE_DISK_FILE_SYSTEM, 0, FALSE, (PDEVICE_OBJECT *)&VolumeDevice); if (!NT_SUCCESS(Status)) { /* Release the global lock */ FatReleaseGlobal(IrpContext); return Status; } /* Match alignment requirements */ if (TargetDeviceObject->AlignmentRequirement > VolumeDevice->DeviceObject.AlignmentRequirement) { VolumeDevice->DeviceObject.AlignmentRequirement = TargetDeviceObject->AlignmentRequirement; } /* Init stack size */ VolumeDevice->DeviceObject.StackSize = TargetDeviceObject->StackSize + 1; /* Get sector size */ Status = FatPerformDevIoCtrl(TargetDeviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DiskGeometry, sizeof(DISK_GEOMETRY), TRUE); if (!NT_SUCCESS(Status)) goto FatMountVolumeCleanup; VolumeDevice->DeviceObject.SectorSize = (USHORT) DiskGeometry.BytesPerSector; /* Signal we're done with initializing */ VolumeDevice->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING; /* Save device object in a VPB */ Vpb->DeviceObject = (PDEVICE_OBJECT)VolumeDevice; /* Initialize VCB for this volume */ Status = FatInitializeVcb(IrpContext, &VolumeDevice->Vcb, TargetDeviceObject, Vpb); if (!NT_SUCCESS(Status)) goto FatMountVolumeCleanup; Vcb = &VolumeDevice->Vcb; /* Initialize FullFAT library */ Vcb->Ioman = FF_CreateIOMAN(NULL, 8192, VolumeDevice->DeviceObject.SectorSize, &Error); ASSERT(Vcb->Ioman); /* Register block device read/write functions */ Error = FF_RegisterBlkDevice(Vcb->Ioman, VolumeDevice->DeviceObject.SectorSize, (FF_WRITE_BLOCKS)FatWriteBlocks, (FF_READ_BLOCKS)FatReadBlocks, Vcb); if (Error) { DPRINT1("Registering block device with FullFAT failed with error %d\n", Error); FF_DestroyIOMAN(Vcb->Ioman); goto FatMountVolumeCleanup; } /* Mount the volume using FullFAT */ if(FF_MountPartition(Vcb->Ioman, 0)) { DPRINT1("Partition mounting failed\n"); FF_DestroyIOMAN(Vcb->Ioman); goto FatMountVolumeCleanup; } /* Read the boot sector */ FatReadStreamFile(Vcb, 0, sizeof(PACKED_BOOT_SECTOR), &BootBcb, (PVOID)&BootSector); /* Check if it's successful */ if (!BootBcb) { Status = STATUS_UNRECOGNIZED_VOLUME; goto FatMountVolumeCleanup; } /* Unpack data */ FatiUnpackBpb(&Vcb->Bpb, &BootSector->PackedBpb); /* Verify if sector size matches */ if (DiskGeometry.BytesPerSector != Vcb->Bpb.BytesPerSector) { DPRINT1("Disk geometry BPS %d and bios BPS %d don't match!\n", DiskGeometry.BytesPerSector, Vcb->Bpb.BytesPerSector); /* Fail */ Status = STATUS_UNRECOGNIZED_VOLUME; goto FatMountVolumeCleanup; } /* If Sectors value is set, discard the LargeSectors value */ if (Vcb->Bpb.Sectors) Vcb->Bpb.LargeSectors = 0; /* Copy serial number */ if (FatiBpbFat32(&BootSector->PackedBpb)) { CopyUchar4(&Vpb->SerialNumber, ((PPACKED_BOOT_SECTOR_EX)BootSector)->Id); } else { /* This is FAT12/16 */ CopyUchar4(&Vpb->SerialNumber, BootSector->Id); } /* Unpin the BCB */ CcUnpinData(BootBcb); /* Create root DCB for it */ FatCreateRootDcb(IrpContext, &VolumeDevice->Vcb); /* Keep trace of media changes */ VolumeDevice->Vcb.MediaChangeCount = MediaChangeCount; //ObDereferenceObject(TargetDeviceObject); /* Release the global lock */ FatReleaseGlobal(IrpContext); /* Notify about volume mount */ //FsRtlNotifyVolumeEvent(VolumeDevice->Vcb.StreamFileObject, FSRTL_VOLUME_MOUNT); /* Return success */ return STATUS_SUCCESS; FatMountVolumeCleanup: /* Unwind the routine actions */ IoDeleteDevice((PDEVICE_OBJECT)VolumeDevice); /* Release the global lock */ FatReleaseGlobal(IrpContext); return Status; }
PLBCB LfsGetLbcb ( IN PLFCB Lfcb ) /*++ Routine Description: This routine is called to add a Lbcb to the active queue. Arguments: Lfcb - This is the file control block for the log file. Return Value: PLBCB - Pointer to the Lbcb allocated. --*/ { PLBCB Lbcb = NULL; PVOID PageHeader; PBCB PageHeaderBcb = NULL; BOOLEAN WrappedOrUsaError; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsGetLbcb: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); // // Use a try-finally to facilitate cleanup. // try { // // Pin the desired record page. // LfsPreparePinWriteData( Lfcb, Lfcb->NextLogPage, (ULONG)Lfcb->LogPageSize, &PageHeader, &PageHeaderBcb ); // // Put our signature into the page so we won't fail if we // see a previous 'BAAD' signature. // *((PULONG) PageHeader) = LFS_SIGNATURE_RECORD_PAGE_ULONG; // // Now allocate an Lbcb. // LfsAllocateLbcb( Lfcb, &Lbcb ); // // If we are at the beginning of the file we test that the // sequence number won't wrap to 0. // if (!FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN | LFCB_REUSE_TAIL ) && ( Lfcb->NextLogPage == Lfcb->FirstLogPage )) { Lfcb->SeqNumber = Lfcb->SeqNumber + 1; // // If the sequence number is going from 0 to 1, then // this is the first time the log file has wrapped. We want // to remember this because it means that we can now do // large spiral writes. // if (Int64ShllMod32( Lfcb->SeqNumber, Lfcb->FileDataBits ) == 0) { LfsDebugTrace( 0, Dbg, "Log sequence number about to wrap: Lfcb -> %08lx\n", Lfcb ); KeBugCheck( FILE_SYSTEM ); } // // If this number is greater or equal to the wrap sequence number in // the Lfcb, set the wrap flag in the Lbcb. // if (!FlagOn( Lfcb->Flags, LFCB_LOG_WRAPPED ) && ( Lfcb->SeqNumber >= Lfcb->SeqNumberForWrap )) { SetFlag( Lbcb->LbcbFlags, LBCB_LOG_WRAPPED ); SetFlag( Lfcb->Flags, LFCB_LOG_WRAPPED ); } } // // Now initialize the rest of the Lbcb fields. // Lbcb->FileOffset = Lfcb->NextLogPage; Lbcb->SeqNumber = Lfcb->SeqNumber; Lbcb->BufferOffset = Lfcb->LogPageDataOffset; // // Store the next page in the Lfcb. // LfsNextLogPageOffset( Lfcb, Lfcb->NextLogPage, &Lfcb->NextLogPage, &WrappedOrUsaError ); Lbcb->Length = Lfcb->LogPageSize; Lbcb->PageHeader = PageHeader; Lbcb->LogPageBcb = PageHeaderBcb; Lbcb->ResourceThread = ExGetCurrentResourceThread(); // // If we are reusing a previous page then set a flag in // the Lbcb to indicate that we should flush a copy // first. // if (FlagOn( Lfcb->Flags, LFCB_REUSE_TAIL )) { SetFlag( Lbcb->LbcbFlags, LBCB_FLUSH_COPY ); ClearFlag( Lfcb->Flags, LFCB_REUSE_TAIL ); (ULONG)Lbcb->BufferOffset = Lfcb->ReusePageOffset; Lbcb->Flags = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Flags; Lbcb->LastLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Copy.LastLsn; Lbcb->LastEndLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Header.Packed.LastEndLsn; } // // Put the Lbcb on the active queue // InsertTailList( &Lfcb->LbcbActive, &Lbcb->ActiveLinks ); SetFlag( Lbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE ); } finally { DebugUnwind( LfsGetLbcb ); // // If an error occurred, we need to clean up any blocks which // have not been added to the active queue. // if (AbnormalTermination()) { if (Lbcb != NULL) { LfsDeallocateLbcb( Lfcb, Lbcb ); Lbcb = NULL; } // // Unpin the system page if pinned. // if (PageHeaderBcb != NULL) { CcUnpinData( PageHeaderBcb ); } } LfsDebugTrace( -1, Dbg, "LfsGetLbcb: Exit\n", 0 ); } return Lbcb; }
VOID LfsReadRestartArea ( IN LFS_LOG_HANDLE LogHandle, IN OUT PULONG BufferLength, IN PVOID Buffer, OUT PLSN Lsn ) /*++ Routine Description: This routine is called by the client when he wishes to read his restart area in the log file. Arguments: LogHandle - Pointer to private Lfs structure used to identify this client. BufferLength - On entry it is the length of the user buffer. On exit it is the size of the data stored in the buffer. Buffer - Pointer to the buffer where the client restart data is to be copied. Lsn - This is the Lsn for client restart area. Return Value: None --*/ { volatile NTSTATUS Status = STATUS_SUCCESS; BOOLEAN UsaError; PLCH Lch; PLFS_CLIENT_RECORD ClientRecord; PLFS_RECORD_HEADER RecordHeader; PBCB RecordHeaderBcb; PLFCB Lfcb; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsReadRestartArea: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle ); LfsDebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength ); LfsDebugTrace( 0, Dbg, "Buffer -> %08lx\n", Buffer ); RecordHeaderBcb = NULL; Lch = (PLCH) LogHandle; // // Check that the structure is a valid log handle structure. // LfsValidateLch( Lch ); // // Use a try-except to catch errors. // try { // // Use a try-finally to facilitate cleanup. // try { // // Acquire the log file control block for this log file. // LfsAcquireLch( Lch ); Lfcb = Lch->Lfcb; // // If the Log file has been closed then refuse access. // if (Lfcb == NULL) { ExRaiseStatus( STATUS_ACCESS_DENIED ); } // // Check that the client Id is valid. // LfsValidateClientId( Lfcb, Lch ); ClientRecord = LfsAdd2Ptr( Lfcb->ClientArray, Lch->ClientArrayByteOffset, PLFS_CLIENT_RECORD ); // // If the client doesn't have a restart area, go ahead and exit // now. // if ( ClientRecord->ClientRestartLsn.QuadPart == 0 ) { //**** xxEqlZero( ClientRecord->ClientRestartLsn ) // // We show there is no restart area by returning a length // of zero. We also set the Lsn value to zero so that // we can catch it if the user tries to use the Lsn. // LfsDebugTrace( 0, Dbg, "No client restart area exists\n", 0 ); *BufferLength = 0; *Lsn = LfsZeroLsn; try_return( NOTHING ); } // // Release the Lfcb as we won't be modifying any fields in it. // LfsReleaseLfcb( Lfcb ); // // Pin the log record for this Lsn. // LfsPinOrMapLogRecordHeader( Lfcb, ClientRecord->ClientRestartLsn, FALSE, FALSE, &UsaError, &RecordHeader, &RecordHeaderBcb ); // // If the Lsn values don't match, then the disk is corrupt. // if ( ClientRecord->ClientRestartLsn.QuadPart != RecordHeader->ThisLsn.QuadPart ) { //**** xxNeq( ClientRecord->ClientRestartLsn, RecordHeader->ThisLsn ) ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR ); } // // Check that the user's buffer is big enough to hold the restart // data. We raise an error status for this error. // if (RecordHeader->ClientDataLength > *BufferLength) { LfsDebugTrace( 0, Dbg, "Client buffer is too small\n", 0 ); *BufferLength = 0; *Lsn = LfsZeroLsn; ExRaiseStatus( STATUS_BUFFER_OVERFLOW ); } // // Use the cache manager to copy the data into the user's buffer. // LfsCopyReadLogRecord( Lfcb, RecordHeader, Buffer ); // // Pass the length and the Lsn of the restart area back to the // caller. // *BufferLength = RecordHeader->ClientDataLength; *Lsn = RecordHeader->ThisLsn; try_exit: NOTHING; } finally { DebugUnwind( LfsReadRestartArea ); // // Release the log file control block if held. // LfsReleaseLch( Lch ); // // Unpin the log record header for the client restart if pinned. // if (RecordHeaderBcb != NULL) { CcUnpinData( RecordHeaderBcb ); } LfsDebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart ); LfsDebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart ); LfsDebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength ); LfsDebugTrace( -1, Dbg, "LfsReadRestartArea: Exit\n", 0 ); } } except (LfsExceptionFilter( GetExceptionInformation() )) { Status = GetExceptionCode(); } if (Status != STATUS_SUCCESS) { ExRaiseStatus( Status ); } 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; }
/* * FUNCTION: Finds the first available cluster in a FAT16 table */ NTSTATUS FAT16FindAndMarkAvailableCluster( PDEVICE_EXTENSION DeviceExt, PULONG Cluster) { ULONG FatLength; ULONG StartCluster; ULONG i, j; PVOID BaseAddress; ULONG ChunkSize; PVOID Context = 0; LARGE_INTEGER Offset; PUSHORT Block; PUSHORT 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 * 2, ChunkSize); if (!CcPinRead(DeviceExt->FATFileObject, &Offset, ChunkSize, 1, &Context, &BaseAddress)) { DPRINT1("CcMapData(Offset %x, Length %u) failed\n", (ULONG)Offset.QuadPart, ChunkSize); return STATUS_UNSUCCESSFUL; } Block = (PUSHORT)((ULONG_PTR)BaseAddress + (i * 2) % ChunkSize); BlockEnd = (PUSHORT)((ULONG_PTR)BaseAddress + ChunkSize); /* Now process the whole block */ while (Block < BlockEnd && i < FatLength) { if (*Block == 0) { DPRINT("Found available cluster 0x%x\n", i); DeviceExt->LastAvailableCluster = *Cluster = i; *Block = 0xffff; 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; }
BOOLEAN LfsFindNextLsn ( IN PLFCB Lfcb, IN PLFS_RECORD_HEADER RecordHeader, OUT PLSN Lsn ) /*++ Routine Description: This routine takes as a starting point the log record header of an Lsn in the log file. It searches for the next Lsn in the file and returns that value in the 'Lsn' argument. The boolean return value indicates whether there is another Lsn in the file. Arguments: Lfcb - This is the file control block for the log file. RecordHeader - This is the log record for the Lsn starting point. Lsn - This supplies the address to store the next Lsn, if found. Return Value: BOOLEAN - Indicates whether the next Lsn was found. --*/ { BOOLEAN FoundNextLsn; LONGLONG LsnOffset; LONGLONG EndOfLogRecord; LONGLONG LogHeaderOffset; LONGLONG SequenceNumber; PLFS_RECORD_PAGE_HEADER LogRecordPage; PBCB LogRecordPageBcb; BOOLEAN UsaError; PAGED_CODE(); DebugTrace( +1, Dbg, "LfsFindNextLsn: Entered\n", 0 ); DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); DebugTrace( 0, Dbg, "Record Header -> %08lx\n", RecordHeader ); LogRecordPageBcb = NULL; FoundNextLsn = FALSE; // // Use a try-finally to facilitate cleanup. // try { // // Find the file offset of the log page which contains the end // of the log record for this Lsn. // LsnOffset = LfsLsnToFileOffset( Lfcb, RecordHeader->ThisLsn ); LfsLsnFinalOffset( Lfcb, RecordHeader->ThisLsn, RecordHeader->ClientDataLength, &EndOfLogRecord ); LfsTruncateOffsetToLogPage( Lfcb, EndOfLogRecord, &LogHeaderOffset ); // // Remember the sequence number for this page. // SequenceNumber = LfsLsnToSeqNumber( Lfcb, RecordHeader->ThisLsn ); // // Remember if we wrapped. // if ( EndOfLogRecord <= LsnOffset ) { //**** xxLeq( EndOfLogRecord, LsnOffset ) SequenceNumber = SequenceNumber + 1; //**** xxAdd( SequenceNumber, LfsLi1 ); } // // Pin the log page header for this page. // LfsPinOrMapData( Lfcb, LogHeaderOffset, (ULONG)Lfcb->LogPageSize, FALSE, FALSE, FALSE, &UsaError, (PVOID *)&LogRecordPage, &LogRecordPageBcb ); // // If the Lsn we were given was not the last Lsn on this page, then // the starting offset for the next Lsn is on a quad word boundary // following the last file offset for the current Lsn. Otherwise // the file offset is the start of the data on the next page. // if ( RecordHeader->ThisLsn.QuadPart == LogRecordPage->Copy.LastLsn.QuadPart ) { //**** xxEql( RecordHeader->ThisLsn, LogRecordPage->Copy.LastLsn ) BOOLEAN Wrapped; LfsNextLogPageOffset( Lfcb, LogHeaderOffset, &LogHeaderOffset, &Wrapped ); LsnOffset = LogHeaderOffset + Lfcb->LogPageDataOffset; //**** xxAdd( LogHeaderOffset, Lfcb->LogPageDataOffset ); // // If we wrapped, we need to increment the sequence number. // if (Wrapped) { SequenceNumber = SequenceNumber + 1; //**** xxAdd( SequenceNumber, LfsLi1 ); } } else { LiQuadAlign( EndOfLogRecord, &LsnOffset ); } // // Compute the Lsn based on the file offset and the sequence count. // Lsn->QuadPart = LfsFileOffsetToLsn( Lfcb, LsnOffset, SequenceNumber ); // // If this Lsn is within the legal range for the file, we return TRUE. // Otherwise FALSE indicates that there are no more Lsn's. // if (LfsIsLsnInFile( Lfcb, *Lsn )) { FoundNextLsn = TRUE; } } finally { DebugUnwind( LfsFindNextLsn ); // // Unpin the log page header if held. // if (LogRecordPageBcb != NULL) { CcUnpinData( LogRecordPageBcb ); } DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart ); DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart ); DebugTrace( -1, Dbg, "LfsFindNextLsn: Exit -> %08x\n", FoundNextLsn ); } return FoundNextLsn; }
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; }
static NTSTATUS CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt, PVOID *Context, PVOID *Block, PLARGE_INTEGER StreamOffset, ULONG DirLength, PVOID *Ptr, PWSTR Name, PULONG pIndex, PULONG pIndex2) /* * FUNCTION: Retrieves the file name, be it in short or long file name format */ { PDIR_RECORD Record; NTSTATUS Status; ULONG Index = 0; ULONG Offset = 0; ULONG BlockOffset = 0; Record = (PDIR_RECORD)*Block; while(Index < *pIndex) { BlockOffset += Record->RecordLength; Offset += Record->RecordLength; Record = (PDIR_RECORD)(*Block + BlockOffset); if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0) { DPRINT("Map next sector\n"); CcUnpinData(*Context); StreamOffset->QuadPart += BLOCKSIZE; Offset = ROUND_UP(Offset, BLOCKSIZE); BlockOffset = 0; if (!CcMapData(DeviceExt->StreamFileObject, StreamOffset, BLOCKSIZE, TRUE, Context, Block)) { DPRINT("CcMapData() failed\n"); return(STATUS_UNSUCCESSFUL); } Record = (PDIR_RECORD)(*Block + BlockOffset); } if (Offset >= DirLength) return(STATUS_NO_MORE_ENTRIES); Index++; } DPRINT("Index %lu RecordLength %lu Offset %lu\n", Index, Record->RecordLength, Offset); if (Record->FileIdLength == 1 && Record->FileId[0] == 0) { wcscpy(Name, L"."); } else if (Record->FileIdLength == 1 && Record->FileId[0] == 1) { wcscpy(Name, L".."); } else { if (DeviceExt->CdInfo.JolietLevel == 0) { ULONG i; for (i = 0; i < Record->FileIdLength && Record->FileId[i] != ';'; i++) Name[i] = (WCHAR)Record->FileId[i]; Name[i] = 0; } else { CdfsSwapString(Name, Record->FileId, Record->FileIdLength); } } DPRINT("Name '%S'\n", Name); *Ptr = Record; *pIndex = Index; return(STATUS_SUCCESS); }
/* * FUNCTION: Retrieves the file name, be it in short or long file name format */ static NTSTATUS CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt, PVOID *Context, PVOID *Block, PLARGE_INTEGER StreamOffset, ULONG DirLength, PVOID *Ptr, PWSTR Name, PULONG pIndex, PULONG CurrentOffset) { PDIR_RECORD Record = *Ptr; ULONG Index; if (*CurrentOffset >= DirLength) return(STATUS_NO_MORE_ENTRIES); if (*CurrentOffset == 0) { Index = 0; Record = (PDIR_RECORD)*Block; while (Index < *pIndex) { (*Ptr) = (PVOID)((ULONG_PTR)(*Ptr) + Record->RecordLength); (*CurrentOffset) += Record->RecordLength; Record = *Ptr; if ((ULONG_PTR)(*Ptr) - (ULONG_PTR)(*Block) >= BLOCKSIZE || Record->RecordLength == 0) { DPRINT("Map next sector\n"); CcUnpinData(*Context); StreamOffset->QuadPart += BLOCKSIZE; *CurrentOffset = ROUND_UP(*CurrentOffset, BLOCKSIZE); if (!CcMapData(DeviceExt->StreamFileObject, StreamOffset, BLOCKSIZE, TRUE, Context, Block)) { DPRINT("CcMapData() failed\n"); return(STATUS_UNSUCCESSFUL); } *Ptr = *Block; Record = (PDIR_RECORD)*Ptr; } if (*CurrentOffset >= DirLength) return(STATUS_NO_MORE_ENTRIES); Index++; } } if ((ULONG_PTR)(*Ptr) - (ULONG_PTR)(*Block) >= BLOCKSIZE || Record->RecordLength == 0) { DPRINT("Map next sector\n"); CcUnpinData(*Context); StreamOffset->QuadPart += BLOCKSIZE; *CurrentOffset = ROUND_UP(*CurrentOffset, BLOCKSIZE); if (!CcMapData(DeviceExt->StreamFileObject, StreamOffset, BLOCKSIZE, TRUE, Context, Block)) { DPRINT("CcMapData() failed\n"); return(STATUS_UNSUCCESSFUL); } *Ptr = *Block; Record = (PDIR_RECORD)*Ptr; } if (*CurrentOffset >= DirLength) return STATUS_NO_MORE_ENTRIES; DPRINT("Index %lu RecordLength %lu Offset %lu\n", *pIndex, Record->RecordLength, *CurrentOffset); if (!CdfsIsRecordValid(DeviceExt, Record)) { CcUnpinData(*Context); return STATUS_DISK_CORRUPT_ERROR; } CdfsGetDirEntryName(DeviceExt, Record, Name); *Ptr = Record; return(STATUS_SUCCESS); }
/* * 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; }
/************************************************************************* * * Function: Ext2MountVolume() * * Description: * This routine verifies and mounts the volume; * Called by FSCTRL IRP handler to attempt a * volume mount. * * Expected Interrupt Level (for execution) : * * IRQL_PASSIVE_LEVEL * * * Arguments: * * Irp - Supplies the Irp being processed * IrpSp - Irp Stack Location pointer * * Return Value: * * NTSTATUS - The Mount status * *************************************************************************/ NTSTATUS Ext2MountVolume ( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp ) { // Volume Parameter Block PVPB PtrVPB; // The target device object PDEVICE_OBJECT TargetDeviceObject = NULL; // The new volume device object (to be created if partition is Ext2) PDEVICE_OBJECT PtrVolumeDeviceObject = NULL; // Return Status NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME; // Number of bytes to read for Volume verification... unsigned long NumberOfBytesToRead = 0; // Starting Offset for 'read' LONGLONG StartingOffset = 0; // Boot Sector information... PPACKED_BOOT_SECTOR BootSector = NULL; // Ext2 Super Block information... PEXT2_SUPER_BLOCK SuperBlock = NULL; // Volume Control Block PtrExt2VCB PtrVCB = NULL; // The File Object for the root directory PFILE_OBJECT PtrRootFileObject = NULL; // Flag int WeClearedVerifyRequiredBit; // Used by a for loop... unsigned int i; // LARGE_INTEGER VolumeByteOffset; unsigned long LogicalBlockSize = 0; // Buffer Control Block PBCB PtrBCB = NULL; // Cache Buffer - used for pinned access of volume... PVOID PtrCacheBuffer = NULL; PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL; // Inititalising variables PtrVPB = IrpSp->Parameters.MountVolume.Vpb; TargetDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject; try { // // 1. Reading in Volume meta data // // Temporarily clear the DO_VERIFY_VOLUME Flag WeClearedVerifyRequiredBit = 0; if ( Ext2IsFlagOn( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ) ) { Ext2ClearFlag( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ); WeClearedVerifyRequiredBit = 1; } // Allocating memory for reading in Boot Sector... NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), TargetDeviceObject->SectorSize ); BootSector = Ext2AllocatePool( PagedPool, NumberOfBytesToRead ); RtlZeroMemory( BootSector, NumberOfBytesToRead ); // Reading in Boot Sector StartingOffset = 0L; Ext2PerformVerifyDiskRead ( TargetDeviceObject, BootSector, StartingOffset, NumberOfBytesToRead ); // Reject a volume that contains fat artifacts DebugTrace(DEBUG_TRACE_MOUNT, "OEM[%s]", BootSector->Oem); if (BootSector->Oem[0]) { try_return(); } // Allocating memory for reading in Super Block... SuperBlock = Ext2AllocatePool( PagedPool, NumberOfBytesToRead ); RtlZeroMemory( SuperBlock, NumberOfBytesToRead ); StartingOffset = 1024; // Reading in the Super Block... Ext2PerformVerifyDiskRead ( TargetDeviceObject, SuperBlock, StartingOffset, NumberOfBytesToRead ); // Resetting the DO_VERIFY_VOLUME Flag if( WeClearedVerifyRequiredBit ) { PtrVPB->RealDevice->Flags |= DO_VERIFY_VOLUME; } // Verifying the Super Block.. if( SuperBlock->s_magic == EXT2_SUPER_MAGIC ) { // // Found a valid super block. // No more tests for now. // Assuming that this is an ext2 partition... // Going ahead with mount. // DebugTrace(DEBUG_TRACE_MOUNT, "Valid Ext2 partition detected\nMounting %s...", SuperBlock->s_volume_name); // // 2. Creating a volume device object // if (!NT_SUCCESS( IoCreateDevice( Ext2GlobalData.Ext2DriverObject, // (This) Driver object Ext2QuadAlign( sizeof(Ext2VCB) ), // Device Extension NULL, // Device Name - no name ;) FILE_DEVICE_DISK_FILE_SYSTEM, // Disk File System 0, // DeviceCharacteristics FALSE, // Not an exclusive device (PDEVICE_OBJECT *)&PtrVolumeDeviceObject)) // The Volume Device Object ) { try_return(); } // // Our alignment requirement is the larger of the processor alignment requirement // already in the volume device object and that in the TargetDeviceObject // if (TargetDeviceObject->AlignmentRequirement > PtrVolumeDeviceObject->AlignmentRequirement) { PtrVolumeDeviceObject->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement; } // // Clearing the Device Initialising Flag // Ext2ClearFlag( PtrVolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING); // // Setting the Stack Size for the newly created Volume Device Object // PtrVolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1); // // 3. Creating the link between Target Device Object // and the Volume Device Object via the Volume Parameter Block // PtrVPB->DeviceObject = PtrVolumeDeviceObject; // Remembring the Volume parameters in the VPB bock for( i = 0; i < 16 ; i++ ) { PtrVPB->VolumeLabel[i] = SuperBlock->s_volume_name[i]; if( SuperBlock->s_volume_name[i] == 0 ) break; } PtrVPB->VolumeLabelLength = i * 2; PtrVPB->SerialNumber = ((ULONG*)SuperBlock->s_uuid)[0]; // // 4. Initialise the Volume Comtrol Block // { LARGE_INTEGER AllocationSize; AllocationSize .QuadPart = ( EXT2_MIN_BLOCK_SIZE << SuperBlock->s_log_block_size ) * SuperBlock->s_blocks_count; Ext2InitializeVCB( PtrVolumeDeviceObject, TargetDeviceObject, PtrVPB, &AllocationSize); PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension); ASSERT( PtrVCB ); } PtrVCB->InodesCount = SuperBlock->s_inodes_count; PtrVCB->BlocksCount = SuperBlock->s_blocks_count; PtrVCB->ReservedBlocksCount = SuperBlock->s_r_blocks_count; PtrVCB->FreeBlocksCount = SuperBlock->s_free_blocks_count; PtrVCB->FreeInodesCount = SuperBlock->s_free_inodes_count; PtrVCB->LogBlockSize = SuperBlock->s_log_block_size; PtrVCB->InodesPerGroup = SuperBlock->s_inodes_per_group; PtrVCB->BlocksPerGroup = SuperBlock->s_blocks_per_group; PtrVCB->NoOfGroups = ( SuperBlock->s_blocks_count - SuperBlock->s_first_data_block + SuperBlock->s_blocks_per_group - 1 ) / SuperBlock->s_blocks_per_group; if( SuperBlock->s_rev_level ) { PtrVCB->InodeSize = SuperBlock->s_inode_size; } else { PtrVCB->InodeSize = sizeof( EXT2_INODE ); } PtrVCB->PtrGroupDescriptors = Ext2AllocatePool( NonPagedPool, sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups ); RtlZeroMemory( PtrVCB->PtrGroupDescriptors , sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups ); // // Attempting to Read in some matadata from the Cache... // using pin access... // LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; // // Reading Group Descriptors... // if( PtrVCB->LogBlockSize ) { // First block contains the descriptors... VolumeByteOffset.QuadPart = LogicalBlockSize; } else { // Second block contains the descriptors... VolumeByteOffset.QuadPart = LogicalBlockSize * 2; } NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc ); NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize ); if (!CcMapData( PtrVCB->PtrStreamFileObject, &VolumeByteOffset, NumberOfBytesToRead, TRUE, &PtrBCB, &PtrCacheBuffer )) { DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0); try_return( Status = STATUS_INSUFFICIENT_RESOURCES ); } else { // // Saving up Often Used Group Descriptor Information in the VCB... // unsigned int DescIndex ; DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); PtrGroupDescriptor = (PEXT2_GROUP_DESCRIPTOR )PtrCacheBuffer; for( DescIndex = 0; DescIndex < PtrVCB->NoOfGroups; DescIndex++ ) { PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeTablesBlock = PtrGroupDescriptor[ DescIndex ].bg_inode_table; PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeBitmapBlock = PtrGroupDescriptor[ DescIndex ].bg_inode_bitmap ; PtrVCB->PtrGroupDescriptors[ DescIndex ].BlockBitmapBlock = PtrGroupDescriptor[ DescIndex ].bg_block_bitmap ; PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeBlocksCount = PtrGroupDescriptor[ DescIndex ].bg_free_blocks_count; PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeInodesCount = PtrGroupDescriptor[ DescIndex ].bg_free_inodes_count; } CcUnpinData( PtrBCB ); PtrBCB = NULL; } // // 5. Creating a Root Directory FCB // PtrRootFileObject = IoCreateStreamFileObject(NULL, TargetDeviceObject ); if( !PtrRootFileObject ) { try_return(); } // // Associate the file stream with the Volume parameter block... // I do it now // PtrRootFileObject->Vpb = PtrVCB->PtrVPB; PtrRootFileObject->ReadAccess = TRUE; PtrRootFileObject->WriteAccess = TRUE; { PtrExt2ObjectName PtrObjectName; LARGE_INTEGER ZeroSize; PtrObjectName = Ext2AllocateObjectName(); RtlInitUnicodeString( &PtrObjectName->ObjectName, L"\\" ); Ext2CopyWideCharToUnicodeString( &PtrObjectName->ObjectName, L"\\" ); ZeroSize.QuadPart = 0; if ( !NT_SUCCESS( Ext2CreateNewFCB( &PtrVCB->PtrRootDirectoryFCB, // Root FCB ZeroSize, // AllocationSize, ZeroSize, // EndOfFile, PtrRootFileObject, // The Root Dircetory File Object PtrVCB, PtrObjectName ) ) ) { try_return(); } PtrVCB->PtrRootDirectoryFCB->FCBFlags |= EXT2_FCB_DIRECTORY | EXT2_FCB_ROOT_DIRECTORY; } PtrVCB->PtrRootDirectoryFCB->DcbFcb.Dcb.PtrDirFileObject = PtrRootFileObject; PtrVCB->PtrRootDirectoryFCB->INodeNo = EXT2_ROOT_INO; PtrRootFileObject->SectionObjectPointer = &(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.SectionObject); RtlInitUnicodeString( &PtrRootFileObject->FileName, L"\\" ); Ext2InitializeFCBInodeInfo( PtrVCB->PtrRootDirectoryFCB ); // // Initiating caching for root directory... // CcInitializeCacheMap(PtrRootFileObject, (PCC_FILE_SIZES)(&(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)), TRUE, // We will utilize pin access for directories &(Ext2GlobalData.CacheMgrCallBacks), // callbacks PtrVCB->PtrRootDirectoryFCB ); // The context used in callbacks // // 6. Update the VCB Flags // PtrVCB->VCBFlags |= EXT2_VCB_FLAGS_VOLUME_MOUNTED ; // | EXT2_VCB_FLAGS_VOLUME_READ_ONLY; // // 7. Mount Success // Status = STATUS_SUCCESS; { // // This block is for testing.... // To be removed... /* EXT2_INODE Inode ; Ext2ReadInode( PtrVCB, 100, &Inode ); DebugTrace( DEBUG_TRACE_MISC, "Inode size= %lX [FS Ctrl]", Inode.i_size ); Ext2DeallocInode( NULL, PtrVCB, 0xfb6 ); */ } // ObDereferenceObject( TargetDeviceObject ); } else { DebugTrace(DEBUG_TRACE_MOUNT, "Failing mount. Partition not Ext2...", 0); } try_exit: NOTHING; } finally { // Freeing Allocated Memory... if( SuperBlock != NULL ) { DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", SuperBlock ); ExFreePool( SuperBlock ); } if( BootSector != NULL ) { DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [FS Ctrl]", BootSector); ExFreePool( BootSector ); } // start unwinding if we were unsuccessful if (!NT_SUCCESS( Status )) { } } return Status; }
/************************************************************************* * * Function: Ext2QueryDirectory() * * Description: * Query directory request. * * Expected Interrupt Level (for execution) : * * IRQL_PASSIVE_LEVEL * * Return Value: STATUS_SUCCESS/Error * *************************************************************************/ NTSTATUS NTAPI Ext2QueryDirectory( PtrExt2IrpContext PtrIrpContext, PIRP PtrIrp, #ifdef _GNU_NTIFS_ PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation, #else PIO_STACK_LOCATION PtrIoStackLocation, #endif PFILE_OBJECT PtrFileObject, PtrExt2FCB PtrFCB, PtrExt2CCB PtrCCB) { NTSTATUS RC = STATUS_SUCCESS; BOOLEAN PostRequest = FALSE; PtrExt2NTRequiredFCB PtrReqdFCB = NULL; BOOLEAN CanWait = FALSE; PtrExt2VCB PtrVCB = NULL; BOOLEAN AcquiredFCB = FALSE; unsigned long BufferLength = 0; unsigned long BufferIndex = 0; unsigned long FileIndex = 0; PUNICODE_STRING PtrSearchPattern = NULL; FILE_INFORMATION_CLASS FileInformationClass; BOOLEAN RestartScan = FALSE; BOOLEAN ReturnSingleEntry = FALSE; BOOLEAN IndexSpecified = FALSE; unsigned char *Buffer = NULL; BOOLEAN FirstTimeQuery = FALSE; unsigned long StartingIndexForSearch = 0; unsigned long BytesReturned = 0; BOOLEAN BufferUsedup = FALSE; BOOLEAN SearchWithWildCards = FALSE; PFILE_BOTH_DIR_INFORMATION BothDirInformation = NULL; PFILE_DIRECTORY_INFORMATION DirectoryInformation = NULL; PEXT2_DIR_ENTRY PtrDirEntry = NULL; PEXT2_INODE PtrInode = NULL; unsigned long LogicalBlockSize; unsigned long ThisBlock; // The starting Physical Block No... //LARGE_INTEGER StartPhysicalBlock; LARGE_INTEGER StartBufferOffset ; ULONG PinBufferLength; // Buffer Control Block PBCB PtrBCB = NULL; BYTE * PtrPinnedBlockBuffer = NULL; unsigned int j; DebugTrace(DEBUG_TRACE_MISC, " === Querying Directory %S", PtrFCB->FCBName->ObjectName.Buffer ); try { // Validate the sent-in FCB if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) { // We will only allow notify requests on directories. RC = STATUS_INVALID_PARAMETER; } PtrReqdFCB = &(PtrFCB->NTRequiredFCB); CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); PtrVCB = PtrFCB->PtrVCB; // // Asynchronous IO requested // Posting request... // /* * This is incorrect because posted IRP_MJ_DIRECTORY_CONTROL * requests aren't handled in the worker thread yet. I tried * adding handling of them to the worked routine, but there * were problems with accessing the PtrIoStackLocation-> * Parameters.QueryDirectory.FileName variable. * -- Filip Navara, 18/08/2004 */ #if 0 if (!CanWait) { PostRequest = TRUE; try_return(RC = STATUS_PENDING); } #endif // Obtain the callers parameters BufferLength = PtrIoStackLocation->Parameters.QueryDirectory.Length; PtrSearchPattern = ( PUNICODE_STRING ) PtrIoStackLocation->Parameters.QueryDirectory.FileName; FileInformationClass = PtrIoStackLocation->Parameters.QueryDirectory.FileInformationClass; FileIndex = PtrIoStackLocation->Parameters.QueryDirectory.FileIndex; // Some additional arguments that affect the FSD behavior RestartScan = (PtrIoStackLocation->Flags & SL_RESTART_SCAN); ReturnSingleEntry = (PtrIoStackLocation->Flags & SL_RETURN_SINGLE_ENTRY); IndexSpecified = (PtrIoStackLocation->Flags & SL_INDEX_SPECIFIED); // // Acquiring exclusive access to the FCB. // This is not mandatory // DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire FCB Exclusively[DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [DirCtrl]", 0); AcquiredFCB = TRUE; // We must determine the buffer pointer to be used. Since this // routine could either be invoked directly in the context of the // calling thread, or in the context of a worker thread, here is // a general way of determining what we should use. Buffer = Ext2GetCallersBuffer ( PtrIrp ); // The method of determining where to look from and what to look for is // unfortunately extremely confusing. However, here is a methodology you // you can broadly adopt: // (a) You have to maintain a search buffer per CCB structure. // (b) This search buffer is initialized the very first time // a query directory operation is performed using the file object. // (For the sample FSD, the search buffer is stored in the // DirectorySearchPattern field) // However, the caller still has the option of "overriding" this stored // search pattern by supplying a new one in a query directory operation. // if( PtrCCB->DirectorySearchPattern.Length ) { if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 ) { DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0); } DebugTrace(DEBUG_TRACE_MISC, " === Old Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer ); } if (PtrSearchPattern != NULL) { // User has supplied a search pattern // Now validate that the search pattern is legitimate if ( PtrCCB->DirectorySearchPattern.Length == 0 ) { // This must be the very first query request. FirstTimeQuery = TRUE; } else { // We should ignore the search pattern in the CCB and instead, // use the user-supplied pattern for this particular query // directory request. Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); } // Now, allocate enough memory to contain the caller // supplied search pattern and fill in the DirectorySearchPattern // field in the CCB Ext2CopyUnicodeString( &PtrCCB->DirectorySearchPattern, PtrSearchPattern ); /* PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof( PtrSearchPattern ) ); ASSERT(PtrCCB->DirectorySearchPattern); RtlCopyMemory( PtrCCB->DirectorySearchPattern, PtrSearchPattern, sizeof( PtrSearchPattern ) ); */ } else if ( PtrCCB->DirectorySearchPattern.Length == 0 ) { // This MUST be the first directory query operation (else the // DirectorySearchPattern field would never be empty. Also, the caller // has neglected to provide a pattern so we MUST invent one. // Use "*" (following NT conventions) as your search pattern // and store it in the PtrCCB->DirectorySearchPattern field. /* PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof(L"*") ); ASSERT(PtrCCB->DirectorySearchPattern); RtlCopyMemory( PtrCCB->DirectorySearchPattern, L"*", 4 );*/ Ext2CopyWideCharToUnicodeString( &PtrCCB->DirectorySearchPattern, L"*" ); FirstTimeQuery = TRUE; } else { // The caller has not supplied any search pattern... // Using previously supplied pattern PtrSearchPattern = &PtrCCB->DirectorySearchPattern; } if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 ) { DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0 ); } DebugTrace(DEBUG_TRACE_MISC, " === Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer ); SearchWithWildCards = FsRtlDoesNameContainWildCards( PtrSearchPattern ); // There is one other piece of information that your FSD must store // in the CCB structure for query directory support. This is the index // value (i.e. the offset in your on-disk directory structure) from // which you should start searching. // However, the flags supplied with the IRP can make us override this // as well. if (FileIndex) { // Caller has told us wherefrom to begin. // You may need to round this to an appropriate directory entry // entry alignment value. StartingIndexForSearch = FileIndex; } else if (RestartScan) { StartingIndexForSearch = 0; } else { // Get the starting offset from the CCB. StartingIndexForSearch = PtrCCB->CurrentByteOffset.LowPart; } // Read in the file inode if it hasn't already been read... Ext2InitializeFCBInodeInfo( PtrFCB ); if (PtrFileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)), TRUE, // We will utilize pin access for directories &(Ext2GlobalData.CacheMgrCallBacks), // callbacks PtrCCB); // The context used in callbacks } // // Read in the next Data Block of this directory // LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize; StartBufferOffset.QuadPart = ( StartingIndexForSearch / LogicalBlockSize ); StartBufferOffset.QuadPart *= LogicalBlockSize; // This should be the StartBufferOffset alaigned to LBlock boundary... PinBufferLength = PtrReqdFCB->CommonFCBHeader.FileSize.LowPart - StartBufferOffset.LowPart; if ( !CcMapData( PtrFileObject, &StartBufferOffset, PinBufferLength, TRUE, &PtrBCB, (PVOID*)&PtrPinnedBlockBuffer ) ) { // Read Failure DebugTrace(DEBUG_TRACE_MISC, "Cache read failiure while reading in volume meta data", 0); try_return(); } else { DebugTrace(DEBUG_TRACE_MISC, "Cache hit while reading in volume meta data", 0); } PtrInode = Ext2AllocatePool( PagedPool, sizeof( EXT2_INODE ) ); // // Walking through the directory entries... for( BufferUsedup = FALSE, BufferIndex = 0; !BufferUsedup && StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; ) { PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ StartingIndexForSearch - StartBufferOffset.LowPart ]; StartingIndexForSearch += PtrDirEntry->rec_len; PtrCCB->CurrentByteOffset.LowPart = StartingIndexForSearch; if( PtrDirEntry->inode == 0 ) { continue; } if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 ) { // // This should not happen // Hqw can this be so!!! // Ext2BreakPoint(); if( BothDirInformation ) { BothDirInformation->NextEntryOffset = 0; } if( !BytesReturned ) { if( FirstTimeQuery ) RC = STATUS_NO_SUCH_FILE; else RC = STATUS_NO_MORE_FILES; } break; } // Does this entry match the search criterian? // Checking // { UNICODE_STRING FileName; LONG Matched = 0; // Constructing a counted Unicode string out of PtrDirEntry Ext2CopyCharToUnicodeString( &FileName, PtrDirEntry->name, PtrDirEntry->name_len ); if ( SearchWithWildCards ) { Matched = FsRtlIsNameInExpression ( PtrSearchPattern, &FileName, FALSE, NULL ); } else { Matched = ! RtlCompareUnicodeString( PtrSearchPattern, &FileName, FALSE ); } Ext2DeallocateUnicodeString( &FileName ); if( !Matched ) { continue; } } switch( FileInformationClass ) { case FileBothDirectoryInformation: DebugTrace(DEBUG_TRACE_DIRINFO, " === FileBothDirectoryInformation", 0 ); ThisBlock = sizeof( FILE_BOTH_DIR_INFORMATION ); ThisBlock += PtrDirEntry->name_len*2; ThisBlock = Ext2QuadAlign( ThisBlock ); if( ( BufferIndex + ThisBlock ) > BufferLength ) { // // Next entry won't fit into the buffer... // will have to return... // :( // if( BothDirInformation ) BothDirInformation->NextEntryOffset = 0; if( !BytesReturned ) RC = STATUS_NO_MORE_FILES; BufferUsedup = TRUE; break; } Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode ); if( !PtrInode ) { try_return( RC = STATUS_UNSUCCESSFUL ); } BothDirInformation = ( PFILE_BOTH_DIR_INFORMATION ) ( Buffer + ( BufferIndex ) ); BothDirInformation->EaSize = 0; BothDirInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512; BothDirInformation->EndOfFile.QuadPart = PtrInode->i_size; BothDirInformation->ChangeTime.QuadPart = 0; BothDirInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000; BothDirInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; BothDirInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 ); BothDirInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 ); // Getting the file type... BothDirInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) ) { // Not a reqular file... if( Ext2IsModeDirectory( PtrInode->i_mode) ) { // Directory... BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; } else { // Special File... // Treated with respect... ;) // BothDirInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); // FILE_ATTRIBUTE_DEVICE } if ( Ext2IsModeHidden( PtrInode->i_mode ) ) { BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } if ( Ext2IsModeReadOnly( PtrInode->i_mode ) ) { BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; } } BothDirInformation->FileIndex = StartingIndexForSearch; BothDirInformation->FileNameLength = PtrDirEntry->name_len*2 + 2; BothDirInformation->ShortNameLength = 0; BothDirInformation->ShortName[0] = 0; // Copying out the name as WCHAR null terminated strings for( j = 0; j< PtrDirEntry->name_len ; j ++ ) { // BothDirInformation->ShortName[ j ] = PtrDirEntry->name[j]; BothDirInformation->FileName[ j ] = PtrDirEntry->name[j]; // if( j < 11 ) // BothDirInformation->ShortName[j] = PtrDirEntry->name[j]; } /* if( j < 11 ) { BothDirInformation->ShortNameLength = j * 2 + 2; BothDirInformation->ShortName[ j ] = 0; } else { BothDirInformation->ShortNameLength = 24; BothDirInformation->ShortName[ 11 ] = 0; }*/ BothDirInformation->FileName[ j ] = 0; BytesReturned += ThisBlock; BufferIndex += ThisBlock; if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) )) BothDirInformation->NextEntryOffset = ThisBlock; else BothDirInformation->NextEntryOffset = 0; break; case FileDirectoryInformation: // DirectoryInformation DebugTrace(DEBUG_TRACE_DIRINFO, " === FileDirectoryInformation", 0 ); ThisBlock = sizeof( FILE_DIRECTORY_INFORMATION ); ThisBlock += PtrDirEntry->name_len*2; ThisBlock = Ext2QuadAlign( ThisBlock ); if( ( BufferIndex + ThisBlock ) > BufferLength ) { // // Next entry won't fit into the buffer... // will have to return... // :( // if( DirectoryInformation ) DirectoryInformation->NextEntryOffset = 0; if( !BytesReturned ) RC = STATUS_NO_MORE_FILES; BufferUsedup = TRUE; break; } Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode ); if( !PtrInode ) { try_return( RC = STATUS_UNSUCCESSFUL ); } DirectoryInformation = ( PFILE_DIRECTORY_INFORMATION ) ( Buffer + ( BufferIndex ) ); DirectoryInformation->AllocationSize.QuadPart = PtrInode->i_blocks * 512; DirectoryInformation->EndOfFile.QuadPart = PtrInode->i_size; DirectoryInformation->ChangeTime.QuadPart = 0; DirectoryInformation->CreationTime.QuadPart = ( __int64 ) PtrInode->i_ctime * 10000000; DirectoryInformation->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart; DirectoryInformation->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 ); DirectoryInformation->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 ); // Getting the file type... DirectoryInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL; if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) ) { // Not a reqular file... if( Ext2IsModeDirectory( PtrInode->i_mode) ) { // Directory... DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; } else { // Special File... // Treated with respect... ;) // DirectoryInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY); // FILE_ATTRIBUTE_DEVICE } if ( Ext2IsModeHidden( PtrInode->i_mode ) ) { DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } if ( Ext2IsModeReadOnly( PtrInode->i_mode ) ) { DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY; } } DirectoryInformation->FileIndex = StartingIndexForSearch; DirectoryInformation->FileNameLength = PtrDirEntry->name_len*2 + 2; // Copying out the name as WCHAR null terminated strings for( j = 0; j< PtrDirEntry->name_len ; j ++ ) { DirectoryInformation->FileName[ j ] = PtrDirEntry->name[j]; } DirectoryInformation->FileName[ j ] = 0; BytesReturned += ThisBlock; BufferIndex += ThisBlock; if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) )) DirectoryInformation->NextEntryOffset = ThisBlock; else DirectoryInformation->NextEntryOffset = 0; break; case FileFullDirectoryInformation: // FullDirInformation-> DebugTrace(DEBUG_TRACE_DIRINFO, " === FileFullDirectoryInformation - Not handled", 0 ); try_return(); case FileNamesInformation: // NamesInformation-> DebugTrace(DEBUG_TRACE_DIRINFO, " === FileNamesInformation - Not handled", 0 ); try_return(); default: DebugTrace(DEBUG_TRACE_DIRINFO, " === Invalid Dir Info class - Not handled", 0 ); try_return( RC = STATUS_INVALID_INFO_CLASS ); } if( ReturnSingleEntry ) { break; } }// end of for... if( !BytesReturned && StartingIndexForSearch >= ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart) ) { Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); PtrCCB->CurrentByteOffset.QuadPart = 0; if( FirstTimeQuery ) RC = STATUS_NO_SUCH_FILE; else RC = STATUS_NO_MORE_FILES; try_return(); } else if( BytesReturned ) { BothDirInformation->NextEntryOffset = 0; } try_exit: NOTHING; } finally { if( PtrInode ) { DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [DirCtrl]", PtrInode ); ExFreePool( PtrInode ); } if( PtrBCB ) { CcUnpinData( PtrBCB ); PtrBCB = NULL; } if (PostRequest) { if (AcquiredFCB) { Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released in [DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); } // Map the users buffer and then post the request. RC = Ext2LockCallersBuffer(PtrIrp, TRUE, BufferLength); ASSERT(NT_SUCCESS(RC)); RC = Ext2PostRequest(PtrIrpContext, PtrIrp); } else if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) { if (AcquiredFCB) { Ext2ReleaseResource(&(PtrReqdFCB->MainResource)); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [DirCtrl]", 0); DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); } // Complete the request. PtrIrp->IoStatus.Status = RC; PtrIrp->IoStatus.Information = BytesReturned; // Free up the Irp Context Ext2ReleaseIrpContext(PtrIrpContext); // complete the IRP IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); } // Flush the saved BCBs... // Ext2FlushSavedBCBs ( PtrIrpContext ); } return(RC); }