/* GLOBALS ********************************************************************/
PDEVICE_OBJECT NpfsDeviceObject;
+PVOID NpAliases;
+PNPFS_ALIAS NpAliasList;
+PNPFS_ALIAS NpAliasListByLength[MAX_INDEXED_LENGTH + 1 - MIN_INDEXED_LENGTH];
+
+FAST_IO_DISPATCH NpFastIoDispatch =
+{
+ sizeof(FAST_IO_DISPATCH),
+ NULL,
+ NpFastRead,
+ NpFastWrite,
+};
/* FUNCTIONS ******************************************************************/
+NTSTATUS
+NTAPI
+NpReadAlias(
+ PWSTR ValueName,
+ ULONG ValueType,
+ PVOID ValueData,
+ ULONG ValueLength,
+ PVOID Context,
+ PVOID EntryContext)
+{
+ PNPFS_QUERY_VALUE_CONTEXT QueryContext = Context;
+ PWSTR CurrentString;
+ USHORT Length;
+ 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;
+}
+
+
NTSTATUS
NTAPI
NpFsdDirectoryControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
+ TRACE("Entered\n");
UNIMPLEMENTED;
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
+
NTSTATUS
NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject,
NTSTATUS Status;
UNREFERENCED_PARAMETER(RegistryPath);
- DPRINT1("Next-Generation NPFS-Lite\n");
+ DPRINT("Next-Generation NPFS-Advanced\n");
+
+ Status = NpInitializeAliases();
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to initialize aliases!\n");
+ return Status;
+ }
DriverObject->MajorFunction[IRP_MJ_CREATE] = NpFsdCreate;
DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = NpFsdCreateNamedPipe;
DriverObject->DriverUnload = NULL;
+ DriverObject->FastIoDispatch = &NpFastIoDispatch;
+
RtlInitUnicodeString(&DeviceName, L"\\Device\\NamedPipe");
Status = IoCreateDevice(DriverObject,
sizeof(NP_VCB),