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); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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 = ⋆ } 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; }