2013-09-11 23:19:20 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Named Pipe FileSystem
|
|
|
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
|
|
|
* FILE: drivers/filesystems/npfs/main.c
|
|
|
|
* PURPOSE: Named Pipe FileSystem Driver Initialization
|
|
|
|
* PROGRAMMERS: ReactOS Portable Systems Group
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
|
2013-09-07 15:32:29 +00:00
|
|
|
#include "npfs.h"
|
|
|
|
|
2013-09-12 00:05:54 +00:00
|
|
|
// File ID number for NPFS bugchecking support
|
|
|
|
#define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_MAIN)
|
|
|
|
|
2013-09-11 23:19:20 +00:00
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
|
2013-09-07 15:32:29 +00:00
|
|
|
PDEVICE_OBJECT NpfsDeviceObject;
|
2014-02-01 14:28:15 +00:00
|
|
|
PVOID NpAliases;
|
|
|
|
PNPFS_ALIAS NpAliasList;
|
|
|
|
PNPFS_ALIAS NpAliasListByLength[MAX_INDEXED_LENGTH + 1 - MIN_INDEXED_LENGTH];
|
2013-09-07 15:32:29 +00:00
|
|
|
|
2014-02-01 20:41:16 +00:00
|
|
|
FAST_IO_DISPATCH NpFastIoDispatch =
|
|
|
|
{
|
|
|
|
sizeof(FAST_IO_DISPATCH),
|
|
|
|
NULL,
|
|
|
|
NpFastRead,
|
|
|
|
NpFastWrite,
|
|
|
|
};
|
|
|
|
|
2013-09-11 23:19:20 +00:00
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
|
2014-02-01 14:28:15 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NpReadAlias(
|
|
|
|
PWSTR ValueName,
|
|
|
|
ULONG ValueType,
|
|
|
|
PVOID ValueData,
|
|
|
|
ULONG ValueLength,
|
|
|
|
PVOID Context,
|
|
|
|
PVOID EntryContext)
|
|
|
|
{
|
|
|
|
PNPFS_QUERY_VALUE_CONTEXT QueryContext = Context;
|
|
|
|
PWSTR CurrentString;
|
2021-06-29 16:50:15 +00:00
|
|
|
SIZE_T Length;
|
2014-02-01 14:28:15 +00:00
|
|
|
PNPFS_ALIAS CurrentAlias;
|
|
|
|
UNICODE_STRING TempString;
|
|
|
|
PUNICODE_STRING CurrentTargetName;
|
|
|
|
|
|
|
|
/* Check if we have the expected type */
|
|
|
|
if (ValueType != REG_MULTI_SZ)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if only the size is requested */
|
|
|
|
if (QueryContext->SizeOnly)
|
|
|
|
{
|
|
|
|
/* Count this entry */
|
|
|
|
QueryContext->NumberOfEntries++;
|
|
|
|
|
|
|
|
/* Get the length of the value name (i.e. the target name). */
|
|
|
|
Length = wcslen(ValueName) * sizeof(WCHAR);
|
|
|
|
|
|
|
|
/* Add the size of the name plus a '\' and a UNICODE_STRING structure */
|
|
|
|
QueryContext->FullSize += Length + sizeof(UNICODE_NULL) +
|
|
|
|
sizeof(OBJ_NAME_PATH_SEPARATOR) +
|
|
|
|
sizeof(UNICODE_STRING);
|
|
|
|
|
|
|
|
/* Loop while we have alias names */
|
|
|
|
CurrentString = ValueData;
|
|
|
|
while (*CurrentString != UNICODE_NULL)
|
|
|
|
{
|
|
|
|
/* Count this alias */
|
|
|
|
QueryContext->NumberOfAliases++;
|
|
|
|
|
|
|
|
/* Get the length of the current string (i.e. the alias name) */
|
|
|
|
Length = wcslen(CurrentString) * sizeof(WCHAR);
|
|
|
|
|
|
|
|
/* Count the length plus the size of an NPFS_ALIAS structure */
|
|
|
|
QueryContext->FullSize += Length + sizeof(UNICODE_NULL) + sizeof(NPFS_ALIAS);
|
|
|
|
|
|
|
|
/* Go to the next string */
|
|
|
|
CurrentString += (Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Get the next name string pointer */
|
|
|
|
CurrentTargetName = QueryContext->CurrentTargetName++;
|
|
|
|
|
|
|
|
/* Get the length of the value name (i.e. the target name). */
|
|
|
|
Length = wcslen(ValueName) * sizeof(WCHAR);
|
|
|
|
|
|
|
|
/* Initialize the current name string (one char more than the name) */
|
|
|
|
CurrentTargetName->Buffer = QueryContext->CurrentStringPointer;
|
|
|
|
CurrentTargetName->Length = Length + sizeof(OBJ_NAME_PATH_SEPARATOR);
|
|
|
|
CurrentTargetName->MaximumLength = CurrentTargetName->Length + sizeof(UNICODE_NULL);
|
|
|
|
|
|
|
|
/* Update the current string pointer */
|
|
|
|
QueryContext->CurrentStringPointer +=
|
|
|
|
CurrentTargetName->MaximumLength / sizeof(WCHAR);
|
|
|
|
|
|
|
|
/* Prepend a '\' before the name */
|
|
|
|
CurrentTargetName->Buffer[0] = OBJ_NAME_PATH_SEPARATOR;
|
|
|
|
|
|
|
|
/* Append the value name (including the NULL termination) */
|
|
|
|
RtlCopyMemory(&CurrentTargetName->Buffer[1],
|
|
|
|
ValueName,
|
|
|
|
Length + sizeof(UNICODE_NULL));
|
|
|
|
|
|
|
|
/* Upcase the target name */
|
|
|
|
RtlUpcaseUnicodeString(CurrentTargetName, CurrentTargetName, 0);
|
|
|
|
|
|
|
|
/* Loop while we have alias names */
|
|
|
|
CurrentString = ValueData;
|
|
|
|
while (*CurrentString != UNICODE_NULL)
|
|
|
|
{
|
|
|
|
/* Get the next alias pointer */
|
|
|
|
CurrentAlias = QueryContext->CurrentAlias++;
|
|
|
|
|
|
|
|
/* Get the length of the current string (i.e. the alias name) */
|
|
|
|
Length = wcslen(CurrentString) * sizeof(WCHAR);
|
|
|
|
|
|
|
|
/* Setup the alias structure */
|
|
|
|
CurrentAlias->TargetName = CurrentTargetName;
|
|
|
|
CurrentAlias->Name.Buffer = QueryContext->CurrentStringPointer;
|
|
|
|
CurrentAlias->Name.Length = Length;
|
|
|
|
CurrentAlias->Name.MaximumLength = Length + sizeof(UNICODE_NULL);
|
|
|
|
|
|
|
|
/* Upcase the alias name */
|
|
|
|
TempString.Buffer = CurrentString;
|
|
|
|
TempString.Length = Length;
|
|
|
|
RtlUpcaseUnicodeString(&CurrentAlias->Name,
|
|
|
|
&TempString,
|
|
|
|
FALSE);
|
|
|
|
|
|
|
|
/* Update the current string pointer */
|
|
|
|
QueryContext->CurrentStringPointer +=
|
|
|
|
CurrentAlias->Name.MaximumLength / sizeof(WCHAR);
|
|
|
|
|
|
|
|
/* Go to the next string */
|
|
|
|
CurrentString += (Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
LONG
|
|
|
|
NTAPI
|
|
|
|
NpCompareAliasNames(
|
|
|
|
_In_ PCUNICODE_STRING String1,
|
|
|
|
_In_ PCUNICODE_STRING String2)
|
|
|
|
{
|
|
|
|
ULONG Count;
|
|
|
|
PWCHAR P1, P2;
|
|
|
|
|
|
|
|
/* First check if the string sizes match */
|
|
|
|
if (String1->Length != String2->Length)
|
|
|
|
{
|
|
|
|
/* They don't, return positive if the first is longer, negative otherwise */
|
|
|
|
return String1->Length - String2->Length;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now loop all characters */
|
|
|
|
Count = String1->Length / sizeof(WCHAR);
|
|
|
|
P1 = String1->Buffer;
|
|
|
|
P2 = String2->Buffer;
|
|
|
|
while (Count)
|
|
|
|
{
|
|
|
|
/* Check if they don't match */
|
|
|
|
if (*P1 != *P2)
|
|
|
|
{
|
|
|
|
/* Return positive if the first char is greater, negative otherwise */
|
|
|
|
return *P1 - *P2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Go to the next buffer position */
|
|
|
|
P1++;
|
|
|
|
P2++;
|
|
|
|
Count--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All characters matched, return 0 */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NpInitializeAliases(VOID)
|
|
|
|
{
|
|
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
|
|
NPFS_QUERY_VALUE_CONTEXT Context;
|
|
|
|
NTSTATUS Status;
|
|
|
|
USHORT Length;
|
|
|
|
ULONG i;
|
|
|
|
PNPFS_ALIAS CurrentAlias, *AliasPointer;
|
|
|
|
|
|
|
|
/* Initialize the query table */
|
|
|
|
QueryTable[0].QueryRoutine = NpReadAlias;
|
|
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
|
|
|
|
QueryTable[0].Name = NULL;
|
|
|
|
QueryTable[0].EntryContext = NULL;
|
|
|
|
QueryTable[0].DefaultType = REG_NONE;
|
|
|
|
QueryTable[0].DefaultData = NULL;
|
|
|
|
QueryTable[0].DefaultLength = 0;
|
|
|
|
QueryTable[1].QueryRoutine = NULL;
|
|
|
|
QueryTable[1].Flags = 0;
|
|
|
|
QueryTable[1].Name = NULL;
|
|
|
|
|
|
|
|
/* Setup the query context */
|
|
|
|
Context.SizeOnly = 1;
|
|
|
|
Context.FullSize = 0;
|
|
|
|
Context.NumberOfAliases = 0;
|
|
|
|
Context.NumberOfEntries = 0;
|
|
|
|
|
|
|
|
/* Query the registry values (calculate length only) */
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
|
|
|
|
L"Npfs\\Aliases",
|
|
|
|
QueryTable,
|
|
|
|
&Context,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if there is anything */
|
|
|
|
if (Context.FullSize == 0)
|
|
|
|
{
|
|
|
|
/* Nothing to do, return success */
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate a structure large enough to hold all the data */
|
|
|
|
NpAliases = ExAllocatePoolWithTag(NonPagedPool, Context.FullSize, 'sfpN');
|
|
|
|
if (NpAliases == NULL)
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
|
|
|
/* Now setup the actual pointers in the context */
|
|
|
|
Context.CurrentTargetName = NpAliases;
|
|
|
|
CurrentAlias = (PNPFS_ALIAS)&Context.CurrentTargetName[Context.NumberOfEntries];
|
|
|
|
Context.CurrentAlias = CurrentAlias;
|
|
|
|
Context.CurrentStringPointer = (PWCHAR)&CurrentAlias[Context.NumberOfAliases];
|
|
|
|
|
|
|
|
/* This time query the real data */
|
|
|
|
Context.SizeOnly = FALSE;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
|
|
|
|
L"Npfs\\Aliases",
|
|
|
|
QueryTable,
|
|
|
|
&Context,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
ExFreePoolWithTag(NpAliases, 0);
|
|
|
|
NpAliases = NULL;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure we didn't go past the end of the allocation! */
|
|
|
|
NT_ASSERT((PUCHAR)Context.CurrentStringPointer <=
|
|
|
|
((PUCHAR)NpAliases + Context.FullSize));
|
|
|
|
|
|
|
|
/* Loop all aliases we got */
|
|
|
|
for (i = 0; i < Context.NumberOfAliases; i++)
|
|
|
|
{
|
|
|
|
/* Get the length and check what list to use */
|
|
|
|
Length = CurrentAlias->Name.Length;
|
|
|
|
if ((Length >= MIN_INDEXED_LENGTH * sizeof(WCHAR)) &&
|
|
|
|
(Length <= MAX_INDEXED_LENGTH * sizeof(WCHAR)))
|
|
|
|
{
|
|
|
|
/* For this length range, we use an indexed list */
|
|
|
|
AliasPointer = &NpAliasListByLength[(Length / sizeof(WCHAR)) - 5];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Length is outside of the range, use the default list */
|
|
|
|
AliasPointer = &NpAliasList;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loop through all aliases already in the list until we find one that
|
|
|
|
is greater than our current alias */
|
|
|
|
while ((*AliasPointer != NULL) &&
|
|
|
|
(NpCompareAliasNames(&CurrentAlias->Name,
|
|
|
|
&(*AliasPointer)->Name) > 0))
|
|
|
|
{
|
|
|
|
/* Go to the next alias */
|
|
|
|
AliasPointer = &(*AliasPointer)->Next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Insert the alias in the list */
|
|
|
|
CurrentAlias->Next = *AliasPointer;
|
|
|
|
*AliasPointer = CurrentAlias;
|
|
|
|
|
|
|
|
/* Go to the next alias in the array */
|
|
|
|
CurrentAlias++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-07 15:32:29 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NpFsdDirectoryControl(IN PDEVICE_OBJECT DeviceObject,
|
|
|
|
IN PIRP Irp)
|
|
|
|
{
|
2014-02-01 14:28:15 +00:00
|
|
|
TRACE("Entered\n");
|
2013-09-07 15:32:29 +00:00
|
|
|
UNIMPLEMENTED;
|
|
|
|
|
|
|
|
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2014-02-01 20:41:16 +00:00
|
|
|
|
2013-09-07 15:32:29 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
DriverEntry(IN PDRIVER_OBJECT DriverObject,
|
|
|
|
IN PUNICODE_STRING RegistryPath)
|
|
|
|
{
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
UNICODE_STRING DeviceName;
|
|
|
|
NTSTATUS Status;
|
|
|
|
UNREFERENCED_PARAMETER(RegistryPath);
|
|
|
|
|
2014-03-08 11:37:03 +00:00
|
|
|
DPRINT("Next-Generation NPFS-Advanced\n");
|
2013-09-07 15:32:29 +00:00
|
|
|
|
2014-02-01 14:28:15 +00:00
|
|
|
Status = NpInitializeAliases();
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to initialize aliases!\n");
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2013-09-07 15:32:29 +00:00
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = NpFsdCreate;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = NpFsdCreateNamedPipe;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = NpFsdClose;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_READ] = NpFsdRead;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = NpFsdWrite;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = NpFsdQueryInformation;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = NpFsdSetInformation;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = NpFsdQueryVolumeInformation;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NpFsdCleanup;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = NpFsdFlushBuffers;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = NpFsdDirectoryControl;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = NpFsdFileSystemControl;
|
2013-09-11 17:10:30 +00:00
|
|
|
DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = NpFsdQuerySecurityInfo;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = NpFsdSetSecurityInfo;
|
2013-09-07 15:32:29 +00:00
|
|
|
|
|
|
|
DriverObject->DriverUnload = NULL;
|
|
|
|
|
2014-02-01 20:41:16 +00:00
|
|
|
DriverObject->FastIoDispatch = &NpFastIoDispatch;
|
|
|
|
|
2013-09-13 07:49:42 +00:00
|
|
|
RtlInitUnicodeString(&DeviceName, L"\\Device\\NamedPipe");
|
2013-09-07 15:32:29 +00:00
|
|
|
Status = IoCreateDevice(DriverObject,
|
|
|
|
sizeof(NP_VCB),
|
|
|
|
&DeviceName,
|
|
|
|
FILE_DEVICE_NAMED_PIPE,
|
|
|
|
0,
|
|
|
|
FALSE,
|
|
|
|
&DeviceObject);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to create named pipe device! (Status %lx)\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the device object */
|
|
|
|
NpfsDeviceObject = DeviceObject;
|
2013-09-11 07:05:15 +00:00
|
|
|
DeviceObject->Flags |= DO_LONG_TERM_REQUESTS;
|
2013-09-07 15:32:29 +00:00
|
|
|
|
|
|
|
/* Initialize the Volume Control Block (VCB) */
|
|
|
|
NpVcb = DeviceObject->DeviceExtension;
|
|
|
|
NpInitializeVcb();
|
|
|
|
Status = NpCreateRootDcb();
|
|
|
|
ASSERT(Status == STATUS_SUCCESS);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
2013-09-11 23:19:20 +00:00
|
|
|
|
|
|
|
/* EOF */
|