예제 #1
0
VOID
NTAPI
NpDeleteFcb(IN PNP_FCB Fcb,
            IN PLIST_ENTRY ListEntry)
{
    PNP_DCB Dcb;
    PAGED_CODE();

    Dcb = Fcb->ParentDcb;
    if (Fcb->CurrentInstances) NpBugCheck(0, 0, 0);

    NpCancelWaiter(&NpVcb->WaitQueue,
                   &Fcb->FullName,
                   STATUS_OBJECT_NAME_NOT_FOUND,
                   ListEntry);

    RemoveEntryList(&Fcb->DcbEntry);

    if (Fcb->SecurityDescriptor)
    {
        ObDereferenceSecurityDescriptor(Fcb->SecurityDescriptor, 1);
    }

    RtlRemoveUnicodePrefix(&NpVcb->PrefixTable, &Fcb->PrefixTableEntry);
    ExFreePool(Fcb->FullName.Buffer);
    ExFreePool(Fcb);
    NpCheckForNotify(Dcb, TRUE, ListEntry);
}
예제 #2
0
NTSTATUS
NTAPI
NpCreateRootDcb(VOID)
{
    PNP_DCB Dcb;
    PAGED_CODE();

    if (NpVcb->RootDcb)
    {
        NpBugCheck(0, 0, 0);
    }

    NpVcb->RootDcb = ExAllocatePoolWithTag(PagedPool, sizeof(*Dcb), NPFS_DCB_TAG);
    if (!NpVcb->RootDcb)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    Dcb = NpVcb->RootDcb;
    RtlZeroMemory(Dcb, sizeof(*Dcb));
    Dcb->NodeType = NPFS_NTC_ROOT_DCB;

    InitializeListHead(&Dcb->DcbEntry);
    InitializeListHead(&Dcb->NotifyList);
    InitializeListHead(&Dcb->NotifyList2);
    InitializeListHead(&Dcb->FcbList);

    Dcb->FullName.Buffer = NpRootDCBName;
    Dcb->FullName.Length = 2;
    Dcb->FullName.MaximumLength = 4;

    Dcb->ShortName.Length = Dcb->FullName.Length;
    Dcb->ShortName.MaximumLength = Dcb->FullName.MaximumLength;
    Dcb->ShortName.Buffer = Dcb->FullName.Buffer;

    if (!RtlInsertUnicodePrefix(&NpVcb->PrefixTable,
                                &Dcb->FullName,
                                &Dcb->PrefixTableEntry))
    {
        NpBugCheck(0, 0, 0);
    }

    return STATUS_SUCCESS;
}
예제 #3
0
NTSTATUS
NTAPI
NpSetListeningPipeState(IN PNP_CCB Ccb,
                        IN PIRP Irp,
                        IN PLIST_ENTRY List)
{
    NTSTATUS Status;

    switch (Ccb->NamedPipeState)
    {
        case FILE_PIPE_DISCONNECTED_STATE:

            Status = NpCancelWaiter(&NpVcb->WaitQueue,
                                    &Ccb->Fcb->FullName,
                                    STATUS_SUCCESS,
                                    List);
            if (!NT_SUCCESS(Status)) return Status;

        //
        // Drop down on purpose
        //

        case FILE_PIPE_LISTENING_STATE:

            if (Ccb->CompletionMode[FILE_PIPE_SERVER_END] == FILE_PIPE_COMPLETE_OPERATION)
            {
                Ccb->NamedPipeState = FILE_PIPE_LISTENING_STATE;
                return STATUS_PIPE_LISTENING;
            }

            IoSetCancelRoutine(Irp, NpCancelListeningQueueIrp);
            if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
            {
                return STATUS_CANCELLED;
            }

            Ccb->NamedPipeState = FILE_PIPE_LISTENING_STATE;
            IoMarkIrpPending(Irp);
            InsertTailList(&Ccb->IrpList, &Irp->Tail.Overlay.ListEntry);
            return STATUS_PENDING;

        case FILE_PIPE_CONNECTED_STATE:
            Status = STATUS_PIPE_CONNECTED;
            break;

        case FILE_PIPE_CLOSING_STATE:
            Status = STATUS_PIPE_CLOSING;
            break;

        default:
            NpBugCheck(Ccb->NamedPipeState, 0, 0);
            break;
    }

    return Status;
}
예제 #4
0
NTSTATUS
NTAPI
NpCreateFcb(IN PNP_DCB Dcb,
            IN PUNICODE_STRING PipeName,
            IN ULONG MaximumInstances,
            IN LARGE_INTEGER Timeout,
            IN USHORT NamedPipeConfiguration,
            IN USHORT NamedPipeType,
            OUT PNP_FCB *NewFcb)
{
    PNP_FCB Fcb;
    BOOLEAN RootPipe;
    PWCHAR NameBuffer;
    ULONG BufferOffset;
    USHORT Length, MaximumLength;
    PAGED_CODE();

    Length = PipeName->Length;
    MaximumLength = Length + sizeof(UNICODE_NULL);

    if ((Length < sizeof(WCHAR)) || (MaximumLength < Length))
    {
        return STATUS_INVALID_PARAMETER;
    }

    RootPipe = FALSE;
    if (PipeName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)
    {
        MaximumLength += sizeof(OBJ_NAME_PATH_SEPARATOR);
        RootPipe = TRUE;
        if (MaximumLength < sizeof(WCHAR))
        {
            return STATUS_INVALID_PARAMETER;
        }
    }

    Fcb = ExAllocatePoolWithTag(PagedPool, sizeof(*Fcb), NPFS_FCB_TAG);
    if (!Fcb) return STATUS_INSUFFICIENT_RESOURCES;

    RtlZeroMemory(Fcb, sizeof(*Fcb));
    Fcb->MaximumInstances = MaximumInstances;
    Fcb->Timeout = Timeout;
    Fcb->NodeType = NPFS_NTC_FCB;
    Fcb->ParentDcb = Dcb;
    InitializeListHead(&Fcb->CcbList);

    NameBuffer = ExAllocatePoolWithTag(PagedPool,
                                       MaximumLength,
                                       NPFS_NAME_BLOCK_TAG);
    if (!NameBuffer)
    {
        ExFreePool(Fcb);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    InsertTailList(&Dcb->FcbList, &Fcb->DcbEntry);

    BufferOffset = 0;
    if (RootPipe)
    {
        NameBuffer[0] = OBJ_NAME_PATH_SEPARATOR;
        BufferOffset = 1;
    }

    RtlCopyMemory(NameBuffer + BufferOffset, PipeName->Buffer, Length);
    NameBuffer[BufferOffset + (Length / sizeof(WCHAR))] = UNICODE_NULL;

    Fcb->FullName.Length = Length;
    Fcb->FullName.MaximumLength = MaximumLength;
    Fcb->FullName.Buffer = NameBuffer;

    Fcb->ShortName.MaximumLength = Length;
    Fcb->ShortName.Length = Length - sizeof(OBJ_NAME_PATH_SEPARATOR);
    Fcb->ShortName.Buffer = NameBuffer + 1;

    if (!RtlInsertUnicodePrefix(&NpVcb->PrefixTable,
                                &Fcb->FullName,
                                &Fcb->PrefixTableEntry))
    {
        NpBugCheck(0, 0, 0);
    }

    Fcb->NamedPipeConfiguration = NamedPipeConfiguration;
    Fcb->NamedPipeType = NamedPipeType;
    *NewFcb = Fcb;
    return STATUS_SUCCESS;
}
예제 #5
0
NTSTATUS
NTAPI
NpSetDisconnectedPipeState(IN PNP_CCB Ccb,
                           IN PLIST_ENTRY List)
{
    PIRP Irp;
    PNP_NONPAGED_CCB NonPagedCcb;
    NTSTATUS Status;
    PLIST_ENTRY NextEntry;
    PNP_EVENT_BUFFER EventBuffer;

    NonPagedCcb = Ccb->NonPagedCcb;

    switch (Ccb->NamedPipeState)
    {
        case FILE_PIPE_DISCONNECTED_STATE:
            Status = STATUS_PIPE_DISCONNECTED;
            break;

        case FILE_PIPE_LISTENING_STATE:
            while (!IsListEmpty(&Ccb->IrpList))
            {
                NextEntry = RemoveHeadList(&Ccb->IrpList);

                Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);

                if (IoSetCancelRoutine(Irp, NULL))
                {
                    Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED;
                    InsertTailList(List, NextEntry);
                }
                else
                {
                    InitializeListHead(NextEntry);
                }
            }

            Status = STATUS_SUCCESS;
            break;

        case FILE_PIPE_CONNECTED_STATE:

            EventBuffer = NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END];

            while (Ccb->DataQueue[FILE_PIPE_INBOUND].QueueState != Empty)
            {
                Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_INBOUND], FALSE, List);
                if (Irp)
                {
                    Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED;
                    InsertTailList(List, &Irp->Tail.Overlay.ListEntry);
                }
            }

            while (Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState != Empty)
            {
                Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_OUTBOUND], FALSE, List);
                if (Irp)
                {
                    Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED;
                    InsertTailList(List, &Irp->Tail.Overlay.ListEntry);
                }
            }

            if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE);

            // drop down on purpose... queue will be empty so flush code is nop
            ASSERT(Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState == Empty);

        case FILE_PIPE_CLOSING_STATE:

            EventBuffer = NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END];

            while (Ccb->DataQueue[FILE_PIPE_INBOUND].QueueState != Empty)
            {
                Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_INBOUND], FALSE, List);
                if (Irp)
                {
                    Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED;
                    InsertTailList(List, &Irp->Tail.Overlay.ListEntry);
                }
            }

            ASSERT(Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState == Empty);

            NpDeleteEventTableEntry(&NpVcb->EventTable, EventBuffer);
            NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END] = NULL;

            NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE);
            Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;

            NpUninitializeSecurity(Ccb);

            if (Ccb->ClientSession)
            {
                ExFreePool(Ccb->ClientSession);
                Ccb->ClientSession = NULL;
            }

            Status = STATUS_SUCCESS;
            break;

        default:
            NpBugCheck(Ccb->NamedPipeState, 0, 0);
            break;
    }

    Ccb->NamedPipeState = FILE_PIPE_DISCONNECTED_STATE;
    return Status;
}
예제 #6
0
NTSTATUS
NTAPI
NpSetClosingPipeState(IN PNP_CCB Ccb,
                      IN PIRP Irp,
                      IN ULONG NamedPipeEnd,
                      IN PLIST_ENTRY List)
{
    PNP_NONPAGED_CCB NonPagedCcb;
    PNP_FCB Fcb;
    PLIST_ENTRY NextEntry;
    PNP_DATA_QUEUE ReadQueue, WriteQueue, DataQueue;
    PNP_EVENT_BUFFER EventBuffer;
    PIRP ListIrp;

    NonPagedCcb = Ccb->NonPagedCcb;
    Fcb = Ccb->Fcb;

    switch (Ccb->NamedPipeState)
    {
        case FILE_PIPE_LISTENING_STATE:

            ASSERT(NamedPipeEnd == FILE_PIPE_SERVER_END);

            while (!IsListEmpty(&Ccb->IrpList))
            {
                NextEntry = RemoveHeadList(&Ccb->IrpList);

                ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);

                if (IoSetCancelRoutine(ListIrp, NULL))
                {
                    ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
                    InsertTailList(List, NextEntry);
                }
                else
                {
                    InitializeListHead(NextEntry);
                }
            }

            // Drop on purpose

        case FILE_PIPE_DISCONNECTED_STATE:

            ASSERT(NamedPipeEnd == FILE_PIPE_SERVER_END);

            NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE);
            Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL;

            NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE);
            Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;

            NpDeleteCcb(Ccb, List);
            if (!Fcb->CurrentInstances) NpDeleteFcb(Fcb, List);
            break;

        case FILE_PIPE_CLOSING_STATE:

            if (NamedPipeEnd == FILE_PIPE_SERVER_END)
            {
                DataQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
            }
            else
            {
                DataQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
            }

            NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE);
            Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL;

            NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE);
            Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;

            while (DataQueue->QueueState != Empty)
            {
                ListIrp = NpRemoveDataQueueEntry(DataQueue, FALSE, List);
                if (ListIrp)
                {
                    ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
                    InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry);
                }
            }

            NpUninitializeSecurity(Ccb);

            if (Ccb->ClientSession)
            {
                ExFreePool(Ccb->ClientSession);
                Ccb->ClientSession = NULL;
            }

            NpDeleteCcb(Ccb, List);
            if (!Fcb->CurrentInstances) NpDeleteFcb(Fcb, List);
            break;

        case FILE_PIPE_CONNECTED_STATE:

            if (NamedPipeEnd == FILE_PIPE_SERVER_END)
            {
                ReadQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
                WriteQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];

                NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE);
                Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL;
            }
            else
            {
                ReadQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
                WriteQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];

                NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE);
                Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;
            }

            EventBuffer = NonPagedCcb->EventBuffer[NamedPipeEnd];

            Ccb->NamedPipeState = FILE_PIPE_CLOSING_STATE;

            while (ReadQueue->QueueState != Empty)
            {
                ListIrp = NpRemoveDataQueueEntry(ReadQueue, FALSE, List);
                if (ListIrp)
                {
                    ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
                    InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry);
                }
            }

            while (WriteQueue->QueueState == ReadEntries)
            {
                ListIrp = NpRemoveDataQueueEntry(WriteQueue, FALSE, List);
                if (ListIrp)
                {
                    ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
                    InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry);
                }
            }

            if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE);
            break;

        default:
            NpBugCheck(Ccb->NamedPipeState, 0, 0);
            break;
    }
    return STATUS_SUCCESS;
}
예제 #7
0
NTSTATUS
NpSetPipeInfo (
    IN PFCB Fcb,
    IN PCCB Ccb,
    IN PFILE_PIPE_INFORMATION Buffer,
    IN NAMED_PIPE_END NamedPipeEnd
    )

/*++

Routine Description:

    This routine sets the pipe information for a named pipe.

Arguments:

    Fcb - Supplies the Fcb for the named pipe being modified

    Ccb - Supplies the ccb for the named pipe being modified

    Buffer - Supplies the buffer containing the data being set

    NamedPipeEnd - Supplies the server/client end doing the operation

Return Value:

    NTSTATUS - Returns our completion status

--*/

{
    PDATA_QUEUE ReadQueue;
    PDATA_QUEUE WriteQueue;

    UNREFERENCED_PARAMETER( Ccb );

    PAGED_CODE();

    DebugTrace(0, Dbg, "NpSetPipeInfo...\n", 0);

    //
    //  If the caller requests message mode reads but the pipe is
    //  byte stream then its an invalid parameter
    //

    if ((Buffer->ReadMode == FILE_PIPE_MESSAGE_MODE) &&
        (Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_BYTE_STREAM_MODE)) {

        return STATUS_INVALID_PARAMETER;
    }

    //
    //  Get a reference to our read queue
    //

    switch (NamedPipeEnd) {

    case FILE_PIPE_SERVER_END:

        ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
        WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];

        break;

    case FILE_PIPE_CLIENT_END:

        ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
        WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];

        break;

    default:

        NpBugCheck( NamedPipeEnd, 0, 0 );
    }

    //
    //  If the completion mode is complete operations and the current mode
    //  is queue operations and there and the data queues are not empty
    //  then its pipe busy
    //

    if ((Buffer->CompletionMode == FILE_PIPE_COMPLETE_OPERATION)

            &&

        (Ccb->CompletionMode[ NamedPipeEnd ] == FILE_PIPE_QUEUE_OPERATION)

            &&

        ((NpIsDataQueueReaders(ReadQueue)) ||
         (NpIsDataQueueWriters(WriteQueue)))) {

        return STATUS_PIPE_BUSY;
    }

    //
    //  Everything is fine so update the pipe
    //

    Ccb->ReadMode[ NamedPipeEnd ] = Buffer->ReadMode;
    Ccb->CompletionMode[ NamedPipeEnd ] = Buffer->CompletionMode;

    //
    //  Check for notify
    //

    NpCheckForNotify( Fcb->ParentDcb, FALSE );

    //
    //  And return to our caller
    //

    return STATUS_SUCCESS;
}
예제 #8
0
NTSTATUS
NTAPI
NpPeek(IN PDEVICE_OBJECT DeviceObject,
       IN PIRP Irp,
       IN PLIST_ENTRY List)
{
    PIO_STACK_LOCATION IoStack;
    NODE_TYPE_CODE Type;
    ULONG OutputLength;
    ULONG NamedPipeEnd;
    PNP_CCB Ccb;
    PFILE_PIPE_PEEK_BUFFER PeekBuffer;
    PNP_DATA_QUEUE DataQueue;
    ULONG_PTR BytesPeeked;
    IO_STATUS_BLOCK IoStatus;
    NTSTATUS Status;
    PNP_DATA_QUEUE_ENTRY DataEntry;
    PAGED_CODE();

    IoStack = IoGetCurrentIrpStackLocation(Irp);
    OutputLength = IoStack->Parameters.FileSystemControl.OutputBufferLength;
    Type = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);

    if (!Type)
    {
        return STATUS_PIPE_DISCONNECTED;
    }

    if ((Type != NPFS_NTC_CCB) &&
            (OutputLength < FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data)))
    {
        return STATUS_INVALID_PARAMETER;
    }

    PeekBuffer = (PFILE_PIPE_PEEK_BUFFER)Irp->AssociatedIrp.SystemBuffer;
    if (NamedPipeEnd != FILE_PIPE_CLIENT_END)
    {
        if (NamedPipeEnd != FILE_PIPE_SERVER_END)
        {
            NpBugCheck(NamedPipeEnd, 0, 0);
        }

        DataQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
    }
    else
    {
        DataQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
    }

    if (Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE)
    {
        if (Ccb->NamedPipeState != FILE_PIPE_CLOSING_STATE)
        {
            return STATUS_INVALID_PIPE_STATE;
        }

        if (DataQueue->QueueState != WriteEntries)
        {
            return STATUS_PIPE_BROKEN;
        }
    }

    PeekBuffer->NamedPipeState = 0;
    PeekBuffer->ReadDataAvailable = 0;
    PeekBuffer->NumberOfMessages = 0;
    PeekBuffer->MessageLength = 0;
    PeekBuffer->NamedPipeState = Ccb->NamedPipeState;
    BytesPeeked = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data);

    if (DataQueue->QueueState == WriteEntries)
    {
        DataEntry = CONTAINING_RECORD(DataQueue->Queue.Flink,
                                      NP_DATA_QUEUE_ENTRY,
                                      QueueEntry);
        ASSERT((DataEntry->DataEntryType == Buffered) || (DataEntry->DataEntryType == Unbuffered));

        PeekBuffer->ReadDataAvailable = DataQueue->BytesInQueue - DataQueue->ByteOffset;
        if (Ccb->Fcb->NamedPipeType == FILE_PIPE_MESSAGE_TYPE)
        {
            PeekBuffer->NumberOfMessages = DataQueue->EntriesInQueue;
            PeekBuffer->MessageLength = DataEntry->DataSize - DataQueue->ByteOffset;
        }

        if (OutputLength == FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data))
        {
            Status = PeekBuffer->ReadDataAvailable ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
        }
        else
        {
            IoStatus = NpReadDataQueue(DataQueue,
                                       TRUE,
                                       FALSE,
                                       PeekBuffer->Data,
                                       OutputLength - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data),
                                       Ccb->Fcb->NamedPipeType == FILE_PIPE_MESSAGE_TYPE,
                                       Ccb,
                                       List);
            Status = IoStatus.Status;
            BytesPeeked += IoStatus.Information;
        }
    }
    else
    {
        Status = STATUS_SUCCESS;
    }

    Irp->IoStatus.Information = BytesPeeked;
    return Status;
}
예제 #9
0
파일: dir.c 프로젝트: BillTheBest/WinNT4
NTSTATUS
NpQueryDirectory (
    IN PROOT_DCB RootDcb,
    IN PROOT_DCB_CCB Ccb,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the work routine for querying a directory.

Arugments:

    RootDcb - Supplies the dcb being queried

    Ccb - Supplies the context of the caller

    Irp - Supplies the Irp being processed

Return Value:

    NTSTATUS - The return status for the operation.

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp;

    PUCHAR Buffer;
    CLONG SystemBufferLength;

    UNICODE_STRING FileName;
    ULONG FileIndex;
    FILE_INFORMATION_CLASS FileInformationClass;
    BOOLEAN RestartScan;
    BOOLEAN ReturnSingleEntry;
    BOOLEAN IndexSpecified;

    static WCHAR Star = L'*';

    BOOLEAN CaseInsensitive = TRUE; //*** Make searches case insensitive

    ULONG CurrentIndex;

    ULONG LastEntry;
    ULONG NextEntry;

    PLIST_ENTRY Links;
    PFCB Fcb;

    PFILE_DIRECTORY_INFORMATION DirInfo;
    PFILE_NAMES_INFORMATION NamesInfo;

    PAGED_CODE();

    //
    //  Get the current stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "NpQueryDirectory\n", 0 );
    DebugTrace( 0, Dbg, "RootDcb              = %08lx\n", RootDcb);
    DebugTrace( 0, Dbg, "Ccb                  = %08lx\n", Ccb);
    DebugTrace( 0, Dbg, "SystemBuffer         = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
    DebugTrace( 0, Dbg, "Length               = %08lx\n", IrpSp->Parameters.QueryDirectory.Length);
    DebugTrace( 0, Dbg, "FileName             = %Z\n",    IrpSp->Parameters.QueryDirectory.FileName);
    DebugTrace( 0, Dbg, "FileIndex            = %08lx\n", IrpSp->Parameters.QueryDirectory.FileIndex);
    DebugTrace( 0, Dbg, "FileInformationClass = %08lx\n", IrpSp->Parameters.QueryDirectory.FileInformationClass);
    DebugTrace( 0, Dbg, "RestartScan          = %08lx\n", FlagOn(IrpSp->Flags, SL_RESTART_SCAN));
    DebugTrace( 0, Dbg, "ReturnSingleEntry    = %08lx\n", FlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY));
    DebugTrace( 0, Dbg, "IndexSpecified       = %08lx\n", FlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED));

    //
    //  Save references to the input parameters within the Irp
    //

    SystemBufferLength   = IrpSp->Parameters.QueryDirectory.Length;

    FileIndex            = IrpSp->Parameters.QueryDirectory.FileIndex;

    FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;

    RestartScan          = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN);
    ReturnSingleEntry    = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
    IndexSpecified       = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);

    if (IrpSp->Parameters.QueryDirectory.FileName != NULL) {

        FileName = *(PUNICODE_STRING)IrpSp->Parameters.QueryDirectory.FileName;

    } else {

        FileName.Length = 0;
        FileName.Buffer = NULL;
    }

    //
    //  Check if the ccb already has a query template attached.  If it
    //  does not already have one then we either use the string we are
    //  given or we attach our own containing "*"
    //

    if (Ccb->QueryTemplate == NULL) {

        //
        //  This is our first time calling query directory so we need
        //  to either set the query template to the user specified string
        //  or to "*"
        //

        if (FileName.Buffer == NULL) {

            DebugTrace(0, Dbg, "Set template to *\n", 0);

            FileName.Length = 2;
            FileName.Buffer = &Star;
        }

        DebugTrace(0, Dbg, "Set query template -> %Z\n", &FileName);

        //
        //  Allocate space for the query template
        //

        Ccb->QueryTemplate = FsRtlAllocatePool( PagedPool,
                                                sizeof(UNICODE_STRING) + FileName.Length );

        //
        //  Initialize the query template and copy over the string
        //

        Ccb->QueryTemplate->Length = FileName.Length;
        Ccb->QueryTemplate->Buffer = (PWCH)Ccb->QueryTemplate +
                                     sizeof(UNICODE_STRING) / sizeof(WCHAR);

        RtlCopyMemory( Ccb->QueryTemplate->Buffer,
                       FileName.Buffer,
                       FileName.Length );

        //
        //  Now zero out the FileName so we won't think we're to use it
        //  as a subsearch string.
        //

        FileName.Length = 0;
        FileName.Buffer = NULL;
    }

    //
    //  Check if we were given an index to start with or if we need to
    //  restart the scan or if we should use the index that was saved in
    //  the ccb
    //

    if (RestartScan) {

        FileIndex = 0;

    } else if (!IndexSpecified) {

        FileIndex = Ccb->IndexOfLastCcbReturned + 1;
    }

    //
    //  Now we are committed to completing the Irp, we do that in
    //  the finally clause of the following try.
    //

    try {

        ULONG BaseLength;
        ULONG LengthAdded;

        //
        // Map the user buffer.
        //

        Buffer = NpMapUserBuffer( Irp );

        //
        //  At this point we are about to enter our query loop.  We have
        //  already decided which Fcb index we need to return.  The variables
        //  LastEntry and NextEntry are used to index into the user buffer.
        //  LastEntry is the last entry we added to the user buffer, and
        //  NextEntry is the current one we're working on.  CurrentIndex
        //  is the Fcb index that we are looking at next.  Logically the
        //  way the loop works is as follows.
        //
        //  Scan all of the Fcb in the directory
        //
        //      if the Fcb matches the query template then
        //
        //          if the CurrentIndex is >= the FileIndex then
        //
        //              process this fcb, and decide if we should
        //              continue the main loop
        //
        //          end if
        //
        //          Increment the current index
        //
        //      end if
        //
        //  end scan
        //

        CurrentIndex = 0;

        LastEntry = 0;
        NextEntry =0;

        switch (FileInformationClass) {

        case FileDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
                                       FileName[0] );
            break;

        case FileFullDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
                                       FileName[0] );
            break;

        case FileNamesInformation:

            BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
                                       FileName[0] );
            break;

        case FileBothDirectoryInformation:

            BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
                                       FileName[0] );
            break;

        default:

            try_return( Status = STATUS_INVALID_INFO_CLASS );
        }

        for (Links = RootDcb->Specific.Dcb.ParentDcbQueue.Flink;
             Links != &RootDcb->Specific.Dcb.ParentDcbQueue;
             Links = Links->Flink) {

            Fcb = CONTAINING_RECORD(Links, FCB, ParentDcbLinks);

            ASSERT(Fcb->NodeTypeCode == NPFS_NTC_FCB);

            DebugTrace(0, Dbg, "Top of Loop\n", 0);
            DebugTrace(0, Dbg, "Fcb          = %08lx\n", Fcb);
            DebugTrace(0, Dbg, "CurrentIndex = %08lx\n", CurrentIndex);
            DebugTrace(0, Dbg, "FileIndex    = %08lx\n", FileIndex);
            DebugTrace(0, Dbg, "LastEntry    = %08lx\n", LastEntry);
            DebugTrace(0, Dbg, "NextEntry    = %08lx\n", NextEntry);

            //
            //  Check if the Fcb represents a named pipe that is part of
            //  our query template
            //

            if (FsRtlIsNameInExpression( Ccb->QueryTemplate,
                                         &Fcb->LastFileName,
                                         CaseInsensitive,
                                         NULL )) {

                //
                //  The fcb is in the query template so now check if
                //  this is the index we should start returning
                //

                if (CurrentIndex >= FileIndex) {

                    ULONG BytesToCopy;
                    ULONG BytesRemainingInBuffer;

                    //
                    //  Here are the rules concerning filling up the buffer:
                    //
                    //  1.  The Io system garentees that there will always be
                    //      enough room for at least one base record.
                    //
                    //  2.  If the full first record (including file name) cannot
                    //      fit, as much of the name as possible is copied and
                    //      STATUS_BUFFER_OVERFLOW is returned.
                    //
                    //  3.  If a subsequent record cannot completely fit into the
                    //      buffer, none of it (as in 0 bytes) is copied, and
                    //      STATUS_SUCCESS is returned.  A subsequent query will
                    //      pick up with this record.
                    //

                    BytesRemainingInBuffer = SystemBufferLength - NextEntry;

                    if ( (NextEntry != 0) &&
                         ( (BaseLength + Fcb->LastFileName.Length > BytesRemainingInBuffer) ||
                           (SystemBufferLength < NextEntry) ) ) {

                        DebugTrace(0, Dbg, "Next entry won't fit\n", 0);

                        try_return( Status = STATUS_SUCCESS );
                    }

                    ASSERT( BytesRemainingInBuffer >= BaseLength );

                    //
                    //  See how much of the name we will be able to copy into
                    //  the system buffer.  This also dictates out return
                    //  value.
                    //

                    if ( BaseLength + Fcb->LastFileName.Length <=
                         BytesRemainingInBuffer ) {

                        BytesToCopy = Fcb->LastFileName.Length;
                        Status = STATUS_SUCCESS;

                    } else {

                        BytesToCopy = BytesRemainingInBuffer - BaseLength;
                        Status = STATUS_BUFFER_OVERFLOW;
                    }

                    //
                    //  Note how much of buffer we are consuming and zero
                    //  the base part of the structure.
                    //

                    LengthAdded = BaseLength + BytesToCopy;

                    RtlZeroMemory( &Buffer[NextEntry], BaseLength );

                    //
                    //  Now fill the base parts of the strucure that are
                    //  applicable.
                    //

                    switch (FileInformationClass) {

                    case FileBothDirectoryInformation:

                        //
                        //  We don't need short name
                        //

                        DebugTrace(0, Dbg, "Getting directory full information\n", 0);

                    case FileFullDirectoryInformation:

                        //
                        //  We don't use EaLength, so fill in nothing here.
                        //

                        DebugTrace(0, Dbg, "Getting directory full information\n", 0);

                    case FileDirectoryInformation:

                        DebugTrace(0, Dbg, "Getting directory information\n", 0);

                        //
                        //  The eof indicates the number of instances and
                        //  allocation size is the maximum allowed
                        //

                        DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry];

                        DirInfo->EndOfFile.QuadPart = Fcb->OpenCount;
                        DirInfo->AllocationSize.QuadPart = Fcb->Specific.Fcb.MaximumInstances;

                        DirInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL;

                        DirInfo->FileNameLength = Fcb->LastFileName.Length;

                        break;

                    case FileNamesInformation:

                        DebugTrace(0, Dbg, "Getting names information\n", 0);


                        NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry];

                        NamesInfo->FileNameLength = Fcb->LastFileName.Length;

                        break;

                    default:

                        NpBugCheck( FileInformationClass, 0, 0 );
                    }

                    RtlCopyMemory( &Buffer[NextEntry + BaseLength],
                                   Fcb->LastFileName.Buffer,
                                   BytesToCopy );

                    //
                    //  Update the ccb to the index we've just used
                    //

                    Ccb->IndexOfLastCcbReturned = CurrentIndex;

                    //
                    //  And indicate how much of the system buffer we have
                    //  currently used up.  We must compute this value before
                    //  we long align outselves for the next entry
                    //

                    Irp->IoStatus.Information = NextEntry + LengthAdded;

                    //
                    //  Setup the previous next entry offset
                    //

                    *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry;

                    //
                    //  Check if the last entry didn't completely fit
                    //

                    if ( Status == STATUS_BUFFER_OVERFLOW ) {

                        try_return( NOTHING );
                    }

                    //
                    //  Check if we are only to return a single entry
                    //

                    if (ReturnSingleEntry) {

                        try_return( Status = STATUS_SUCCESS );
                    }

                    //
                    //  Set ourselves up for the next iteration
                    //

                    LastEntry = NextEntry;
                    NextEntry += (ULONG)QuadAlign( LengthAdded );
                }

                //
                //  Increment the current index by one
                //

                CurrentIndex += 1;
            }
        }

        //
        //  At this point we've scanned the entire list of Fcb so if
        //  the NextEntry is zero then we haven't found anything so we
        //  will return no more files, otherwise we return success.
        //

        if (NextEntry == 0) {

            Status = STATUS_NO_MORE_FILES;

        } else {

            Status = STATUS_SUCCESS;
        }

    try_exit: NOTHING;
    } finally {

        if (!AbnormalTermination()) {

            NpCompleteRequest( Irp, Status );
        }

        DebugTrace(-1, Dbg, "NpQueryDirectory -> %08lx\n", Status);
    }

    return Status;
}