Exemplo n.º 1
0
/*
 * 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;
}
Exemplo n.º 2
0
/*
 * 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;
}
Exemplo n.º 3
0
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);
}
Exemplo n.º 4
0
Arquivo: fat.c Projeto: RPG-7/reactos
/*
 * 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;
}
Exemplo n.º 5
0
Arquivo: fat.c Projeto: RPG-7/reactos
/*
 * 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;
}
Exemplo n.º 6
0
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);
}
Exemplo n.º 7
0
Arquivo: fat.c Projeto: RPG-7/reactos
/*
 * 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;
}
Exemplo n.º 8
0
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;
}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 11
0
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;
}
Exemplo n.º 12
0
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;
}
Exemplo n.º 13
0
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);
}
Exemplo n.º 14
0
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;
}
Exemplo n.º 15
0
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;
}
Exemplo n.º 16
0
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;
}
Exemplo n.º 17
0
/*
* 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;
}
Exemplo n.º 18
0
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;
}
Exemplo n.º 19
0
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;
}
Exemplo n.º 20
0
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;
}
Exemplo n.º 21
0
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;
}
Exemplo n.º 22
0
Arquivo: fat.c Projeto: RPG-7/reactos
/*
 * 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;
}
Exemplo n.º 23
0
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;
}
Exemplo n.º 24
0
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;
}
Exemplo n.º 25
0
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);
}
Exemplo n.º 26
0
/*
* 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);
}
Exemplo n.º 27
0
/*
 * 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;
    }
Exemplo n.º 28
0
/*************************************************************************
*
* 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;
}
Exemplo n.º 29
0
/*************************************************************************
*
* 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);
}