mirror of
https://github.com/reactos/reactos.git
synced 2024-11-05 14:19:25 +00:00
f22ed7dc10
Sync trunk up to r50570. svn path=/branches/cmake-bringup/; revision=50581
336 lines
12 KiB
C
336 lines
12 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: drivers/filesastems/npfs/dirctl.c
|
|
* PURPOSE: Named pipe filesystem
|
|
* PROGRAMMER: Eric Kohl
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include "npfs.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
static NTSTATUS
|
|
NpfsQueryDirectory(PNPFS_CCB Ccb,
|
|
PIRP Irp,
|
|
PULONG Size)
|
|
{
|
|
PIO_STACK_LOCATION Stack;
|
|
LONG BufferLength = 0;
|
|
PUNICODE_STRING SearchPattern = NULL;
|
|
FILE_INFORMATION_CLASS FileInformationClass;
|
|
ULONG FileIndex = 0;
|
|
PUCHAR Buffer = NULL;
|
|
BOOLEAN First = FALSE;
|
|
PLIST_ENTRY CurrentEntry;
|
|
PNPFS_VCB Vcb;
|
|
PNPFS_FCB PipeFcb;
|
|
ULONG PipeIndex;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PFILE_NAMES_INFORMATION NamesBuffer;
|
|
PFILE_DIRECTORY_INFORMATION DirectoryBuffer;
|
|
PFILE_FULL_DIR_INFORMATION FullDirBuffer;
|
|
PFILE_BOTH_DIR_INFORMATION BothDirBuffer;
|
|
ULONG InfoSize = 0;
|
|
ULONG NameLength;
|
|
ULONG CurrentOffset = 0;
|
|
ULONG LastOffset = 0;
|
|
PULONG NextEntryOffset;
|
|
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* Obtain the callers parameters */
|
|
BufferLength = Stack->Parameters.QueryDirectory.Length;
|
|
SearchPattern = Stack->Parameters.QueryDirectory.FileName;
|
|
FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
|
|
FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
|
|
|
|
DPRINT("SearchPattern: %p '%wZ'\n", SearchPattern, SearchPattern);
|
|
|
|
/* Determine Buffer for result */
|
|
if (Irp->MdlAddress)
|
|
{
|
|
Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
|
|
}
|
|
else
|
|
{
|
|
Buffer = Irp->UserBuffer;
|
|
}
|
|
|
|
/* Build the search pattern string */
|
|
DPRINT("Ccb->u.Directory.SearchPattern.Buffer: %p\n", Ccb->u.Directory.SearchPattern.Buffer);
|
|
if (Ccb->u.Directory.SearchPattern.Buffer == NULL)
|
|
{
|
|
First = TRUE;
|
|
|
|
if (SearchPattern != NULL)
|
|
{
|
|
Ccb->u.Directory.SearchPattern.Buffer =
|
|
ExAllocatePool(NonPagedPool, SearchPattern->Length + sizeof(WCHAR));
|
|
if (Ccb->u.Directory.SearchPattern.Buffer == NULL)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Ccb->u.Directory.SearchPattern.Length = SearchPattern->Length;
|
|
Ccb->u.Directory.SearchPattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
|
|
RtlCopyMemory(Ccb->u.Directory.SearchPattern.Buffer,
|
|
SearchPattern->Buffer,
|
|
SearchPattern->Length);
|
|
Ccb->u.Directory.SearchPattern.Buffer[SearchPattern->Length / sizeof(WCHAR)] = 0;
|
|
}
|
|
else
|
|
{
|
|
Ccb->u.Directory.SearchPattern.Buffer =
|
|
ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR));
|
|
if (Ccb->u.Directory.SearchPattern.Buffer == NULL)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Ccb->u.Directory.SearchPattern.Length = sizeof(WCHAR);
|
|
Ccb->u.Directory.SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
|
|
Ccb->u.Directory.SearchPattern.Buffer[0] = L'*';
|
|
Ccb->u.Directory.SearchPattern.Buffer[1] = 0;
|
|
}
|
|
}
|
|
DPRINT("Search pattern: '%wZ'\n", &Ccb->u.Directory.SearchPattern);
|
|
|
|
/* Determine the file index */
|
|
if (First || (Stack->Flags & SL_RESTART_SCAN))
|
|
{
|
|
FileIndex = 0;
|
|
}
|
|
else if ((Stack->Flags & SL_INDEX_SPECIFIED) == 0)
|
|
{
|
|
FileIndex = Ccb->u.Directory.FileIndex + 1;
|
|
}
|
|
DPRINT("FileIndex: %lu\n", FileIndex);
|
|
|
|
DPRINT("Buffer = %p tofind = %wZ\n", Buffer, &Ccb->u.Directory.SearchPattern);
|
|
|
|
switch (FileInformationClass)
|
|
{
|
|
case FileDirectoryInformation:
|
|
InfoSize = sizeof(FILE_DIRECTORY_INFORMATION) - sizeof(WCHAR);
|
|
break;
|
|
|
|
case FileFullDirectoryInformation:
|
|
InfoSize = sizeof(FILE_FULL_DIR_INFORMATION) - sizeof(WCHAR);
|
|
break;
|
|
|
|
case FileBothDirectoryInformation:
|
|
InfoSize = sizeof(FILE_BOTH_DIR_INFORMATION) - sizeof(WCHAR);
|
|
break;
|
|
|
|
case FileNamesInformation:
|
|
InfoSize = sizeof(FILE_NAMES_INFORMATION) - sizeof(WCHAR);
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("Invalid information class: %lu\n", FileInformationClass);
|
|
return STATUS_INVALID_INFO_CLASS;
|
|
}
|
|
|
|
PipeIndex = 0;
|
|
|
|
Vcb = Ccb->Fcb->Vcb;
|
|
CurrentEntry = Vcb->PipeListHead.Flink;
|
|
while (CurrentEntry != &Vcb->PipeListHead &&
|
|
Status == STATUS_SUCCESS)
|
|
{
|
|
/* Get the FCB of the next pipe */
|
|
PipeFcb = CONTAINING_RECORD(CurrentEntry,
|
|
NPFS_FCB,
|
|
PipeListEntry);
|
|
|
|
/* Make sure it is a pipe FCB */
|
|
ASSERT(PipeFcb->Type == FCB_PIPE);
|
|
|
|
DPRINT("PipeName: %wZ\n", &PipeFcb->PipeName);
|
|
|
|
if (FsRtlIsNameInExpression(&Ccb->u.Directory.SearchPattern,
|
|
&PipeFcb->PipeName,
|
|
TRUE,
|
|
NULL))
|
|
{
|
|
DPRINT("Found pipe: %wZ\n", &PipeFcb->PipeName);
|
|
|
|
if (PipeIndex >= FileIndex)
|
|
{
|
|
/* Determine whether or not the full pipe name fits into the buffer */
|
|
if (InfoSize + PipeFcb->PipeName.Length > BufferLength)
|
|
{
|
|
NameLength = BufferLength - InfoSize;
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
NameLength = PipeFcb->PipeName.Length;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Initialize the information struct */
|
|
RtlZeroMemory(&Buffer[CurrentOffset], InfoSize);
|
|
|
|
switch (FileInformationClass)
|
|
{
|
|
case FileDirectoryInformation:
|
|
DirectoryBuffer = (PFILE_DIRECTORY_INFORMATION)&Buffer[CurrentOffset];
|
|
DirectoryBuffer->FileIndex = PipeIndex;
|
|
DirectoryBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
DirectoryBuffer->EndOfFile.QuadPart = PipeFcb->CurrentInstances;
|
|
DirectoryBuffer->AllocationSize.LowPart = PipeFcb->MaximumInstances;
|
|
DirectoryBuffer->FileNameLength = NameLength;
|
|
RtlCopyMemory(DirectoryBuffer->FileName,
|
|
PipeFcb->PipeName.Buffer,
|
|
NameLength);
|
|
break;
|
|
|
|
case FileFullDirectoryInformation:
|
|
FullDirBuffer = (PFILE_FULL_DIR_INFORMATION)&Buffer[CurrentOffset];
|
|
FullDirBuffer->FileIndex = PipeIndex;
|
|
FullDirBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
FullDirBuffer->EndOfFile.QuadPart = PipeFcb->CurrentInstances;
|
|
FullDirBuffer->AllocationSize.LowPart = PipeFcb->MaximumInstances;
|
|
FullDirBuffer->FileNameLength = NameLength;
|
|
RtlCopyMemory(FullDirBuffer->FileName,
|
|
PipeFcb->PipeName.Buffer,
|
|
NameLength);
|
|
break;
|
|
|
|
case FileBothDirectoryInformation:
|
|
BothDirBuffer = (PFILE_BOTH_DIR_INFORMATION)&Buffer[CurrentOffset];
|
|
BothDirBuffer->NextEntryOffset = 0;
|
|
BothDirBuffer->FileIndex = PipeIndex;
|
|
BothDirBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
BothDirBuffer->EndOfFile.QuadPart = PipeFcb->CurrentInstances;
|
|
BothDirBuffer->AllocationSize.LowPart = PipeFcb->MaximumInstances;
|
|
BothDirBuffer->FileNameLength = NameLength;
|
|
RtlCopyMemory(BothDirBuffer->FileName,
|
|
PipeFcb->PipeName.Buffer,
|
|
NameLength);
|
|
break;
|
|
|
|
case FileNamesInformation:
|
|
NamesBuffer = (PFILE_NAMES_INFORMATION)&Buffer[CurrentOffset];
|
|
NamesBuffer->FileIndex = PipeIndex;
|
|
NamesBuffer->FileNameLength = NameLength;
|
|
RtlCopyMemory(NamesBuffer->FileName,
|
|
PipeFcb->PipeName.Buffer,
|
|
NameLength);
|
|
break;
|
|
|
|
default:
|
|
/* Should never happen! */
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
DPRINT("CurrentOffset: %lu\n", CurrentOffset);
|
|
|
|
/* Store the current pipe index in the CCB */
|
|
Ccb->u.Directory.FileIndex = PipeIndex;
|
|
|
|
/* Get the pointer to the previous entries NextEntryOffset */
|
|
NextEntryOffset = (PULONG)&Buffer[LastOffset];
|
|
|
|
/* Set the previous entries NextEntryOffset */
|
|
*NextEntryOffset = CurrentOffset - LastOffset;
|
|
|
|
/* Return the used buffer size */
|
|
*Size = CurrentOffset + InfoSize + NameLength;
|
|
|
|
/* Leave, if there is no space left in the buffer */
|
|
if (Status == STATUS_BUFFER_OVERFLOW)
|
|
return Status;
|
|
|
|
/* Leave, if we should return only one entry */
|
|
if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
|
|
return STATUS_SUCCESS;
|
|
|
|
/* Store the current offset for the next round */
|
|
LastOffset = CurrentOffset;
|
|
|
|
/* Set the offset for the next entry */
|
|
CurrentOffset += ROUND_UP(InfoSize + NameLength, sizeof(ULONG));
|
|
}
|
|
|
|
PipeIndex++;
|
|
}
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
}
|
|
|
|
/* Return STATUS_NO_MORE_FILES if no matching pipe name was found */
|
|
if (CurrentOffset == 0)
|
|
Status = STATUS_NO_MORE_FILES;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
NpfsDirectoryControl(PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PFILE_OBJECT FileObject;
|
|
PNPFS_CCB Ccb;
|
|
PNPFS_FCB Fcb;
|
|
NTSTATUS Status;
|
|
ULONG Size = 0;
|
|
|
|
DPRINT("NpfsDirectoryControl() called\n");
|
|
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
FileObject = IoStack->FileObject;
|
|
|
|
if (NpfsGetCcb(FileObject, &Ccb) != CCB_DIRECTORY)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return Status;
|
|
}
|
|
|
|
Fcb = Ccb->Fcb;
|
|
|
|
switch (IoStack->MinorFunction)
|
|
{
|
|
case IRP_MN_QUERY_DIRECTORY:
|
|
Status = NpfsQueryDirectory(Ccb,
|
|
Irp,
|
|
&Size);
|
|
break;
|
|
|
|
case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
|
|
DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("NPFS: MinorFunction %d\n", IoStack->MinorFunction);
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
Irp->IoStatus.Information = Size;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/* EOF */
|